37 import java.text.SimpleDateFormat; |
36 import java.text.SimpleDateFormat; |
38 import java.net.URI; |
37 import java.net.URI; |
39 import java.util.*; |
38 import java.util.*; |
40 |
39 |
41 import com.sun.tools.sjavac.options.Options; |
40 import com.sun.tools.sjavac.options.Options; |
42 import com.sun.tools.sjavac.options.SourceLocation; |
41 import com.sun.tools.sjavac.server.Sjavac; |
43 import com.sun.tools.sjavac.server.JavacService; |
|
44 |
42 |
45 /** |
43 /** |
46 * The javac state class maintains the previous (prev) and the current (now) |
44 * The javac state class maintains the previous (prev) and the current (now) |
47 * build states and everything else that goes into the javac_state file. |
45 * build states and everything else that goes into the javac_state file. |
48 * |
46 * |
49 * <p><b>This is NOT part of any supported API. |
47 * <p><b>This is NOT part of any supported API. |
50 * If you write code that depends on this, you do so at your own |
48 * If you write code that depends on this, you do so at your own risk. |
51 * risk. This code and its internal interfaces are subject to change |
49 * This code and its internal interfaces are subject to change or |
52 * or deletion without notice.</b></p> |
50 * deletion without notice.</b> |
53 */ |
51 */ |
54 public class JavacState |
52 public class JavacState { |
55 { |
|
56 // The arguments to the compile. If not identical, then it cannot |
53 // The arguments to the compile. If not identical, then it cannot |
57 // be an incremental build! |
54 // be an incremental build! |
58 String theArgs; |
55 String theArgs; |
59 // The number of cores limits how many threads are used for heavy concurrent work. |
56 // The number of cores limits how many threads are used for heavy concurrent work. |
60 int numCores; |
57 int numCores; |
61 |
58 |
62 // The bin_dir/javac_state |
59 // The bin_dir/javac_state |
63 private String javacStateFilename; |
|
64 private File javacState; |
60 private File javacState; |
65 |
61 |
66 // The previous build state is loaded from javac_state |
62 // The previous build state is loaded from javac_state |
67 private BuildState prev; |
63 private BuildState prev; |
68 // The current build state is constructed during the build, |
64 // The current build state is constructed during the build, |
97 // Copy over the javac_state for the packages that did not need recompilation, |
93 // Copy over the javac_state for the packages that did not need recompilation, |
98 // verbatim from the previous (prev) to the new (now) build state. |
94 // verbatim from the previous (prev) to the new (now) build state. |
99 private Set<String> recompiledPackages; |
95 private Set<String> recompiledPackages; |
100 |
96 |
101 // The output directories filled with tasty artifacts. |
97 // The output directories filled with tasty artifacts. |
102 private File binDir, gensrcDir, headerDir; |
98 private File binDir, gensrcDir, headerDir, stateDir; |
103 |
99 |
104 // The current status of the file system. |
100 // The current status of the file system. |
105 private Set<File> binArtifacts; |
101 private Set<File> binArtifacts; |
106 private Set<File> gensrcArtifacts; |
102 private Set<File> gensrcArtifacts; |
107 private Set<File> headerArtifacts; |
103 private Set<File> headerArtifacts; |
126 private CompileJavaPackages compileJavaPackages = new CompileJavaPackages(); |
122 private CompileJavaPackages compileJavaPackages = new CompileJavaPackages(); |
127 |
123 |
128 // Where to send stdout and stderr. |
124 // Where to send stdout and stderr. |
129 private PrintStream out, err; |
125 private PrintStream out, err; |
130 |
126 |
131 JavacState(Options options, boolean removeJavacState, PrintStream o, PrintStream e) { |
127 // Command line options. |
|
128 private Options options; |
|
129 |
|
130 JavacState(Options op, boolean removeJavacState, PrintStream o, PrintStream e) { |
|
131 options = op; |
132 out = o; |
132 out = o; |
133 err = e; |
133 err = e; |
134 numCores = options.getNumCores(); |
134 numCores = options.getNumCores(); |
135 theArgs = options.getStateArgsString(); |
135 theArgs = options.getStateArgsString(); |
136 binDir = Util.pathToFile(options.getDestDir()); |
136 binDir = Util.pathToFile(options.getDestDir()); |
137 gensrcDir = Util.pathToFile(options.getGenSrcDir()); |
137 gensrcDir = Util.pathToFile(options.getGenSrcDir()); |
138 headerDir = Util.pathToFile(options.getHeaderDir()); |
138 headerDir = Util.pathToFile(options.getHeaderDir()); |
139 javacStateFilename = binDir.getPath()+File.separator+"javac_state"; |
139 stateDir = Util.pathToFile(options.getStateDir()); |
140 javacState = new File(javacStateFilename); |
140 javacState = new File(stateDir, "javac_state"); |
141 if (removeJavacState && javacState.exists()) { |
141 if (removeJavacState && javacState.exists()) { |
142 javacState.delete(); |
142 javacState.delete(); |
143 } |
143 } |
144 newJavacState = false; |
144 newJavacState = false; |
145 if (!javacState.exists()) { |
145 if (!javacState.exists()) { |
146 newJavacState = true; |
146 newJavacState = true; |
147 // If there is no javac_state then delete the contents of all the artifact dirs! |
147 // If there is no javac_state then delete the contents of all the artifact dirs! |
148 // We do not want to risk building a broken incremental build. |
148 // We do not want to risk building a broken incremental build. |
149 // BUT since the makefiles still copy things straight into the bin_dir et al, |
149 // BUT since the makefiles still copy things straight into the bin_dir et al, |
150 // we avoid deleting files here, if the option --permit-unidentified-classes was supplied. |
150 // we avoid deleting files here, if the option --permit-unidentified-classes was supplied. |
151 if (!options.isUnidentifiedArtifactPermitted()) { |
151 if (!options.areUnidentifiedArtifactsPermitted()) { |
152 deleteContents(binDir); |
152 deleteContents(binDir); |
153 deleteContents(gensrcDir); |
153 deleteContents(gensrcDir); |
154 deleteContents(headerDir); |
154 deleteContents(headerDir); |
155 } |
155 } |
156 needsSaving = true; |
156 needsSaving = true; |
266 /** |
266 /** |
267 * Save the javac_state file. |
267 * Save the javac_state file. |
268 */ |
268 */ |
269 public void save() throws IOException { |
269 public void save() throws IOException { |
270 if (!needsSaving) return; |
270 if (!needsSaving) return; |
271 try (FileWriter out = new FileWriter(javacStateFilename)) { |
271 try (FileWriter out = new FileWriter(javacState)) { |
272 StringBuilder b = new StringBuilder(); |
272 StringBuilder b = new StringBuilder(); |
273 long millisNow = System.currentTimeMillis(); |
273 long millisNow = System.currentTimeMillis(); |
274 Date d = new Date(millisNow); |
274 Date d = new Date(millisNow); |
275 SimpleDateFormat df = |
275 SimpleDateFormat df = |
276 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); |
276 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); |
309 boolean noFileFound = false; |
309 boolean noFileFound = false; |
310 boolean foundCorrectVerNr = false; |
310 boolean foundCorrectVerNr = false; |
311 boolean newCommandLine = false; |
311 boolean newCommandLine = false; |
312 boolean syntaxError = false; |
312 boolean syntaxError = false; |
313 |
313 |
314 try (BufferedReader in = new BufferedReader(new FileReader(db.javacStateFilename))) { |
314 try (BufferedReader in = new BufferedReader(new FileReader(db.javacState))) { |
315 for (;;) { |
315 for (;;) { |
316 String l = in.readLine(); |
316 String l = in.readLine(); |
317 if (l==null) break; |
317 if (l==null) break; |
318 if (l.length()>=3 && l.charAt(1) == ' ') { |
318 if (l.length()>=3 && l.charAt(1) == ' ') { |
319 char c = l.charAt(0); |
319 char c = l.charAt(0); |
510 } |
510 } |
511 // Do not forget about javac_state.... |
511 // Do not forget about javac_state.... |
512 allKnownArtifacts.add(javacState); |
512 allKnownArtifacts.add(javacState); |
513 |
513 |
514 for (File f : binArtifacts) { |
514 for (File f : binArtifacts) { |
515 if (!allKnownArtifacts.contains(f)) { |
515 if (!allKnownArtifacts.contains(f) && |
|
516 !options.isUnidentifiedArtifactPermitted(f.getAbsolutePath())) { |
516 Log.debug("Removing "+f.getPath()+" since it is unknown to the javac_state."); |
517 Log.debug("Removing "+f.getPath()+" since it is unknown to the javac_state."); |
517 f.delete(); |
518 f.delete(); |
518 } |
519 } |
519 } |
520 } |
520 for (File f : headerArtifacts) { |
521 for (File f : headerArtifacts) { |
603 } |
604 } |
604 |
605 |
605 /** |
606 /** |
606 * Recursively delete a directory and all its contents. |
607 * Recursively delete a directory and all its contents. |
607 */ |
608 */ |
608 private static void deleteContents(File dir) { |
609 private void deleteContents(File dir) { |
609 if (dir != null && dir.exists()) { |
610 if (dir != null && dir.exists()) { |
610 for (File f : dir.listFiles()) { |
611 for (File f : dir.listFiles()) { |
611 if (f.isDirectory()) { |
612 if (f.isDirectory()) { |
612 deleteContents(f); |
613 deleteContents(f); |
613 } |
614 } |
614 f.delete(); |
615 if (!options.isUnidentifiedArtifactPermitted(f.getAbsolutePath())) { |
|
616 Log.debug("Removing "+f.getAbsolutePath()); |
|
617 f.delete(); |
|
618 } |
615 } |
619 } |
616 } |
620 } |
617 } |
621 } |
618 |
622 |
619 /** |
623 /** |
646 } |
650 } |
647 |
651 |
648 /** |
652 /** |
649 * Compile all the java sources. Return true, if it needs to be called again! |
653 * Compile all the java sources. Return true, if it needs to be called again! |
650 */ |
654 */ |
651 public boolean performJavaCompilations(JavacService javacService, |
655 public boolean performJavaCompilations(Sjavac sjavac, |
652 Options args, |
656 Options args, |
653 Set<String> recentlyCompiled, |
657 Set<String> recentlyCompiled, |
654 boolean[] rcValue) { |
658 boolean[] rcValue) { |
655 Map<String,Transformer> suffixRules = new HashMap<>(); |
659 Map<String,Transformer> suffixRules = new HashMap<>(); |
656 suffixRules.put(".java", compileJavaPackages); |
660 suffixRules.put(".java", compileJavaPackages); |
657 compileJavaPackages.setExtra(args); |
661 compileJavaPackages.setExtra(args); |
658 |
662 |
659 rcValue[0] = perform(javacService, binDir, suffixRules); |
663 rcValue[0] = perform(sjavac, binDir, suffixRules); |
660 recentlyCompiled.addAll(taintedPackages()); |
664 recentlyCompiled.addAll(taintedPackages()); |
661 clearTaintedPackages(); |
665 clearTaintedPackages(); |
662 boolean again = !packagesWithChangedPublicApis.isEmpty(); |
666 boolean again = !packagesWithChangedPublicApis.isEmpty(); |
663 taintPackagesDependingOnChangedPackages(packagesWithChangedPublicApis, recentlyCompiled); |
667 taintPackagesDependingOnChangedPackages(packagesWithChangedPublicApis, recentlyCompiled); |
664 packagesWithChangedPublicApis = new HashSet<>(); |
668 packagesWithChangedPublicApis = new HashSet<>(); |
684 |
688 |
685 /** |
689 /** |
686 * For all packages, find all sources belonging to the package, group the sources |
690 * For all packages, find all sources belonging to the package, group the sources |
687 * based on their transformers and apply the transformers on each source code group. |
691 * based on their transformers and apply the transformers on each source code group. |
688 */ |
692 */ |
689 private boolean perform(JavacService javacService, |
693 private boolean perform(Sjavac sjavac, |
690 File outputDir, |
694 File outputDir, |
691 Map<String,Transformer> suffixRules) |
695 Map<String,Transformer> suffixRules) { |
692 { |
|
693 boolean rc = true; |
696 boolean rc = true; |
694 // Group sources based on transforms. A source file can only belong to a single transform. |
697 // Group sources based on transforms. A source file can only belong to a single transform. |
695 Map<Transformer,Map<String,Set<URI>>> groupedSources = new HashMap<>(); |
698 Map<Transformer,Map<String,Set<URI>>> groupedSources = new HashMap<>(); |
696 for (Source src : now.sources().values()) { |
699 for (Source src : now.sources().values()) { |
697 Transformer t = suffixRules.get(src.suffix()); |
700 Transformer t = suffixRules.get(src.suffix()); |
711 Map<String,Set<String>> packageDependencies = |
714 Map<String,Set<String>> packageDependencies = |
712 Collections.synchronizedMap(new HashMap<String,Set<String>>()); |
715 Collections.synchronizedMap(new HashMap<String,Set<String>>()); |
713 Map<String,String> packagePublicApis = |
716 Map<String,String> packagePublicApis = |
714 Collections.synchronizedMap(new HashMap<String, String>()); |
717 Collections.synchronizedMap(new HashMap<String, String>()); |
715 |
718 |
716 boolean r = t.transform(javacService, |
719 boolean r = t.transform(sjavac, |
717 srcs, |
720 srcs, |
718 visibleSrcs, |
721 visibleSrcs, |
719 visibleClasses, |
722 visibleClasses, |
720 prev.dependents(), |
723 prev.dependents(), |
721 outputDir.toURI(), |
724 outputDir.toURI(), |
789 /** |
792 /** |
790 * Compare the calculate source list, with an explicit list, usually supplied from the makefile. |
793 * Compare the calculate source list, with an explicit list, usually supplied from the makefile. |
791 * Used to detect bugs where the makefile and sjavac have different opinions on which files |
794 * Used to detect bugs where the makefile and sjavac have different opinions on which files |
792 * should be compiled. |
795 * should be compiled. |
793 */ |
796 */ |
794 public void compareWithMakefileList(File makefileSourceList) |
797 public void compareWithMakefileList(File makefileSourceList) throws ProblemException { |
795 throws ProblemException |
|
796 { |
|
797 // If we are building on win32 using for example cygwin the paths in the makefile source list |
798 // If we are building on win32 using for example cygwin the paths in the makefile source list |
798 // might be /cygdrive/c/.... which does not match c:\.... |
799 // might be /cygdrive/c/.... which does not match c:\.... |
799 // We need to adjust our calculated sources to be identical, if necessary. |
800 // We need to adjust our calculated sources to be identical, if necessary. |
800 boolean mightNeedRewriting = File.pathSeparatorChar == ';'; |
801 boolean mightNeedRewriting = File.pathSeparatorChar == ';'; |
801 |
802 |