Search in sources :

Example 1 with Archive

use of org.revapi.Archive in project revapi by revapi.

the class SemverIgnoreTransform method initialize.

@Override
public void initialize(@Nonnull AnalysisContext analysisContext) {
    ModelNode node = analysisContext.getConfiguration();
    if (hasMultipleElements(analysisContext.getOldApi().getArchives()) || hasMultipleElements(analysisContext.getNewApi().getArchives())) {
        throw new IllegalArgumentException("The semver extension doesn't handle changes in multiple archives at once.");
    }
    enabled = node.get("enabled").isDefined() && node.get("enabled").asBoolean();
    if (enabled) {
        Iterator<? extends Archive> oldArchives = analysisContext.getOldApi().getArchives().iterator();
        Iterator<? extends Archive> newArchives = analysisContext.getNewApi().getArchives().iterator();
        if (!oldArchives.hasNext() || !newArchives.hasNext()) {
            enabled = false;
            return;
        }
        Archive oldArchive = oldArchives.next();
        Archive newArchive = newArchives.next();
        if (!(oldArchive instanceof Archive.Versioned)) {
            throw new IllegalArgumentException("Old archive doesn't support extracting the version.");
        }
        if (!(newArchive instanceof Archive.Versioned)) {
            throw new IllegalArgumentException("New archive doesn't support extracting the version.");
        }
        String oldVersionString = ((Archive.Versioned) oldArchive).getVersion();
        String newVersionString = ((Archive.Versioned) newArchive).getVersion();
        Version oldVersion = Version.parse(oldVersionString);
        Version newVersion = Version.parse(newVersionString);
        if (newVersion.major == 0 && oldVersion.major == 0 && !node.get("versionIncreaseAllows").isDefined()) {
            DifferenceSeverity minorChangeAllowed = asSeverity(node.get("versionIncreaseAllows", "minor"), DifferenceSeverity.BREAKING);
            DifferenceSeverity patchVersionAllowed = asSeverity(node.get("versionIncreaseAllows", "patch"), DifferenceSeverity.NON_BREAKING);
            if (newVersion.minor > oldVersion.minor) {
                allowedSeverity = minorChangeAllowed;
            } else if (newVersion.minor == oldVersion.minor && newVersion.patch > oldVersion.patch) {
                allowedSeverity = patchVersionAllowed;
            } else {
                allowedSeverity = null;
            }
        } else {
            DifferenceSeverity majorChangeAllowed = asSeverity(node.get("versionIncreaseAllows", "major"), DifferenceSeverity.BREAKING);
            DifferenceSeverity minorChangeAllowed = asSeverity(node.get("versionIncreaseAllows", "minor"), DifferenceSeverity.NON_BREAKING);
            DifferenceSeverity patchVersionAllowed = asSeverity(node.get("versionIncreaseAllows", "patch"), DifferenceSeverity.EQUIVALENT);
            if (newVersion.major > oldVersion.major) {
                allowedSeverity = majorChangeAllowed;
            } else if (newVersion.major == oldVersion.major && newVersion.minor > oldVersion.minor) {
                allowedSeverity = minorChangeAllowed;
            } else {
                allowedSeverity = patchVersionAllowed;
            }
        }
        passThroughDifferences = Collections.emptyList();
        if (node.get("passThroughDifferences").isDefined()) {
            passThroughDifferences = node.get("passThroughDifferences").asList().stream().map(ModelNode::asString).collect(toList());
        }
    }
}
Also used : Archive(org.revapi.Archive) DifferenceSeverity(org.revapi.DifferenceSeverity) ModelNode(org.jboss.dmr.ModelNode)

Example 2 with Archive

use of org.revapi.Archive in project revapi by revapi.

the class Compiler method compile.

