8000 Fix issue #1 (#10) · sakerbuild/saker.java.compiler@6c25805 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6c25805

Browse files
authored
Fix issue #1 (#10)
* Cache annotation processor classpaths in repository storage dir The input classpaths from where the saker.java.processor task loads the annotation processors are cached in the storage directory associated with the saker.java.compiler package. * Add API for representing static classpath in ClassPathEntry * Report execution property dependency on cached jar outputs So if they are deleted between build executions, they are re-cached again.
1 parent c1b55de commit 6c25805

File tree

11 files changed

+824
-365
lines changed

11 files changed

+824
-365
lines changed

api/src/main/saker/java/compiler/api/classpath/ClassPathEntry.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,45 @@ public default StructuredTaskResult getDocumentationAttachment() {
120120
* In general, if the implementation version key of a classpath changes, the dependent code needs to be re-executed
121121
* or recompiled.
122122
* <p>
123-
* The implementation verison key should include all aspects of the class files available in the (non-transitive)
123+
* The implementation version key should include all aspects of the class files available in the (non-transitive)
124124
* classpath.
125125
*
126126
* @return The implementation version key or <code>null</code> if none.
127127
* @see JavaCompilerWorkerTaskOutput#getImplementationVersionKey()
128128
*/
129129
public Object getImplementationVersionKey();
130130

131+
/**
132+
* Checks if the {@linkplain #getFileLocation() file location} of this classpath may be considered static.
133+
* <p>
134+
* A static classpath is one that doesn't change during the lifetime of the enclosing build environment. The files
135+
* of a static classpath will not be attempted to be modified by other agents on the same computer. If the classpath
136+
* represents a directory, then the enclosed files in the directory mustn't change. If it is a JAR, or other
137+
* archive, then the file itself mustn't change.
138+
* <p>
139+
* If a classpath is static, that means that the users of the classpath are allowed to load the files of the
140+
* classpath directly from its location and doesn't need to copy it elsewhere. As the classpath is opened,
141+
* modifications may be blocked to them by the operating system.
142+
* <p>
143+
* E.g. if a static JAR path is opened by the build environment, and the user attempts to delete, rename, modify, or
144+
* otherwise manipulate the JAR, then it may fail, as the build environment loaded it.
145+
* <p>
146+
* In order to modify static classpaths, the user may need to reload the build environment. If that is distruptive
147+
* to the normal workflow, then the classpath shouldn't be considered static.
148+
* <p>
149+
* An example for static classpaths are classpaths from SDKs, artifacts from repositories, and others. These are
150+
* expected to not be modified after they've been published.
151+
* <p>
152+
* Using static classpaths can improve performance as various tasks may not need to cache them in an off-site
153+
* location, but can use them in-place as that doesn't distrupt the workflow.
154+
*
155+
* @return <code>true</code> if the classpath is static.
156+
* @since saker.java.compiler 0.8.1
157+
*/
158+
public default boolean isStaticFile() {
159+
return false;
160+
}
161+
131162
@Override
132163
public int hashCode();
133164

api/src/main/saker/java/compiler/api/processor/ProcessorCreationContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,4 @@ public interface ProcessorCreationContext {
3939
* @return The environment.
4040
*/
4141
public SakerEnvironment getEnvironment();
42-
}
42+
}

impl/src/main/saker/java/compiler/impl/JavaTaskUtils.java

Lines changed: 12 additions & 191 deletions
-
* @return The content descriptors may be <code>null</code>.
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,15 @@
1616
package saker.java.compiler.impl;
1717

