1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.ant;
22
23import org.apache.tools.ant.BuildException;
24import proguard.*;
25import proguard.classfile.util.ClassUtil;
26
27import java.io.*;
28import java.util.*;
29
30/**
31 * This Task allows to configure and run ProGuard from Ant.
32 *
33 * @author Eric Lafortune
34 */
35public class ProGuardTask extends ConfigurationTask
36{
37    // Ant task attributes.
38
39    public void setConfiguration(File configurationFile) throws BuildException
40    {
41        try
42        {
43            // Get the combined system properties and Ant properties, for
44            // replacing ProGuard-style properties ('<...>').
45            Properties properties = new Properties();
46            properties.putAll(getProject().getProperties());
47
48            ConfigurationParser parser = new ConfigurationParser(configurationFile,
49                                                                 properties);
50            try
51            {
52                parser.parse(configuration);
53            }
54            catch (ParseException ex)
55            {
56                throw new BuildException(ex.getMessage());
57            }
58            finally
59            {
60                parser.close();
61            }
62        }
63        catch (IOException ex)
64        {
65            throw new BuildException(ex.getMessage());
66        }
67    }
68
69
70    /**
71     * @deprecated Use the nested outjar element instead.
72     */
73    public void setOutjar(String parameters)
74    {
75        throw new BuildException("Use the <outjar> nested element instead of the 'outjar' attribute");
76    }
77
78
79    public void setSkipnonpubliclibraryclasses(boolean skipNonPublicLibraryClasses)
80    {
81        configuration.skipNonPublicLibraryClasses = skipNonPublicLibraryClasses;
82    }
83
84
85    public void setSkipnonpubliclibraryclassmembers(boolean skipNonPublicLibraryClassMembers)
86    {
87        configuration.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembers;
88    }
89
90
91    public void setTarget(String target)
92    {
93        configuration.targetClassVersion = ClassUtil.internalClassVersion(target);
94        if (configuration.targetClassVersion == 0)
95        {
96            throw new BuildException("Unsupported target '"+target+"'");
97        }
98    }
99
100
101    public void setForceprocessing(boolean forceProcessing)
102    {
103        configuration.lastModified = forceProcessing ? Long.MAX_VALUE : 0;
104    }
105
106
107    public void setPrintseeds(File printSeeds)
108    {
109        configuration.printSeeds = optionalFile(printSeeds);
110    }
111
112
113    public void setShrink(boolean shrink)
114    {
115        configuration.shrink = shrink;
116    }
117
118
119    public void setPrintusage(File printUsage)
120    {
121        configuration.printUsage = optionalFile(printUsage);
122    }
123
124
125    public void setOptimize(boolean optimize)
126    {
127        configuration.optimize = optimize;
128    }
129
130
131    public void setOptimizationpasses(int optimizationPasses)
132    {
133        configuration.optimizationPasses = optimizationPasses;
134    }
135
136
137    public void setAllowaccessmodification(boolean allowAccessModification)
138    {
139        configuration.allowAccessModification = allowAccessModification;
140    }
141
142
143    public void setMergeinterfacesaggressively(boolean mergeinterfacesaggressively)
144    {
145        configuration.mergeInterfacesAggressively = mergeinterfacesaggressively;
146    }
147
148
149    public void setObfuscate(boolean obfuscate)
150    {
151        configuration.obfuscate = obfuscate;
152    }
153
154
155    public void setPrintmapping(File printMapping)
156    {
157        configuration.printMapping = optionalFile(printMapping);
158    }
159
160
161    public void setApplymapping(File applyMapping)
162    {
163        configuration.applyMapping = resolvedFile(applyMapping);
164    }
165
166
167    public void setObfuscationdictionary(File obfuscationDictionary)
168    {
169        configuration.obfuscationDictionary = resolvedFile(obfuscationDictionary);
170    }
171
172
173    public void setClassobfuscationdictionary(File classObfuscationDictionary)
174    {
175        configuration.classObfuscationDictionary = resolvedFile(classObfuscationDictionary);
176    }
177
178
179    public void setPackageobfuscationdictionary(File packageObfuscationDictionary)
180    {
181        configuration.packageObfuscationDictionary = resolvedFile(packageObfuscationDictionary);
182    }
183
184
185    public void setOverloadaggressively(boolean overloadAggressively)
186    {
187        configuration.overloadAggressively = overloadAggressively;
188    }
189
190
191    public void setUseuniqueclassmembernames(boolean useUniqueClassMemberNames)
192    {
193        configuration.useUniqueClassMemberNames = useUniqueClassMemberNames;
194    }
195
196
197    public void setUsemixedcaseclassnames(boolean useMixedCaseClassNames)
198    {
199        configuration.useMixedCaseClassNames = useMixedCaseClassNames;
200    }
201
202
203    public void setFlattenpackagehierarchy(String flattenPackageHierarchy)
204    {
205        configuration.flattenPackageHierarchy = ClassUtil.internalClassName(flattenPackageHierarchy);
206    }
207
208
209    public void setRepackageclasses(String repackageClasses)
210    {
211        configuration.repackageClasses = ClassUtil.internalClassName(repackageClasses);
212    }
213
214    /**
215     * @deprecated Use the repackageclasses attribute instead.
216     */
217    public void setDefaultpackage(String defaultPackage)
218    {
219        configuration.repackageClasses = ClassUtil.internalClassName(defaultPackage);
220    }
221
222
223    public void setKeepparameternames(boolean keepParameterNames)
224    {
225        configuration.keepParameterNames = keepParameterNames;
226    }
227
228
229    public void setRenamesourcefileattribute(String newSourceFileAttribute)
230    {
231        configuration.newSourceFileAttribute = newSourceFileAttribute;
232    }
233
234
235    public void setPreverify(boolean preverify)
236    {
237        configuration.preverify = preverify;
238    }
239
240
241    public void setMicroedition(boolean microEdition)
242    {
243        configuration.microEdition = microEdition;
244    }
245
246
247    public void setVerbose(boolean verbose)
248    {
249        configuration.verbose = verbose;
250    }
251
252
253    public void setNote(boolean note)
254    {
255        if (note)
256        {
257            // Switch on notes if they were completely disabled.
258            if (configuration.note != null &&
259                configuration.note.isEmpty())
260            {
261                configuration.note = null;
262            }
263        }
264        else
265        {
266            // Switch off notes.
267            configuration.note = new ArrayList();
268        }
269    }
270
271
272    public void setWarn(boolean warn)
273    {
274        if (warn)
275        {
276            // Switch on warnings if they were completely disabled.
277            if (configuration.warn != null &&
278                configuration.warn.isEmpty())
279            {
280                configuration.warn = null;
281            }
282        }
283        else
284        {
285            // Switch off warnings.
286            configuration.warn = new ArrayList();
287        }
288    }
289
290
291    public void setIgnorewarnings(boolean ignoreWarnings)
292    {
293        configuration.ignoreWarnings = ignoreWarnings;
294    }
295
296
297    public void setPrintconfiguration(File printConfiguration)
298    {
299        configuration.printConfiguration = optionalFile(printConfiguration);
300    }
301
302
303    public void setDump(File dump)
304    {
305        configuration.dump = optionalFile(dump);
306    }
307
308
309    // Implementations for Task.
310
311    public void execute() throws BuildException
312    {
313        try
314        {
315            ProGuard proGuard = new ProGuard(configuration);
316            proGuard.execute();
317        }
318        catch (IOException ex)
319        {
320            throw new BuildException(ex.getMessage());
321        }
322    }
323
324
325    // Small utility methods.
326
327    /**
328     * Returns a file that is properly resolved with respect to the project
329     * directory, or <code>null</code> or empty if its name is actually a
330     * boolean flag.
331     */
332    private File optionalFile(File file)
333    {
334        String fileName = file.getName();
335
336        return
337            fileName.equalsIgnoreCase("false") ||
338            fileName.equalsIgnoreCase("no")    ||
339            fileName.equalsIgnoreCase("off")    ? null :
340            fileName.equalsIgnoreCase("true")  ||
341            fileName.equalsIgnoreCase("yes")   ||
342            fileName.equalsIgnoreCase("on")     ? Configuration.STD_OUT :
343                                                  resolvedFile(file);
344    }
345
346
347    /**
348     * Returns a file that is properly resolved with respect to the project
349     * directory.
350     */
351    private File resolvedFile(File file)
352    {
353        return file.isAbsolute() ? file :
354                                   new File(getProject().getBaseDir(),
355                                            file.getName());
356    }
357}
358