org.jboss.prod.jardif.JarDif.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.prod.jardif.JarDif.java

Source

/**
 * JBoss, Home of Professional Open Source.
 * Copyright 2017 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jboss.prod.jardif;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.jboss.prod.jardif.utils.OSUtils;
import org.jboss.prod.jardif.utils.ZipUtils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.jboss.prod.jardif.utils.OSUtils.runCommand;

/**
 * Author: Michal Szynkiewicz, michal.l.szynkiewicz@gmail.com
 * Date: 3/22/17
 * Time: 10:10 AM
 */
public class JarDif {
    private static final String mvnVersion = System.getProperty("mvnVersion", "-0.4.9");
    private static final String gradleVersion = System.getProperty("gradleVersion", "-0.1.0-SNAPSHOT");
    private static final String[] neglected = new String[] { "-tests.jar", "-sources.jar", "-javadoc.jar",
            "-benchmarks.jar" };
    private static final File workDir = new File(".jardif");

    private static final Boolean verbose = Boolean.valueOf(System.getProperty("verbose", "false"));
    public static final Predicate<String> skipNotImportant = name -> Stream.of(neglected).noneMatch(name::endsWith);

    private List<String> gradleJars() {
        return runCommand("find . -path '*/build/*.jar'");
    }

    private List<String> mavenJars() {
        return runCommand("find . -path '*/target/*.jar'");
    }

    private Map<Path, Path> common() {
        Map<Path, Path> resultMap = new HashMap<>();
        List<Path> maven = mavenJars().stream().filter(skipNotImportant).map(Paths::get)
                .collect(Collectors.toList());
        List<Path> gradle = gradleJars().stream().filter(skipNotImportant).map(Paths::get)
                .collect(Collectors.toList());

        maven.forEach(m -> {
            Optional<Path> gradlePath = findCorrespondingGradle(gradle, m);
            gradlePath.ifPresent(p -> {
                resultMap.put(m, p);
                gradle.remove(p);
            });
        });
        if (!gradle.isEmpty()) {
            System.err.println("MISSING MAVEN JARS: " + gradle);
        }
        List<String> missingMaven = new ArrayList<>();
        missingMaven.removeAll(resultMap.keySet());
        if (!missingMaven.isEmpty()) {
            System.err.println("MISSING GRADLE JARS: " + gradle);
        }

        return resultMap;
    }

    private Optional<Path> findCorrespondingGradle(List<Path> gradle, Path mavenJar) {
        String mvnJarName = mavenJar.getFileName().toString();
        String gradleJarName = mvnJarName.replaceAll(Pattern.quote(mvnVersion), gradleVersion);
        return gradle.stream().filter(p -> p.getFileName().toString().equals(gradleJarName)).findAny();
    }

    private void analyze() {
        Map<Path, Path> common = common();
        common.entrySet().stream().forEach(e -> compare(e.getKey(), e.getValue()));
    }

    private void compare(Path maven, Path gradle) {
        System.out.println("===============================================");
        System.out.println(maven + " vs " + gradle);
        System.out.println("===============================================");
        Path gradleDir = new File(workDir, "gradle-" + gradle.getFileName().toString()).toPath();
        Path mvnDir = new File(workDir, "maven-" + maven.getFileName().toString()).toPath();
        ZipUtils.unzip(maven, mvnDir);
        ZipUtils.unzip(gradle, gradleDir);

        List<String> mvnContents = OSUtils.runCommandIn("find . -type f", mvnDir);
        mvnContents.sort(Comparator.comparingInt(String::hashCode));
        List<String> gradleContents = OSUtils.runCommandIn("find . -type f", gradleDir);
        gradleContents.sort(Comparator.comparingInt(String::hashCode));

        Iterator<String> mvnFiles = mvnContents.stream().iterator();
        Iterator<String> gradleFiles = gradleContents.stream().iterator();

        if (!mvnFiles.hasNext() || !gradleFiles.hasNext()) {
            throw new IllegalStateException("One of the jars: " + maven + ", " + gradle + " is empty! Exitting");
        }
        String mvnFile = mvnFiles.next();
        String gradleFile = gradleFiles.next();

        while (mvnFiles.hasNext() && gradleFiles.hasNext()) {
            if (mvnFile.equals(gradleFile)) {
                compareFiles(new File(mvnDir.toFile(), mvnFile), new File(gradleDir.toFile(), gradleFile));
                mvnFile = mvnFiles.next();
                gradleFile = gradleFiles.next();
            } else if (mvnFile.hashCode() < gradleFile.hashCode()) {
                System.out.println("+" + mvnFile);
                mvnFile = mvnFiles.next();
            } else {
                System.out.println("-" + gradleFile);
                gradleFile = gradleFiles.next();
            }
        }

        mvnFiles.forEachRemaining(e -> System.out.println("+" + e));
        gradleFiles.forEachRemaining(e -> System.out.println("-" + e));
        System.out.println();
        System.out.println();
    }

    private void compareFiles(File mavenFile, File gradleFile) {
        String mavenFileName = mavenFile.getAbsolutePath();
        String gradleFileName = gradleFile.getAbsolutePath();
        String mvnToCompare = mavenFileName;
        String gradleToCompare = gradleFileName;

        if (mavenFileName.endsWith(".class")) {
            String gradleBytecodeFile = extractBytecode(gradleFileName);
            String mvnBytecodeFile = extractBytecode(mavenFileName);

            mvnToCompare = mvnBytecodeFile;
            gradleToCompare = gradleBytecodeFile;

        }

        OSUtils.CommandExecutor exec = OSUtils.executor("diff " + mvnToCompare + " " + gradleToCompare).exec();
        int status = exec.getStatus();
        if (status != 0) {
            System.out.println("* " + mavenFile.getAbsolutePath() + " X " + gradleFile.getAbsolutePath());
            if (verbose)
                System.out.println(StringUtils.join(exec.getOut(), "\n"));
        }
    }

    private String extractBytecode(String fileName) {
        String bytecodeFileName = fileName.replace(".class", ".bytecode");
        OSUtils.executor("javap -c " + fileName).failOnInvalidStatusCode().toFile(bytecodeFileName).exec();
        return bytecodeFileName;
    }

    public static void main(String[] args) throws IOException {
        if (args.length > 1) {
            throw new IllegalStateException("Run the program in the project directory");
        }
        if (workDir.exists()) {
            FileUtils.deleteDirectory(workDir);
        }
        workDir.mkdirs();

        new JarDif().analyze();
    }
}