Home | History | Annotate | Download | only in proguard
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 Eric Lafortune (eric (at) 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  */
     21 package proguard;
     22 
     23 import java.io.File;
     24 
     25 /**
     26  * This class checks whether the output is up to date.
     27  *
     28  * @author Eric Lafortune
     29  */
     30 public class UpToDateChecker
     31 {
     32     private final Configuration configuration;
     33 
     34 
     35     /**
     36      * Creates a new UpToDateChecker with the given configuration.
     37      */
     38     public UpToDateChecker(Configuration configuration)
     39     {
     40         this.configuration = configuration;
     41     }
     42 
     43 
     44     /**
     45      * Returns whether the output is up to date, based on the modification times
     46      * of the input jars, output jars, and library jars (or directories).
     47      */
     48     public boolean check()
     49     {
     50         try
     51         {
     52             ModificationTimeChecker checker = new ModificationTimeChecker();
     53 
     54             checker.updateInputModificationTime(configuration.lastModified);
     55 
     56             ClassPath programJars = configuration.programJars;
     57             ClassPath libraryJars = configuration.libraryJars;
     58 
     59             // Check the dates of the program jars, if any.
     60             if (programJars != null)
     61             {
     62                 for (int index = 0; index < programJars.size(); index++)
     63                 {
     64                     // Update the input and output modification times.
     65                     ClassPathEntry classPathEntry = programJars.get(index);
     66 
     67                     checker.updateModificationTime(classPathEntry.getFile(),
     68                                                    classPathEntry.isOutput());
     69                 }
     70             }
     71 
     72             // Check the dates of the library jars, if any.
     73             if (libraryJars != null)
     74             {
     75                 for (int index = 0; index < libraryJars.size(); index++)
     76                 {
     77                     // Update the input modification time.
     78                     ClassPathEntry classPathEntry = libraryJars.get(index);
     79 
     80                     checker.updateModificationTime(classPathEntry.getFile(),
     81                                                    false);
     82                 }
     83             }
     84 
     85             // Check the dates of the auxiliary input files.
     86             checker.updateInputModificationTime(configuration.applyMapping);
     87             checker.updateInputModificationTime(configuration.obfuscationDictionary);
     88             checker.updateInputModificationTime(configuration.classObfuscationDictionary);
     89             checker.updateInputModificationTime(configuration.packageObfuscationDictionary);
     90 
     91             // Check the dates of the auxiliary output files.
     92             checker.updateOutputModificationTime(configuration.printSeeds);
     93             checker.updateOutputModificationTime(configuration.printUsage);
     94             checker.updateOutputModificationTime(configuration.printMapping);
     95             checker.updateOutputModificationTime(configuration.printConfiguration);
     96             checker.updateOutputModificationTime(configuration.dump);
     97         }
     98         catch (IllegalStateException e)
     99         {
    100             // The output is outdated.
    101             return false;
    102         }
    103 
    104         System.out.println("The output seems up to date");
    105 
    106         return true;
    107     }
    108 
    109 
    110     /**
    111      * This class maintains the modification times of input and output.
    112      * The methods throw an IllegalStateException if the output appears
    113      * outdated.
    114      */
    115     private static class ModificationTimeChecker {
    116 
    117         private long inputModificationTime  = Long.MIN_VALUE;
    118         private long outputModificationTime = Long.MAX_VALUE;
    119 
    120 
    121         /**
    122          * Updates the input modification time based on the given file or
    123          * directory (recursively).
    124          */
    125         public void updateInputModificationTime(File file)
    126         {
    127             if (file != null)
    128             {
    129                 updateModificationTime(file, false);
    130             }
    131         }
    132 
    133 
    134         /**
    135          * Updates the input modification time based on the given file or
    136          * directory (recursively).
    137          */
    138         public void updateOutputModificationTime(File file)
    139         {
    140             if (file != null && file.getName().length() > 0)
    141             {
    142                 updateModificationTime(file, true);
    143             }
    144         }
    145 
    146 
    147         /**
    148          * Updates the specified modification time based on the given file or
    149          * directory (recursively).
    150          */
    151         public void updateModificationTime(File file, boolean isOutput)
    152         {
    153             // Is it a directory?
    154             if (file.isDirectory())
    155             {
    156                 // Ignore the directory's modification time; just recurse on
    157                 // its files.
    158                 File[] files = file.listFiles();
    159 
    160                 // Still, an empty output directory is probably a sign that it
    161                 // is not up to date.
    162                 if (files.length == 0 && isOutput)
    163                 {
    164                     updateOutputModificationTime(Long.MIN_VALUE);
    165                 }
    166 
    167                 for (int index = 0; index < files.length; index++)
    168                 {
    169                     updateModificationTime(files[index], isOutput);
    170                 }
    171             }
    172             else
    173             {
    174                 // Update with the file's modification time.
    175                 updateModificationTime(file.lastModified(), isOutput);
    176             }
    177         }
    178 
    179 
    180         /**
    181          * Updates the specified modification time.
    182          */
    183         public void updateModificationTime(long time, boolean isOutput)
    184         {
    185             if (isOutput)
    186             {
    187                 updateOutputModificationTime(time);
    188             }
    189             else
    190             {
    191                 updateInputModificationTime(time);
    192             }
    193         }
    194 
    195 
    196         /**
    197          * Updates the input modification time.
    198          */
    199         public void updateInputModificationTime(long time)
    200         {
    201             if (inputModificationTime < time)
    202             {
    203                 inputModificationTime = time;
    204 
    205                 checkModificationTimes();
    206             }
    207         }
    208 
    209 
    210         /**
    211          * Updates the output modification time.
    212          */
    213         public void updateOutputModificationTime(long time)
    214         {
    215             if (outputModificationTime > time)
    216             {
    217                 outputModificationTime = time;
    218 
    219                 checkModificationTimes();
    220             }
    221         }
    222 
    223 
    224         private void checkModificationTimes()
    225         {
    226             if (inputModificationTime > outputModificationTime)
    227             {
    228                 throw new IllegalStateException("The output is outdated");
    229             }
    230         }
    231     }
    232 }
    233