1818
import java.io.Externalizable;
19-
import java.io.FileNotFoundException;
2019
import java.io.IOException;
2120
import java.io.ObjectInput;
2221
import java.io.ObjectOutput;
2322
import java.util.Collection;
2423
import java.util.Collections;
2524
import java.util.Comparator;
2625
import java.util.HashSet;
27-
import java.util.LinkedHashMap;
2826
import java.util.LinkedHashSet;
2927
import java.util.List;
30-
import java.util.Map;
3128
import java.util.Map.Entry;
3229
import java.util.NavigableMap;
3330
import java.util.NavigableSet;
@@ -36,27 +33,15 @@
3633
import java.util.TreeSet;
3734
import java.util.function.Function;
3835

39-
import saker.build.file.SakerDirectory;
40-
import saker.build.file.SakerFile;
4136
import saker.build.file.content.ContentDescriptor;
42-
import saker.build.file.content.DirectoryContentDescriptor;
43-
import saker.build.file.content.MultiPathContentDescriptor;
44-
import saker.build.file.content.SerializableContentDescriptor;
4537
import saker.build.file.path.SakerPath;
4638
import saker.build.file.provider.FileEntry;
4739
import saker.build.file.provider.LocalFileProvider;
48-
import saker.build.file.provider.SakerPathFiles;
4940
import saker.build.runtime.execution.ExecutionContext;
5041
import saker.build.runtime.execution.ExecutionProperty;
51-
import saker.build.runtime.execution.SakerLog;
52-
import saker.build.task.TaskContext;
53-
import saker.build.task.TaskDependencyFuture;
54-
import saker.build.task.TaskExecutionUtilities;
5542
import saker.build.task.dependencies.CommonTaskOutputChangeDetector;
56-
import saker.build.task.dependencies.FileCollectionStrategy;
5743
import saker.build.task.dependencies.TaskOutputChangeDetector;
5844
import saker.build.task.identifier.TaskIdentifier;
59-
import saker.build.task.utils.dependencies.RecursiveIgnoreCaseExtensionFileCollectionStrategy;
6045
import saker.build.thirdparty.org.objectweb.asm.ClassReader;
6146
import saker.build.thirdparty.org.objectweb.asm.ClassVisitor;
6247
import saker.build.thirdparty.org.objectweb.asm.ModuleVisitor;
@@ -67,28 +52,11 @@
6752
import saker.build.thirdparty.saker.util.io.ByteArrayRegion;
6853
import saker.build.thirdparty.saker.util.io.FileUtils;
6954
import saker.build.thirdparty.saker.util.io.SerialUtils;
70-
import saker.java.compiler.api.classpath.ClassPathEntry;
71-
import saker.java.compiler.api.classpath.ClassPathReference;
72-
import saker.java.compiler.api.classpath.ClassPathVisitor;
73-
import saker.java.compiler.api.classpath.CompilationClassPath;
74-
import saker.java.compiler.api.classpath.FileClassPath;
75-
import saker.java.compiler.api.classpath.JavaClassPath;
76-
import saker.java.compiler.api.classpath.JavaClassPathBuilder;
77-
import saker.java.compiler.api.classpath.SDKClassPath;
7855
import saker.java.compiler.api.compile.JavaCompilationWorkerTaskIdentifier;
79-
import saker.java.compiler.api.compile.JavaCompilerWorkerTaskOutput;
8056
import saker.java.compiler.api.compile.SakerJavaCompilerUtils;
8157
import saker.java.compiler.api.option.JavaAddExports;
82-
import saker.java.compiler.impl.JavaTaskUtils.LocalDirectoryClassFilesExecutionProperty.PropertyValue;
8358
import saker.java.compiler.impl.compile.InternalJavaCompilerOutput;
8459
import saker.java.compiler.impl.compile.util.LocalPathFileContentDescriptorExecutionProperty;
85-
import saker.sdk.support.api.SDKPathReference;
86-
import saker.sdk.support.api.SDKReference;
87-
import saker.sdk.support.api.SDKSupportUtils;
88-
import saker.std.api.file.location.ExecutionFileLocation;
89-
import saker.std.api.file.location.FileLocation;
90-
import saker.std.api.file.location.FileLocationVisitor;
91-
import saker.std.api.file.location.LocalFileLocation;
9260