public CompilationValve compile(final ProbingEnvironment environment, final AnalysisConfiguration.MissingClassReporting missingClassReporting, final boolean ignoreMissingAnnotations, final InclusionFilter inclusionFilter) throws Exception {
    File targetPath = Files.createTempDirectory("revapi-java").toAbsolutePath().toFile();
    File sourceDir = new File(targetPath, "sources");
    sourceDir.mkdir();
    File lib = new File(targetPath, "lib");
    lib.mkdir();
    // make sure the classpath is in the same order as passed in
    int classPathSize = size(classPath);
    int nofArchives = classPathSize + size(additionalClassPath);
    int prefixLength = (int) Math.log10(nofArchives) + 1;
    IdentityHashMap<Archive, File> classPathFiles = copyArchives(classPath, lib, 0, prefixLength);
    IdentityHashMap<Archive, File> additionClassPathFiles = copyArchives(additionalClassPath, lib, classPathSize, prefixLength);
    List<String> options = Arrays.asList("-d", sourceDir.toString(), "-cp", composeClassPath(lib));
    List<JavaFileObject> sources = Arrays.<JavaFileObject>asList(new MarkerAnnotationObject(), new ArchiveProbeObject());
    // the locale and charset are actually not important, because the only sources we're providing
    // are not file-based. The rest of the stuff the compiler will be touching is already compiled
    // and therefore not affected by the charset.
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, Locale.getDefault(), Charset.forName("UTF-8"));
    final JavaCompiler.CompilationTask task = compiler.getTask(output, fileManager, null, options, Collections.singletonList(ArchiveProbeObject.CLASS_NAME), sources);
    ProbingAnnotationProcessor processor = new ProbingAnnotationProcessor(environment);
    task.setProcessors(Collections.singletonList(processor));
    Future<Boolean> future = processor.submitWithCompilationAwareness(executor, task, () -> {
        if (Timing.LOG.isDebugEnabled()) {
            Timing.LOG.debug("About to crawl " + environment.getApi());
        }
        try {
            new ClasspathScanner(fileManager, environment, classPathFiles, additionClassPathFiles, missingClassReporting, ignoreMissingAnnotations, inclusionFilter).initTree();
        } catch (IOException e) {
            throw new IllegalStateException("Failed to scan the classpath.", e);
        }
        if (Timing.LOG.isDebugEnabled()) {
            Timing.LOG.debug("Crawl finished for " + environment.getApi());
        }
    });
    return new CompilationValve(future, targetPath, environment, fileManager);
}
Also used : Archive(org.revapi.Archive) JavaCompiler(javax.tools.JavaCompiler) IOException(java.io.IOException) JavaFileObject(javax.tools.JavaFileObject) StandardJavaFileManager(javax.tools.StandardJavaFileManager) File(java.io.File)

Example 3 with Archive

use of org.revapi.Archive in project revapi by revapi.

the class ClasspathScanner method initTree.

