1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package util.build;
18 
19 import java.io.File;
20 import java.io.FileWriter;
21 import java.io.IOException;
22 import java.io.Writer;
23 import java.util.ArrayList;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Set;
27 
28 public class JackBuildStep extends SourceBuildStep {
29 
30     private final String destPath;
31     private final String classPath;
32     private final Set<String> sourceFiles = new HashSet<String>();
33 
JackBuildStep(String destPath, String classPath)34     public JackBuildStep(String destPath, String classPath) {
35         super(new File(destPath));
36         this.destPath = destPath;
37         this.classPath = classPath;
38     }
39 
40     @Override
addSourceFile(String sourceFile)41     public void addSourceFile(String sourceFile) {
42         sourceFiles.add(sourceFile);
43     }
44 
45     @Override
build()46     boolean build() {
47         if (super.build()) {
48             if (sourceFiles.isEmpty()) {
49                 return true;
50             }
51 
52             File outDir = new File(destPath).getParentFile();
53             if (!outDir.exists() && !outDir.mkdirs()) {
54                 System.err.println("failed to create output dir: "
55                         + outDir.getAbsolutePath());
56                 return false;
57             }
58 
59             File tmpOutDir = new File(outDir, outputFile.fileName.getName() + ".dexTmp");
60             if (!tmpOutDir.exists() && !tmpOutDir.mkdirs()) {
61                 System.err.println("failed to create temp dir: "
62                         + tmpOutDir.getAbsolutePath());
63                 return false;
64             }
65             File tmpDex = new File(tmpOutDir, "classes.dex");
66 
67             File tmpArgs = new File(outDir, outputFile.fileName.getName() + ".args");
68 
69             Writer argsOut = null;
70             try {
71                 argsOut = new FileWriter(tmpArgs);
72                 for (String source : sourceFiles) {
73                     argsOut.append(source);
74                     argsOut.append('\n');
75                 }
76                 argsOut.close();
77                 argsOut = null;
78 
79                 List<String> commandLine = new ArrayList<String>(6 + sourceFiles.size());
80                 commandLine.add("--verbose");
81                 commandLine.add("error");
82                 commandLine.add("--classpath");
83                 commandLine.add(classPath);
84                 commandLine.add("--output-dex");
85                 commandLine.add(tmpOutDir.getAbsolutePath());
86                 commandLine.add("@" + tmpArgs.getPath());
87 
88                 ExecuteFile exec = new ExecuteFile(JackBuildDalvikSuite.JACK,
89                     commandLine.toArray(new String[commandLine.size()]));
90                 exec.setErr(System.err);
91                 exec.setOut(System.out);
92                 if (!exec.run()) {
93                     return false;
94                 }
95 
96                 JarBuildStep jarStep = new JarBuildStep(
97                     new BuildFile(tmpDex),
98                     "classes.dex",
99                     outputFile,
100                     /* deleteInputFileAfterBuild = */ true);
101                 if (!jarStep.build()) {
102                   throw new IOException("Failed to make jar: " + outputFile.getPath());
103                 }
104                 return true;
105             } catch (Throwable ex) {
106                 ex.printStackTrace();
107                 return false;
108             } finally {
109                 tmpDex.delete();
110                 tmpArgs.delete();
111                 tmpOutDir.delete();
112                 if (argsOut != null) {
113                     try {
114                         argsOut.close();
115                     } catch (IOException io) {
116                         // Ignore, don't override already thrown exception
117                     }
118                 }
119             }
120         }
121         return false;
122     }
123 
124     @Override
equals(Object obj)125     public boolean equals(Object obj) {
126         if (super.equals(obj)) {
127             JackBuildStep other = (JackBuildStep) obj;
128             return destPath.equals(other.destPath) && classPath.equals(other.classPath)
129                     && sourceFiles.equals(other.sourceFiles);
130         }
131         return false;
132     }
133 
134     @Override
hashCode()135     public int hashCode() {
136         return destPath.hashCode() ^ classPath.hashCode() ^ sourceFiles.hashCode();
137     }
138 }
139