8000 Fix issue #1 by Sipkab · Pull Request #10 · sakerbuild/saker.java.compiler · GitHub
[go: up one dir, main page]

Skip to content

Fix issue #1 #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,45 @@ public default StructuredTaskResult getDocumentationAttachment() {
* In general, if the implementation version key of a classpath changes, the dependent code needs to be re-executed
* or recompiled.
* <p>
* The implementation verison key should include all aspects of the class files available in the (non-transitive)
* The implementation version key should include all aspects of the class files available in the (non-transitive)
* classpath.
*
* @return The implementation version key or <code>null</code> if none.
* @see JavaCompilerWorkerTaskOutput#getImplementationVersionKey()
*/
public Object getImplementationVersionKey();

/**
* Checks if the {@linkplain #getFileLocation() file location} of this classpath may be considered static.
* <p>
* A static classpath is one that doesn't change during the lifetime of the enclosing build environment. The files
* of a static classpath will not be attempted to be modified by other agents on the same computer. If the classpath
* represents a directory, then the enclosed files in the directory mustn't change. If it is a JAR, or other
* archive, then the file itself mustn't change.
* <p>
* If a classpath is static, that means that the users of the classpath are allowed to load the files of the
* classpath directly from its location and doesn't need to copy it elsewhere. As the classpath is opened,
* modifications may be blocked to them by the operating system.
* <p>
* E.g. if a static JAR path is opened by the build environment, and the user attempts to delete, rename, modify, or
* otherwise manipulate the JAR, then it may fail, as the build environment loaded it.
* <p>
* In order to modify static classpaths, the user may need to reload the build environment. If that is distruptive
* to the normal workflow, then the classpath shouldn't be considered static.
* <p>
* An example for static classpaths are classpaths from SDKs, artifacts from repositories, and others. These are
* expected to not be modified after they've been published.
* <p>
* Using static classpaths can improve performance as various tasks may not need to cache them in an off-site
* location, but can use them in-place as that doesn't distrupt the workflow.
*
* @return <code>true</code> if the classpath is static.
* @since saker.java.compiler 0.8.1
*/
public default boolean isStaticFile() {
return false;
}

@Override
public int hashCode();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ public interface ProcessorCreationContext {
* @return The environment.
*/
public SakerEnvironment getEnvironment();
}
}
203 changes: 12 additions & 191 deletions impl/src/main/saker/java/compiler/impl/JavaTaskUtils.java
67E6
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,15 @@
package saker.java.compiler.impl;

import java.io.Externalizable;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.NavigableSet;
Expand All @@ -36,27 +33,15 @@
import java.util.TreeSet;
import java.util.function.Function;

import saker.build.file.SakerDirectory;
import saker.build.file.SakerFile;
import saker.build.file.content.ContentDescriptor;
import saker.build.file.content.DirectoryContentDescriptor;
import saker.build.file.content.MultiPathContentDescriptor;
import saker.build.file.content.SerializableContentDescriptor;
import saker.build.file.path.SakerPath;
import saker.build.file.provider.FileEntry;
import saker.build.file.provider.LocalFileProvider;
import saker.build.file.provider.SakerPathFiles;
import saker.build.runtime.execution.ExecutionContext;
import saker.build.runtime.execution.ExecutionProperty;
import saker.build.runtime.execution.SakerLog;
import saker.build.task.TaskContext;
import saker.build.task.TaskDependencyFuture;
import saker.build.task.TaskExecutionUtilities;
import saker.build.task.dependencies.CommonTaskOutputChangeDetector;
import saker.build.task.dependencies.FileCollectionStrategy;
import saker.build.task.dependencies.TaskOutputChangeDetector;
import saker.build.task.identifier.TaskIdentifier;
import saker.build.task.utils.dependencies.RecursiveIgnoreCaseExtensionFileCollectionStrategy;
import saker.build.thirdparty.org.objectweb.asm.ClassReader;
import saker.build.thirdparty.org.objectweb.asm.ClassVisitor;
import saker.build.thirdparty.org.objectweb.asm.ModuleVisitor;
Expand All @@ -67,28 +52,11 @@
import saker.build.thirdparty.saker.util.io.ByteArrayRegion;
import saker.build.thirdparty.saker.util.io.FileUtils;
import saker.build.thirdparty.saker.util.io.SerialUtils;
import saker.java.compiler.api.classpath.ClassPathEntry;
import saker.java.compiler.api.classpath.ClassPathReference;
import saker.java.compiler.api.classpath.ClassPathVisitor;
import saker.java.compiler.api.classpath.CompilationClassPath;
import saker.java.compiler.api.classpath.FileClassPath;
import saker.java.compiler.api.classpath.JavaClassPath;
import saker.java.compiler.api.classpath.JavaClassPathBuilder;
import saker.java.compiler.api.classpath.SDKClassPath;
import saker.java.compiler.api.compile.JavaCompilationWorkerTaskIdentifier;
import saker.java.compiler.api.compile.JavaCompilerWorkerTaskOutput;
import saker.java.compiler.api.compile.SakerJavaCompilerUtils;
import saker.java.compiler.api.option.JavaAddExports;
import saker.java.compiler.impl.JavaTaskUtils.LocalDirectoryClassFilesExecutionProperty.PropertyValue;
import saker.java.compiler.impl.compile.InternalJavaCompilerOutput;
import saker.java.compiler.impl.compile.util.LocalPathFileContentDescriptorExecutionProperty;
import saker.sdk.support.api.SDKPathReference;
import saker.sdk.support.api.SDKReference;
import saker.sdk.support.api.SDKSupportUtils;
import saker.std.api.file.location.ExecutionFileLocation;
import saker.std.api.file.location.FileLocation;
import saker.std.api.file.location.FileLocationVisitor;
import s 8000 aker.std.api.file.location.LocalFileLocation;

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