void initTree() throws IOException {
    List<ArchiveLocation> classPathLocations = classPath.keySet().stream().map(ArchiveLocation::new).collect(toList());
    Scanner scanner = new Scanner();
    for (ArchiveLocation loc : classPathLocations) {
        scanner.scan(loc, classPath.get(loc.getArchive()), true);
    }
    SyntheticLocation allLoc = new SyntheticLocation();
    fileManager.setLocation(allLoc, classPath.values());
    Function<String, JavaFileObject> searchHard = className -> Stream.concat(Stream.of(allLoc), Stream.of(POSSIBLE_SYSTEM_CLASS_LOCATIONS)).map(l -> {
        try {
            return fileManager.getJavaFileForInput(l, className, JavaFileObject.Kind.CLASS);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }).filter(Objects::nonNull).findFirst().orElse(null);
    Set<TypeElement> lastUnknowns = Collections.emptySet();
    Map<String, ArchiveLocation> cachedArchives = new HashMap<>(additionalClassPath.size());
    while (!scanner.requiredTypes.isEmpty() && !lastUnknowns.equals(scanner.requiredTypes.keySet())) {
        lastUnknowns = new HashSet<>(scanner.requiredTypes.keySet());
        for (TypeElement t : lastUnknowns) {
            String name = environment.getElementUtils().getBinaryName(t).toString();
            JavaFileObject jfo = searchHard.apply(name);
            if (jfo == null) {
                // this type is really missing
                continue;
            }
            URI uri = jfo.toUri();
            String path;
            if ("jar".equals(uri.getScheme())) {
                // we pass our archives as jars, so let's dig only into those
                path = uri.getSchemeSpecificPart();
                // jar:file:/path .. let's get rid of the "file:" part
                int colonIdx = path.indexOf(':');
                if (colonIdx >= 0) {
                    path = path.substring(colonIdx + 1);
                }
                // separate the file path from the in-jar path
                path = path.substring(0, path.lastIndexOf('!'));
                // remove superfluous forward slashes at the start of the path, if any
                int lastSlashIdx = -1;
                for (int i = 0; i < path.length() - 1; ++i) {
                    if (path.charAt(i) == '/' && path.charAt(i + 1) != '/') {
                        lastSlashIdx = i;
                        break;
                    }
                }
                if (lastSlashIdx > 0) {
                    path = path.substring(lastSlashIdx);
                }
            } else {
                path = uri.getPath();
            }
            ArchiveLocation loc = cachedArchives.get(path);
            if (loc == null) {
                Archive ar = null;
                for (Map.Entry<Archive, File> e : additionalClassPath.entrySet()) {
                    if (e.getValue().getAbsolutePath().equals(path)) {
                        ar = e.getKey();
                        break;
                    }
                }
                if (ar != null) {
                    loc = new ArchiveLocation(ar);
                    cachedArchives.put(path, loc);
                }
            }
            if (loc != null) {
                scanner.scanClass(loc, t, false);
            }
        }
    }
    // ok, so scanning the archives doesn't give us any new resolved classes that we need in the API...
    // let's scan the system classpath. What will be left after this will be the truly missing classes.
    // making a copy because the required types might be modified during scanning
    Map<TypeElement, Boolean> rts = new HashMap<>(scanner.requiredTypes);
    ArchiveLocation systemClassPath = new ArchiveLocation(new Archive() {

        @Nonnull
        @Override
        public String getName() {
            return SYSTEM_CLASSPATH_NAME;
        }

        @Nonnull
        @Override
        public InputStream openStream() throws IOException {
            throw new UnsupportedOperationException();
        }
    });
    for (Map.Entry<TypeElement, Boolean> e : rts.entrySet()) {
        scanner.scanClass(systemClassPath, e.getKey(), false);
    }
    scanner.initEnvironment();
}
Also used : Arrays(java.util.Arrays) SimpleTypeVisitor8(javax.lang.model.util.SimpleTypeVisitor8) Modifier(javax.lang.model.element.Modifier) JavaFileManager(javax.tools.JavaFileManager) LoggerFactory(org.slf4j.LoggerFactory) Random(java.util.Random) TypeElement(javax.lang.model.element.TypeElement) Elements(javax.lang.model.util.Elements) Collectors.toMap(java.util.stream.Collectors.toMap) Map(java.util.Map) URI(java.net.URI) WildcardType(javax.lang.model.type.WildcardType) SimpleElementVisitor8(javax.lang.model.util.SimpleElementVisitor8) Collectors.toSet(java.util.stream.Collectors.toSet) EnumSet(java.util.EnumSet) ArrayType(javax.lang.model.type.ArrayType) Filter(org.revapi.query.Filter) StandardLocation(javax.tools.StandardLocation) IdentityHashMap(java.util.IdentityHashMap) EnumMap(java.util.EnumMap) AnnotationElement(org.revapi.java.model.AnnotationElement) Set(java.util.Set) Element(javax.lang.model.element.Element) Types(javax.lang.model.util.Types) Collectors(java.util.stream.Collectors) TypeKind(javax.lang.model.type.TypeKind) Objects(java.util.Objects) JavaFileObject(javax.tools.JavaFileObject) List(java.util.List) IntersectionType(javax.lang.model.type.IntersectionType) Stream(java.util.stream.Stream) TypeVisitor(javax.lang.model.type.TypeVisitor) TypeVariable(javax.lang.model.type.TypeVariable) REPORT(org.revapi.java.AnalysisConfiguration.MissingClassReporting.REPORT) IgnoreCompletionFailures(org.revapi.java.spi.IgnoreCompletionFailures) ErrorType(javax.lang.model.type.ErrorType) AnalysisConfiguration(org.revapi.java.AnalysisConfiguration) VariableElement(javax.lang.model.element.VariableElement) HashMap(java.util.HashMap) Function(java.util.function.Function) HashSet(java.util.HashSet) JavaElementFactory.elementFor(org.revapi.java.model.JavaElementFactory.elementFor) ERROR(org.revapi.java.AnalysisConfiguration.MissingClassReporting.ERROR) Util(org.revapi.java.spi.Util) DeclaredType(javax.lang.model.type.DeclaredType) Archive(org.revapi.Archive) JavaElementBase(org.revapi.java.model.JavaElementBase) ElementFilter(javax.lang.model.util.ElementFilter) MissingClassElement(org.revapi.java.model.MissingClassElement) Nonnull(javax.annotation.Nonnull) LinkedHashSet(java.util.LinkedHashSet) Logger(org.slf4j.Logger) ElementKind(javax.lang.model.element.ElementKind) ExecutableType(javax.lang.model.type.ExecutableType) NoType(javax.lang.model.type.NoType) ExecutableElement(javax.lang.model.element.ExecutableElement) IOException(java.io.IOException) AnnotationMirror(javax.lang.model.element.AnnotationMirror) File(java.io.File) FlatFilter(org.revapi.java.FlatFilter) JavaElementFactory(org.revapi.java.model.JavaElementFactory) StandardJavaFileManager(javax.tools.StandardJavaFileManager) Collectors.toList(java.util.stream.Collectors.toList) AbstractMap(java.util.AbstractMap) TypeMirror(javax.lang.model.type.TypeMirror) MethodElement(org.revapi.java.model.MethodElement) PrimitiveType(javax.lang.model.type.PrimitiveType) UseSite(org.revapi.java.spi.UseSite) ArrayDeque(java.util.ArrayDeque) Comparator(java.util.Comparator) Collections(java.util.Collections) InputStream(java.io.InputStream) Archive(org.revapi.Archive) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) URI(java.net.URI) JavaFileObject(javax.tools.JavaFileObject) Nonnull(javax.annotation.Nonnull) TypeElement(javax.lang.model.element.TypeElement) InputStream(java.io.InputStream) IOException(java.io.IOException) Objects(java.util.Objects) Collectors.toMap(java.util.stream.Collectors.toMap) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) EnumMap(java.util.EnumMap) HashMap(java.util.HashMap) AbstractMap(java.util.AbstractMap) File(java.io.File)

