Skip to content

Commit

Permalink
Merge branch '1.0' into wip/integration
Browse files Browse the repository at this point in the history
DefaultExternalHooks and WrappedClassFileManager are moved to xsbt.compile.
  • Loading branch information
eed3si9n committed Jul 15, 2017
2 parents 855d8e6 + 1de92bf commit b5bcc8b
Show file tree
Hide file tree
Showing 30 changed files with 500 additions and 192 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,7 @@ public static java.util.Map<String, String> defaultExtra() {
return new java.util.HashMap<String, String>();
}
public static ExternalHooks defaultExternal() {
return new ExternalHooks() {
@Override
public java.util.Optional<Lookup> externalLookup() {
return java.util.Optional.empty();
}
@Override
public java.util.Optional<ClassFileManager> externalClassFileManager() {
return java.util.Optional.empty();
}
};
return new DefaultExternalHooks(java.util.Optional.empty(), java.util.Optional.empty());
}
public static boolean defaultLogRecompileOnMacro() {
return true;
Expand Down
11 changes: 1 addition & 10 deletions internal/compiler-interface/src/main/contraband/incremental.json
Original file line number Diff line number Diff line change
Expand Up @@ -230,16 +230,7 @@
" return new java.util.HashMap<String, String>();",
"}",
"public static ExternalHooks defaultExternal() {",
" return new ExternalHooks() {",
" @Override",
" public java.util.Optional<Lookup> externalLookup() {",
" return java.util.Optional.empty();",
" }",
" @Override",
" public java.util.Optional<ClassFileManager> externalClassFileManager() {",
" return java.util.Optional.empty();",
" }",
" };",
" return new DefaultExternalHooks(java.util.Optional.empty(), java.util.Optional.empty());",
"}",
"public static boolean defaultLogRecompileOnMacro() {",
" return true;",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Zinc - The incremental compiler for Scala.
* Copyright 2011 - 2017, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* This software is released under the terms written in LICENSE.
*/

package xsbti.compile;

import java.io.File;
import java.util.Optional;
import java.util.Set;

public class DefaultExternalHooks implements ExternalHooks {
private Optional<ExternalHooks.Lookup> lookup = Optional.empty();
private Optional<ClassFileManager> classFileManager = Optional.empty();

public DefaultExternalHooks(Optional<ExternalHooks.Lookup> lookup, Optional<ClassFileManager> classFileManager) {
this.lookup = lookup;
this.classFileManager = classFileManager;
}

@Override
public Optional<Lookup> getExternalLookup() {
return lookup;
}

@Override
public Optional<ClassFileManager> getExternalClassFileManager() {
return classFileManager;
}

@Override
public ExternalHooks withExternalClassFileManager(ClassFileManager externalClassFileManager) {
Optional<ClassFileManager> currentManager = this.getExternalClassFileManager();
Optional<ClassFileManager> mixedManager = currentManager;
if (currentManager.isPresent()) {
Optional<ClassFileManager> external = Optional.of(externalClassFileManager);
mixedManager = Optional.of(WrappedClassFileManager.of(currentManager.get(), external));
}
return new DefaultExternalHooks(this.getExternalLookup(), mixedManager);
}

@Override
public ExternalHooks withExternalLookup(Lookup externalLookup) {
return new DefaultExternalHooks(Optional.of(externalLookup), this.getExternalClassFileManager());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
import java.util.Set;

/**
* Define hooks that can be user-defined to modify the behaviour of
* Defines hooks that can be user-defined to modify the behaviour of
* internal components of the incremental compiler.
*/
public interface ExternalHooks {
/**
* Define an interface for a lookup mechanism.
* Defines an interface for a lookup mechanism.
*/
public static interface Lookup {
interface Lookup {

/**
* Used to provide information from external tools into sbt (e.g. IDEs)
Expand Down Expand Up @@ -54,17 +54,36 @@ public static interface Lookup {
}

/**
* Return the implementation of a lookup mechanism to be used instead of
* Returns the implementation of a lookup mechanism to be used instead of
* the internal lookup provided by the default implementation.
*/
Optional<Lookup> externalLookup();
Optional<Lookup> getExternalLookup();

/**
* Return the implementation of a {@link ClassFileManager} to be used
* Returns the implementation of a {@link ClassFileManager} to be used
* alongside the internal manager provided by the default implementation.
* <p>
* This class file manager is run after the internal
* {@link ClassFileManager} defined in {@link IncOptions}.
*/
Optional<ClassFileManager> externalClassFileManager();
Optional<ClassFileManager> getExternalClassFileManager();

/**
* Returns an instance of hooks that executes the external passed class file manager.
*
* If several class file manager are passed, they are aggregated and their execution happens
* in the order of invocations of this method.
*
* @return An instance of {@link ExternalHooks} with the aggregated external class file manager.
*/
ExternalHooks withExternalClassFileManager(ClassFileManager externalClassFileManager);

/**
* Returns an instance of hooks with one lookup.
*
* If used several times, only the last lookup instance will be used.
*
* @return An instance of {@link ExternalHooks} with the specified lookup.
*/
ExternalHooks withExternalLookup(Lookup externalLookup);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Zinc - The incremental compiler for Scala.
* Copyright 2011 - 2017, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* This software is released under the terms written in LICENSE.
*/

package xsbti.compile;

import java.io.File;
import java.util.Optional;

/**
* Defines a classfile manager that composes the operation of two classfile manager,
* one being the internal classfile manager (the one used by the compiler) and the
* other one being the external classfile manager (a customizable, build tool-defined
* class file manager to control which class files should be notified/removed/generated
* aside from the ones covered by the internal classfile manager).
*
* @param internal Compiler classfile manager.
* @param external Build tool (or external) classfile manager the complements the internal one.
*/
public class WrappedClassFileManager implements ClassFileManager {
private ClassFileManager internal;
private Optional<ClassFileManager> external;

public static WrappedClassFileManager of(ClassFileManager internal, Optional<ClassFileManager> external) {
return new WrappedClassFileManager(internal, external);
}

protected WrappedClassFileManager(ClassFileManager internal,
Optional<ClassFileManager> external) {
this.internal = internal;
this.external = external;
}

@Override
public void delete(File[] classes) {
// Avoid Java 8 syntax to accommodate Scala 2.10
if (external.isPresent()) {
external.get().delete(classes);
}
internal.delete(classes);
}

@Override
public void complete(boolean success) {
// Avoid Java 8 syntax to accommodate Scala 2.10
if (external.isPresent()) {
external.get().complete(success);
}
internal.complete(success);
}

@Override
public void generated(File[] classes) {
// Avoid Java 8 syntax to accommodate Scala 2.10
if (external.isPresent()) {
external.get().generated(classes);
}
internal.generated(classes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package xsbti.compile;

import sbt.internal.inc.ConcreteAnalysisContents;

/**
* Defines an analysis file that contains information about every incremental compile.
*
* This information can be persisted using an {@link AnalysisStore}.
*/
public interface AnalysisContents {
/**
* Returns an instance of {@link AnalysisContents} backed up by the default implementation.
*
* @param analysis An instance of {@link CompileAnalysis}.
* @param setup An instance of {@link MiniSetup}.
* @return An instance of {@link AnalysisContents}.
*/
static AnalysisContents create(CompileAnalysis analysis, MiniSetup setup) {
return new ConcreteAnalysisContents(analysis, setup);
}

/**
* @return An instance of {@link CompileAnalysis}.
*/
CompileAnalysis getAnalysis();

/**
* @return An instance of {@link MiniSetup}.
*/
MiniSetup getMiniSetup();
}
65 changes: 65 additions & 0 deletions internal/zinc-core/src/main/java/xsbti/compile/AnalysisStore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package xsbti.compile;

import java.util.Optional;

/**
* Defines a store interface that provides analysis read and write capabilities to users.
*
* The store is a backend-independent interface that allows implementors to decide how
* the analysis stores are read and written before or after every incremental compile.
*
* The implementations of {@link AnalysisStore} live in interfaces extending this one.
*/
public interface AnalysisStore {
/**
* Returns an analysis store whose last contents are kept in-memory.
*
* There will be only one memory reference to an analysis files. Previous contents
* will be discarded as {@link AnalysisStore#set(AnalysisContents)} or
* {@link AnalysisStore#get()} is used.
*
* @param analysisStore The underlying analysis store that knows how to read/write contents.
* @return An instance of a cached {@link AnalysisStore}.
*/
static AnalysisStore getCachedStore(AnalysisStore analysisStore) {
return sbt.internal.inc.AnalysisStore.cached(analysisStore);
}

/**
* Returns a synchronized analysis store that is thread-safe.
*
* Thread-safety is achieved by synchronizing in the object.
*
* @param analysisStore The underlying analysis store that knows how to read/write contents.
* @return An instance of a thread-safe {@link AnalysisStore}.
*/
static AnalysisStore getThreadSafeStore(AnalysisStore analysisStore) {
return sbt.internal.inc.AnalysisStore.sync(analysisStore);
}

/**
* Gets an {@link AnalysisContents} from the underlying store.
*
* The contents of the analysis file are necessary for subsequent incremental compiles
* given that the analysis files contains information about the previous incremental
* compile and lets the incremental compiler decide what needs or needs not to be recompiled.
*
* This method should be called before every incremental compile.
*
* @return An instance of an optional {@link AnalysisContents}, depending on whether if exists or not.
*/
Optional<AnalysisContents> get();

/**
* Sets an {@link AnalysisContents} to the underlying store.
*
* The contents of the analysis file are necessary for subsequent incremental compiles
* given that the analysis files contains information about the previous incremental
* compile and lets the incremental compiler decide what needs or needs not to be recompiled.
*
* This method is called after every incremental compile.
*
* @return An instance of {@link AnalysisContents}.
*/
void set(AnalysisContents analysisContents);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ public class IncOptionsUtil {
public static final String DELETE_IMMEDIATELY_MANAGER_TYPE = "deleteImmediatelyManagerType";
private static final String XSBTI_NOTHING = "NOTHING";

public static IncOptions defaultIncOptions() {
IncOptions retval = new IncOptions();
return retval;
}

// Small utility function for logging
private static Supplier<String> f0(String message) {
return new Supplier<String>() {
Expand All @@ -63,7 +58,7 @@ public String get() {
* @return An instance of {@link IncOptions}.
*/
public static IncOptions fromStringMap(Map<String, String> values, Logger logger) {
IncOptions base = defaultIncOptions();
IncOptions base = IncOptions.of();
logger.debug(f0("Reading incremental options from map"));

if (values.containsKey(TRANSITIVE_STEP_KEY)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,34 @@ package sbt
package internal
package inc

import xsbti.compile.{ CompileAnalysis, MiniSetup }
import java.util.Optional

trait AnalysisStore {
def set(analysis: CompileAnalysis, setup: MiniSetup): Unit
def get(): Option[(CompileAnalysis, MiniSetup)]
}
import xsbti.compile.{ AnalysisContents, AnalysisStore }

object AnalysisStore {
def cached(backing: AnalysisStore): AnalysisStore = new AnalysisStore {
private var last: Option[(CompileAnalysis, MiniSetup)] = None
def set(analysis: CompileAnalysis, setup: MiniSetup): Unit = {
backing.set(analysis, setup)
last = Some((analysis, setup))
def cached(backing: AnalysisStore): AnalysisStore = new CachedAnalysisStore(backing)
private final class CachedAnalysisStore(backing: AnalysisStore) extends AnalysisStore {
private var lastStore: Optional[AnalysisContents] = Optional.empty()
override def get(): Optional[AnalysisContents] = {
if (!lastStore.isPresent())
lastStore = backing.get()
lastStore
}
def get(): Option[(CompileAnalysis, MiniSetup)] = {
if (last.isEmpty)
last = backing.get()
last

override def set(analysisFile: AnalysisContents): Unit = {
backing.set(analysisFile)
lastStore = Optional.of(analysisFile)
}
}
def sync(backing: AnalysisStore): AnalysisStore = new AnalysisStore {
def set(analysis: CompileAnalysis, setup: MiniSetup): Unit = synchronized {
backing.set(analysis, setup)

def sync(backing: AnalysisStore): AnalysisStore = new SyncedAnalysisStore(backing)
private final class SyncedAnalysisStore(backing: AnalysisStore) extends AnalysisStore {
override def get(): Optional[AnalysisContents] = synchronized {
backing.get()
}

override def set(analysisFile: AnalysisContents): Unit = synchronized {
backing.set(analysisFile)
}
def get(): Option[(CompileAnalysis, MiniSetup)] = synchronized { backing.get() }
}
}
Loading

0 comments on commit b5bcc8b

Please sign in to comment.