/**
* @return The content descriptors may be <code>null</code>.
*/
public static Map<FileLocation, ContentDescriptor> collectFileLocationsWithImplementationDependencyReporting(
TaskContext taskcontext, JavaClassPath classpath, Object tag, Map<String, SDKReference> sdks,
Function<ClassPathEntry, FileLocation> classpathentryfilelocationhandler) throws IOException {
if (classpath == null) {
return Collections.emptyMap();
}
Map<FileLocation, ContentDescriptor> result = new LinkedHashMap<>();
classpath.accept(new ClassPathVisitor() {
private Set<JavaCompilationWorkerTaskIdentifier> handledWorkerTaskIds = new HashSet<>();

@Override
public void visit(ClassPathReference classpath) {
Collection<? extends ClassPathEntry> entries = classpath.getEntries();
if (ObjectUtils.isNullOrEmpty(entries)) {
SakerLog.warning().println("No class path entries found for: " + classpath);
return;
}
for (ClassPathEntry entry : entries) {
if (entry == null) {
SakerLog.warning().println("Class path entry is null for: " + classpath);
continue;
}
FileLocation filelocation = classpathentryfilelocationhandler.apply(entry);
if (filelocation == null) {
SakerLog.warning().println("No class path file location for: " + entry);
continue;
}
handleFileLocation(filelocation);

Collection<? extends ClassPathReference> additionalclasspaths = entry
.getAdditionalClassPathReferences();
if (!ObjectUtils.isNullOrEmpty(additionalclasspaths)) {
JavaClassPathBuilder additionalcpbuilder = JavaClassPathBuilder.newBuilder();
for (ClassPathReference additionalcp : additionalclasspaths) {
additionalcpbuilder.addClassPath(additionalcp);
}
JavaClassPath additionalcp = additionalcpbuilder.build();
additionalcp.accept(this);
}
}
}

@Override
public void visit(CompilationClassPath classpath) {
JavaCompilationWorkerTaskIdentifier workertaskid = classpath.getCompilationWorkerTaskIdentifier();
if (!handledWorkerTaskIds.add(workertaskid)) {
//don't get the task result to not install another dependency
return;
}
TaskDependencyFuture<?> depresult = taskcontext.getTaskDependencyFuture(workertaskid);
JavaCompilerWorkerTaskOutput output = (JavaCompilerWorkerTaskOutput) depresult.getFinished();
SakerPath classdirpath = output.getClassDirectory();
ExecutionFileLocation filelocation = ExecutionFileLocation.create(classdirpath);
JavaClassPath outputcp = output.getClassPath();

Object implversionkey = output.getImplementationVersionKey();
if (implversionkey != null) {
depresult.setTaskOutputChangeDetector(SakerJavaCompilerUtils
.getCompilerOutputImplementationVersionKeyTaskOutputChangeDetector(implversionkey));
depresult.setTaskOutputChangeDetector(
SakerJavaCompilerUtils.getCompilerOutputClassPathTaskOutputChangeDetector(outputcp));
result.put(filelocation, new SerializableContentDescriptor(implversionkey));
} else {
SakerDirectory classesdir = taskcontext.getTaskUtilities().resolveDirectoryAtPath(classdirpath);
if (classesdir == null) {
throw ObjectUtils.sneakyThrow(
new FileNotFoundException("Compilation class directory not found: " + classesdir));
}

FileCollectionStrategy classfileadditiondep = RecursiveIgnoreCaseExtensionFileCollectionStrategy
.create(classdirpath, "." + EXTENSION_CLASSFILE);
NavigableMap<SakerPath, SakerFile> classfiles = taskcontext.getTaskUtilities()
.collectFilesReportInputFileAndAdditionDependency(tag, classfileadditiondep);

NavigableMap<SakerPath, ContentDescriptor> contentmap = SakerPathFiles.toFileContentMap(classfiles);
result.put(filelocation, new MultiPathContentDescriptor(contentmap));
}
if (outputcp != null) {
outputcp.accept(this);
}
}

@Override
public void visit(FileClassPath classpath) {
FileLocation location = classpath.getFileLocation();
handleFileLocation(location);
}

@Override
public void visit(SDKClassPath classpath) {
SDKPathReference sdkpathref = classpath.getSDKPathReference();
SakerPath path = SDKSupportUtils.getSDKPathReferencePath(sdkpathref, sdks);
LocalFileLocation fileloc = LocalFileLocation.create(path);
result.put(fileloc, null);
}

private ContentDescriptor handleExecutionFileLocation(SakerPath path, SakerFile cpfile) {
if (cpfile instanceof SakerDirectory) {
FileCollectionStrategy classfileadditiondep = RecursiveIgnoreCaseExtensionFileCollectionStrategy
.create(path, "." + EXTENSION_CLASSFILE);
NavigableMap<SakerPath, SakerFile> classfiles = taskcontext.getTaskUtilities()
.collectFilesReportInputFileAndAdditionDependency(tag, classfileadditiondep);
return new MultiPathContentDescriptor(SakerPathFiles.toFileContentMap(classfiles));
}
taskcontext.getTaskUtilities().reportInputFileDependency(tag, cpfile);
return cpfile.getContentDescriptor();
}

private void handleFileLocation(FileLocation location) {
if (result.containsKey(location)) {
return;
}
ContentDescriptor[] cdres = { null };
location.accept(new FileLocationVisitor() {
@Override
public void visit(ExecutionFileLocation loc) {
SakerPath path = loc.getPath();
SakerFile cpfile = taskcontext.getTaskUtilities().resolveAtPath(path);
if (cpfile == null) {
throw ObjectUtils
.sneakyThrow(new FileNotFoundException("Class path file not found: " + path));
}
cdres[0] = handleExecutionFileLocation(path, cpfile);
}

@Override
public void visit(LocalFileLocation loc) {
SakerPath path = loc.getLocalPath();
TaskExecutionUtilities taskutils = taskcontext.getTaskUtilities();
ContentDescriptor cd = taskutils.getReportExecutionDependency(
new LocalPathFileContentDescriptorExecutionProperty(path));
if (cd == null) {
throw ObjectUtils
.sneakyThrow(new FileNotFoundException("Class path local file not found: " + path));
}

if (DirectoryContentDescriptor.INSTANCE.equals(cd)) {
//the class path denotes a directory
//add the dependencies on the class files

PropertyValue pval = taskutils
.getReportExecutionDependency(new LocalDirectoryClassFilesExecutionProperty(path));
cdres[0] = new MultiPathContentDescriptor(pval.getContents());
} else {
cdres[0] = cd;
}
}
});
result.put(location, cdres[0]);
}
});
return result;
}

