From 537dad4d409a8ea1e9f4ca420d5aedd4b10b2b43 Mon Sep 17 00:00:00 2001 From: Martijn Hoekstra Date: Wed, 31 Mar 2021 15:25:27 +0200 Subject: [PATCH] split jardiff into lib, cli, and sbt sbt being new --- .gitignore | 2 + build.sbt | 42 ++++- cli/src/main/resources/LICENSE | 13 ++ cli/src/main/resources/logback.xml | 14 ++ .../main/scala/scala/tools/jardiff/Main.scala | 0 .../scala/tools/jardiff/IOUtilSpec.scala | 13 +- .../jardiff/sbt-jardiff/SbtJardiff.scala | 172 ++++++++++++++++++ .../sbt-test/jardifftest/jardiffs/build.sbt | 17 ++ .../changed/src/main/scala/Example.scala | 11 ++ .../jardiffs/expected/base.expected | 133 ++++++++++++++ .../jardiffs/expected/bodies.expected | 82 +++++++++ .../jardiffs/expected/ignore.expected | 118 ++++++++++++ .../jardiffs/expected/ignore2.expected | 82 +++++++++ .../jardiffs/expected/privates.expected | 73 ++++++++ .../jardiffs/expected/raw.expected | 99 ++++++++++ .../original/src/main/scala/Example.scala | 4 + .../jardiffs/project/build.properties | 1 + .../jardifftest/jardiffs/project/plugins.sbt | 8 + .../src/sbt-test/jardifftest/jardiffs/test | 33 ++++ 19 files changed, 903 insertions(+), 14 deletions(-) create mode 100644 cli/src/main/resources/LICENSE create mode 100644 cli/src/main/resources/logback.xml rename {core => cli}/src/main/scala/scala/tools/jardiff/Main.scala (100%) create mode 100644 sbtPlugin/src/main/scala/scala/tools/jardiff/sbt-jardiff/SbtJardiff.scala create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/build.sbt create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/changed/src/main/scala/Example.scala create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/base.expected create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/bodies.expected create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/ignore.expected create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/ignore2.expected create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/privates.expected create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/raw.expected create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/original/src/main/scala/Example.scala create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/project/build.properties create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/project/plugins.sbt create mode 100644 sbtPlugin/src/sbt-test/jardifftest/jardiffs/test diff --git a/.gitignore b/.gitignore index dbd4d5f..cf87eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ bin/ .history .classpath .project +.metals +.bloop **/eclipse.sbt **/.cache /.idea/ diff --git a/build.sbt b/build.sbt index 03ac20b..581ecf4 100644 --- a/build.sbt +++ b/build.sbt @@ -1,9 +1,9 @@ val buildName = "jardiff" inThisBuild(Seq[Setting[_]]( - version := "1.0-SNAPSHOT", + version := "2.0.0-SNAPSHOT", organization := "org.scala-lang", - scalaVersion := "2.13.0", + scalaVersion := "2.12.13", startYear := Some(2017), organizationName := "Lightbend Inc. ", licenses := List(("Apache-2.0", url("https://www.apache.org/licenses/LICENSE-2.0.txt"))), @@ -17,18 +17,35 @@ inThisBuild(Seq[Setting[_]]( lazy val root = ( project.in(file(".")) - aggregate(core) + aggregate(core, cli, sbtPlugin) settings( name := buildName, skip in publish := true, ) ) -lazy val core = ( +lazy val cli = ( project. settings( libraryDependencies ++= Seq( "commons-cli" % "commons-cli" % "1.4", + "org.scalatest" %% "scalatest" % "3.1.1" % Test, + ), + name := buildName + "-cli", + headerLicense := Some(HeaderLicense.Custom("Copyright (C) Lightbend Inc. ")), + assemblyMergeStrategy in assembly := { + case "module-info.class" => MergeStrategy.discard + case "rootdoc.txt" => MergeStrategy.discard + case x => (assemblyMergeStrategy in assembly).value(x) + }, + ) + .dependsOn(core) +) + +lazy val core = ( + project. + settings( + libraryDependencies ++= Seq( "org.ow2.asm" % "asm" % AsmVersion, "org.ow2.asm" % "asm-util" % AsmVersion, "org.scala-lang" % "scalap" % System.getProperty("scalap.version", scalaVersion.value), @@ -40,12 +57,19 @@ lazy val core = ( ), name := buildName + "-core", headerLicense := Some(HeaderLicense.Custom("Copyright (C) Lightbend Inc. ")), - assemblyMergeStrategy in assembly := { - case "module-info.class" => MergeStrategy.discard - case "rootdoc.txt" => MergeStrategy.discard - case x => (assemblyMergeStrategy in assembly).value(x) - }, ) ) +lazy val sbtPlugin = + project. + enablePlugins(SbtPlugin). + settings( + name := "sbt-jardiff", + headerLicense := Some(HeaderLicense.Custom("Copyright (C) Lightbend Inc. ")), + scriptedLaunchOpts := { scriptedLaunchOpts.value ++ + Seq("-Xmx1024M", "-Dplugin.version=" + version.value) + }, + scriptedBufferLog := false + ).dependsOn(core) + val AsmVersion = "7.2" diff --git a/cli/src/main/resources/LICENSE b/cli/src/main/resources/LICENSE new file mode 100644 index 0000000..01beb31 --- /dev/null +++ b/cli/src/main/resources/LICENSE @@ -0,0 +1,13 @@ +Copyright 2017-2019 Lightbend, Inc. + +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. diff --git a/cli/src/main/resources/logback.xml b/cli/src/main/resources/logback.xml new file mode 100644 index 0000000..10050b8 --- /dev/null +++ b/cli/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + diff --git a/core/src/main/scala/scala/tools/jardiff/Main.scala b/cli/src/main/scala/scala/tools/jardiff/Main.scala similarity index 100% rename from core/src/main/scala/scala/tools/jardiff/Main.scala rename to cli/src/main/scala/scala/tools/jardiff/Main.scala diff --git a/core/src/test/scala/scala/tools/jardiff/IOUtilSpec.scala b/core/src/test/scala/scala/tools/jardiff/IOUtilSpec.scala index 1d3bea7..4434e88 100644 --- a/core/src/test/scala/scala/tools/jardiff/IOUtilSpec.scala +++ b/core/src/test/scala/scala/tools/jardiff/IOUtilSpec.scala @@ -6,15 +6,18 @@ import java.util.zip.ZipOutputStream import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import scala.util.Using - final class IOUtilSpec extends AnyFlatSpec with Matchers { behavior of "IOUtil.rootPath" it should "handle jar path with spaces" in { val jar = Files.createTempDirectory("app support").resolve("best project.jar") - Using.resource(new ZipOutputStream(Files.newOutputStream(jar)))(_.closeEntry()) // create jar - IOUtil.rootPath(jar).toString shouldBe "/" - IOUtil.rootPath(jar.resolve("foo/Bar.class")).toString shouldBe "/foo/Bar.class" + val stream = new ZipOutputStream(Files.newOutputStream(jar)) + try { + IOUtil.rootPath(jar).toString shouldBe "/" + IOUtil.rootPath(jar.resolve("foo/Bar.class")).toString shouldBe "/foo/Bar.class" + } + finally { + stream.closeEntry() + } } } diff --git a/sbtPlugin/src/main/scala/scala/tools/jardiff/sbt-jardiff/SbtJardiff.scala b/sbtPlugin/src/main/scala/scala/tools/jardiff/sbt-jardiff/SbtJardiff.scala new file mode 100644 index 0000000..724e5c7 --- /dev/null +++ b/sbtPlugin/src/main/scala/scala/tools/jardiff/sbt-jardiff/SbtJardiff.scala @@ -0,0 +1,172 @@ +package scala.tools.jardiff + +package sbtjardiff + +import sbt._ +import Keys._ +import sbt.librarymanagement.ModuleFilter + +object SbtJardiff extends AutoPlugin { + override def trigger = allRequirements + + object autoImport { + val jardiff = + taskKey[Boolean]("run jardiff, returning true if there is a difference") + val jardiffGetPreviousVersion = + taskKey[File]("Resolves and downloads the version set in jardiffPreviousVersionCoordinates") + + val jardiffSettings = taskKey[JarDiff.Config]("jardiff settings") + val jardiffLeaveRepoAt = settingKey[Option[String]]( + "Directory to output a git repository containing the diff" + ) + val jardiffMethodBodies = settingKey[Boolean]( + "Whether or not method bodies should be included in the output" + ) + val jardiffRaw = settingKey[Boolean]("unsorted and unfiltered") + val jardiffIncludePrivates = settingKey[Boolean]("include private members") + val jardiffUnifiedDiffContext = settingKey[Option[Int]]( + "Create a unified diff with this number of context lines" + ) + val jardiffOutputStream = + taskKey[java.io.OutputStream]("Stream to write the diff to. Defaults to stdout") + val jardiffIgnore = settingKey[List[String]]( + "list of file patterns to ignore, using .gitignore syntax" + ) + val jardiffReferenceVersionCoordinates = + settingKey[ModuleID]("reference to jardiff against, in libraryDependencies format") + + val jardiffReferenceVersion = settingKey[String]( + "version number of version to compare against, resolved with current organization and name." + + " If those changed, set jardiffReferenceVersionCoordinates instead, and leave this unset" + ) + } + + import autoImport._ + override lazy val globalSettings: Seq[Setting[_]] = Seq( + jardiffMethodBodies := true, + jardiffLeaveRepoAt := None, + jardiffRaw := false, + jardiffIncludePrivates := true, + jardiffOutputStream := System.out, + jardiffUnifiedDiffContext := None, + jardiffIgnore := Nil + ) + + override lazy val projectSettings: Seq[Setting[_]] = Seq( + jardiffSettings := { + val repo = jardiffLeaveRepoAt.value.map(java.nio.file.Paths.get(_)) + val code = jardiffMethodBodies.value + val raw = jardiffRaw.value + val privates = jardiffIncludePrivates.value + val contextLines = jardiffUnifiedDiffContext.value + val output = jardiffOutputStream.value + val ignore = jardiffIgnore.value + JarDiff.Config(repo, code, raw, privates, contextLines, output, ignore) + }, + jardiffGetPreviousVersion := { + //Adapted from a demonstration by Anton Sviridov + val logger = streams.value.log + val scalaV = scalaBinaryVersion.value + val moduleId = jardiffReferenceVersionCoordinates.?.value + .orElse { + jardiffReferenceVersion.?.value.map(v => organization.value %% name.value % v) + } + .getOrElse { + logger.error( + "sbt-jardiff: set jardiffReferenceVersion to the version to compare to" + ) + throw new Exception("failed to resolve jardiff previous version") + } + val resolver = dependencyResolution.in(update).value + val updateConfiguration_ = updateConfiguration.in(update).value + val unresolvedWarningConfiguration_ = unresolvedWarningConfiguration.in(update).value + val descriptor = resolver.wrapDependencyInModule(moduleId) + + val mfilter: ModuleFilter = module => { + val orgResult = module.organization == moduleId.organization + val nameResult = module.name == moduleId.name + val nameResultAlt = module.name == s"${moduleId.name}_$scalaV" + val revisionResult = module.revision == moduleId.revision + val result = orgResult && (nameResult || nameResultAlt) && revisionResult + + if (result) + logger.debug( + s"module $module matched search for $moduleId, matched by matching name ${module.name} against ${moduleId.name}" + ) + else { + logger.debug(s"module $module is not our dreamed module $moduleId") + if (!orgResult) + logger.debug( + s"the organization doesn't match: ${module.organization} vs ${moduleId.organization}" + ) + else if (!nameResult) + logger.debug( + s"the name doesn't match: ${module.name} vs ${moduleId.name} or ${moduleId.name}_$scalaV" + ) + else if (!revisionResult) + logger.debug(s"the revision doesn't match: ${module.revision} vs ${moduleId.revision}") + } + result + } + + resolver + .update(descriptor, updateConfiguration_, unresolvedWarningConfiguration_, logger) + .fold( + uw => throw uw.resolveException, + x => + x.select(mfilter) match { + case Vector(head) => head + case Vector(head, tail @ _*) => { + logger.warn( + s"sbt-jardiff expected single file for moduleId $moduleId, but got more than that. Arbitrarily selecting $head and discarding ${tail + .mkString(", ")}" + ) + head + } + case v => { + logger.error(s"no file found for module $moduleId. This is a bug in sbt-jardiff") + v.head + } + } + ) + }, + jardiff := { + //register the call to value on compile to make it a dependency of this + //task so it gets executed and completes before this task gets executed + //TODO: figure out what to do when compilation fails and how to + //how to communicate that back upstream + val _ = (Compile / compile).value + + //we assume the previous version can be compared to whatever + //is in the classDirectory directory after compilation. + //It's a somewhat daring assumption that underlines our swashbuckling + //and freebooting disposition. + + //As a mild justification: this is the default location and we're just + //going to have to hope that the project using this plugin don't change + //that. It's unlikely that they'll have: in order to do that, they would + //have had to modified one of the upstreams of classDirectory: + //productDirectories, bloopGenerate, compileIncremental, + //manipulateBytecode or compile itself. + //Modifying these is to the best of my knowledge rare enough that assuming + //they're unchanged. If they are changed, this will break, but the user + //will probably know they are doing something unconventional. + + //That there aren't further steps that happen before the artifact ends up + //is harder to justify, which we do only through furious handwaving and + //victim blaming if it doesn't work, to hide my own incompetence in + //figuring out where to get the exact compilation artifacts for some + //project. + val classDir = (Compile / classDirectory).value + val currentPath = JarDiff.expandClassPath(classDir.getAbsolutePath()) + + val previousJar = jardiffGetPreviousVersion.value + val previousPath = JarDiff.expandClassPath(previousJar.getAbsolutePath()) + + val config = jardiffSettings.value + val differ = JarDiff.apply(List(previousPath, currentPath), config) + + differ.diff() + } + ) +} diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/build.sbt b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/build.sbt new file mode 100644 index 0000000..6414c15 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/build.sbt @@ -0,0 +1,17 @@ +inThisBuild(Seq[Setting[_]]( + scalaVersion := "2.13.1", + organization := "org.example" +)) + +lazy val original = (project in file("empty")) + .settings( + name := "exampleproject", + version := "0.1.0" + ) + +lazy val changed = (project in file("changed")) + .settings( + name := "exampleproject", + version := "0.2.0", + jardiffPreviousVersion := "0.1.0", + ) \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/changed/src/main/scala/Example.scala b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/changed/src/main/scala/Example.scala new file mode 100644 index 0000000..6171b67 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/changed/src/main/scala/Example.scala @@ -0,0 +1,11 @@ +package org.example + +object Example { + def member = "public has method body" + private[this] def privatethis = "privatethis has method body" + private[this] val privatefield: Int = 7 +} + +class OtherExample { + def othermember = "other public has method body" +} \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/base.expected b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/base.expected new file mode 100644 index 0000000..fbb9262 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/base.expected @@ -0,0 +1,133 @@ +diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF +deleted file mode 100644 +index c59a4dc..0000000 +--- a/META-INF/MANIFEST.MF ++++ /dev/null +@@ -1,9 +0,0 @@ +-Manifest-Version: 1.0 +-Specification-Title: exampleproject +-Specification-Version: 0.1.0 +-Specification-Vendor: org.example +-Implementation-Title: exampleproject +-Implementation-Version: 0.1.0 +-Implementation-Vendor: org.example +-Implementation-Vendor-Id: org.example +- +diff --git a/org/example/Example$.class.asm b/org/example/Example$.class.asm +new file mode 100644 +index 0000000..5b35e83 +--- /dev/null ++++ b/org/example/Example$.class.asm +@@ -0,0 +1,45 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example$ { ++ ++ ++ // access flags 0x19 ++ public final static Lorg/example/Example$; MODULE$ ++ ++ // access flags 0x1A ++ private final static I privatefield ++ ++ // access flags 0x9 ++ public static ()V ++ NEW org/example/Example$ ++ DUP ++ INVOKESPECIAL org/example/Example$. ()V ++ PUTSTATIC org/example/Example$.MODULE$ : Lorg/example/Example$; ++ BIPUSH 7 ++ PUTSTATIC org/example/Example$.privatefield : I ++ RETURN ++ MAXSTACK = 2 ++ MAXLOCALS = 0 ++ ++ // access flags 0x2 ++ private ()V ++ ALOAD 0 ++ INVOKESPECIAL java/lang/Object. ()V ++ RETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++ ++ // access flags 0x1 ++ public member()Ljava/lang/String; ++ LDC "public has method body" ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++ ++ // access flags 0x2 ++ private privatethis()Ljava/lang/String; ++ LDC "privatethis has method body" ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++} +diff --git a/org/example/Example.class.asm b/org/example/Example.class.asm +new file mode 100644 +index 0000000..a9f0e10 +--- /dev/null ++++ b/org/example/Example.class.asm +@@ -0,0 +1,13 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example { ++ ++ ++ // access flags 0x9 ++ public static member()Ljava/lang/String; ++ GETSTATIC org/example/Example$.MODULE$ : Lorg/example/Example$; ++ INVOKEVIRTUAL org/example/Example$.member ()Ljava/lang/String; ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 0 ++} +diff --git a/org/example/Example.class.scalap b/org/example/Example.class.scalap +new file mode 100644 +index 0000000..d27f104 +--- /dev/null ++++ b/org/example/Example.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++object Example extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def member: java.lang.String = { /* compiled code */ } ++} +diff --git a/org/example/OtherExample.class.asm b/org/example/OtherExample.class.asm +new file mode 100644 +index 0000000..78d9301 +--- /dev/null ++++ b/org/example/OtherExample.class.asm +@@ -0,0 +1,20 @@ ++// class version 52.0 (52) ++// access flags 0x21 ++public class org/example/OtherExample { ++ ++ ++ // access flags 0x1 ++ public ()V ++ ALOAD 0 ++ INVOKESPECIAL java/lang/Object. ()V ++ RETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++ ++ // access flags 0x1 ++ public othermember()Ljava/lang/String; ++ LDC "other public has method body" ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++} +diff --git a/org/example/OtherExample.class.scalap b/org/example/OtherExample.class.scalap +new file mode 100644 +index 0000000..6ada8a7 +--- /dev/null ++++ b/org/example/OtherExample.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++class OtherExample extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def othermember: java.lang.String = { /* compiled code */ } ++} \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/bodies.expected b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/bodies.expected new file mode 100644 index 0000000..bc4b376 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/bodies.expected @@ -0,0 +1,82 @@ +diff --git a/org/example/Example$.class.asm b/org/example/Example$.class.asm +new file mode 100644 +index 0000000..f284161 +--- /dev/null ++++ b/org/example/Example$.class.asm +@@ -0,0 +1,23 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example$ { ++ ++ ++ // access flags 0x19 ++ public final static Lorg/example/Example$; MODULE$ ++ ++ // access flags 0x1A ++ private final static I privatefield ++ ++ // access flags 0x9 ++ public static ()V ++ ++ // access flags 0x2 ++ private ()V ++ ++ // access flags 0x1 ++ public member()Ljava/lang/String; ++ ++ // access flags 0x2 ++ private privatethis()Ljava/lang/String; ++} +diff --git a/org/example/Example.class.asm b/org/example/Example.class.asm +new file mode 100644 +index 0000000..64d61b8 +--- /dev/null ++++ b/org/example/Example.class.asm +@@ -0,0 +1,8 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example { ++ ++ ++ // access flags 0x9 ++ public static member()Ljava/lang/String; ++} +diff --git a/org/example/Example.class.scalap b/org/example/Example.class.scalap +new file mode 100644 +index 0000000..d27f104 +--- /dev/null ++++ b/org/example/Example.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++object Example extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def member: java.lang.String = { /* compiled code */ } ++} +diff --git a/org/example/OtherExample.class.asm b/org/example/OtherExample.class.asm +new file mode 100644 +index 0000000..0e76fb7 +--- /dev/null ++++ b/org/example/OtherExample.class.asm +@@ -0,0 +1,11 @@ ++// class version 52.0 (52) ++// access flags 0x21 ++public class org/example/OtherExample { ++ ++ ++ // access flags 0x1 ++ public ()V ++ ++ // access flags 0x1 ++ public othermember()Ljava/lang/String; ++} +diff --git a/org/example/OtherExample.class.scalap b/org/example/OtherExample.class.scalap +new file mode 100644 +index 0000000..6ada8a7 +--- /dev/null ++++ b/org/example/OtherExample.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++class OtherExample extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def othermember: java.lang.String = { /* compiled code */ } ++} \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/ignore.expected b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/ignore.expected new file mode 100644 index 0000000..08d0297 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/ignore.expected @@ -0,0 +1,118 @@ +diff --git a/org/example/Example$.class.asm b/org/example/Example$.class.asm +new file mode 100644 +index 0000000..5b35e83 +--- /dev/null ++++ b/org/example/Example$.class.asm +@@ -0,0 +1,45 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example$ { ++ ++ ++ // access flags 0x19 ++ public final static Lorg/example/Example$; MODULE$ ++ ++ // access flags 0x1A ++ private final static I privatefield ++ ++ // access flags 0x9 ++ public static ()V ++ NEW org/example/Example$ ++ DUP ++ INVOKESPECIAL org/example/Example$. ()V ++ PUTSTATIC org/example/Example$.MODULE$ : Lorg/example/Example$; ++ BIPUSH 7 ++ PUTSTATIC org/example/Example$.privatefield : I ++ RETURN ++ MAXSTACK = 2 ++ MAXLOCALS = 0 ++ ++ // access flags 0x2 ++ private ()V ++ ALOAD 0 ++ INVOKESPECIAL java/lang/Object. ()V ++ RETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++ ++ // access flags 0x1 ++ public member()Ljava/lang/String; ++ LDC "public has method body" ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++ ++ // access flags 0x2 ++ private privatethis()Ljava/lang/String; ++ LDC "privatethis has method body" ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++} +diff --git a/org/example/Example.class.asm b/org/example/Example.class.asm +new file mode 100644 +index 0000000..a9f0e10 +--- /dev/null ++++ b/org/example/Example.class.asm +@@ -0,0 +1,13 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example { ++ ++ ++ // access flags 0x9 ++ public static member()Ljava/lang/String; ++ GETSTATIC org/example/Example$.MODULE$ : Lorg/example/Example$; ++ INVOKEVIRTUAL org/example/Example$.member ()Ljava/lang/String; ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 0 ++} +diff --git a/org/example/Example.class.scalap b/org/example/Example.class.scalap +new file mode 100644 +index 0000000..d27f104 +--- /dev/null ++++ b/org/example/Example.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++object Example extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def member: java.lang.String = { /* compiled code */ } ++} +diff --git a/org/example/OtherExample.class.asm b/org/example/OtherExample.class.asm +new file mode 100644 +index 0000000..78d9301 +--- /dev/null ++++ b/org/example/OtherExample.class.asm +@@ -0,0 +1,20 @@ ++// class version 52.0 (52) ++// access flags 0x21 ++public class org/example/OtherExample { ++ ++ ++ // access flags 0x1 ++ public ()V ++ ALOAD 0 ++ INVOKESPECIAL java/lang/Object. ()V ++ RETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++ ++ // access flags 0x1 ++ public othermember()Ljava/lang/String; ++ LDC "other public has method body" ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++} +diff --git a/org/example/OtherExample.class.scalap b/org/example/OtherExample.class.scalap +new file mode 100644 +index 0000000..6ada8a7 +--- /dev/null ++++ b/org/example/OtherExample.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++class OtherExample extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def othermember: java.lang.String = { /* compiled code */ } ++} \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/ignore2.expected b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/ignore2.expected new file mode 100644 index 0000000..276438d --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/ignore2.expected @@ -0,0 +1,82 @@ +diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF +deleted file mode 100644 +index c59a4dc..0000000 +--- a/META-INF/MANIFEST.MF ++++ /dev/null +@@ -1,9 +0,0 @@ +-Manifest-Version: 1.0 +-Specification-Title: exampleproject +-Specification-Version: 0.1.0 +-Specification-Vendor: org.example +-Implementation-Title: exampleproject +-Implementation-Version: 0.1.0 +-Implementation-Vendor: org.example +-Implementation-Vendor-Id: org.example +- +diff --git a/org/example/Example.class.asm b/org/example/Example.class.asm +new file mode 100644 +index 0000000..a9f0e10 +--- /dev/null ++++ b/org/example/Example.class.asm +@@ -0,0 +1,13 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example { ++ ++ ++ // access flags 0x9 ++ public static member()Ljava/lang/String; ++ GETSTATIC org/example/Example$.MODULE$ : Lorg/example/Example$; ++ INVOKEVIRTUAL org/example/Example$.member ()Ljava/lang/String; ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 0 ++} +diff --git a/org/example/Example.class.scalap b/org/example/Example.class.scalap +new file mode 100644 +index 0000000..d27f104 +--- /dev/null ++++ b/org/example/Example.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++object Example extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def member: java.lang.String = { /* compiled code */ } ++} +diff --git a/org/example/OtherExample.class.asm b/org/example/OtherExample.class.asm +new file mode 100644 +index 0000000..78d9301 +--- /dev/null ++++ b/org/example/OtherExample.class.asm +@@ -0,0 +1,20 @@ ++// class version 52.0 (52) ++// access flags 0x21 ++public class org/example/OtherExample { ++ ++ ++ // access flags 0x1 ++ public ()V ++ ALOAD 0 ++ INVOKESPECIAL java/lang/Object. ()V ++ RETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++ ++ // access flags 0x1 ++ public othermember()Ljava/lang/String; ++ LDC "other public has method body" ++ ARETURN ++ MAXSTACK = 1 ++ MAXLOCALS = 1 ++} +diff --git a/org/example/OtherExample.class.scalap b/org/example/OtherExample.class.scalap +new file mode 100644 +index 0000000..6ada8a7 +--- /dev/null ++++ b/org/example/OtherExample.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++class OtherExample extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def othermember: java.lang.String = { /* compiled code */ } ++} \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/privates.expected b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/privates.expected new file mode 100644 index 0000000..9db3824 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/privates.expected @@ -0,0 +1,73 @@ +diff --git a/org/example/Example$.class.asm b/org/example/Example$.class.asm +new file mode 100644 +index 0000000..ee1acd7 +--- /dev/null ++++ b/org/example/Example$.class.asm +@@ -0,0 +1,14 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example$ { ++ ++ ++ // access flags 0x19 ++ public final static Lorg/example/Example$; MODULE$ ++ ++ // access flags 0x9 ++ public static ()V ++ ++ // access flags 0x1 ++ public member()Ljava/lang/String; ++} +diff --git a/org/example/Example.class.asm b/org/example/Example.class.asm +new file mode 100644 +index 0000000..64d61b8 +--- /dev/null ++++ b/org/example/Example.class.asm +@@ -0,0 +1,8 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example { ++ ++ ++ // access flags 0x9 ++ public static member()Ljava/lang/String; ++} +diff --git a/org/example/Example.class.scalap b/org/example/Example.class.scalap +new file mode 100644 +index 0000000..d27f104 +--- /dev/null ++++ b/org/example/Example.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++object Example extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def member: java.lang.String = { /* compiled code */ } ++} +diff --git a/org/example/OtherExample.class.asm b/org/example/OtherExample.class.asm +new file mode 100644 +index 0000000..0e76fb7 +--- /dev/null ++++ b/org/example/OtherExample.class.asm +@@ -0,0 +1,11 @@ ++// class version 52.0 (52) ++// access flags 0x21 ++public class org/example/OtherExample { ++ ++ ++ // access flags 0x1 ++ public ()V ++ ++ // access flags 0x1 ++ public othermember()Ljava/lang/String; ++} +diff --git a/org/example/OtherExample.class.scalap b/org/example/OtherExample.class.scalap +new file mode 100644 +index 0000000..6ada8a7 +--- /dev/null ++++ b/org/example/OtherExample.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++class OtherExample extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def othermember: java.lang.String = { /* compiled code */ } ++} \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/raw.expected b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/raw.expected new file mode 100644 index 0000000..cea4de8 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/expected/raw.expected @@ -0,0 +1,99 @@ +diff --git a/org/example/Example$.class.asm b/org/example/Example$.class.asm +new file mode 100644 +index 0000000..bbbcf39 +--- /dev/null ++++ b/org/example/Example$.class.asm +@@ -0,0 +1,28 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example$ { ++ ++ // compiled from: Example.scala ++ ++ ATTRIBUTE Scala : unknown ++ ++ ATTRIBUTE ScalaInlineInfo : unknown ++ ++ // access flags 0x19 ++ public final static Lorg/example/Example$; MODULE$ ++ ++ // access flags 0x1A ++ private final static I privatefield ++ ++ // access flags 0x9 ++ public static ()V ++ ++ // access flags 0x1 ++ public member()Ljava/lang/String; ++ ++ // access flags 0x2 ++ private privatethis()Ljava/lang/String; ++ ++ // access flags 0x2 ++ private ()V ++} +diff --git a/org/example/Example.class.asm b/org/example/Example.class.asm +new file mode 100644 +index 0000000..b250bb6 +--- /dev/null ++++ b/org/example/Example.class.asm +@@ -0,0 +1,13 @@ ++// class version 52.0 (52) ++// access flags 0x31 ++public final class org/example/Example { ++ ++ // compiled from: Example.scala ++ ++ @Lscala/reflect/ScalaSignature;(bytes="\u0006\u0005\u001d:QAB\u0004\u0009\u000211QAD\u0004\u0009\u0002=AQAF\u0001\u0005\u0002]AQ\u0001G\u0001\u0005\u0002eAaAI\u0001!\n\u0013I\u0002BB\u0012\u0002A\u0003%A%A\u0004Fq\u0006l\u0007\u000f\\3\u000b\u0005!I\u0011aB3yC6\u0004H.\u001a\u0006\u0002\u0015\u0005\u0019qN]4\u0004\u0001A\u0011Q\"A\u0007\u0002\u000f\u00099Q\u0009_1na2,7CA\u0001\u0011!\u0009\u0009B#D\u0001\u0013\u0015\u0005\u0019\u0012!B:dC2\u000c\u0017BA\u000b\u0013\u0005\u0019\u0009e.\u001f*fM\u00061A(\u001b8jiz\"\u0012\u0001D\u0001\u0007[\u0016l'-\u001a:\u0016\u0003i\u0001\"a\u0007\u0011\u000e\u0003qQ!!\u0008\u0010\u0002\u00091\u000cgn\u001a\u0006\u0002?\u0005!!.\u0019()V ++} +diff --git a/org/example/OtherExample.class.scalap b/org/example/OtherExample.class.scalap +new file mode 100644 +index 0000000..6ada8a7 +--- /dev/null ++++ b/org/example/OtherExample.class.scalap +@@ -0,0 +1,5 @@ ++package org.example ++class OtherExample extends scala.AnyRef { ++ def this() = { /* compiled code */ } ++ def othermember: java.lang.String = { /* compiled code */ } ++} \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/original/src/main/scala/Example.scala b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/original/src/main/scala/Example.scala new file mode 100644 index 0000000..58c5cb9 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/original/src/main/scala/Example.scala @@ -0,0 +1,4 @@ +package org.example + +object Example { +} \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/project/build.properties b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/project/build.properties new file mode 100644 index 0000000..0b2e09c --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.4.7 diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/project/plugins.sbt b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/project/plugins.sbt new file mode 100644 index 0000000..00ec237 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/project/plugins.sbt @@ -0,0 +1,8 @@ +sys.props.get("plugin.version") match { + case Some(x) => { + addSbtPlugin("org.scala-lang" % "sbt-jardiff" % x) + } + case _ => { + addSbtPlugin("org.scala-lang" % "sbt-jardiff" % "1.3-SNAPSHOT") + } +} \ No newline at end of file diff --git a/sbtPlugin/src/sbt-test/jardifftest/jardiffs/test b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/test new file mode 100644 index 0000000..9f78ef0 --- /dev/null +++ b/sbtPlugin/src/sbt-test/jardifftest/jardiffs/test @@ -0,0 +1,33 @@ +# project original is near-empty. Use it as a reference to jardiff with various options +# first publish the original +> project original +> publishLocal +# then run jardiff against that project +> project changed +> set jardiffOutputStream := new java.io.FileOutputStream("base.out") +> jardiff +# and check if the output is as expected +$ must-mirror base.out expected/base.expected +# ignore list works both ways +> set jardiffIgnore := List("Example$*") +> set jardiffOutputStream := new java.io.FileOutputStream("ignore2.out") +> jardiff +> set jardiffIgnore := List("MANIFEST.MF") +> set jardiffOutputStream := new java.io.FileOutputStream("ignore.out") +> jardiff +$ must-mirror ignore.out expected/ignore.expected +$ must-mirror ignore2.out expected/ignore2.expected +# omit message bodies +> set jardiffMethodBodies := false +> set jardiffOutputStream := new java.io.FileOutputStream("bodies.out") +> jardiff +$ must-mirror bodies.out expected/bodies.expected +> set jardiffRaw := true +> set jardiffOutputStream := new java.io.FileOutputStream("raw.out") +> jardiff +$ must-mirror raw.out expected/raw.expected +> set jardiffRaw := false +> set jardiffIncludePrivates := false +> set jardiffOutputStream := new java.io.FileOutputStream("privates.out") +> jardiff +$ must-mirror privates.out expected/privates.expected