Example 4 with Archive

use of org.revapi.Archive in project revapi by revapi.

the class JavaArchiveAnalyzerTest method testPreventRecursionWhenConstructingInheritedMembers.

@Test
public void testPreventRecursionWhenConstructingInheritedMembers() throws Exception {
    ArchiveAndCompilationPath archive = createCompiledJar("a.jar", "misc/MemberInheritsOwner.java");
    JavaArchiveAnalyzer analyzer = new JavaArchiveAnalyzer(new API(Arrays.asList(new ShrinkwrapArchive(archive.archive)), null), Executors.newSingleThreadExecutor(), null, false, InclusionFilter.acceptAll());
    try {
        JavaElementForest forest = analyzer.analyze();
        forest.getRoots();
        Assert.assertEquals(1, forest.getRoots().size());
        Predicate<Element> findMethod = c -> "method void MemberInheritsOwner::method()".equals(c.getFullHumanReadableString());
        Predicate<Element> findMember1 = c -> "interface MemberInheritsOwner.Member1".equals(c.getFullHumanReadableString());
        Predicate<Element> findMember2 = c -> "interface MemberInheritsOwner.Member2".equals(c.getFullHumanReadableString());
        Element root = forest.getRoots().first();
        Assert.assertEquals(3, root.getChildren().size());
        Assert.assertTrue(root.getChildren().stream().anyMatch(findMethod));
        Assert.assertTrue(root.getChildren().stream().anyMatch(findMember1));
        Assert.assertTrue(root.getChildren().stream().anyMatch(findMember2));
        Assert.assertEquals(1, root.getChildren().stream().filter(findMember1).findFirst().get().getChildren().size());
        Assert.assertEquals(1, root.getChildren().stream().filter(findMember2).findFirst().get().getChildren().size());
    } finally {
        deleteDir(archive.compilationPath);
        analyzer.getCompilationValve().removeCompiledResults();
    }
}
Also used : API(org.revapi.API) Arrays(java.util.Arrays) ShrinkWrap(org.jboss.shrinkwrap.api.ShrinkWrap) Iterator(java.util.Iterator) Predicate(java.util.function.Predicate) TypeElement(org.revapi.java.model.TypeElement) Element(org.revapi.Element) Set(java.util.Set) JavaElementForest(org.revapi.java.model.JavaElementForest) IOException(java.io.IOException) Test(org.junit.Test) ZipExporter(org.jboss.shrinkwrap.api.exporter.ZipExporter) Executors(java.util.concurrent.Executors) JavaArchive(org.jboss.shrinkwrap.api.spec.JavaArchive) Archive(org.revapi.Archive) Assert(org.junit.Assert) Nonnull(javax.annotation.Nonnull) InclusionFilter(org.revapi.java.compilation.InclusionFilter) InputStream(java.io.InputStream) JavaElementForest(org.revapi.java.model.JavaElementForest) TypeElement(org.revapi.java.model.TypeElement) Element(org.revapi.Element) API(org.revapi.API) Test(org.junit.Test)

Example 5 with Archive

use of org.revapi.Archive in project revapi by revapi.

the class BuildTimeReporter method initialize.

@Override
public void initialize(@Nonnull AnalysisContext context) {
    allProblems = new ArrayList<>();
    oldApi = new ArrayList<>();
    for (Archive a : context.getOldApi().getArchives()) {
        oldApi.add(a);
    }
    newApi = new ArrayList<>();
    for (Archive a : context.getNewApi().getArchives()) {
        newApi.add(a);
    }
    this.breakingSeverity = (DifferenceSeverity) context.getData(BREAKING_SEVERITY_KEY);
}
Also used : Archive(org.revapi.Archive)

Aggregations

Archive (org.revapi.Archive)7 IOException (java.io.IOException)4 File (java.io.File)3 InputStream (java.io.InputStream)3 Arrays (java.util.Arrays)2 Map (java.util.Map)2 Set (java.util.Set)2 Nonnull (javax.annotation.Nonnull)2 JavaFileObject (javax.tools.JavaFileObject)2 StandardJavaFileManager (javax.tools.StandardJavaFileManager)2 URI (java.net.URI)1 Path (java.nio.file.Path)1 AbstractMap (java.util.AbstractMap)1 ArrayDeque (java.util.ArrayDeque)1 Collections (java.util.Collections)1 Comparator (java.util.Comparator)1 EnumMap (java.util.EnumMap)1 EnumSet (java.util.EnumSet)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1