public static class LocalDirectoryClassFilesExecutionProperty
implements ExecutionProperty<LocalDirectoryClassFilesExecutionProperty.PropertyValue>, Externalizable {
private static final long serialVersionUID = 1L;
Expand Down Expand Up @@ -438,6 +249,7 @@ public String toString() {

}

private TaskIdentifier associatedTaskId;
private SakerPath path;

/**
Expand All @@ -446,7 +258,8 @@ public String toString() {
public LocalDirectoryClassFilesExecutionProperty() {
}

public LocalDirectoryClassFilesExecutionProperty(SakerPath path) {
public LocalDirectoryClassFilesExecutionProperty(TaskIdentifier associatedTaskId, SakerPath path) {
this.associatedTaskId = associatedTaskId;
this.path = path;
}

Expand All @@ -465,7 +278,7 @@ public PropertyValue getCurrentValue(ExecutionContext executioncontext) throws E
}
SakerPath cpabspath = path.resolve(keypath);
ContentDescriptor classfilecd = executioncontext.getExecutionPropertyCurrentValue(
new LocalPathFileContentDescriptorExecutionProperty(cpabspath));
new LocalPathFileContentDescriptorExecutionProperty(associatedTaskId, cpabspath));
if (classfilecd == null) {
continue;
}
Expand All @@ -476,18 +289,21 @@ public PropertyValue getCurrentValue(ExecutionContext executioncontext) throws E

@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(associatedTaskId);
out.writeObject(path);
}

@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
associatedTaskId = (TaskIdentifier) in.readObject();
path = (SakerPath) in.readObject();
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((associatedTaskId == null) ? 0 : associatedTaskId.hashCode());
result = prime * result + ((path == null) ? 0 : path.hashCode());
return result;
}
Expand All @@ -501,6 +317,11 @@ public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
LocalDirectoryClassFilesExecutionProperty other = (LocalDirectoryClassFilesExecutionProperty) obj;
if (associatedTaskId == null) {
if (other.associatedTaskId != null)
return false;
} else if (!associatedTaskId.equals(other.associatedTaskId))
return false;
if (path == null) {
if (other.path != null)
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ public FileLocation getFileLocation() {
return LocalFileLocation.create(SakerPath.valueOf(jarbundle.getJarPath()));
}

@Override
public boolean isStaticFile() {
//the bundle files doesn't change during the lifetime of the build environment, so they are static
return true;
}

@Override
public Collection<? extends ClassPathReference> getAdditionalClassPathReferences() {
return null;
Expand Down
Loading
0