9361
public class JavaTaskUtils {
9462
public static final String EXTENSION_CLASSFILE = "class";
@@ -217,163 +185,6 @@ public static Collection<String> toAddExportsCommandLineStrings(JavaAddExports a
217185
return SakerJavaCompilerUtils.toAddExportsCommandLineStrings(addexports);
218186
}
219187

220-
/**
221
222-
*/
223-
public static Map<FileLocation, ContentDescriptor> collectFileLocationsWithImplementationDependencyReporting(
224-
TaskContext taskcontext, JavaClassPath classpath, Object tag, Map<String, SDKReference> sdks,
225-
Function<ClassPathEntry, FileLocation> classpathentryfilelocationhandler) throws IOException {
226-
if (classpath == null) {
227-
return Collections.emptyMap();
228-
}
229-
Map<FileLocation, ContentDescriptor> result = new LinkedHashMap<>();
230-
classpath.accept(new ClassPathVisitor() {
231-
private Set<JavaCompilationWorkerTaskIdentifier> handledWorkerTaskIds = new HashSet<>();
232-
233-
@Override
234-
public void visit(ClassPathReference classpath) {
235-
Collection<? extends ClassPathEntry> entries = classpath.getEntries();
236-
if (ObjectUtils.isNullOrEmpty(entries)) {
237-
SakerLog.warning().println("No class path entries found for: " + classpath);
238-
return;
239-
}
240-
for (ClassPathEntry entry : entries) {
241-
if (entry == null) {
242-
SakerLog.warning().println("Class path entry is null for: " + classpath);
243-
continue;
244-
}
245-
FileLocation filelocation = classpathentryfilelocationhandler.apply(entry);
246-
if (filelocation == null) {
247-
SakerLog.warning().println("No class path file location for: " + entry);
248-
continue;
249-
}
250-
handleFileLocation(filelocation);
251-
252-
Collection<? extends ClassPathReference> additionalclasspaths = entry
253-
.getAdditionalClassPathReferences();
254-
if (!ObjectUtils.isNullOrEmpty(additionalclasspaths)) {
255-
JavaClassPathBuilder additionalcpbuilder = JavaClassPathBuilder.newBuilder();
256-
for (ClassPathReference additionalcp : additionalclasspaths) {
257-
additionalcpbuilder.addClassPath(additionalcp);
258-
}
259-
JavaClassPath additionalcp = additionalcpbuilder.build();
260-
additionalcp.accept(this);
261-
}
262-
}
263-
}
264-
265-
@Override
266-
public void visit(CompilationClassPath classpath) {
267-
JavaCompilationWorkerTaskIdentifier workertaskid = classpath.getCompilationWorkerTaskIdentifier();
268-
if (!handledWorkerTaskIds.add(workertaskid)) {
269-
//don't get the task result to not install another dependency
270-
return;
271-
}
272-
TaskDependencyFuture<?> depresult = taskcontext.getTaskDependencyFuture(workertaskid);
273-
JavaCompilerWorkerTaskOutput output = (JavaCompilerWorkerTaskOutput) depresult.getFinished();
274-
SakerPath classdirpath = output.getClassDirectory();
275-
ExecutionFileLocation filelocation = ExecutionFileLocation.create(classdirpath);
276-
JavaClassPath outputcp = output.getClassPath();
277-
278-
Object implversionkey = output.getImplementationVersionKey();
279-
if (implversionkey != null) {
280-
depresult.setTaskOutputChangeDetector(SakerJavaCompilerUtils
281-
.getCompilerOutputImplementationVersionKeyTaskOutputChangeDetector(implversionkey));
282-
depresult.setTaskOutputChangeDetector(
283-
SakerJavaCompilerUtils.getCompilerOutputClassPathTaskOutputChangeDetector(outputcp));
284-
result.put(filelocation, new SerializableContentDescriptor(implversionkey));
285-
} else {
286-
SakerDirectory classesdir = taskcontext.getTaskUtilities().resolveDirectoryAtPath(classdirpath);
287-
if (classesdir == null) {
288-
throw ObjectUtils.sneakyThrow(
289-
new FileNotFoundException("Compilation class directory not found: " + classesdir));
290-
}
291-
292-
FileCollectionStrategy classfileadditiondep = RecursiveIgnoreCaseExtensionFileCollectionStrategy
293-
.create(classdirpath, "." + EXTENSION_CLASSFILE);
294-
NavigableMap<SakerPath, SakerFile> classfiles = taskcontext.getTaskUtilities()
295-
.collectFilesReportInputFileAndAdditionDependency(tag, classfileadditiondep);
296-
297-
NavigableMap<SakerPath, ContentDescriptor> contentmap = SakerPathFiles.toFileContentMap(classfiles);
298-
result.put(filelocation, new MultiPathContentDescriptor(contentmap));
299-
}
300-
if (outputcp != null) {
301-
outputcp.accept(this);
302-
}
303-
}
304-
305-
@Override
306-
public void visit(FileClassPath classpath) {
307-
FileLocation location = classpath.getFileLocation();
308-
handleFileLocation(location);
309-
}
310-
311-
@Override
312-
public void visit(SDKClassPath classpath) {
313-
SDKPathReference sdkpathref = classpath.getSDKPathReference();
314-
SakerPath path = SDKSupportUtils.getSDKPathReferencePath(sdkpathref, sdks);
315-
LocalFileLocation fileloc = LocalFileLocation.create(path);
316-
result.put(fileloc, null);
317-
}
318-
319-
private ContentDescriptor handleExecutionFileLocation(SakerPath path, SakerFile cpfile) {
320-
if (cpfile instanceof SakerDirectory) {
321-
FileCollectionStrategy classfileadditiondep = RecursiveIgnoreCaseExtensionFileCollectionStrategy
322-
.create(path, "." + EXTENSION_CLASSFILE);
323-
NavigableMap<SakerPath, SakerFile> classfiles = taskcontext.getTaskUtilities()
324-
.collectFilesReportInputFileAndAdditionDependency(tag, classfileadditiondep);
325-
return new MultiPathContentDescriptor(SakerPathFiles.toFileContentMap(classfiles));
326-
}
327-
taskcontext.getTaskUtilities().reportInputFileDependency(tag, cpfile);
328-
return cpfile.getContentDescriptor();
329-
}
330-
331-
private void handleFileLocation(FileLocation location) {
332-
if (result.containsKey(location)) {
333-
return;
334-
}
335-
ContentDescriptor[] cdres = { null };
336-
location.accept(new FileLocationVisitor() {
337-
@Override
338-
public void visit(ExecutionFileLocation loc) {
339-
SakerPath path = loc.getPath();
340-
SakerFile cpfile = taskcontext.getTaskUtilities().resolveAtPath(path);
341-
if (cpfile == null) {
342-
throw ObjectUtils
343-
.sneakyThrow(new FileNotFoundException("Class path file not found: " + path));
344-
}
345-
cdres[0] = handleExecutionFileLocation(path, cpfile);
346-
}
347-
348-
@Override
349-
public void visit(LocalFileLocation loc) {
350-
SakerPath path = loc.getLocalPath();
351-
TaskExecutionUtilities taskutils = taskcontext.getTaskUtilities();
352-
ContentDescriptor cd = taskutils.getReportExecutionDependency(
353-
new LocalPathFileContentDescriptorExecutionProperty(path));
354-
if (cd == null) {
355-
throw ObjectUtils
356-
.sneakyThrow(new FileNotFoundException("Class path local file not found: " + path));
357-
}
358-
359-
if (DirectoryContentDescriptor.INSTANCE.equals(cd)) {
360-
//the class path denotes a directory
361-
//add the dependencies on the class files
362-
363-
PropertyValue pval = taskutils
364-
.getReportExecutionDependency(new LocalDirectoryClassFilesExecutionProperty(path));
365-
cdres[0] = new MultiPathContentDescriptor(pval.getContents());
366-
} else {
367-
cdres[0] = cd;
368-
}
369-
}
370-
});
371-
result.put(location, cdres[0]);
372-
}
373-
});
374-
return result;
375-
}
376-
377188
public static class LocalDirectoryClassFilesExecutionProperty
378189
implements ExecutionProperty<LocalDirectoryClassFilesExecutionProperty.PropertyValue>, Externalizable {
379190
private static final long serialVersionUID = 1L;
@@ -438,6 +249,7 @@ public String toString() {
438249

439250
}
440251

252+
private TaskIdentifier associatedTaskId;
441253
private SakerPath path;
442254

443255
/**
@@ -446,7 +258,8 @@ public String toString() {
446258
public LocalDirectoryClassFilesExecutionProperty() {
447259
}
448260

449-
public LocalDirectoryClassFilesExecutionProperty(SakerPath path) {
261+
public LocalDirectoryClassFilesExecutionProperty(TaskIdentifier associatedTaskId, SakerPath path) {
262+
this.associatedTaskId = associatedTaskId;
450263
this.path = path;
451264
}
452265

@@ -465,7 +278,7 @@ public PropertyValue getCurrentValue(ExecutionContext executioncontext) throws E
465278
}
466279
SakerPath cpabspath = path.resolve(keypath);
467280
ContentDescriptor classfilecd = executioncontext.getExecutionPropertyCurrentValue(
468-
new LocalPathFileContentDescriptorExecutionProperty(cpabspath));
281+
new LocalPathFileContentDescriptorExecutionProperty(associatedTaskId, cpabspath));
469282
if (classfilecd == null) {
470283
continue;
471284
}
@@ -476,18 +289,21 @@ public PropertyValue getCurrentValue(ExecutionContext executioncontext) throws E
476289

477290
@Override
478291
public void writeExternal(ObjectOutput out) throws IOException {
292+
out.writeObject(associatedTaskId);
479293
out.writeObject(path);
480294
}
481295

482296
@Override
483297
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
298+
associatedTaskId = (TaskIdentifier) in.readObject();
484299
path = (SakerPath) in.readObject();
485300
}
486301

487302
@Override
488303
public int hashCode() {
489304
final int prime = 31;
490305
int result = 1;
306+
result = prime * result + ((associatedTaskId == null) ? 0 : associatedTaskId.hashCode());
491307
result = prime * result + ((path == null) ? 0 : path.hashCode());
492308
return result;
493309
}
@@ -501,6 +317,11 @@ public boolean equals(Object obj) {
501317
if (getClass() != obj.getClass())
502318
return false;
503319
LocalDirectoryClassFilesExecutionProperty other = (LocalDirectoryClassFilesExecutionProperty) obj;
320+
if (associatedTaskId == null) {
321+
if (other.associatedTaskId != null)
322+
return false;
323+
} else if (!associatedTaskId.equals(other.associatedTaskId))
324+
return false;
504325
if (path == null) {
505326
if (other.path != null)
506327
return false;

impl/src/main/saker/java/compiler/impl/classpath/bundle/BundleClassPathEntry.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ public FileLocation getFileLocation() {
9595
return LocalFileLocation.create(SakerPath.valueOf(jarbundle.getJarPath()));
9696
}
9797

98+
@Override
99+
public boolean isStaticFile() {
100+
//the bundle files doesn't change during the lifetime of the build environment, so they are static
101+
return true;
102+
}
103+
98104
@Override
99105
public Collection<? extends ClassPathReference> getAdditionalClassPathReferences() {
100106
return null;

0 commit comments

Comments
 (0)
0