From 6dfe498932b4d2881d581d58d7a627652f518fb1 Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Mon, 20 Oct 2025 13:35:34 +0200 Subject: [PATCH 1/3] Add Mill build --- .github/scripts/ci.sh | 37 -- .github/workflows/ci.yml | 38 +- .gitignore | 1 + build.mill | 357 ++++++++++++++++++ mill | 329 ++++++++++++++++ mill-build/build.mill | 11 + .../lolgab/mill/mima/InterfaceMima.scala | 48 +++ mill-build/src/interfacebuild/Check.scala | 27 ++ .../CoursierInterfaceVersion.scala | 38 ++ mill-build/src/interfacebuild/ZipUtil.scala | 111 ++++++ mill.bat | 299 +++++++++++++++ 11 files changed, 1246 insertions(+), 50 deletions(-) delete mode 100755 .github/scripts/ci.sh create mode 100644 build.mill create mode 100755 mill create mode 100644 mill-build/build.mill create mode 100644 mill-build/src/com/github/lolgab/mill/mima/InterfaceMima.scala create mode 100644 mill-build/src/interfacebuild/Check.scala create mode 100644 mill-build/src/interfacebuild/CoursierInterfaceVersion.scala create mode 100644 mill-build/src/interfacebuild/ZipUtil.scala create mode 100644 mill.bat diff --git a/.github/scripts/ci.sh b/.github/scripts/ci.sh deleted file mode 100755 index 93a83a0..0000000 --- a/.github/scripts/ci.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash -set -exo pipefail - -# Re-enable when switching to an sbt version that pulls an lm-coursier version -# that has https://github.com/coursier/sbt-coursier/pull/403. -# export COURSIER_JNI="force" - -TEST_VERSION="0.1.0-test" - -echo "Running tests" -sbt +test - -IS_UNIX="false" -case "$(uname -s)" in - Linux*) IS_UNIX="true";; - Darwin*) IS_UNIX="true";; - *) -esac - -if [ "$IS_UNIX" == "true" ]; then - echo "Running MiMA checks" - sbt +mimaReportBinaryIssues - - echo "Publishing locally" - sbt \ - 'set version in ThisBuild := "'"$TEST_VERSION"'"' \ - publishLocal - echo "Running JDK 8 tests…" - - TEST_JDK="adoptium:8" - eval "$(cs java --jvm "$TEST_JDK" --env)" - - java -Xmx32m -version - - export TEST_VERSION - sbt test -fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a908c40..88b45e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,10 +24,27 @@ jobs: - uses: coursier/setup-action@v1.3 with: jvm: 21 - apps: sbt - name: Test - run: ./.github/scripts/ci.sh - shell: bash + run: ./mill -i __.test + + mima: + runs-on: ${{ matrix.OS }} + name: Test ${{ matrix.OS }} + strategy: + fail-fast: false + matrix: + OS: ["ubuntu-latest", "macos-13", "windows-latest"] + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + submodules: true + - uses: coursier/cache-action@v6 + - uses: coursier/setup-action@v1.3 + with: + jvm: 21 + - name: Test + run: ./mill -i __.mimaReportBinaryIssues publish: if: github.event_name == 'push' @@ -41,15 +58,10 @@ jobs: - uses: coursier/setup-action@v1.3 with: jvm: 21 - apps: sbt sbtn - - run: .github/scripts/gpg-setup.sh - shell: bash - env: - PGP_SECRET: ${{ secrets.PUBLISH_SECRET_KEY }} - name: Release - run: sbtn ci-release + run: ./mill -i mill.scalalib.SonatypeCentralPublishModule/ env: - PGP_SECRET: ${{ secrets.PUBLISH_SECRET_KEY }} - PGP_PASSPHRASE: ${{ secrets.PUBLISH_SECRET_KEY_PASSWORD }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + MILL_PGP_SECRET_BASE64: ${{ secrets.PUBLISH_SECRET_KEY }} + MILL_PGP_PASSPHRASE: ${{ secrets.PUBLISH_SECRET_KEY_PASSWORD }} + MILL_SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + MILL_SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} diff --git a/.gitignore b/.gitignore index 850d894..e32af4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target/ +out/ .bsp/ .metals/ .vscode/ diff --git a/build.mill b/build.mill new file mode 100644 index 0000000..e1a7bfb --- /dev/null +++ b/build.mill @@ -0,0 +1,357 @@ +//| mill-version: 1.0.6 + +import interfacebuild.* + +import com.github.lolgab.mill.mima.* +import mill.* +import mill.api.BuildCtx +import mill.scalalib.* +import mill.util.Jvm + +import java.util.Locale + +import scala.util.Properties + +object Versions { + def scala213 = "2.13.17" + def scala212 = "2.12.20" + + def scala = Seq(scala212, scala213) + + def junit = "4.13.2" + def utest = "0.9.1" +} + +object Deps { + def coursier = mvn"io.get-coursier::coursier:2.1.25-M19" + def coursierJvm = mvn"io.get-coursier::coursier-jvm:2.1.25-M19".exclude(("net.java.dev.jna", "jna")) + def scalaReflect(sv: String) = mvn"org.scala-lang:scala-reflect:$sv" + def slf4j = mvn"org.slf4j:slf4j-api:1.7.36" + def windowsJniCoursierApi = mvn"io.get-coursier.jniutils:windows-jni-utils-coursierapi:0.3.3" + + def proguard = mvn"com.guardsquare:proguard-base:7.8.1" +} + +trait CoursierInterfaceModule extends ScalaModule { + def scalacOptions = super.scalacOptions() ++ Seq( + "-deprecation", + "--release", "8" + ) + def javacOptions = Task { + super.javacOptions() ++ Seq( + "-source", "8", + "-target", "8", + "-bootclasspath", Util.rtJar.toString + ) + } + def javadocOptions = Task { + super.javadocOptions() ++ Seq( + "-source", "8", + "-bootclasspath", Util.rtJar.toString + ) + } +} + +object CoursierInterfacePublishedModule { + def organization = "io.get-coursier" +} + +trait CoursierInterfacePublishedModule extends CoursierInterfaceModule with PublishModule { + import mill.scalalib.publish._ + + def pomSettings = PomSettings( + description = artifactName(), + organization = CoursierInterfacePublishedModule.organization, + url = "https://github.com/coursier/interface", + licenses = Seq(License.`Apache-2.0`), + versionControl = VersionControl.github("coursier", "interface"), + developers = Seq( + Developer("alexarchambault", "Alex Archambault", "https://github.com/alexarchambault") + ) + ) + + def publishVersion = CoursierInterfaceVersion.buildVersion +} + +trait CoursierInterfaceBinCompatModule extends JavaModule with InterfaceMima { + def mimaPreviousVersions = { + + def stable(ver: String): Boolean = + ver.exists(c => c != '0' && c != '.') && + ver + .replace("-RC", "-") + .forall(c => c == '.' || c == '-' || c.isDigit) + + os.proc(("git", "tag", "--merged", "HEAD^")) + .call(cwd = BuildCtx.workspaceRoot, stdin = os.Inherit) + .out.lines() + .iterator + .map(_.trim) + .filter(_.startsWith("v")) + .map(_.stripPrefix("v")) + .filter(stable) + // filtering out non cross versioned module in 0.0.1 (published cross-versioned there, added below) + // TODO Mill: Add 0.0.1 + .filter(_ != "0.0.1") + // borked release, jline and jansi not shaded in it + .filter(_ != "0.0.11") + .toSeq + } +} + +object interface extends Cross[Interface](Versions.scala) + +trait Interface extends CoursierInterfacePublishedModule with CrossSbtModule { + def artifactName = "interface-no-shading" + def mvnDeps = super.mvnDeps() ++ Seq( + Deps.coursier, + Deps.coursierJvm, + Deps.windowsJniCoursierApi, + Deps.slf4j // no need to shade that one… + ) + + object test extends CrossSbtTests with TestModule.Utest { + def utestVersion = Versions.utest + } +} + +object proguarded extends CoursierInterfacePublishedModule { + def interfaceSv = Versions.scala213 + def artifactId = "interface" + def scalaVersion = interface(interfaceSv).scalaVersion() + def mvnDeps = Seq( + Deps.slf4j + ) + + object mima extends CoursierInterfaceBinCompatModule { + def jar = Task { + val input = proguarded.jar().path + val dest = Task.dest / "interface.jar" + InterfaceMima.cleanUpJar( + proguarded.jar().path, + Task.dest / "interface.jar", + ignore = name => !name.startsWith("coursierapi/shaded/") || name.startsWith("coursierapi/internal/") + ) + PathRef(dest) + } + def mimaPreviousArtifacts = Task { + mimaPreviousVersions().map(ver => mvn"${proguarded.pomSettings().organization}:${proguarded.artifactId()}:$ver") + } + } + + def mimaBinaryIssueFilters = Seq( + ProblemFilter.exclude[Problem]("coursierapi.shaded.*"), + ProblemFilter.exclude[Problem]("coursierapi.internal.*") + ) + + def proguardedJar = Task { + val dest = Task.dest / "interface.jar" + val configFile = Task.dest / "config.pro" + val proguardOptions = { + val baseOptions = Seq( + "-dontnote", + "-dontwarn", + "-dontobfuscate", + "-dontoptimize", + "-keep class coursierapi.** {\n public protected *;\n}" + ) + val maybeJava9Options = + if (Util.isJava9OrMore) { + val javaHome = os.Path(sys.props.getOrElse("java.home", ???)) + Seq( + s"-libraryjars ${javaHome / "jmods/java.base.jmod"}", + s"-libraryjars ${javaHome / "jmods/java.xml.jmod"}" + ) + } + else + Nil + val classPathOptions = interface(interfaceSv) + .runClasspath() + .map(_.path) + .filter(os.exists) + .flatMap { path => + val isLibrary = path.last.startsWith("slf4j-api-") && path.last.endsWith(".jar") + if (isLibrary) + Seq("-libraryjars", path.toString) + else { + val filterOpt = path.last match { + case n if n.startsWith("interface") => None // keep META-INF from main JAR + case n if n.startsWith("windows-jni-utils") => Some("!META-INF/MANIFEST.MF") + case n if n.startsWith("coursier-core") => Some("!META-INF/**,!coursier.properties,!coursier/coursier.properties") + case n if n.startsWith("scala-xml") => Some("!META-INF/**,!scala-xml.properties") + case n if n.startsWith("scala-library") => Some("!META-INF/**,!library.properties,!rootdoc.txt") + case n if n.startsWith("tika-core") => Some("!META-INF/**,!pipes-fork-server-default-log4j2.xml") + case _ => Some("!META-INF/**") + } + Seq("-injars", path.toString + filterOpt.fold("")("(" + _ + ")")) + } + } + val outputOptions = Seq("-outjars", dest.toString) + baseOptions ++ maybeJava9Options ++ classPathOptions ++ outputOptions + } + os.write(configFile, proguardOptions.map(_ + System.lineSeparator()).mkString) + val proguardCp = defaultResolver() + .classpath(Seq(Deps.proguard)) + .map(_.path) + Jvm.callProcess( + mainClass = "proguard.ProGuard", + mainArgs = Seq("-include", configFile.toString), + classPath = proguardCp, + jvmArgs = Seq("-Xmx3172M"), + stdin = os.Inherit, + stdout = os.Inherit, + stderr = os.Inherit + ) + PathRef(dest) + } + def proguardedAndShadedJar = Task { + import com.eed3si9n.jarjar._ + import com.eed3si9n.jarjar.util.StandaloneJarProcessor + val input = proguardedJar().path + def rename(from: String, to: String): Rule = { + val rule = new Rule + rule.setPattern(from) + rule.setResult(to) + rule + } + val rules = Seq( + rename("scala.**", "coursierapi.shaded.scala.@1"), + rename("coursier.**", "coursierapi.shaded.coursier.@1"), + rename("dependency.**", "coursierapi.shaded.dependency.@1"), + rename("org.fusesource.**", "coursierapi.shaded.org.fusesource.@1"), + rename("io.github.alexarchambault.windowsansi.**", "coursierapi.shaded.windowsansi.@1"), + rename("concurrentrefhashmap.**", "coursierapi.shaded.concurrentrefhashmap.@1"), + rename("org.apache.commons.codec.**", "coursierapi.shaded.commonscodec.@1"), + rename("org.apache.commons.compress.**", "coursierapi.shaded.commonscompress.@1"), + rename("org.apache.commons.io.**", "coursierapi.shaded.commonsio.@1"), + rename("org.codehaus.plexus.**", "coursierapi.shaded.plexus.@1"), + rename("org.tukaani.xz.**", "coursierapi.shaded.xz.@1"), + rename("org.iq80.snappy.**", "coursierapi.shaded.snappy.@1"), + rename("com.github.plokhotnyuk.jsoniter_scala.core.**", "coursierapi.shaded.jsoniter.@1"), + rename("com.github.luben.zstd.**", "coursierapi.shaded.zstd.@1"), + rename("io.airlift.compress.**", "coursierapi.shaded.compress.@1"), + rename("io.github.alexarchambault.isterminal.**", "coursierapi.shaded.isterminal.@1"), + rename("org.apache.commons.lang3.**", "coursierapi.shaded.lang3.@1"), + rename("org.apache.tika.**", "coursierapi.shaded.tika.@1") + ) + val processor = new com.eed3si9n.jarjar.JJProcessor( + rules, + verbose = false, + skipManifest = true, + misplacedClassStrategy = "fatal" + ) + val dest = Task.dest / "interface.jar" + StandaloneJarProcessor.run(input.toIO, dest.toIO, processor) + PathRef(dest) + } + def cleanedUpJar = Task { + val input = proguardedAndShadedJar().path + val intermediaryDest = Task.dest / "intermediary.jar" + val dest = Task.dest / "interface.jar" + val toBeRemoved = Set( + "LICENSE", + "NOTICE", + "README" + ) + val directoriesToBeRemoved = Seq( + "licenses/" + ) + assert(directoriesToBeRemoved.forall(_.endsWith("/"))) + ZipUtil.removeFromZip( + input, + intermediaryDest, + name => + toBeRemoved(name) || directoriesToBeRemoved.exists(dir => + name.startsWith(dir) + ) + ) + val serviceContent = + ZipUtil.zipEntryContent(proguardedJar().path, "META-INF/services/coursier.jniutils.NativeApi").getOrElse { + sys.error(s"META-INF/services/coursier.jniutils.NativeApi not found in ${proguardedJar().path}") + } + ZipUtil.addOrOverwriteInZip( + intermediaryDest, + dest, + Seq( + "META-INF/services/coursierapi.shaded.coursier.jniutils.NativeApi" -> serviceContent + ) + ) + PathRef(dest) + } + def jar = Task { + val jar0 = cleanedUpJar() + Check.onlyNamespace("coursierapi", jar0.path.toIO) + jar0 + } + def docJar = interface(interfaceSv).docJar() + def sourceJar = interface(interfaceSv).sourceJar() +} + +trait DependsOnProguarded extends JavaModule { + def mvnDeps = super.mvnDeps() ++ Seq( + mvn"${CoursierInterfacePublishedModule.organization}:interface:${proguarded.publishVersion()}" + ) + def repositories = super.repositories() ++ Seq( + proguarded.publishLocalTestRepo().path.toNIO.toUri.toASCIIString + ) +} + +object interpolators extends Cross[Interpolators](Versions.scala) + +trait Interpolators extends CoursierInterfacePublishedModule with CoursierInterfaceBinCompatModule with CrossSbtModule with DependsOnProguarded { + def compileMvnDeps = super.compileMvnDeps() ++ Seq( + Deps.scalaReflect(scalaVersion()) + ) + + def mimaPreviousVersions = Task { + val ignore = + if (scalaVersion().startsWith("2.13.")) (0 to 8).map("0.0." + _).toSet + else Set() + if (ignore.isEmpty) + super.mimaPreviousVersions() + else + super.mimaPreviousVersions().filter(!ignore(_)) + } + + def mimaBinaryIssueFilters = Seq( + ProblemFilter.exclude[MissingClassProblem]("coursierapi.Interpolators$Macros$"), + ) + + object test extends CrossSbtTests with TestModule.Utest { + def utestVersion = Versions.utest + } +} + +object `interface-test` extends Cross[InterfaceTest](Versions.scala) + +trait InterfaceTest extends CoursierInterfaceModule with CrossSbtModule with DependsOnProguarded { interfaceTest => + object test extends interfaceTest.SbtTests with TestModule.Junit4 { + def junit4Version = Versions.junit + } +} + +object Util { + private def isArm64 = + Option(System.getProperty("os.arch")).map(_.toLowerCase(Locale.ROOT)) match { + case Some("aarch64" | "arm64") => true + case _ => false + } + private lazy val java8Home = Option(System.getenv("COURSIER_INTERFACE_JAVA8_HOME")).getOrElse { + val jvmId = + if (Properties.isMac && isArm64) + // no native JDK 8 on Mac ARM, using amd64 one + "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u432-b06/OpenJDK8U-jdk_x64_mac_hotspot_8u432b06.tar.gz" + else + "adoptium:8" + os.proc("cs", "java-home", "--jvm", jvmId) + .call() + .out.trim() + } + lazy val rtJar = { + val path = os.Path(java8Home) / "jre/lib/rt.jar" + assert(os.isFile(path)) + path + } + + lazy val isJava9OrMore = sys.props.get("java.version").exists(!_.startsWith("1.")) +} diff --git a/mill b/mill new file mode 100755 index 0000000..0343f0d --- /dev/null +++ b/mill @@ -0,0 +1,329 @@ +#!/usr/bin/env sh + +# This is a wrapper script, that automatically selects or downloads Mill from Maven Central or GitHub release pages. +# +# This script determines the Mill version to use by trying these sources +# - env-variable `MILL_VERSION` +# - local file `.mill-version` +# - local file `.config/mill-version` +# - `mill-version` from YAML fronmatter of current buildfile +# - if accessible, find the latest stable version available on Maven Central (https://repo1.maven.org/maven2) +# - env-variable `DEFAULT_MILL_VERSION` +# +# If a version has the suffix '-native' a native binary will be used. +# If a version has the suffix '-jvm' an executable jar file will be used, requiring an already installed Java runtime. +# If no such suffix is found, the script will pick a default based on version and platform. +# +# Once a version was determined, it tries to use either +# - a system-installed mill, if found and it's version matches +# - an already downloaded version under ~/.cache/mill/download +# +# If no working mill version was found on the system, +# this script downloads a binary file from Maven Central or Github Pages (this is version dependent) +# into a cache location (~/.cache/mill/download). +# +# Mill Project URL: https://github.com/com-lihaoyi/mill +# Script Version: 1.0.0-M1-21-7b6fae-DIRTY892b63e8 +# +# If you want to improve this script, please also contribute your changes back! +# This script was generated from: dist/scripts/src/mill.sh +# +# Licensed under the Apache License, Version 2.0 + +set -e + +if [ "$1" = "--setup-completions" ] ; then + # Need to preserve the first position of those listed options + MILL_FIRST_ARG=$1 + shift +fi + +if [ -z "${DEFAULT_MILL_VERSION}" ] ; then + DEFAULT_MILL_VERSION="0.12.10" +fi + + +if [ -z "${GITHUB_RELEASE_CDN}" ] ; then + GITHUB_RELEASE_CDN="" +fi + + +MILL_REPO_URL="https://github.com/com-lihaoyi/mill" + +if [ -z "${CURL_CMD}" ] ; then + CURL_CMD=curl +fi + +# Explicit commandline argument takes precedence over all other methods +if [ "$1" = "--mill-version" ] ; then + echo "The --mill-version option is no longer supported." 1>&2 +fi + +MILL_BUILD_SCRIPT="" + +if [ -f "build.mill" ] ; then + MILL_BUILD_SCRIPT="build.mill" +fi + +# Please note, that if a MILL_VERSION is already set in the environment, +# We reuse it's value and skip searching for a value. + +# If not already set, read .mill-version file +if [ -z "${MILL_VERSION}" ] ; then + if [ -f ".mill-version" ] ; then + MILL_VERSION="$(tr '\r' '\n' < .mill-version | head -n 1 2> /dev/null)" + elif [ -f ".config/mill-version" ] ; then + MILL_VERSION="$(tr '\r' '\n' < .config/mill-version | head -n 1 2> /dev/null)" + elif [ -n "${MILL_BUILD_SCRIPT}" ] ; then + MILL_VERSION="$(cat ${MILL_BUILD_SCRIPT} | grep '//[|] *mill-version: *' | sed 's;//| *mill-version: *;;')" + fi +fi + +MILL_USER_CACHE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/mill" + +if [ -z "${MILL_DOWNLOAD_PATH}" ] ; then + MILL_DOWNLOAD_PATH="${MILL_USER_CACHE_DIR}/download" +fi + +# If not already set, try to fetch newest from Github +if [ -z "${MILL_VERSION}" ] ; then + # TODO: try to load latest version from release page + echo "No mill version specified." 1>&2 + echo "You should provide a version via a '//| mill-version: ' comment or a '.mill-version' file." 1>&2 + + mkdir -p "${MILL_DOWNLOAD_PATH}" + LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" 2>/dev/null || ( + # we might be on OSX or BSD which don't have -d option for touch + # but probably a -A [-][[hh]mm]SS + touch "${MILL_DOWNLOAD_PATH}/.expire_latest"; touch -A -010000 "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) || ( + # in case we still failed, we retry the first touch command with the intention + # to show the (previously suppressed) error message + LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) + + # POSIX shell variant of bash's -nt operator, see https://unix.stackexchange.com/a/449744/6993 + # if [ "${MILL_DOWNLOAD_PATH}/.latest" -nt "${MILL_DOWNLOAD_PATH}/.expire_latest" ] ; then + if [ -n "$(find -L "${MILL_DOWNLOAD_PATH}/.latest" -prune -newer "${MILL_DOWNLOAD_PATH}/.expire_latest")" ]; then + # we know a current latest version + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # we don't know a current latest version + echo "Retrieving latest mill version ..." 1>&2 + LANG=C ${CURL_CMD} -s -i -f -I ${MILL_REPO_URL}/releases/latest 2> /dev/null | grep --ignore-case Location: | sed s'/^.*tag\///' | tr -d '\r\n' > "${MILL_DOWNLOAD_PATH}/.latest" + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # Last resort + MILL_VERSION="${DEFAULT_MILL_VERSION}" + echo "Falling back to hardcoded mill version ${MILL_VERSION}" 1>&2 + else + echo "Using mill version ${MILL_VERSION}" 1>&2 + fi +fi + +MILL_NATIVE_SUFFIX="-native" +MILL_JVM_SUFFIX="-jvm" +FULL_MILL_VERSION=$MILL_VERSION +ARTIFACT_SUFFIX="" +set_artifact_suffix(){ + if [ "$(expr substr $(uname -s) 1 5 2>/dev/null)" = "Linux" ]; then + if [ "$(uname -m)" = "aarch64" ]; then + ARTIFACT_SUFFIX="-native-linux-aarch64" + else + ARTIFACT_SUFFIX="-native-linux-amd64" + fi + elif [ "$(uname)" = "Darwin" ]; then + if [ "$(uname -m)" = "arm64" ]; then + ARTIFACT_SUFFIX="-native-mac-aarch64" + else + ARTIFACT_SUFFIX="-native-mac-amd64" + fi + else + echo "This native mill launcher supports only Linux and macOS." 1>&2 + exit 1 + fi +} + +case "$MILL_VERSION" in + *"$MILL_NATIVE_SUFFIX") + MILL_VERSION=${MILL_VERSION%"$MILL_NATIVE_SUFFIX"} + set_artifact_suffix + ;; + + *"$MILL_JVM_SUFFIX") + MILL_VERSION=${MILL_VERSION%"$MILL_JVM_SUFFIX"} + ;; + + *) + case "$MILL_VERSION" in + 0.1.*) ;; + 0.2.*) ;; + 0.3.*) ;; + 0.4.*) ;; + 0.5.*) ;; + 0.6.*) ;; + 0.7.*) ;; + 0.8.*) ;; + 0.9.*) ;; + 0.10.*) ;; + 0.11.*) ;; + 0.12.*) ;; + *) + set_artifact_suffix + esac + ;; +esac + +MILL="${MILL_DOWNLOAD_PATH}/$MILL_VERSION$ARTIFACT_SUFFIX" + +try_to_use_system_mill() { + if [ "$(uname)" != "Linux" ]; then + return 0 + fi + + MILL_IN_PATH="$(command -v mill || true)" + + if [ -z "${MILL_IN_PATH}" ]; then + return 0 + fi + + SYSTEM_MILL_FIRST_TWO_BYTES=$(head --bytes=2 "${MILL_IN_PATH}") + if [ "${SYSTEM_MILL_FIRST_TWO_BYTES}" = "#!" ]; then + # MILL_IN_PATH is (very likely) a shell script and not the mill + # executable, ignore it. + return 0 + fi + + SYSTEM_MILL_PATH=$(readlink -e "${MILL_IN_PATH}") + SYSTEM_MILL_SIZE=$(stat --format=%s "${SYSTEM_MILL_PATH}") + SYSTEM_MILL_MTIME=$(stat --format=%y "${SYSTEM_MILL_PATH}") + + if [ ! -d "${MILL_USER_CACHE_DIR}" ]; then + mkdir -p "${MILL_USER_CACHE_DIR}" + fi + + SYSTEM_MILL_INFO_FILE="${MILL_USER_CACHE_DIR}/system-mill-info" + if [ -f "${SYSTEM_MILL_INFO_FILE}" ]; then + parseSystemMillInfo() { + LINE_NUMBER="${1}" + # Select the line number of the SYSTEM_MILL_INFO_FILE, cut the + # variable definition in that line in two halves and return + # the value, and finally remove the quotes. + sed -n "${LINE_NUMBER}p" "${SYSTEM_MILL_INFO_FILE}" |\ + cut -d= -f2 |\ + sed 's/"\(.*\)"/\1/' + } + + CACHED_SYSTEM_MILL_PATH=$(parseSystemMillInfo 1) + CACHED_SYSTEM_MILL_VERSION=$(parseSystemMillInfo 2) + CACHED_SYSTEM_MILL_SIZE=$(parseSystemMillInfo 3) + CACHED_SYSTEM_MILL_MTIME=$(parseSystemMillInfo 4) + + if [ "${SYSTEM_MILL_PATH}" = "${CACHED_SYSTEM_MILL_PATH}" ] \ + && [ "${SYSTEM_MILL_SIZE}" = "${CACHED_SYSTEM_MILL_SIZE}" ] \ + && [ "${SYSTEM_MILL_MTIME}" = "${CACHED_SYSTEM_MILL_MTIME}" ]; then + if [ "${CACHED_SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then + MILL="${SYSTEM_MILL_PATH}" + return 0 + else + return 0 + fi + fi + fi + + SYSTEM_MILL_VERSION=$(${SYSTEM_MILL_PATH} --version | head -n1 | sed -n 's/^Mill.*version \(.*\)/\1/p') + + cat < "${SYSTEM_MILL_INFO_FILE}" +CACHED_SYSTEM_MILL_PATH="${SYSTEM_MILL_PATH}" +CACHED_SYSTEM_MILL_VERSION="${SYSTEM_MILL_VERSION}" +CACHED_SYSTEM_MILL_SIZE="${SYSTEM_MILL_SIZE}" +CACHED_SYSTEM_MILL_MTIME="${SYSTEM_MILL_MTIME}" +EOF + + if [ "${SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then + MILL="${SYSTEM_MILL_PATH}" + fi +} +try_to_use_system_mill + +# If not already downloaded, download it +if [ ! -s "${MILL}" ] || [ "$MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT" = "1" ] ; then + case $MILL_VERSION in + 0.0.* | 0.1.* | 0.2.* | 0.3.* | 0.4.* ) + DOWNLOAD_SUFFIX="" + DOWNLOAD_FROM_MAVEN=0 + ;; + 0.5.* | 0.6.* | 0.7.* | 0.8.* | 0.9.* | 0.10.* | 0.11.0-M* ) + DOWNLOAD_SUFFIX="-assembly" + DOWNLOAD_FROM_MAVEN=0 + ;; + *) + DOWNLOAD_SUFFIX="-assembly" + DOWNLOAD_FROM_MAVEN=1 + ;; + esac + case $MILL_VERSION in + 0.12.0 | 0.12.1 | 0.12.2 | 0.12.3 | 0.12.4 | 0.12.5 | 0.12.6 | 0.12.7 | 0.12.8 | 0.12.9 | 0.12.10 | 0.12.11 ) + DOWNLOAD_EXT="jar" + ;; + 0.12.* ) + DOWNLOAD_EXT="exe" + ;; + 0.* ) + DOWNLOAD_EXT="jar" + ;; + *) + DOWNLOAD_EXT="exe" + ;; + esac + + DOWNLOAD_FILE=$(mktemp mill.XXXXXX) + if [ "$DOWNLOAD_FROM_MAVEN" = "1" ] ; then + DOWNLOAD_URL="https://repo1.maven.org/maven2/com/lihaoyi/mill-dist${ARTIFACT_SUFFIX}/${MILL_VERSION}/mill-dist${ARTIFACT_SUFFIX}-${MILL_VERSION}.${DOWNLOAD_EXT}" + else + MILL_VERSION_TAG=$(echo "$MILL_VERSION" | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/') + DOWNLOAD_URL="${GITHUB_RELEASE_CDN}${MILL_REPO_URL}/releases/download/${MILL_VERSION_TAG}/${MILL_VERSION}${DOWNLOAD_SUFFIX}" + unset MILL_VERSION_TAG + fi + + if [ "$MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT" = "1" ] ; then + echo $DOWNLOAD_URL + echo $MILL + exit 0 + fi + # TODO: handle command not found + echo "Downloading mill ${MILL_VERSION} from ${DOWNLOAD_URL} ..." 1>&2 + ${CURL_CMD} -f -L -o "${DOWNLOAD_FILE}" "${DOWNLOAD_URL}" + chmod +x "${DOWNLOAD_FILE}" + mkdir -p "${MILL_DOWNLOAD_PATH}" + mv "${DOWNLOAD_FILE}" "${MILL}" + + unset DOWNLOAD_FILE + unset DOWNLOAD_SUFFIX +fi + +if [ -z "$MILL_MAIN_CLI" ] ; then + MILL_MAIN_CLI="${0}" +fi + +MILL_FIRST_ARG="" +if [ "$1" = "--bsp" ] || [ "${1#"-i"}" != "$1" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--no-daemon" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then + # Need to preserve the first position of those listed options + MILL_FIRST_ARG=$1 + shift +fi + +unset MILL_DOWNLOAD_PATH +unset MILL_OLD_DOWNLOAD_PATH +unset OLD_MILL +unset MILL_VERSION +unset MILL_REPO_URL + +# -D mill.main.cli is for compatibility with Mill 0.10.9 - 0.13.0-M2 +# We don't quote MILL_FIRST_ARG on purpose, so we can expand the empty value without quotes +# shellcheck disable=SC2086 +exec "${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@" diff --git a/mill-build/build.mill b/mill-build/build.mill new file mode 100644 index 0000000..6983042 --- /dev/null +++ b/mill-build/build.mill @@ -0,0 +1,11 @@ +import mill._ +import mill.meta.MillBuildRootModule +import mill.scalalib._ + +object `package` extends MillBuildRootModule { + + override def mvnDeps = Seq( + mvn"com.github.lolgab::mill-mima::0.2.0", + mvn"com.eed3si9n.jarjarabrams::jarjar-abrams-core:1.16.0" + ) +} diff --git a/mill-build/src/com/github/lolgab/mill/mima/InterfaceMima.scala b/mill-build/src/com/github/lolgab/mill/mima/InterfaceMima.scala new file mode 100644 index 0000000..e333f4a --- /dev/null +++ b/mill-build/src/com/github/lolgab/mill/mima/InterfaceMima.scala @@ -0,0 +1,48 @@ +package com.github.lolgab.mill.mima + +import mill.javalib.Dep +import mill.api.* +import mill.* + +import java.util.zip.{ZipEntry, ZipFile, ZipOutputStream} + +import scala.jdk.CollectionConverters.* +import scala.util.Using + +trait InterfaceMima extends Mima { + def resolvedMimaPreviousArtifacts: T[Seq[(Dep, PathRef)]] = Task { + val base = super.resolvedMimaPreviousArtifacts() + val dir = Task.dest + base.zipWithIndex.map { + case ((dep, ref), idx) => + val dest = dir / s"$idx.jar" + InterfaceMima.cleanUpJar( + ref.path, + dest, + ignore = name => !name.startsWith("coursierapi/shaded/") || name.startsWith("coursierapi/internal/") + ) + (dep, PathRef(dest)) + } + } +} + +object InterfaceMima { + def cleanUpJar(input: os.Path, output: os.Path, ignore: String => Boolean): Unit = + Using.resources( + new ZipFile(input.toIO), + os.write.outputStream(output) + ) { (zf, os0) => + val zos = new ZipOutputStream(os0) + def keep(name: String) = + !name.startsWith("coursierapi/shaded/") && + !name.startsWith("coursierapi/internal/") + for (ent <- zf.entries().asScala if keep(ent.getName)) { + val ent0 = new ZipEntry(ent) + zos.putNextEntry(ent0) + val entryContent = zf.getInputStream(ent).readAllBytes() + zos.write(entryContent) + zos.closeEntry() + } + zos.finish() + } +} diff --git a/mill-build/src/interfacebuild/Check.scala b/mill-build/src/interfacebuild/Check.scala new file mode 100644 index 0000000..74714eb --- /dev/null +++ b/mill-build/src/interfacebuild/Check.scala @@ -0,0 +1,27 @@ +package interfacebuild + +import java.io.File +import java.util.zip.ZipFile + +import scala.jdk.CollectionConverters.* + +object Check { + + def onlyNamespace(ns: String, jar: File): Unit = { + val zf = new ZipFile(jar) + val unrecognized = zf.entries() + .asScala + .map(_.getName) + .filter { n => + !n.startsWith("META-INF/") && !n.startsWith(ns + "/") && + n != "scala-collection-compat.properties" && // collection-compat adds that + !n.contains("/libzstd-jni-") // com.github.luben:zstd-jni stuff (pulled via plexus-archiver) + } + .toVector + .sorted + for (u <- unrecognized) + System.err.println(s"Unrecognized: $u") + assert(unrecognized.isEmpty) + } + +} diff --git a/mill-build/src/interfacebuild/CoursierInterfaceVersion.scala b/mill-build/src/interfacebuild/CoursierInterfaceVersion.scala new file mode 100644 index 0000000..d1a99fa --- /dev/null +++ b/mill-build/src/interfacebuild/CoursierInterfaceVersion.scala @@ -0,0 +1,38 @@ +package interfacebuild + +import mill.* +import mill.api.* + +object CoursierInterfaceVersion extends ExternalModule { + + def latestTaggedVersion(): String = + os.proc("git", "describe", "--abbrev=0", "--tags", "--match", "v*") + .call().out + .trim() + + def computeBuildVersion(): String = { + val gitHead = os.proc("git", "rev-parse", "HEAD").call().out.trim() + val maybeExactTag = { + val res = os.proc("git", "describe", "--exact-match", "--tags", "--always", gitHead) + .call(stderr = os.Pipe, check = false) + if (res.exitCode == 0) + Some(res.out.trim().stripPrefix("v")) + else + None + } + maybeExactTag.getOrElse { + val latestTaggedVersion0 = latestTaggedVersion() + val commitsSinceTaggedVersion = + os.proc("git", "rev-list", gitHead, "--not", latestTaggedVersion0, "--count") + .call().out.trim() + .toInt + val gitHash = os.proc("git", "rev-parse", "--short", "HEAD").call().out.trim() + s"${latestTaggedVersion0.stripPrefix("v")}-$commitsSinceTaggedVersion-$gitHash-SNAPSHOT" + } + } + def buildVersion: T[String] = Task.Input { + computeBuildVersion() + } + + lazy val millDiscover: Discover = Discover[this.type] +} diff --git a/mill-build/src/interfacebuild/ZipUtil.scala b/mill-build/src/interfacebuild/ZipUtil.scala new file mode 100644 index 0000000..31c36ce --- /dev/null +++ b/mill-build/src/interfacebuild/ZipUtil.scala @@ -0,0 +1,111 @@ +package interfacebuild + +import java.io.{ByteArrayOutputStream, File, FileInputStream, FileOutputStream, InputStream} +import java.util.zip.{ZipEntry, ZipFile, ZipInputStream, ZipOutputStream} + +object ZipUtil { + + private def readFullySync(is: InputStream) = { + val buffer = new ByteArrayOutputStream + val data = Array.ofDim[Byte](16384) + + var nRead = is.read(data, 0, data.length) + while (nRead != -1) { + buffer.write(data, 0, nRead) + nRead = is.read(data, 0, data.length) + } + + buffer.flush() + buffer.toByteArray + } + + private def zipEntries(zipStream: ZipInputStream): Iterator[(ZipEntry, Array[Byte])] = + new Iterator[(ZipEntry, Array[Byte])] { + private var nextEntry = Option.empty[ZipEntry] + private def update() = + nextEntry = Option(zipStream.getNextEntry) + + update() + + def hasNext = nextEntry.nonEmpty + def next() = { + val ent = nextEntry.get + val data = readFullySync(zipStream) + + update() + + (ent, data) + } + } + + def removeFromZip(sourceZip: os.Path, destZip: os.Path, remove: String => Boolean): Unit = { + + val is = os.read.inputStream(sourceZip) + val os0 = os.write.outputStream(destZip) + val bootstrapZip = new ZipInputStream(is) + val outputZip = new ZipOutputStream(os0) + + for ((ent, data) <- zipEntries(bootstrapZip) if !remove(ent.getName)) { + + // Same workaround as https://github.com/spring-projects/spring-boot/issues/13720 + // (https://github.com/spring-projects/spring-boot/commit/a50646b7cc3ad941e748dfb450077e3a73706205#diff-2ff64cd06c0b25857e3e0dfdb6733174R144) + ent.setCompressedSize(-1L) + + outputZip.putNextEntry(ent) + outputZip.write(data) + outputZip.closeEntry() + } + + outputZip.finish() + outputZip.close() + + is.close() + os0.close() + + } + + def addOrOverwriteInZip(sourceZip: os.Path, destZip: os.Path, toAdd: Seq[(String, Array[Byte])]): Unit = { + + val is = os.read.inputStream(sourceZip) + val os0 = os.write.outputStream(destZip) + val bootstrapZip = new ZipInputStream(is) + val outputZip = new ZipOutputStream(os0) + + val strip = toAdd.map(_._1).toSet + + for ((ent, data) <- zipEntries(bootstrapZip) if !strip.contains(ent.getName)) { + + // Same workaround as https://github.com/spring-projects/spring-boot/issues/13720 + // (https://github.com/spring-projects/spring-boot/commit/a50646b7cc3ad941e748dfb450077e3a73706205#diff-2ff64cd06c0b25857e3e0dfdb6733174R144) + ent.setCompressedSize(-1L) + + outputZip.putNextEntry(ent) + outputZip.write(data) + outputZip.closeEntry() + } + + for ((name, content) <- toAdd) { + val ent = new ZipEntry(name) + outputZip.putNextEntry(ent) + outputZip.write(content) + outputZip.closeEntry() + } + + outputZip.finish() + outputZip.close() + + is.close() + os0.close() + } + + def zipEntryContent(sourceZip: os.Path, entryName: String): Option[Array[Byte]] = { + val zf = new ZipFile(sourceZip.toIO) + val entryOpt = Option(zf.getEntry(entryName)) + val content = entryOpt.map { entry => + readFullySync(zf.getInputStream(entry)) + } + zf.close() + content + } + +} diff --git a/mill.bat b/mill.bat new file mode 100644 index 0000000..f36d812 --- /dev/null +++ b/mill.bat @@ -0,0 +1,299 @@ +@echo off + +rem This is a wrapper script, that automatically selects or downloads Mill from Maven Central or GitHub release pages. +rem +rem This script determines the Mill version to use by trying these sources +rem - env-variable `MILL_VERSION` +rem - local file `.mill-version` +rem - local file `.config/mill-version` +rem - `mill-version` from YAML fronmatter of current buildfile +rem - if accessible, find the latest stable version available on Maven Central (https://repo1.maven.org/maven2) +rem - env-variable `DEFAULT_MILL_VERSION` +rem +rem If a version has the suffix '-native' a native binary will be used. +rem If a version has the suffix '-jvm' an executable jar file will be used, requiring an already installed Java runtime. +rem If no such suffix is found, the script will pick a default based on version and platform. +rem +rem Once a version was determined, it tries to use either +rem - a system-installed mill, if found and it's version matches +rem - an already downloaded version under %USERPROFILE%\.mill\download +rem +rem If no working mill version was found on the system, +rem this script downloads a binary file from Maven Central or Github Pages (this is version dependent) +rem into a cache location (%USERPROFILE%\.mill\download). +rem +rem Mill Project URL: https://github.com/com-lihaoyi/mill +rem Script Version: 1.0.0-M1-21-7b6fae-DIRTY892b63e8 +rem +rem If you want to improve this script, please also contribute your changes back! +rem This script was generated from: dist/scripts/src/mill.bat +rem +rem Licensed under the Apache License, Version 2.0 + +rem setlocal seems to be unavailable on Windows 95/98/ME +rem but I don't think we need to support them in 2019 +setlocal enabledelayedexpansion + +if [!DEFAULT_MILL_VERSION!]==[] ( set "DEFAULT_MILL_VERSION=0.12.10" ) + +if [!MILL_GITHUB_RELEASE_CDN!]==[] ( set "MILL_GITHUB_RELEASE_CDN=" ) + +if [!MILL_MAIN_CLI!]==[] ( set "MILL_MAIN_CLI=%~f0" ) + +set "MILL_REPO_URL=https://github.com/com-lihaoyi/mill" + +SET MILL_BUILD_SCRIPT= + +if exist "build.mill" ( + set MILL_BUILD_SCRIPT=build.mill +) else ( + if exist "build.mill.scala" ( + set MILL_BUILD_SCRIPT=build.mill.scala + ) else ( + if exist "build.sc" ( + set MILL_BUILD_SCRIPT=build.sc + ) else ( + rem no-op + ) + ) +) + +if [!MILL_VERSION!]==[] ( + if exist .mill-version ( + set /p MILL_VERSION=<.mill-version + ) else ( + if exist .config\mill-version ( + set /p MILL_VERSION=<.config\mill-version + ) else ( + if not "%MILL_BUILD_SCRIPT%"=="" ( + for /f "tokens=1-2*" %%a in ('findstr /C:"//| mill-version:" %MILL_BUILD_SCRIPT%') do ( + set "MILL_VERSION=%%c" + ) + ) else ( + rem no-op + ) + ) + ) +) + +if [!MILL_VERSION!]==[] set MILL_VERSION=%DEFAULT_MILL_VERSION% + +if [!MILL_DOWNLOAD_PATH!]==[] set MILL_DOWNLOAD_PATH=%USERPROFILE%\.mill\download + +rem without bat file extension, cmd doesn't seem to be able to run it + +set "MILL_NATIVE_SUFFIX=-native" +set "MILL_JVM_SUFFIX=-jvm" +set "FULL_MILL_VERSION=%MILL_VERSION%" +set "MILL_EXT=.bat" +set "ARTIFACT_SUFFIX=" +REM Check if MILL_VERSION contains MILL_NATIVE_SUFFIX +echo !MILL_VERSION! | findstr /C:"%MILL_NATIVE_SUFFIX%" >nul +if !errorlevel! equ 0 ( + set "MILL_VERSION=%MILL_VERSION:-native=%" + REM -native images compiled with graal do not support windows-arm + REM https://github.com/oracle/graal/issues/9215 + IF /I NOT "%PROCESSOR_ARCHITECTURE%"=="ARM64" ( + set "ARTIFACT_SUFFIX=-native-windows-amd64" + set "MILL_EXT=.exe" + ) else ( + rem no-op + ) +) else ( + echo !MILL_VERSION! | findstr /C:"%MILL_JVM_SUFFIX%" >nul + if !errorlevel! equ 0 ( + set "MILL_VERSION=%MILL_VERSION:-jvm=%" + ) else ( + set "SKIP_VERSION=false" + set "MILL_PREFIX=%MILL_VERSION:~0,4%" + if "!MILL_PREFIX!"=="0.1." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.2." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.3." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.4." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.5." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.6." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.7." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.8." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.9." set "SKIP_VERSION=true" + set "MILL_PREFIX=%MILL_VERSION:~0,5%" + if "!MILL_PREFIX!"=="0.10." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.11." set "SKIP_VERSION=true" + if "!MILL_PREFIX!"=="0.12." set "SKIP_VERSION=true" + + if "!SKIP_VERSION!"=="false" ( + IF /I NOT "%PROCESSOR_ARCHITECTURE%"=="ARM64" ( + set "ARTIFACT_SUFFIX=-native-windows-amd64" + set "MILL_EXT=.exe" + ) + ) else ( + rem no-op + ) + ) +) + +set MILL=%MILL_DOWNLOAD_PATH%\!FULL_MILL_VERSION!!MILL_EXT! + +set MILL_RESOLVE_DOWNLOAD= + +if not exist "%MILL%" ( + set MILL_RESOLVE_DOWNLOAD=true +) else ( + if defined MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT ( + set MILL_RESOLVE_DOWNLOAD=true + ) else ( + rem no-op + ) +) + + +if [!MILL_RESOLVE_DOWNLOAD!]==[true] ( + set MILL_VERSION_PREFIX=%MILL_VERSION:~0,4% + set MILL_SHORT_VERSION_PREFIX=%MILL_VERSION:~0,2% + rem Since 0.5.0 + set MILL_DOWNLOAD_SUFFIX=-assembly + rem Since 0.11.0 + set MILL_DOWNLOAD_FROM_MAVEN=1 + if [!MILL_VERSION_PREFIX!]==[0.0.] ( + set MILL_DOWNLOAD_SUFFIX= + set MILL_DOWNLOAD_FROM_MAVEN=0 + ) + if [!MILL_VERSION_PREFIX!]==[0.1.] ( + set MILL_DOWNLOAD_SUFFIX= + set MILL_DOWNLOAD_FROM_MAVEN=0 + ) + if [!MILL_VERSION_PREFIX!]==[0.2.] ( + set MILL_DOWNLOAD_SUFFIX= + set MILL_DOWNLOAD_FROM_MAVEN=0 + ) + if [!MILL_VERSION_PREFIX!]==[0.3.] ( + set MILL_DOWNLOAD_SUFFIX= + set MILL_DOWNLOAD_FROM_MAVEN=0 + ) + if [!MILL_VERSION_PREFIX!]==[0.4.] ( + set MILL_DOWNLOAD_SUFFIX= + set MILL_DOWNLOAD_FROM_MAVEN=0 + ) + if [!MILL_VERSION_PREFIX!]==[0.5.] set MILL_DOWNLOAD_FROM_MAVEN=0 + if [!MILL_VERSION_PREFIX!]==[0.6.] set MILL_DOWNLOAD_FROM_MAVEN=0 + if [!MILL_VERSION_PREFIX!]==[0.7.] set MILL_DOWNLOAD_FROM_MAVEN=0 + if [!MILL_VERSION_PREFIX!]==[0.8.] set MILL_DOWNLOAD_FROM_MAVEN=0 + if [!MILL_VERSION_PREFIX!]==[0.9.] set MILL_DOWNLOAD_FROM_MAVEN=0 + + set MILL_VERSION_PREFIX=%MILL_VERSION:~0,5% + if [!MILL_VERSION_PREFIX!]==[0.10.] set MILL_DOWNLOAD_FROM_MAVEN=0 + + set MILL_VERSION_PREFIX=%MILL_VERSION:~0,8% + if [!MILL_VERSION_PREFIX!]==[0.11.0-M] set MILL_DOWNLOAD_FROM_MAVEN=0 + + set MILL_VERSION_PREFIX=%MILL_VERSION:~0,5% + set DOWNLOAD_EXT=exe + if [!MILL_SHORT_VERSION_PREFIX!]==[0.] set DOWNLOAD_EXT=jar + if [!MILL_VERSION_PREFIX!]==[0.12.] set DOWNLOAD_EXT=exe + if [!MILL_VERSION!]==[0.12.0] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.1] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.2] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.3] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.4] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.5] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.6] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.7] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.8] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.9] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.10] set DOWNLOAD_EXT=jar + if [!MILL_VERSION!]==[0.12.11] set DOWNLOAD_EXT=jar + + set MILL_VERSION_PREFIX= + set MILL_SHORT_VERSION_PREFIX= + + for /F "delims=- tokens=1" %%A in ("!MILL_VERSION!") do set MILL_VERSION_BASE=%%A + set MILL_VERSION_MILESTONE= + for /F "delims=- tokens=2" %%A in ("!MILL_VERSION!") do set MILL_VERSION_MILESTONE=%%A + set MILL_VERSION_MILESTONE_START=!MILL_VERSION_MILESTONE:~0,1! + if [!MILL_VERSION_MILESTONE_START!]==[M] ( + set MILL_VERSION_TAG=!MILL_VERSION_BASE!-!MILL_VERSION_MILESTONE! + ) else ( + set MILL_VERSION_TAG=!MILL_VERSION_BASE! + ) + if [!MILL_DOWNLOAD_FROM_MAVEN!]==[1] ( + set MILL_DOWNLOAD_URL=https://repo1.maven.org/maven2/com/lihaoyi/mill-dist!ARTIFACT_SUFFIX!/!MILL_VERSION!/mill-dist!ARTIFACT_SUFFIX!-!MILL_VERSION!.!DOWNLOAD_EXT! + ) else ( + set MILL_DOWNLOAD_URL=!MILL_GITHUB_RELEASE_CDN!%MILL_REPO_URL%/releases/download/!MILL_VERSION_TAG!/!MILL_VERSION!!MILL_DOWNLOAD_SUFFIX! + ) + + if defined MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT ( + echo !MILL_DOWNLOAD_URL! + echo !MILL! + exit /b 0 + ) + + rem there seems to be no way to generate a unique temporary file path (on native Windows) + set MILL_DOWNLOAD_FILE=%MILL%.tmp + + echo Downloading mill !MILL_VERSION! from !MILL_DOWNLOAD_URL! ... 1>&2 + + if not exist "%MILL_DOWNLOAD_PATH%" mkdir "%MILL_DOWNLOAD_PATH%" + rem curl is bundled with recent Windows 10 + rem but I don't think we can expect all the users to have it in 2019 + where /Q curl + if !ERRORLEVEL! EQU 0 ( + curl -f -L "!MILL_DOWNLOAD_URL!" -o "!MILL_DOWNLOAD_FILE!" + ) else ( + rem bitsadmin seems to be available on Windows 7 + rem without /dynamic, github returns 403 + rem bitsadmin is sometimes needlessly slow but it looks better with /priority foreground + bitsadmin /transfer millDownloadJob /dynamic /priority foreground "!MILL_DOWNLOAD_URL!" "!MILL_DOWNLOAD_FILE!" + ) + if not exist "!MILL_DOWNLOAD_FILE!" ( + echo Could not download mill !MILL_VERSION! 1>&2 + exit /b 1 + ) + + move /y "!MILL_DOWNLOAD_FILE!" "%MILL%" + + set MILL_DOWNLOAD_FILE= + set MILL_DOWNLOAD_SUFFIX= +) + +set MILL_DOWNLOAD_PATH= +set MILL_VERSION= +set MILL_REPO_URL= + +rem Need to preserve the first position of those listed options +set MILL_FIRST_ARG= +if [%~1%]==[--bsp] ( + set MILL_FIRST_ARG=%1% +) else ( + if [%~1%]==[-i] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--interactive] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--no-server] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--no-daemon] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--repl] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--help] ( + set MILL_FIRST_ARG=%1% + ) + ) + ) + ) + ) + ) +) +set "MILL_PARAMS=%*%" + +if not [!MILL_FIRST_ARG!]==[] ( + for /f "tokens=1*" %%a in ("%*") do ( + set "MILL_PARAMS=%%b" + ) +) + +rem -D mill.main.cli is for compatibility with Mill 0.10.9 - 0.13.0-M2 +"%MILL%" %MILL_FIRST_ARG% -D "mill.main.cli=%MILL_MAIN_CLI%" %MILL_PARAMS% From 23db1ba5a604c7791144b5df796c412e9a56f74a Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Mon, 27 Oct 2025 18:32:12 +0100 Subject: [PATCH 2/3] Remove sbt build --- .github/scripts/gpg-setup.sh | 10 -- build.sbt | 312 ----------------------------------- project/Check.scala | 26 --- project/Mima.scala | 23 --- project/Settings.scala | 87 ---------- project/ZipUtil.scala | 111 ------------- project/build.properties | 1 - project/plugins.sbt | 7 - 8 files changed, 577 deletions(-) delete mode 100755 .github/scripts/gpg-setup.sh delete mode 100644 build.sbt delete mode 100644 project/Check.scala delete mode 100644 project/Mima.scala delete mode 100644 project/Settings.scala delete mode 100644 project/ZipUtil.scala delete mode 100644 project/build.properties delete mode 100644 project/plugins.sbt diff --git a/.github/scripts/gpg-setup.sh b/.github/scripts/gpg-setup.sh deleted file mode 100755 index ad58f40..0000000 --- a/.github/scripts/gpg-setup.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env sh - -# from https://github.com/coursier/apps/blob/f1d2bf568bf466a98569a85c3f23c5f3a8eb5360/.github/scripts/gpg-setup.sh - -echo $PGP_SECRET | base64 --decode | gpg --import --no-tty --batch --yes - -echo "allow-loopback-pinentry" >>~/.gnupg/gpg-agent.conf -echo "pinentry-mode loopback" >>~/.gnupg/gpg.conf - -gpg-connect-agent reloadagent /bye diff --git a/build.sbt b/build.sbt deleted file mode 100644 index 78df311..0000000 --- a/build.sbt +++ /dev/null @@ -1,312 +0,0 @@ -import com.typesafe.tools.mima.core.{MissingClassProblem, Problem, ProblemFilters} - -import scala.xml.{Node => XmlNode, _} -import scala.xml.transform.{RewriteRule, RuleTransformer} - -inThisBuild(List( - organization := "io.get-coursier", - homepage := Some(url("https://github.com/coursier/interface")), - licenses := List("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")), - developers := List( - Developer( - "alexarchambault", - "Alexandre Archambault", - "alexandre.archambault@gmail.com", - url("https://github.com/alexarchambault") - ) - ) -)) - -lazy val finalPackageBin = taskKey[File]("") - -lazy val isJava9OrMore = sys.props.get("java.version").exists(!_.startsWith("1.")) - -lazy val interface = project - .enablePlugins(SbtProguard) - .settings( - scalacOptions += "-deprecation", - moduleName := { - val former = moduleName.value - val sv = scalaVersion.value - val sbv = sv.split('.').take(2).mkString(".") - if (sv == Settings.scala213) - former - else - former + "-scala-" + sbv + "-shaded" - }, - finalPackageBin := { - import com.eed3si9n.jarjar._ - import com.eed3si9n.jarjar.util.StandaloneJarProcessor - - val orig = (Proguard / proguard).value.head - val origLastModified = orig.lastModified() - val dest = orig.getParentFile / s"${orig.getName.stripSuffix(".jar")}-with-renaming-test.jar" - if (!dest.exists() || dest.lastModified() < origLastModified) { - val tmpDest = orig.getParentFile / s"${orig.getName.stripSuffix(".jar")}-with-renaming-test-0.jar" - val tmpDest1 = orig.getParentFile / s"${orig.getName.stripSuffix(".jar")}-with-renaming-test-1.jar" - - def rename(from: String, to: String): Rule = { - val rule = new Rule - rule.setPattern(from) - rule.setResult(to) - rule - } - - val rules = Seq( - rename("scala.**", "coursierapi.shaded.scala.@1"), - rename("coursier.**", "coursierapi.shaded.coursier.@1"), - rename("dependency.**", "coursierapi.shaded.dependency.@1"), - rename("org.fusesource.**", "coursierapi.shaded.org.fusesource.@1"), - rename("io.github.alexarchambault.windowsansi.**", "coursierapi.shaded.windowsansi.@1"), - rename("concurrentrefhashmap.**", "coursierapi.shaded.concurrentrefhashmap.@1"), - rename("org.apache.commons.codec.**", "coursierapi.shaded.commonscodec.@1"), - rename("org.apache.commons.compress.**", "coursierapi.shaded.commonscompress.@1"), - rename("org.apache.commons.io.**", "coursierapi.shaded.commonsio.@1"), - rename("org.codehaus.plexus.**", "coursierapi.shaded.plexus.@1"), - rename("org.tukaani.xz.**", "coursierapi.shaded.xz.@1"), - rename("org.iq80.snappy.**", "coursierapi.shaded.snappy.@1"), - rename("com.github.plokhotnyuk.jsoniter_scala.core.**", "coursierapi.shaded.jsoniter.@1"), - rename("com.github.luben.zstd.**", "coursierapi.shaded.zstd.@1"), - rename("io.airlift.compress.**", "coursierapi.shaded.compress.@1"), - rename("io.github.alexarchambault.isterminal.**", "coursierapi.shaded.isterminal.@1"), - rename("org.apache.commons.lang3.**", "coursierapi.shaded.lang3.@1"), - rename("org.apache.tika.**", "coursierapi.shaded.tika.@1") - ) - - val processor = new com.eed3si9n.jarjar.JJProcessor( - rules, - verbose = false, - skipManifest = true, - misplacedClassStrategy = "fatal" - ) - StandaloneJarProcessor.run(orig, tmpDest, processor) - - val toBeRemoved = Set( - "LICENSE", - "NOTICE", - "README" - ) - val directoriesToBeRemoved = Seq( - "licenses/" - ) - assert(directoriesToBeRemoved.forall(_.endsWith("/"))) - ZipUtil.removeFromZip( - tmpDest, - tmpDest1, - name => - toBeRemoved(name) || directoriesToBeRemoved.exists(dir => - name.startsWith(dir) - ) - ) - tmpDest.delete() - - val serviceContent = - ZipUtil.zipEntryContent(orig, "META-INF/services/coursier.jniutils.NativeApi").getOrElse { - sys.error(s"META-INF/services/coursier.jniutils.NativeApi not found in $orig") - } - - ZipUtil.addOrOverwriteInZip( - tmpDest1, - dest, - Seq( - "META-INF/services/coursierapi.shaded.coursier.jniutils.NativeApi" -> serviceContent - ) - ) - - tmpDest1.delete() - } - Check.onlyNamespace("coursierapi", dest) - dest - }, - addArtifact(Compile / packageBin / artifact, finalPackageBin), - Proguard / proguardVersion := "7.8.1", - Proguard / proguardOptions ++= { - val baseOptions = Seq( - "-dontnote", - "-dontwarn", - "-dontobfuscate", - "-dontoptimize", - "-keep class coursierapi.** {\n public protected *;\n}" - ) - - val maybeJava9Options = - if (isJava9OrMore) { - val javaHome = sys.props.getOrElse("java.home", ???) - Seq( - s"-libraryjars $javaHome/jmods/java.base.jmod", - s"-libraryjars $javaHome/jmods/java.xml.jmod" - ) - } - else - Nil - - val slf4jJarsOptions = { - val updateReport = updateFull.value - val report = updateReport - .configurations - .find(_.configuration.name == Compile.name) - .getOrElse { - sys.error(s"Configuration ${Compile.name} not found in update report (found configs: ${updateReport.configurations.map(_.configuration.name)})") - } - val moduleReports = report.modules - val slf4jJars = moduleReports - .find(r => r.module.organization == "org.slf4j" && r.module.name == "slf4j-api") - .toVector - .flatMap(_.artifacts.map(_._2)) - slf4jJars.map(jar => s"-libraryjars $jar") - } - - baseOptions ++ maybeJava9Options ++ slf4jJarsOptions - }, - Proguard / proguard / javaOptions := Seq("-Xmx3172M"), - - // Adding the interface JAR rather than its classes directory. - // The former contains META-INF stuff in particular. - Proguard / proguardInputs := (Proguard / proguardInputs).value.filter(f => (!f.isDirectory || f.getName != "classes") && !f.getName.startsWith("slf4j-api-")), - Proguard / proguardInputs += (Compile / packageBin).value, - - Proguard / proguardBinaryDeps := Settings.getAllBinaryDeps.value, - Proguard / proguardBinaryDeps ++= Settings.rtJarOpt.toSeq, // seems needed with sbt 1.4.0 - - Proguard / proguardInputFilter := { file => - file.name match { - case n if n.startsWith("interface") => None // keep META-INF from main JAR - case n if n.startsWith("windows-jni-utils") => Some("!META-INF/MANIFEST.MF") - case n if n.startsWith("coursier-core") => Some("!META-INF/**,!coursier.properties,!coursier/coursier.properties") - case n if n.startsWith("scala-xml") => Some("!META-INF/**,!scala-xml.properties") - case n if n.startsWith("scala-library") => Some("!META-INF/**,!library.properties,!rootdoc.txt") - case n if n.startsWith("tika-core") => Some("!META-INF/**,!pipes-fork-server-default-log4j2.xml") - case _ => Some("!META-INF/**") - } - }, - - // inspired by https://github.com/olafurpg/coursier-small/blob/408528d10cea1694c536f55ba1b023e55af3e0b2/build.sbt#L44-L56 - pomPostProcess := { node => - new RuleTransformer(new RewriteRule { - override def transform(node: XmlNode) = node match { - case elem: Elem if node.label == "dependency" && node.child.exists(n => n.label == "artifactId" && n.text.trim == "slf4j-api") => - elem - case _: Elem if node.label == "dependency" => - val org = node.child.find(_.label == "groupId").fold("")(_.text.trim) - val name = node.child.find(_.label == "artifactId").fold("")(_.text.trim) - val ver = node.child.find(_.label == "version").fold("")(_.text.trim) - Comment(s"shaded dependency $org:$name:$ver") - case _ => node - } - }).transform(node).head - }, - - Settings.shared, - Settings.mima(), - libraryDependencies ++= Seq( - "io.get-coursier" %% "coursier" % "2.1.25-M19", - ("io.get-coursier" %% "coursier-jvm" % "2.1.25-M19").exclude("net.java.dev.jna", "jna"), - "io.get-coursier.jniutils" % "windows-jni-utils-coursierapi" % "0.3.3", - "org.slf4j" % "slf4j-api" % "1.7.36" // no need to shade that one… - ), - - libraryDependencies += "com.lihaoyi" %% "utest" % "0.9.1" % Test, - testFrameworks += new TestFramework("utest.runner.Framework"), - - mimaBinaryIssueFilters ++= Seq( - // users shouldn't ever reference those - ProblemFilters.exclude[Problem]("coursierapi.shaded.*"), - ProblemFilters.exclude[Problem]("coursierapi.internal.*") - ), - - // clearing scalaModuleInfo in ivyModule, so that evicted doesn't - // check scala versions - ivyModule := { - val is = ivySbt.value - val config = moduleSettings.value match { - case config0: ModuleDescriptorConfiguration => - config0.withScalaModuleInfo(None) - case other => other - } - new is.Module(config) - }, - autoScalaLibrary := false, - crossVersion := CrossVersion.disabled, - - // filtering out non cross versioned module in 0.0.1 (published cross-versioned there, added below) - mimaPreviousArtifacts := mimaPreviousArtifacts.value.filter(_.revision != "0.0.1"), - - // was cross-versioned publishing in 0.0.1 - mimaPreviousArtifacts ++= { - val sv = scalaVersion.value - // TODO When removing 2.12 support in the future, use org % interface_2.12 below? - val is212 = sv.startsWith("2.12") - if (is212) - Set(organization.value %% "interface" % "0.0.1") - else - Set.empty[ModuleID] - }, - - ) - -lazy val `interface-svm-subs` = project - .disablePlugins(MimaPlugin) - .dependsOn(interface) - .settings( - Settings.shared, - libraryDependencies += "org.graalvm.nativeimage" % "svm" % "22.0.0.2" % Provided, - autoScalaLibrary := false, - crossVersion := CrossVersion.disabled, - // we don't actually depend on that thanks to proguarding / shading in interface - dependencyOverrides += "org.scala-lang" % "scala-library" % scalaVersion.value - ) - -lazy val interpolators = project - .dependsOn(interface) - .settings( - Settings.shared, - Settings.mima(no213 = true), - libraryDependencies ++= Seq( - "org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided, - "com.lihaoyi" %% "utest" % "0.9.1" % Test - ), - testFrameworks += new TestFramework("utest.runner.Framework"), - - mimaBinaryIssueFilters ++= Seq( - // only used at compile time, not runtime - ProblemFilters.exclude[MissingClassProblem]("coursierapi.Interpolators$Macros$"), - ) - ) - -lazy val `interface-test` = project - .disablePlugins(MimaPlugin) - // .dependsOn(interface) - .settings( - Settings.shared, - publish / skip := true, - crossPaths := false, // https://github.com/sbt/junit-interface/issues/35 - autoScalaLibrary := false, - crossVersion := CrossVersion.disabled, - libraryDependencies ++= Seq( - "junit" % "junit" % "4.13.2" % Test, - "com.github.sbt" % "junit-interface" % "0.13.3" % Test - ), - libraryDependencies += { - val org = (interface / organization).value - val name = (interface / moduleName).value - sys.env.get("TEST_VERSION") match { - case Some(v) => - org % name % v - case None => - // only dependency of coursier-interface - "org.slf4j" % "slf4j-api" % "2.0.17" - } - }, - Test / unmanagedClasspath ++= Def.taskDyn { - if (sys.env.get("TEST_VERSION").isEmpty) - Def.task { - Seq((interface / finalPackageBin).value) - } - else - Def.task(Seq.empty[File]) - }.value - ) - -publish / skip := true -Settings.shared -disablePlugins(MimaPlugin) diff --git a/project/Check.scala b/project/Check.scala deleted file mode 100644 index 2d689be..0000000 --- a/project/Check.scala +++ /dev/null @@ -1,26 +0,0 @@ -import java.io.File -import java.util.zip.ZipFile - -import scala.collection.JavaConverters._ - -object Check { - - def onlyNamespace(ns: String, jar: File): Unit = { - val zf = new ZipFile(jar) - val unrecognized = zf.entries() - .asScala - .map(_.getName) - .filter { n => - !n.startsWith("META-INF/") && !n.startsWith(ns + "/") && - n != "reflect.properties" && // scala-reflect adds that - n != "scala-collection-compat.properties" && // collection-compat adds that - !n.contains("/libzstd-jni-") // com.github.luben:zstd-jni stuff (pulled via plexus-archiver) - } - .toVector - .sorted - for (u <- unrecognized) - System.err.println(s"Unrecognized: $u") - assert(unrecognized.isEmpty) - } - -} diff --git a/project/Mima.scala b/project/Mima.scala deleted file mode 100644 index 1ec2fe2..0000000 --- a/project/Mima.scala +++ /dev/null @@ -1,23 +0,0 @@ - -import sys.process._ - -object Mima { - - private def stable(ver: String): Boolean = - ver.exists(c => c != '0' && c != '.') && - ver - .replace("-RC", "-") - .forall(c => c == '.' || c == '-' || c.isDigit) - - def binaryCompatibilityVersions: Set[String] = - Seq("git", "tag", "--merged", "HEAD^") - .!! - .linesIterator - .map(_.trim) - .filter(_.startsWith("v")) - .map(_.stripPrefix("v")) - .filter(stable) - .filter(_ != "0.0.11") // borked release, jline and jansi not shaded in it - .toSet - -} diff --git a/project/Settings.scala b/project/Settings.scala deleted file mode 100644 index 6dd9f3b..0000000 --- a/project/Settings.scala +++ /dev/null @@ -1,87 +0,0 @@ - -import com.typesafe.tools.mima.plugin.MimaPlugin -import sbt._ -import sbt.Keys._ - -import scala.util.Properties - -import java.util.Locale - -object Settings { - - def scala213 = "2.13.17" - - def scala212 = "2.12.20" - - private def isArm64 = - Option(System.getProperty("os.arch")).map(_.toLowerCase(Locale.ROOT)) match { - case Some("aarch64" | "arm64") => true - case _ => false - } - private lazy val java8Home = Option(System.getenv("COURSIER_INTERFACE_JAVA8_HOME")).getOrElse { - val jvmId = - if (Properties.isMac && isArm64) - // no native JDK 8 on Mac ARM, using amd64 one - "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u432-b06/OpenJDK8U-jdk_x64_mac_hotspot_8u432b06.tar.gz" - else - "adoptium:8" - os.proc("cs", "java-home", "--jvm", jvmId) - .call() - .out.trim() - } - private lazy val rtJar = { - val path = os.Path(java8Home) / "jre/lib/rt.jar" - assert(os.isFile(path)) - path - } - lazy val shared = Seq( - scalaVersion := scala213, - crossScalaVersions := Seq(scala213, scala212), - scalacOptions ++= Seq("--release", "8", "-deprecation"), - javacOptions ++= Seq( - "-source", "8", - "-target", "8", - "-bootclasspath", rtJar.toString - ), - Compile / doc / javacOptions := Seq( - "-source", "8", - "-bootclasspath", rtJar.toString - ) - ) - - private val filterOut = Set("0.0.1") - private def no212Versions = (0 to 14).map("0.0." + _).toSet - def mima(no213: Boolean = false) = Seq( - MimaPlugin.autoImport.mimaPreviousArtifacts := { - val sv = scalaVersion.value - val is212 = sv.startsWith("2.12.") - val is213 = sv.startsWith("2.13.") - Mima.binaryCompatibilityVersions - .filter(v => !filterOut(v)) - .filter(v => (!is213 || !no213) && (!is212 || !no212Versions(v))) - .map { ver => - (organization.value % moduleName.value % ver) - .cross(crossVersion.value) - } - } - ) - - // https://github.com/sbt/sbt-proguard/blob/2c502f961245a18677ef2af4220a39e7edf2f996/src/main/scala-sbt-1.0/com/typesafe/sbt/proguard/Sbt10Compat.scala#L8-L13 - // but sbt 1.4-compatible - val getAllBinaryDeps: Def.Initialize[Task[Seq[java.io.File]]] = Def.task { - import sbt.internal.inc.Analysis - val converter = fileConverter.value - (Compile / compile).value match { - case analysis: Analysis => - analysis.relations.allLibraryDeps.toSeq.map(converter.toPath(_).toFile) - } - } - - lazy val rtJarOpt = sys.props.get("sun.boot.class.path") - .toSeq - .flatMap(_.split(java.io.File.pathSeparator).toSeq) - .map(java.nio.file.Paths.get(_)) - .find(_.endsWith("rt.jar")) - .map(_.toFile) - -} diff --git a/project/ZipUtil.scala b/project/ZipUtil.scala deleted file mode 100644 index 0482bbd..0000000 --- a/project/ZipUtil.scala +++ /dev/null @@ -1,111 +0,0 @@ - -import java.io.{ByteArrayOutputStream, File, FileInputStream, FileOutputStream, InputStream} -import java.util.zip.{ZipEntry, ZipFile, ZipInputStream, ZipOutputStream} - -object ZipUtil { - - private def readFullySync(is: InputStream) = { - val buffer = new ByteArrayOutputStream - val data = Array.ofDim[Byte](16384) - - var nRead = is.read(data, 0, data.length) - while (nRead != -1) { - buffer.write(data, 0, nRead) - nRead = is.read(data, 0, data.length) - } - - buffer.flush() - buffer.toByteArray - } - - private def zipEntries(zipStream: ZipInputStream): Iterator[(ZipEntry, Array[Byte])] = - new Iterator[(ZipEntry, Array[Byte])] { - private var nextEntry = Option.empty[ZipEntry] - private def update() = - nextEntry = Option(zipStream.getNextEntry) - - update() - - def hasNext = nextEntry.nonEmpty - def next() = { - val ent = nextEntry.get - val data = readFullySync(zipStream) - - update() - - (ent, data) - } - } - - def removeFromZip(sourceZip: File, destZip: File, remove: String => Boolean): Unit = { - - val is = new FileInputStream(sourceZip) - val os = new FileOutputStream(destZip) - val bootstrapZip = new ZipInputStream(is) - val outputZip = new ZipOutputStream(os) - - for ((ent, data) <- zipEntries(bootstrapZip) if !remove(ent.getName)) { - - // Same workaround as https://github.com/spring-projects/spring-boot/issues/13720 - // (https://github.com/spring-projects/spring-boot/commit/a50646b7cc3ad941e748dfb450077e3a73706205#diff-2ff64cd06c0b25857e3e0dfdb6733174R144) - ent.setCompressedSize(-1L) - - outputZip.putNextEntry(ent) - outputZip.write(data) - outputZip.closeEntry() - } - - outputZip.finish() - outputZip.close() - - is.close() - os.close() - - } - - def addOrOverwriteInZip(sourceZip: File, destZip: File, toAdd: Seq[(String, Array[Byte])]): Unit = { - - val is = new FileInputStream(sourceZip) - val os = new FileOutputStream(destZip) - val bootstrapZip = new ZipInputStream(is) - val outputZip = new ZipOutputStream(os) - - val strip = toAdd.map(_._1).toSet - - for ((ent, data) <- zipEntries(bootstrapZip) if !strip.contains(ent.getName)) { - - // Same workaround as https://github.com/spring-projects/spring-boot/issues/13720 - // (https://github.com/spring-projects/spring-boot/commit/a50646b7cc3ad941e748dfb450077e3a73706205#diff-2ff64cd06c0b25857e3e0dfdb6733174R144) - ent.setCompressedSize(-1L) - - outputZip.putNextEntry(ent) - outputZip.write(data) - outputZip.closeEntry() - } - - for ((name, content) <- toAdd) { - val ent = new ZipEntry(name) - outputZip.putNextEntry(ent) - outputZip.write(content) - outputZip.closeEntry() - } - - outputZip.finish() - outputZip.close() - - is.close() - os.close() - - } - - def zipEntryContent(sourceZip: File, entryName: String): Option[Array[Byte]] = { - val zf = new ZipFile(sourceZip) - val entryOpt = Option(zf.getEntry(entryName)) - val content = entryOpt.map { entry => - readFullySync(zf.getInputStream(entry)) - } - zf.close() - content - } - -} diff --git a/project/build.properties b/project/build.properties deleted file mode 100644 index 01a16ed..0000000 --- a/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.11.7 diff --git a/project/plugins.sbt b/project/plugins.sbt deleted file mode 100644 index 931058b..0000000 --- a/project/plugins.sbt +++ /dev/null @@ -1,7 +0,0 @@ -addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.11.2") -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.8.1") -addSbtPlugin("com.lightbend.sbt" % "sbt-proguard" % "0.4.0") - -libraryDependencies += "com.eed3si9n.jarjarabrams" %% "jarjar-abrams-core" % "1.16.0" - -libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.11.6" From d78cbded1b1bc731c0cc276774a9d993a3d9af40 Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Mon, 27 Oct 2025 18:37:30 +0100 Subject: [PATCH 3/3] Run CI Mac jobs on macos-15 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88b45e8..9d7684d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - OS: ["ubuntu-latest", "macos-13", "windows-latest"] + OS: ["ubuntu-latest", "macos-15", "windows-latest"] steps: - uses: actions/checkout@v5 with: @@ -33,7 +33,7 @@ jobs: strategy: fail-fast: false matrix: - OS: ["ubuntu-latest", "macos-13", "windows-latest"] + OS: ["ubuntu-latest", "macos-15", "windows-latest"] steps: - uses: actions/checkout@v5 with: