diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..58bd4ac
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,9 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "chore"
+ include: "scope"
diff --git a/.github/workflows/branch-build-and-publish.yml b/.github/workflows/branch-build-and-publish.yml
new file mode 100644
index 0000000..11dfe37
--- /dev/null
+++ b/.github/workflows/branch-build-and-publish.yml
@@ -0,0 +1,380 @@
+name: Branch — Build & Publish (reactor + agent natives)
+
+on:
+ push:
+ branches-ignore: [ main, master ]
+ pull_request:
+
+permissions:
+ contents: read
+ packages: write
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ GITHUB_PACKAGES_URL: https://maven.pkg.github.com/${{ github.repository }}
+ JAVA_VERSION: "21"
+ JAVA_DISTRIBUTION: "temurin"
+
+jobs:
+ prepare:
+ name: Prepare version
+ runs-on: ubuntu-latest
+ outputs:
+ new_version: ${{ steps.vars.outputs.new_version }}
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - id: vars
+ run: |
+ SHORT_SHA=$(git rev-parse --short=8 HEAD)
+ BASE_VER=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' \
+ --non-recursive org.codehaus.mojo:exec-maven-plugin:3.5.1:exec)
+ if [[ "$BASE_VER" != *-SNAPSHOT ]]; then
+ echo "Branch workflow skipped: version '$BASE_VER' is not a SNAPSHOT"
+ echo "new_version=" >> $GITHUB_OUTPUT
+ exit 0
+ fi
+ # Replace -SNAPSHOT with -SHORT_SHA-RUN_ATTEMPT
+ #NEW_VER="${BASE_VER%-SNAPSHOT}-${SHORT_SHA}-${GITHUB_RUN_ATTEMPT}"
+ NEW_VER="${BASE_VER%-SNAPSHOT}-${SHORT_SHA}"
+ echo "new_version=${NEW_VER}" >> $GITHUB_OUTPUT
+ echo "Using ${NEW_VER}"
+
+ tests:
+ name: Tests
+ runs-on: ubuntu-latest
+ needs: prepare
+ if: ${{ needs.prepare.outputs.new_version != '' }}
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Set version
+ run: mvn -q -DnewVersion="${{ needs.prepare.outputs.new_version }}" -DgenerateBackupPoms=false versions:set
+ - name: Run reactor tests
+ run: |
+ mvn -B -pl '!modules/agent' test
+ mvn -B -pl modules/agent -DskipNativeBuild=true test
+
+ macos:
+ name: macOS (x86_64 + arm64)
+ runs-on: macos-14
+ needs: prepare
+ if: ${{ needs.prepare.outputs.new_version != '' }}
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Make scripts executable
+ run: |
+ if git ls-files | grep -E "src/main/scripts/.*\\.sh$" | head -1; then
+ git ls-files | grep -E "src/main/scripts/.*\\.sh$" | xargs chmod +x
+ else
+ echo "No shell scripts found to make executable"
+ fi
+ - name: Set version
+ run: mvn -q -DnewVersion="${{ needs.prepare.outputs.new_version }}" -DgenerateBackupPoms=false versions:set
+ - name: Build packages
+ run: mvn -B -DskipTests -pl modules/agent package
+ - name: Upload native jars
+ uses: actions/upload-artifact@v4.3.3
+ with:
+ name: native-macos
+ path: "**/target/*-mac_*.jar"
+
+ linux-x:
+ name: Linux (x86_32 + x86_64 + aarch64 cross)
+ runs-on: ubuntu-22.04
+ needs: prepare
+ if: ${{ needs.prepare.outputs.new_version != '' }}
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Install cross-compilation tools
+ run: |
+ set -euo pipefail
+ sudo dpkg --add-architecture i386
+ sudo apt-get update
+
+ # Install 32-bit support step by step
+ echo "Installing 32-bit development libraries..."
+ sudo apt-get install -y libc6-dev:i386 || echo "Could not install libc6-dev:i386"
+
+ echo "Installing multilib GCC..."
+ sudo apt-get install -y gcc-multilib g++-multilib || {
+ echo "multilib installation failed, trying alternative approach"
+ # Alternative: install 32-bit libraries manually
+ sudo apt-get install -y libc6-dev-i386 lib32gcc-s1 lib32stdc++6
+ }
+
+ # Install ARM64 cross-compilation tools
+ echo "Installing ARM64 cross-compilation tools..."
+ if ! sudo apt-get install -y crossbuild-essential-arm64; then
+ echo "Fallback: Installing explicit aarch64 packages"
+ sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
+ fi
+
+ # Verify installations
+ echo "=== Verifying toolchains ==="
+ echo "32-bit GCC test:"
+ if echo 'int main(){}' | gcc -m32 -x c - -o /dev/null 2>/dev/null; then
+ echo "✓ 32-bit compilation works"
+ gcc -m32 --version | head -1
+ else
+ echo "✗ 32-bit compilation failed"
+ fi
+
+ echo "ARM64 GCC test:"
+ aarch64-linux-gnu-gcc --version | head -1 || { echo "ARM64 cross-compiler not available"; exit 1; }
+
+ - name: Make scripts executable
+ run: |
+ if git ls-files | grep -E "src/main/scripts/.*\\.sh$" | head -1; then
+ git ls-files | grep -E "src/main/scripts/.*\\.sh$" | xargs chmod +x
+ else
+ echo "No shell scripts found to make executable"
+ fi
+ - name: Set version
+ run: mvn -q -DnewVersion="${{ needs.prepare.outputs.new_version }}" -DgenerateBackupPoms=false versions:set
+ - name: Build x86 packages
+ run: mvn -B -DskipTests -pl modules/agent package
+ - name: Build ARM64 package (cross-compilation)
+ run: mvn -B -DskipTests -pl modules/agent -Dlinux.arm64.cross=true package
+ - name: Upload native jars
+ uses: actions/upload-artifact@v4.3.3
+ with:
+ name: native-linux
+ path: |
+ **/target/*-linux_x86_*.jar
+ **/target/*-linux_aarch64.jar
+
+ windows-x86:
+ name: Windows (x86 + x64)
+ runs-on: windows-latest
+ needs: prepare
+ if: ${{ needs.prepare.outputs.new_version != '' }}
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Install MinGW (32/64)
+ shell: powershell
+ run: |
+ choco install mingw --yes --no-progress
+ echo "C:\\ProgramData\\chocolatey\\lib\\mingw\\tools\\install\\mingw64\\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+ echo "C:\\ProgramData\\chocolatey\\lib\\mingw\\tools\\install\\mingw32\\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+ - name: Set version
+ shell: bash
+ run: mvn -q -DnewVersion="${{ needs.prepare.outputs.new_version }}" -DgenerateBackupPoms=false versions:set
+ - name: Build packages
+ shell: bash
+ run: mvn -B -DskipTests -pl modules/agent package
+ - name: Upload native jars
+ uses: actions/upload-artifact@v4.3.3
+ with:
+ name: native-windows-x86
+ path: "**/target/*-windows_x86_*.jar"
+
+ deploy-reactor:
+ name: Deploy non-agent modules
+ needs: [prepare, tests, macos, linux-x, windows-x86]
+ if: ${{ github.event_name == 'push' && needs.prepare.outputs.new_version != '' }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Setup Maven settings for GitHub Packages
+ run: |
+ mkdir -p $HOME/.m2
+ cat > $HOME/.m2/settings.xml <<'XML'
+
+
+
+ github
+ ${env.GITHUB_ACTOR}
+ ${env.GITHUB_TOKEN}
+
+
+
+ XML
+ - name: Set version
+ run: mvn -q -DnewVersion="${{ needs.prepare.outputs.new_version }}" -DgenerateBackupPoms=false versions:set
+ - name: Deploy all non-agent modules
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ mvn -B -DskipTests -pl '!modules/agent' -DaltDeploymentRepository=github::${{ env.GITHUB_PACKAGES_URL }} deploy
+
+ publish-agent-classifiers:
+ name: Publish agent POM + native classifiers
+ needs: [prepare, tests, macos, linux-x, windows-x86, deploy-reactor]
+ if: ${{ github.event_name == 'push' && needs.prepare.outputs.new_version != '' }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Setup Maven settings for GitHub Packages
+ run: |
+ mkdir -p $HOME/.m2
+ cat > $HOME/.m2/settings.xml <<'XML'
+
+
+
+ github
+ ${env.GITHUB_ACTOR}
+ ${env.GITHUB_TOKEN}
+
+
+
+ XML
+ - uses: actions/download-artifact@v4.1.7
+ with:
+ path: dist
+ - name: Set version for agent module
+ run: |
+ mvn -q -DnewVersion="${{ needs.prepare.outputs.new_version }}" -DgenerateBackupPoms=false versions:set
+ - name: Deploy agent POM + classifier jars
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ set -euo pipefail
+ V="${{ needs.prepare.outputs.new_version }}"
+
+ if [ ! -d "modules/agent" ]; then
+ echo "Error: modules/agent directory not found"
+ exit 1
+ fi
+
+ pushd modules/agent >/dev/null
+ G=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.groupId}' --non-recursive org.codehaus.mojo:exec-maven-plugin:3.5.1:exec)
+ A=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.artifactId}' --non-recursive org.codehaus.mojo:exec-maven-plugin:3.5.1:exec)
+
+ if [ ! -f "pom.xml" ]; then
+ echo "Error: pom.xml not found in modules/agent"
+ exit 1
+ fi
+
+ # Create a dummy main JAR
+ echo "Creating dummy main JAR"
+ mkdir -p target
+ echo "# This is a dummy JAR - native libraries are provided as classifiers" > target/README.txt
+ jar cf "target/${A}-${V}.jar" -C target README.txt
+
+ # Copy all classifier JARs to target and build deployment parameters
+ echo "Copying classifier JARs to target directory"
+ CLASSIFIER_JARS=$(find ../../dist -type f \( -name "*-mac_*.jar" -o -name "*-linux_*.jar" -o -name "*-windows_*.jar" \) | grep "$A-")
+
+ FILES=""
+ CLASSIFIERS=""
+ TYPES=""
+
+ if [ -z "$CLASSIFIER_JARS" ]; then
+ echo "Error: no classifier JARs found to publish"
+ exit 1
+ fi
+
+ if [ -n "$CLASSIFIER_JARS" ]; then
+ echo "Found classifier JARs:"
+ echo "$CLASSIFIER_JARS"
+
+ for J in $CLASSIFIER_JARS; do
+ if [ -n "$J" ] && [ -f "$J" ]; then
+ BN=$(basename "$J")
+ # Extract classifier from filename: artifact-version-classifier.jar
+ NAME_NO_JAR=${BN%.jar}
+ CLASSIFIER="${NAME_NO_JAR#${A}-${V}-}"
+
+ if [ -z "$CLASSIFIER" ] || [ "$CLASSIFIER" = "$NAME_NO_JAR" ]; then
+ echo "Warning: Could not extract classifier from $BN, skipping"
+ continue
+ fi
+
+ # Copy to target directory
+ cp "$J" "target/${BN}"
+ echo "Copied $BN with classifier: $CLASSIFIER"
+
+ # Build comma-separated parameter lists
+ if [ -z "$FILES" ]; then
+ FILES="target/${BN}"
+ CLASSIFIERS="$CLASSIFIER"
+ TYPES="jar"
+ else
+ FILES="${FILES},target/${BN}"
+ CLASSIFIERS="${CLASSIFIERS},${CLASSIFIER}"
+ TYPES="${TYPES},jar"
+ fi
+ fi
+ done
+ fi
+
+ # Deploy main JAR with POM and all classifiers in a single command
+ if [ -n "$FILES" ]; then
+ echo "Deploying ${G}:${A}:${V} with classifiers: $CLASSIFIERS"
+ mvn -B -q deploy:deploy-file \
+ -DrepositoryId=github -Durl="${{ env.GITHUB_PACKAGES_URL }}" \
+ -DgroupId="$G" -DartifactId="$A" -Dversion="$V" \
+ -Dpackaging=jar \
+ -Dfile="target/${A}-${V}.jar" \
+ -DpomFile=pom.xml \
+ -Dfiles="$FILES" \
+ -Dclassifiers="$CLASSIFIERS" \
+ -Dtypes="$TYPES"
+ else
+ echo "No classifier JARs found, deploying only main JAR and POM"
+ mvn -B -q deploy:deploy-file \
+ -DrepositoryId=github -Durl="${{ env.GITHUB_PACKAGES_URL }}" \
+ -DgroupId="$G" -DartifactId="$A" -Dversion="$V" \
+ -Dpackaging=jar \
+ -Dfile="target/${A}-${V}.jar" \
+ -DpomFile=pom.xml
+ fi
+
+ popd >/dev/null
+ - name: Create distribution bundle
+ run: |
+ mkdir -p dist/bundle
+ find dist -type f -name "*.jar" -exec cp -t dist/bundle {} + 2>/dev/null || echo "No JARs found to bundle"
+ if [ -d "dist/bundle" ] && [ "$(ls -A dist/bundle)" ]; then
+ (cd dist && zip -r faketime-native-${{ needs.prepare.outputs.new_version }}-${{ github.sha }}.zip bundle)
+ else
+ echo "No files to bundle, creating empty archive"
+ (cd dist && zip faketime-native-${{ needs.prepare.outputs.new_version }}-${{ github.sha }}.zip -T)
+ fi
+ - uses: actions/upload-artifact@v4.3.3
+ with:
+ name: faketime-native-${{ needs.prepare.outputs.new_version }}-${{ github.sha }}
+ path: dist/faketime-native-${{ needs.prepare.outputs.new_version }}-${{ github.sha }}.zip
diff --git a/.github/workflows/main-publish-pom-version.yml b/.github/workflows/main-publish-pom-version.yml
new file mode 100644
index 0000000..79f0350
--- /dev/null
+++ b/.github/workflows/main-publish-pom-version.yml
@@ -0,0 +1,352 @@
+name: Main — build & publish POM version (SNAPSHOT/RELEASE)
+
+on:
+ push:
+ branches: [ main, master ]
+
+permissions:
+ contents: read
+ packages: write
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ GITHUB_PACKAGES_URL: https://maven.pkg.github.com/${{ github.repository }}
+ JAVA_VERSION: "21"
+ JAVA_DISTRIBUTION: "temurin"
+
+jobs:
+ prepare:
+ name: Prepare POM version
+ runs-on: ubuntu-latest
+ outputs:
+ version: ${{ steps.vars.outputs.version }}
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - id: vars
+ name: Read version from POM
+ run: |
+ VER=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:3.5.1:exec)
+ echo "version=${VER}" >> $GITHUB_OUTPUT
+ echo "Publishing version ${VER}"
+
+ tests:
+ name: Tests
+ runs-on: ubuntu-latest
+ needs: prepare
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Run reactor tests
+ run: |
+ mvn -B -pl '!modules/agent' test
+ mvn -B -pl modules/agent -DskipNativeBuild=true test
+
+ macos:
+ name: macOS (x86_64 + arm64)
+ runs-on: macos-14
+ needs: prepare
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Make scripts executable
+ run: |
+ if git ls-files | grep -E "src/main/scripts/.*\\.sh$" | head -1; then
+ git ls-files | grep -E "src/main/scripts/.*\\.sh$" | xargs chmod +x
+ else
+ echo "No shell scripts found to make executable"
+ fi
+ - name: Build packages
+ run: mvn -B -DskipTests -pl modules/agent package
+ - name: Upload native jars
+ uses: actions/upload-artifact@v4.3.3
+ with:
+ name: native-macos
+ path: "**/target/*-mac_*.jar"
+
+ linux-x:
+ name: Linux (x86_32 + x86_64 + aarch64 cross)
+ runs-on: ubuntu-22.04
+ needs: prepare
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Install cross-compilation tools
+ run: |
+ set -euo pipefail
+ sudo dpkg --add-architecture i386
+ sudo apt-get update
+
+ # Install 32-bit support step by step
+ echo "Installing 32-bit development libraries..."
+ sudo apt-get install -y libc6-dev:i386 || echo "Could not install libc6-dev:i386"
+
+ echo "Installing multilib GCC..."
+ sudo apt-get install -y gcc-multilib g++-multilib || {
+ echo "multilib installation failed, trying alternative approach"
+ # Alternative: install 32-bit libraries manually
+ sudo apt-get install -y libc6-dev-i386 lib32gcc-s1 lib32stdc++6
+ }
+
+ # Install ARM64 cross-compilation tools
+ echo "Installing ARM64 cross-compilation tools..."
+ if ! sudo apt-get install -y crossbuild-essential-arm64; then
+ echo "Fallback: Installing explicit aarch64 packages"
+ sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
+ fi
+
+ # Verify installations
+ echo "=== Verifying toolchains ==="
+ echo "32-bit GCC test:"
+ if echo 'int main(){}' | gcc -m32 -x c - -o /dev/null 2>/dev/null; then
+ echo "✓ 32-bit compilation works"
+ gcc -m32 --version | head -1
+ else
+ echo "✗ 32-bit compilation failed"
+ fi
+
+ echo "ARM64 GCC test:"
+ aarch64-linux-gnu-gcc --version | head -1 || { echo "ARM64 cross-compiler not available"; exit 1; }
+
+ - name: Make scripts executable
+ run: |
+ if git ls-files | grep -E "src/main/scripts/.*\\.sh$" | head -1; then
+ git ls-files | grep -E "src/main/scripts/.*\\.sh$" | xargs chmod +x
+ else
+ echo "No shell scripts found to make executable"
+ fi
+ - name: Build x86 packages
+ run: mvn -B -DskipTests -pl modules/agent package
+ - name: Build ARM64 package (cross-compilation)
+ run: mvn -B -DskipTests -pl modules/agent -Dlinux.arm64.cross=true package
+ - name: Upload native jars
+ uses: actions/upload-artifact@v4.3.3
+ with:
+ name: native-linux
+ path: |
+ **/target/*-linux_x86_*.jar
+ **/target/*-linux_aarch64.jar
+
+ windows-x86:
+ name: Windows (x86 + x64)
+ runs-on: windows-latest
+ needs: prepare
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Install MinGW (32/64)
+ shell: powershell
+ run: |
+ choco install mingw --yes --no-progress
+ echo "C:\\ProgramData\\chocolatey\\lib\\mingw\\tools\\install\\mingw64\\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+ echo "C:\\ProgramData\\chocolatey\\lib\\mingw\\tools\\install\\mingw32\\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+ - name: Build packages
+ shell: bash
+ run: mvn -B -DskipTests -pl modules/agent package
+ - name: Upload native jars
+ uses: actions/upload-artifact@v4.3.3
+ with:
+ name: native-windows-x86
+ path: "**/target/*-windows_x86_*.jar"
+
+ deploy-reactor:
+ name: Deploy non-agent modules
+ needs: [prepare, tests, macos, linux-x, windows-x86]
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Setup Maven settings for GitHub Packages
+ run: |
+ mkdir -p $HOME/.m2
+ cat > $HOME/.m2/settings.xml <<'XML'
+
+
+
+ github
+ ${env.GITHUB_ACTOR}
+ ${env.GITHUB_TOKEN}
+
+
+
+ XML
+ - name: Ensure reactor version (no-op if already same)
+ run: mvn -q -DnewVersion="${{ needs.prepare.outputs.version }}" -DgenerateBackupPoms=false versions:set
+ - name: Deploy all non-agent modules
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ mvn -B -DskipTests -pl '!modules/agent' -DaltDeploymentRepository=github::${{ env.GITHUB_PACKAGES_URL }} deploy
+
+ publish-agent-classifiers:
+ name: Publish agent POM + native classifiers
+ needs: [prepare, tests, macos, linux-x, windows-x86, deploy-reactor]
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4.1.7
+ - uses: actions/setup-java@v4.2.1
+ with:
+ distribution: ${{ env.JAVA_DISTRIBUTION }}
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+ - name: Setup Maven settings for GitHub Packages
+ run: |
+ mkdir -p $HOME/.m2
+ cat > $HOME/.m2/settings.xml <<'XML'
+
+
+
+ github
+ ${env.GITHUB_ACTOR}
+ ${env.GITHUB_TOKEN}
+
+
+
+ XML
+ - uses: actions/download-artifact@v4.1.7
+ with:
+ path: dist
+ - name: Deploy agent POM + classifier jars
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ set -euo pipefail
+ V="${{ needs.prepare.outputs.version }}"
+
+ if [ ! -d "modules/agent" ]; then
+ echo "Error: modules/agent directory not found"
+ exit 1
+ fi
+
+ pushd modules/agent >/dev/null
+ G=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.groupId}' --non-recursive org.codehaus.mojo:exec-maven-plugin:3.5.1:exec)
+ A=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.artifactId}' --non-recursive org.codehaus.mojo:exec-maven-plugin:3.5.1:exec)
+
+ if [ ! -f "pom.xml" ]; then
+ echo "Error: pom.xml not found in modules/agent"
+ exit 1
+ fi
+
+ # Create a dummy main JAR
+ echo "Creating dummy main JAR"
+ mkdir -p target
+ echo "# This is a dummy JAR - native libraries are provided as classifiers" > target/README.txt
+ jar cf "target/${A}-${V}.jar" -C target README.txt
+
+ # Copy all classifier JARs to target and build deployment parameters
+ echo "Copying classifier JARs to target directory"
+ CLASSIFIER_JARS=$(find ../../dist -type f \( -name "*-mac_*.jar" -o -name "*-linux_*.jar" -o -name "*-windows_*.jar" \) | grep "$A-")
+
+ FILES=""
+ CLASSIFIERS=""
+ TYPES=""
+
+ if [ -z "$CLASSIFIER_JARS" ]; then
+ echo "Error: no classifier JARs found to publish"
+ exit 1
+ fi
+
+ if [ -n "$CLASSIFIER_JARS" ]; then
+ echo "Found classifier JARs:"
+ echo "$CLASSIFIER_JARS"
+
+ for J in $CLASSIFIER_JARS; do
+ if [ -n "$J" ] && [ -f "$J" ]; then
+ BN=$(basename "$J")
+ # Extract classifier from filename: artifact-version-classifier.jar
+ NAME_NO_JAR=${BN%.jar}
+ CLASSIFIER="${NAME_NO_JAR#${A}-${V}-}"
+
+ if [ -z "$CLASSIFIER" ] || [ "$CLASSIFIER" = "$NAME_NO_JAR" ]; then
+ echo "Warning: Could not extract classifier from $BN, skipping"
+ continue
+ fi
+
+ # Copy to target directory
+ cp "$J" "target/${BN}"
+ echo "Copied $BN with classifier: $CLASSIFIER"
+
+ # Build comma-separated parameter lists
+ if [ -z "$FILES" ]; then
+ FILES="target/${BN}"
+ CLASSIFIERS="$CLASSIFIER"
+ TYPES="jar"
+ else
+ FILES="${FILES},target/${BN}"
+ CLASSIFIERS="${CLASSIFIERS},${CLASSIFIER}"
+ TYPES="${TYPES},jar"
+ fi
+ fi
+ done
+ fi
+
+ # Deploy main JAR with POM and all classifiers in a single command
+ if [ -n "$FILES" ]; then
+ echo "Deploying ${G}:${A}:${V} with classifiers: $CLASSIFIERS"
+ mvn -B -q deploy:deploy-file \
+ -DrepositoryId=github -Durl="${{ env.GITHUB_PACKAGES_URL }}" \
+ -DgroupId="$G" -DartifactId="$A" -Dversion="$V" \
+ -Dpackaging=jar \
+ -Dfile="target/${A}-${V}.jar" \
+ -DpomFile=pom.xml \
+ -Dfiles="$FILES" \
+ -Dclassifiers="$CLASSIFIERS" \
+ -Dtypes="$TYPES"
+ else
+ echo "No classifier JARs found, deploying only main JAR and POM"
+ mvn -B -q deploy:deploy-file \
+ -DrepositoryId=github -Durl="${{ env.GITHUB_PACKAGES_URL }}" \
+ -DgroupId="$G" -DartifactId="$A" -Dversion="$V" \
+ -Dpackaging=jar \
+ -Dfile="target/${A}-${V}.jar" \
+ -DpomFile=pom.xml
+ fi
+
+ popd >/dev/null
+ - name: Create distribution bundle
+ run: |
+ mkdir -p dist/bundle
+ find dist -type f -name "*.jar" -exec cp -t dist/bundle {} + 2>/dev/null || echo "No JARs found to bundle"
+ if [ -d "dist/bundle" ] && [ "$(ls -A dist/bundle)" ]; then
+ (cd dist && zip -r faketime-native-${{ needs.prepare.outputs.version }}-${{ github.sha }}.zip bundle)
+ else
+ echo "No files to bundle, creating empty archive"
+ (cd dist && zip faketime-native-${{ needs.prepare.outputs.version }}-${{ github.sha }}.zip -T)
+ fi
+ - uses: actions/upload-artifact@v4.3.3
+ with:
+ name: faketime-native-${{ needs.prepare.outputs.version }}-${{ github.sha }}
+ path: dist/faketime-native-${{ needs.prepare.outputs.version }}-${{ github.sha }}.zip
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
deleted file mode 100644
index 41c70a7..0000000
Binary files a/.mvn/wrapper/maven-wrapper.jar and /dev/null differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
index 0061e75..12fbe1e 100644
--- a/.mvn/wrapper/maven-wrapper.properties
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -1 +1,19 @@
-distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
\ No newline at end of file
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+wrapperVersion=3.3.2
+distributionType=only-script
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
diff --git a/.sdkmanrc b/.sdkmanrc
new file mode 100644
index 0000000..3b3f7c5
--- /dev/null
+++ b/.sdkmanrc
@@ -0,0 +1,4 @@
+# Enable auto-env through the sdkman_auto_env config
+# Add key=value pairs of SDKs to use below
+java=17.0.16-zulu
+maven=3.9.11
\ No newline at end of file
diff --git a/BUILD.md b/BUILD.md
new file mode 100644
index 0000000..28ad4b9
--- /dev/null
+++ b/BUILD.md
@@ -0,0 +1,83 @@
+# Build Guide — faketime-java
+
+This project builds platform-specific JNI native libraries packaged as classifier JARs under the `faketime-agent` module.
+
+## Supported Platforms
+
+The CI matrix builds and publishes the following classifiers:
+
+- **macOS**
+ - `mac_x86_64`
+ - `mac_aarch64`
+
+- **Linux**
+ - `linux_x86_32`
+ - `linux_x86_64`
+ - `linux_aarch64` (native if running on ARM64, or cross-compiled using `aarch64-linux-gnu-gcc` on x86_64)
+
+- **Windows**
+ - `windows_x86_32`
+ - `windows_x86_64`
+
+## Windows ARM64
+
+- Not built on GitHub-hosted runners: Ubuntu’s `mingw-w64` only supports x86 and x64 targets.
+- The old `windows-arm64-cross` profile has been **removed** to avoid confusion.
+- To support Windows ARM64:
+ - Provide a **self-hosted Windows ARM64 runner** (e.g. Surface Pro X, Windows Dev Kit 2023).
+ - Add a `` to `modules/agent/pom.xml` with activation `aarch64`.
+ - Update `compile_win32.bat` or create `compile_win_arm64.bat` using MSVC or a custom MinGW-w64 ARM64 toolchain.
+ - Add a workflow job with `runs-on: [self-hosted, Windows, ARM64]`.
+
+## Local Build
+
+Make sure `JAVA_HOME` is set to a JDK (Java 21 recommended).
+
+### macOS (x86_64 + arm64)
+```bash
+cd modules/agent
+mvn -DskipTests package
+```
+
+### Linux x86_64 host
+Install multilib toolchain for 32-bit:
+```bash
+sudo apt-get update
+sudo apt-get install -y build-essential gcc-multilib g++-multilib
+cd modules/agent
+mvn -DskipTests package
+```
+
+### Linux ARM64 host
+```bash
+cd modules/agent
+mvn -DskipTests package
+```
+
+### Linux ARM64 cross on x86_64 host
+```bash
+sudo apt-get update
+sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
+cd modules/agent
+mvn -DskipTests -Dlinux.arm64.cross=true package
+```
+
+### Windows (x86 + x64)
+Install MinGW via Chocolatey:
+```powershell
+choco install mingw --yes
+cd modules/agent
+mvn -DskipTests package
+```
+
+## CI Workflows
+
+- **Branch builds** (`branch-snapshot-hash.yml`):
+ - Computes a snapshot version with commit hash suffix.
+ - Builds/publishes all classifiers.
+
+- **Main builds** (`main-publish-pom-version.yml`):
+ - Uses the POM version (snapshot or release).
+ - Builds/publishes all classifiers.
+
+Artifacts are published to GitHub Packages and uploaded as workflow artifacts for download.
diff --git a/e2e-tests/pom.xml b/e2e-tests/pom.xml
index 0d77a97..9586817 100644
--- a/e2e-tests/pom.xml
+++ b/e2e-tests/pom.xml
@@ -2,131 +2,128 @@
- 4.0.0
+ 4.0.0
- FakeTime E2E Tests
- faketime-e2e-tests
- jar
- 0-SNAPSHOT
-
-
- io.github.faketime-java
- faketime-parent
- 0-SNAPSHOT
- ../pom.xml
-
-
-
- libfaketime
-
-
-
-
- faketimeBinary
-
-
- windows
-
-
-
- faketime.dll
-
-
-
-
-
-
- io.github.faketime-java
- faketime-junit
- 0-SNAPSHOT
- test
-
+
+ io.github.faketime-java
+ faketime-parent
+ 0.9.0-SNAPSHOT
+ ../pom.xml
+
-
- junit
- junit
- 4.12
- test
-
+ FakeTime E2E Tests
+ faketime-e2e-tests
+ jar
-
- org.assertj
- assertj-core
- 3.11.1
- test
-
-
+
+
+
+ libfaketime
+
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 2.22.1
+
+
+ faketimeBinary
+
+
+ windows
+
+
+
+
+ faketime.dll
+
+
+
-
- random
-
- **/*
-
- ${faketime.argLine}
-
-
+
+
+ io.github.faketime-java
+ faketime-junit
+ test
+
-
- org.apache.maven.plugins
- maven-failsafe-plugin
- 2.22.1
+
+ junit
+ junit
+ test
+
-
- random
-
- **/*
-
-
- -agentpath:${project.build.directory}/${faketime.binary}
- -XX:+UnlockDiagnosticVMOptions
- -XX:DisableIntrinsic=_currentTimeMillis
- -XX:CompileCommand=quiet
- -XX:CompileCommand=exclude,java/lang/System.currentTimeMillis
- -XX:CompileCommand=exclude,jdk/internal/misc/VM.getNanoTimeAdjustment
-
-
+
+ org.assertj
+ assertj-core
+ 3.27.4
+ test
+
+
-
-
-
- integration-test
- verify
-
-
-
-
+
+
+
+ kr.motd.maven
+ os-maven-plugin
+ 1.7.1
+
+
+ initialize
+
+ detect
+
+
+
+
+
+
+
+ io.github.faketime-java
+ faketime-maven-plugin
+ ${project.version}
+
+
+
+ prepare
+
+
+
+
-
- io.github.faketime-java
- faketime-maven-plugin
- 0-SNAPSHOT
-
-
-
- prepare
-
-
-
-
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.5.3
+
+
+ random
+
+ **/*
+
+ @{argLine} ${faketime.argLine}
+
+
-
- org.apache.maven.plugins
- maven-jar-plugin
- 3.1.0
-
-
- default-jar
- none
-
-
-
-
-
-
\ No newline at end of file
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 3.5.3
+
+
+ random
+
+ **/*
+
+ @{argLine} ${faketime.argLine}
+
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+
+
diff --git a/modules/agent/compile_darwin.sh b/modules/agent/compile_darwin.sh
deleted file mode 100755
index 845ff2c..0000000
--- a/modules/agent/compile_darwin.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-gcc -O2 -fPIC -pthread -c -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin src/main/c/agent.c
-gcc -shared -o src/main/resources/darwin_x86_32/libfaketime agent.o -lc
-rm agent.o
-
-gcc -O2 -fPIC -pthread -D_LP64=1 -c -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin src/main/c/agent.c
-gcc -shared -o src/main/resources/darwin_x86_64/libfaketime agent.o -lc
-rm agent.o
diff --git a/modules/agent/compile_linux.sh b/modules/agent/compile_linux.sh
deleted file mode 100755
index 2a0c1ba..0000000
--- a/modules/agent/compile_linux.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-gcc -O2 -fPIC -pthread -c -I $JAVA_HOME/include -I $JAVA_HOME/include/linux src/main/c/agent.c
-gcc -z defs -static-libgcc -shared -o src/main/resources/linux_x86_32/libfaketime agent.o -lc
-rm agent.o
-
-gcc -O2 -fPIC -pthread -D_LP64=1 -c -I $JAVA_HOME/include -I $JAVA_HOME/include/linux src/main/c/agent.c
-gcc -z defs -static-libgcc -shared -o src/main/resources/linux_x86_64/libfaketime agent.o -lc
-rm agent.o
diff --git a/modules/agent/compile_win32.bat b/modules/agent/compile_win32.bat
deleted file mode 100644
index e721b78..0000000
--- a/modules/agent/compile_win32.bat
+++ /dev/null
@@ -1,16 +0,0 @@
-set VC_BIN=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin
-set PATH=%VC_BIN%;%PATH%
-
-call "%VC_BIN%\vcvars32.bat"
-cl /O1 /MD /D _STATIC_CPPLIB /c /I"%JAVA_HOME%\include" /I"%JAVA_HOME%\include\win32" src\main\c\agent.c
-link /dll /opt:REF /out:src\main\resources\win32_x86_32\faketime.dll agent.obj
-del agent.obj
-del src\main\resources\win32_x86_32\faketime.exp
-del src\main\resources\win32_x86_32\faketime.lib
-
-call "%VC_BIN%\amd64\vcvars64.bat"
-cl /O1 /MD /D _STATIC_CPPLIB /c /I"%JAVA_HOME%\include" /I"%JAVA_HOME%\include\win32" src\main\c\agent.c
-link /dll /opt:REF /out:src\main\resources\win32_x86_64\faketime.dll agent.obj
-del agent.obj
-del src\main\resources\win32_x86_64\faketime.exp
-del src\main\resources\win32_x86_64\faketime.lib
diff --git a/modules/agent/pom.xml b/modules/agent/pom.xml
index 551e86b..54a8554 100644
--- a/modules/agent/pom.xml
+++ b/modules/agent/pom.xml
@@ -1,160 +1,318 @@
- 4.0.0
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
- FakeTime Native Agent
- faketime-agent
- jar
- 0-SNAPSHOT
+
+ io.github.faketime-java
+ faketime-parent
+ 0.9.0-SNAPSHOT
+ ../../pom.xml
+
-
io.github.faketime-java
- faketime-parent
- 0-SNAPSHOT
- ../../pom.xml
-
+ faketime-agent
+ FakeTime Native Agent
+ pom
-
-
- compile-agents
-
-
-
- org.codehaus.mojo
- exec-maven-plugin
- 1.5.0
-
-
- compile-agents
- compile
-
- exec
-
-
- ./${compile.script}
-
-
-
-
-
-
-
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 3.5.1
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.4.2
+
+
+
+
-
- darwin
-
-
- mac
-
-
-
- compile_darwin.sh
-
-
+
+
+
+ darwin
+
+
+ mac
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+ compile-native-darwin
+ compile
+
+ exec
+
+
+ ${project.basedir}/src/main/scripts/compile_darwin.sh
+
+
+
+
-
- linux
-
-
- unix
- Linux
-
-
-
- compile_linux.sh
-
-
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ darwin_x86_64
+ package
+
+ jar
+
+
+ mac_x86_64
+ ${project.build.directory}/native/darwin_x86_64
+
+
+
+ darwin_aarch64
+ package
+
+ jar
+
+
+ mac_aarch64
+ ${project.build.directory}/native/darwin_aarch64
+
+
+
+
+
+
+
-
- windows
-
-
- windows
-
-
-
- compile_win32.bat
-
-
-
+
+
+ linux
+
+
+ unix
+ Linux
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+ compile-native-linux
+ compile
+
+ exec
+
+
+ ${project.basedir}/src/main/scripts/compile_linux.sh
+
+
+
+
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- 3.0.2
-
-
- darwin_x86_32
- package
-
- jar
-
-
- mac32
- ${project.build.outputDirectory}/darwin_x86_32
-
-
-
- darwin_x86_64
- package
-
- jar
-
-
- mac64
- ${project.build.outputDirectory}/darwin_x86_64
-
-
-
- linux_x86_32
- package
-
- jar
-
-
- linux32
- ${project.build.outputDirectory}/linux_x86_32
-
-
-
- linux_x86_64
- package
-
- jar
-
-
- linux64
- ${project.build.outputDirectory}/linux_x86_64
-
-
-
- win32_x86_32
- package
-
- jar
-
-
- windows32
- ${project.build.outputDirectory}/win32_x86_32
-
-
-
- win32_x86_64
- package
-
- jar
-
-
- windows64
- ${project.build.outputDirectory}/win32_x86_64
-
-
-
-
-
-
-
\ No newline at end of file
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ linux_x86_32
+ package
+
+ jar
+
+
+ linux_x86_32
+ ${project.build.directory}/native/linux_x86_32
+
+
+
+ linux_x86_64
+ package
+
+ jar
+
+
+ linux_x86_64
+ ${project.build.directory}/native/linux_x86_64
+
+
+
+
+
+
+
+
+
+
+ linux-arm64
+
+
+ unix
+ Linux
+ aarch64
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+ compile-native-linux-arm64
+ compile
+
+ exec
+
+
+ ${project.basedir}/src/main/scripts/compile_linux.sh
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ native-jar-linux_aarch64
+ package
+
+ jar
+
+
+ linux_aarch64
+ ${project.build.directory}/native/linux_aarch64
+
+
+
+
+
+
+
+
+
+
+ linux-arm64-cross
+
+
+ linux.arm64.cross
+ true
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+ compile-linux-aarch64-cross
+ compile
+
+ exec
+
+
+ ${project.basedir}/src/main/scripts/compile_linux.sh
+
+ true
+ aarch64-linux-gnu-gcc
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ native-jar-linux_aarch64-cross
+ package
+
+ jar
+
+
+ linux_aarch64
+ ${project.build.directory}/native/linux_aarch64
+
+
+
+
+
+
+
+
+
+
+ windows
+
+
+ windows
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+ compile-native-windows
+ compile
+
+ exec
+
+
+ ${project.basedir}/src/main/scripts/compile_win32.bat
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ win32_x86_32
+ package
+
+ jar
+
+
+ windows_x86_32
+ ${project.build.directory}/native/win32_x86_32
+
+
+
+ win32_x86_64
+ package
+
+ jar
+
+
+ windows_x86_64
+ ${project.build.directory}/native/win32_x86_64
+
+
+
+
+
+
+
+
+
diff --git a/modules/agent/src/main/resources/darwin_x86_32/libfaketime b/modules/agent/src/main/resources/darwin_x86_32/libfaketime
deleted file mode 100755
index f4e81bb..0000000
Binary files a/modules/agent/src/main/resources/darwin_x86_32/libfaketime and /dev/null differ
diff --git a/modules/agent/src/main/resources/darwin_x86_64/libfaketime b/modules/agent/src/main/resources/darwin_x86_64/libfaketime
deleted file mode 100755
index 50031b8..0000000
Binary files a/modules/agent/src/main/resources/darwin_x86_64/libfaketime and /dev/null differ
diff --git a/modules/agent/src/main/resources/linux_x86_32/libfaketime b/modules/agent/src/main/resources/linux_x86_32/libfaketime
deleted file mode 100755
index 0e1af4b..0000000
Binary files a/modules/agent/src/main/resources/linux_x86_32/libfaketime and /dev/null differ
diff --git a/modules/agent/src/main/resources/linux_x86_64/libfaketime b/modules/agent/src/main/resources/linux_x86_64/libfaketime
deleted file mode 100755
index 0e1af4b..0000000
Binary files a/modules/agent/src/main/resources/linux_x86_64/libfaketime and /dev/null differ
diff --git a/modules/agent/src/main/resources/win32_x86_32/faketime.dll b/modules/agent/src/main/resources/win32_x86_32/faketime.dll
deleted file mode 100644
index dd56ff6..0000000
Binary files a/modules/agent/src/main/resources/win32_x86_32/faketime.dll and /dev/null differ
diff --git a/modules/agent/src/main/resources/win32_x86_64/faketime.dll b/modules/agent/src/main/resources/win32_x86_64/faketime.dll
deleted file mode 100644
index 12bb902..0000000
Binary files a/modules/agent/src/main/resources/win32_x86_64/faketime.dll and /dev/null differ
diff --git a/modules/agent/src/main/scripts/compile_darwin.sh b/modules/agent/src/main/scripts/compile_darwin.sh
new file mode 100755
index 0000000..be930a0
--- /dev/null
+++ b/modules/agent/src/main/scripts/compile_darwin.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Build JNI dylibs for macOS: x86_64 and arm64 (aarch64)
+# Requires: Xcode command line tools / clang, a JDK (JAVA_HOME)
+
+CC="${CC:-clang}"
+CFLAGS="-O2 -fPIC -pthread -D_LP64=1"
+INCLUDES=(-I "$JAVA_HOME/include" -I "$JAVA_HOME/include/darwin")
+
+OUT_X86="target/native/darwin_x86_64"
+OUT_ARM="target/native/darwin_aarch64"
+
+mkdir -p "$OUT_X86" "$OUT_ARM"
+
+echo "==> macOS x86_64"
+$CC $CFLAGS "${INCLUDES[@]}" -c -arch x86_64 src/main/c/agent.c -o agent_x86_64.o
+$CC -dynamiclib -arch x86_64 agent_x86_64.o -lc -o "$OUT_X86/libfaketime.dylib"
+rm -f agent_x86_64.o
+
+echo "==> macOS arm64"
+$CC $CFLAGS "${INCLUDES[@]}" -c -arch arm64 src/main/c/agent.c -o agent_arm64.o
+$CC -dynamiclib -arch arm64 agent_arm64.o -lc -o "$OUT_ARM/libfaketime.dylib"
+rm -f agent_arm64.o
+
+echo "done."
diff --git a/modules/agent/src/main/scripts/compile_linux.sh b/modules/agent/src/main/scripts/compile_linux.sh
new file mode 100755
index 0000000..bae8209
--- /dev/null
+++ b/modules/agent/src/main/scripts/compile_linux.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Build JNI .so for Linux.
+# - On x86_64 host: builds x86_32 and x86_64.
+# - On aarch64 host: builds aarch64.
+# - Cross mode: if LINUX_AARCH64_CROSS=true, build aarch64 on x86 using aarch64-linux-gnu-gcc.
+
+CC="${CC:-gcc}"
+CFLAGS_COMMON="-O2 -fPIC -pthread"
+INCLUDES=(-I "$JAVA_HOME/include" -I "$JAVA_HOME/include/linux")
+
+# ---------- Cross-compile path for linux aarch64 ----------
+if [[ "${LINUX_AARCH64_CROSS:-}" == "true" ]]; then
+ OUTARM="target/native/linux_aarch64"
+ mkdir -p "$OUTARM"
+ : "${CC:=aarch64-linux-gnu-gcc}"
+ echo "==> Linux aarch64 (cross; CC=$CC)"
+ $CC $CFLAGS_COMMON -D_LP64=1 "${INCLUDES[@]}" -c src/main/c/agent.c -o agent_aarch64.o
+ $CC -shared -Wl,-z,defs -static-libgcc agent_aarch64.o -lc -o "$OUTARM/libfaketime.so"
+ rm -f agent_aarch64.o
+ echo "done (cross)."
+ exit 0
+fi
+# ----------------------------------------------------------
+
+ARCH="$(uname -m || true)"
+
+if [[ "${ARCH}" == "x86_64" ]]; then
+ OUT32="target/native/linux_x86_32"
+ OUT64="target/native/linux_x86_64"
+ mkdir -p "$OUT32" "$OUT64"
+
+ echo "==> Linux x86_32"
+ if ! echo 'int main(){}' | $CC -m32 -x c - -o /dev/null >/dev/null 2>&1; then
+ echo "WARNING: 32-bit toolchain not available; skipping linux_x86_32." >&2
+ else
+ $CC -m32 $CFLAGS_COMMON "${INCLUDES[@]}" -c src/main/c/agent.c -o agent_x86_32.o
+ $CC -m32 -shared -Wl,-z,defs -static-libgcc agent_x86_32.o -lc -o "$OUT32/libfaketime.so"
+ rm -f agent_x86_32.o
+ fi
+
+ echo "==> Linux x86_64"
+ $CC -m64 $CFLAGS_COMMON -D_LP64=1 "${INCLUDES[@]}" -c src/main/c/agent.c -o agent_x86_64.o
+ $CC -m64 -shared -Wl,-z,defs -static-libgcc agent_x86_64.o -lc -o "$OUT64/libfaketime.so"
+ rm -f agent_x86_64.o
+
+elif [[ "${ARCH}" == "aarch64" ]]; then
+ OUTARM="target/native/linux_aarch64"
+ mkdir -p "$OUTARM"
+
+ echo "==> Linux aarch64 (native)"
+ $CC $CFLAGS_COMMON -D_LP64=1 "${INCLUDES[@]}" -c src/main/c/agent.c -o agent_aarch64.o
+ $CC -shared -Wl,-z,defs -static-libgcc agent_aarch64.o -lc -o "$OUTARM/libfaketime.so"
+ rm -f agent_aarch64.o
+else
+ echo "ERROR: Unsupported Linux host arch '${ARCH}'. Supported: x86_64, aarch64." >&2
+ exit 1
+fi
+
+echo "done."
diff --git a/modules/agent/src/main/scripts/compile_win32.bat b/modules/agent/src/main/scripts/compile_win32.bat
new file mode 100644
index 0000000..c29fd4b
--- /dev/null
+++ b/modules/agent/src/main/scripts/compile_win32.bat
@@ -0,0 +1,31 @@
+@echo off
+REM Build JNI DLLs for Windows (x86 and x64) using MinGW (gcc).
+REM Outputs go to target\native\win32_\
+
+setlocal enabledelayedexpansion
+
+if "%JAVA_HOME%"=="" (
+ echo ERROR: JAVA_HOME must be set
+ exit /b 1
+)
+
+set CC32=%CC32%
+if "%CC32%"=="" set CC32=gcc
+set CC64=%CC64%
+if "%CC64%"=="" set CC64=x86_64-w64-mingw32-gcc
+
+set INCLUDES=-I "%JAVA_HOME%\include" -I "%JAVA_HOME%\include\win32"
+
+set OUT32=target\native\win32_x86_32
+set OUT64=target\native\win32_x86_64
+
+if not exist "%OUT32%" mkdir "%OUT32%"
+if not exist "%OUT64%" mkdir "%OUT64%"
+
+echo ==> Windows x86 (32-bit)
+%CC32% -m32 -O2 -shared -static-libgcc -Wl,--add-stdcall-alias -o "%OUT32%\faketime.dll" -D_JNI_IMPLEMENTATION_ %INCLUDES% src\main\c\agent.c
+
+echo ==> Windows x86_64
+%CC64% -O2 -shared -static-libgcc -Wl,--add-stdcall-alias -o "%OUT64%\faketime.dll" -D_JNI_IMPLEMENTATION_ %INCLUDES% src\main\c\agent.c
+
+echo done.
diff --git a/modules/api/pom.xml b/modules/api/pom.xml
index ded76ce..ed71bea 100644
--- a/modules/api/pom.xml
+++ b/modules/api/pom.xml
@@ -2,17 +2,17 @@
- 4.0.0
+ 4.0.0
- FakeTime API
- faketime-api
- jar
- 0-SNAPSHOT
+
+ io.github.faketime-java
+ faketime-parent
+ 0.9.0-SNAPSHOT
+ ../../pom.xml
+
-
- io.github.faketime-java
- faketime-parent
- 0-SNAPSHOT
- ../../pom.xml
-
-
\ No newline at end of file
+ FakeTime API
+ faketime-api
+ jar
+
+
diff --git a/modules/junit/pom.xml b/modules/junit/pom.xml
index 3c87662..6f53c05 100644
--- a/modules/junit/pom.xml
+++ b/modules/junit/pom.xml
@@ -2,33 +2,27 @@
- 4.0.0
+ 4.0.0
- FakeTime JUnit API
- faketime-junit
- jar
- 0-SNAPSHOT
+
+ io.github.faketime-java
+ faketime-parent
+ 0.9.0-SNAPSHOT
+ ../../pom.xml
+
-
- io.github.faketime-java
- faketime-parent
- 0-SNAPSHOT
- ../../pom.xml
-
+ FakeTime JUnit API
+ faketime-junit
+ jar
-
-
- io.github.faketime-java
- faketime-api
- 0-SNAPSHOT
- compile
-
-
-
- junit
- junit
- 4.12
- compile
-
-
-
\ No newline at end of file
+
+
+ io.github.faketime-java
+ faketime-api
+
+
+ junit
+ junit
+
+
+
diff --git a/modules/maven-plugin/pom.xml b/modules/maven-plugin/pom.xml
index 1c06e22..5e0aadc 100644
--- a/modules/maven-plugin/pom.xml
+++ b/modules/maven-plugin/pom.xml
@@ -2,74 +2,106 @@
- 4.0.0
+ 4.0.0
- FakeTime Maven Plugin
- faketime-maven-plugin
- maven-plugin
- 0-SNAPSHOT
+
+ io.github.faketime-java
+ faketime-parent
+ 0.9.0-SNAPSHOT
+ ../../pom.xml
+
-
- io.github.faketime-java
- faketime-parent
- 0-SNAPSHOT
- ../../pom.xml
-
+ FakeTime Maven Plugin
+ faketime-maven-plugin
+ maven-plugin
-
-
- org.apache.maven
- maven-core
- 3.6.0
- provided
-
+
+
+ org.apache.maven
+ maven-artifact
+ ${maven.version}
+ provided
+
+
+ org.apache.maven
+ maven-core
+ ${maven.version}
+ provided
+
+
+ org.apache.maven
+ maven-model
+ ${maven.version}
+ provided
+
+
+ org.apache.maven
+ maven-plugin-api
+ ${maven.version}
+ provided
+
+
+ org.apache.maven.plugin-tools
+ maven-plugin-annotations
+ ${maven.version}
+ provided
+
-
- org.apache.maven.plugin-tools
- maven-plugin-annotations
- 3.6.0
- provided
-
+
+ org.apache.maven.shared
+ maven-artifact-transfer
+ 0.13.1
+ compile
+
-
- org.apache.maven.shared
- maven-artifact-transfer
- 0.10.0
- compile
-
+
+ org.codehaus.plexus
+ plexus-archiver
+ 4.10.0
+ compile
+
+
-
- org.codehaus.plexus
- plexus-archiver
- 3.7.0
- compile
-
-
-
-
-
-
- maven-plugin-plugin
- 3.6.0
-
- faketime
- true
-
-
-
- mojo-descriptor
-
- descriptor
-
-
-
- help-goal
-
- helpmojo
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.apache.maven.plugin-tools
+ maven-plugin-annotations
+ ${maven.version}
+
+
+
+
+
+ maven-plugin-plugin
+ ${maven.version}
+
+ faketime
+ true
+
+
+
+ mojo-descriptor
+
+ descriptor
+
+
+
+ help-goal
+
+ helpmojo
+
+
+
+
+
+
+
+ 3.9.0
+
+
diff --git a/modules/maven-plugin/src/main/java/io/github/faketime/FakeTimeMojo.java b/modules/maven-plugin/src/main/java/io/github/faketime/FakeTimeMojo.java
index 254f610..fdad22a 100644
--- a/modules/maven-plugin/src/main/java/io/github/faketime/FakeTimeMojo.java
+++ b/modules/maven-plugin/src/main/java/io/github/faketime/FakeTimeMojo.java
@@ -1,15 +1,5 @@
package io.github.faketime;
-import static org.apache.maven.plugins.annotations.LifecyclePhase.VALIDATE;
-import static org.codehaus.plexus.util.Os.OS_ARCH;
-import static org.codehaus.plexus.util.Os.OS_NAME;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-import java.util.stream.Stream;
-
import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
@@ -27,102 +17,110 @@
import org.codehaus.plexus.components.io.fileselectors.FileSelector;
import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.stream.Stream;
+
+import static org.apache.maven.plugins.annotations.LifecyclePhase.VALIDATE;
+import static org.codehaus.plexus.util.Os.OS_ARCH;
+import static org.codehaus.plexus.util.Os.OS_NAME;
+
/**
* @threadSafe
*/
-@Mojo(name="prepare", defaultPhase = VALIDATE)
+@Mojo(name = "prepare", defaultPhase = VALIDATE)
public class FakeTimeMojo extends AbstractMojo {
- private static final String GROUP_ID = "io.github.faketime-java";
- private static final String ARTIFACT_ID = "faketime-maven-plugin";
- private static final String AGENT_ARTIFACT_ID = "faketime-agent";
+ private static final String GROUP_ID = "io.github.faketime-java";
+ private static final String ARTIFACT_ID = "faketime-maven-plugin";
+ private static final String AGENT_ARTIFACT_ID = "faketime-agent";
- private static final String ARG_LINE_PROPERTY_NAME = "faketime.argLine";
+ private static final String ARG_LINE_PROPERTY_NAME = "faketime.argLine";
- @Component
- private ArtifactResolver artifactResolver;
+ @Component
+ private ArtifactResolver artifactResolver;
- @Component
- private ArchiverManager archiverManager;
+ @Component
+ private ArchiverManager archiverManager;
- @Parameter(defaultValue = "${session}", readonly = true)
- private MavenSession session;
+ @Parameter(defaultValue = "${session}", readonly = true)
+ private MavenSession session;
- @Override
- public void execute() throws MojoFailureException {
- if (getOs() == null || Os.getBitness() == null) {
- getLog().warn(String.format("!!! %s %s is not supported by FakeTime !!!", OS_NAME, OS_ARCH));
- return;
+ @Override
+ public void execute() throws MojoFailureException {
+ if (getOs() == null || Os.getArch() == null) {
+ getLog().warn(String.format("!!! %s %s is not supported by FakeTime !!!", OS_NAME, OS_ARCH));
+ return;
+ }
+
+ unpackAgent();
+ setArgLineProperty();
}
- unpackAgent();
- setArgLineProperty();
- }
+ private void unpackAgent() {
+ try {
+ Artifact artifact = artifactResolver.resolveArtifact(session.getProjectBuildingRequest(), getAgentArtifactCoordinate()).getArtifact();
- private void unpackAgent() {
- try {
- Artifact artifact = artifactResolver.resolveArtifact(session.getProjectBuildingRequest(), getAgentArtifactCoordinate()).getArtifact();
+ getTargetDirectory().mkdirs();
- getTargetDirectory().mkdirs();
+ UnArchiver unArchiver = archiverManager.getUnArchiver(artifact.getType());
+ unArchiver.setSourceFile(artifact.getFile());
+ unArchiver.setDestDirectory(getTargetDirectory());
+ unArchiver.setFileSelectors(getAgentBinaryFileSelector());
+ unArchiver.extract();
+ } catch (ArtifactResolverException | NoSuchArchiverException e) {
+ throw new RuntimeException(e);
+ }
+ }
- UnArchiver unArchiver = archiverManager.getUnArchiver(artifact.getType());
- unArchiver.setSourceFile(artifact.getFile());
- unArchiver.setDestDirectory(getTargetDirectory());
- unArchiver.setFileSelectors(getAgentBinaryFileSelector());
- unArchiver.extract();
+ private void setArgLineProperty() {
+ session.getCurrentProject().getProperties().setProperty(ARG_LINE_PROPERTY_NAME, getAgentJvmArguments());
}
- catch (ArtifactResolverException | NoSuchArchiverException e) {
- throw new RuntimeException(e);
+
+ private ArtifactCoordinate getAgentArtifactCoordinate() {
+ DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
+ coordinate.setGroupId(GROUP_ID);
+ coordinate.setArtifactId(AGENT_ARTIFACT_ID);
+ coordinate.setVersion(getPluginVersion());
+ coordinate.setClassifier(String.format("%s_%s", getOs().getClassifierName(), Os.getArch()));
+ return coordinate;
}
- }
-
- private void setArgLineProperty() {
- session.getCurrentProject().getProperties().setProperty(ARG_LINE_PROPERTY_NAME, getAgentJvmArguments());
- }
-
- private ArtifactCoordinate getAgentArtifactCoordinate() {
- DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
- coordinate.setGroupId(GROUP_ID);
- coordinate.setArtifactId(AGENT_ARTIFACT_ID);
- coordinate.setVersion(getPluginVersion());
- coordinate.setClassifier(getOs().getClassifierName() + Os.getBitness());
- return coordinate;
- }
-
- private File getTargetDirectory() {
- return new File(session.getCurrentProject().getBuild().getDirectory());
- }
-
- private FileSelector[] getAgentBinaryFileSelector() {
- IncludeExcludeFileSelector fileSelector = new IncludeExcludeFileSelector();
- fileSelector.setIncludes(new String[] { getOs().getAgentBinaryName() });
- return new IncludeExcludeFileSelector[] { fileSelector };
- }
-
- private String getPluginVersion() {
- try {
- try (InputStream is = getClass().getResourceAsStream("/META-INF/maven/" + GROUP_ID + "/" + ARTIFACT_ID + "/pom.properties")) {
- Properties properties = new Properties();
- properties.load(is);
- return properties.getProperty("version");
- }
+
+ private File getTargetDirectory() {
+ return new File(session.getCurrentProject().getBuild().getDirectory());
}
- catch (IOException e) {
- throw new RuntimeException(e);
+
+ private FileSelector[] getAgentBinaryFileSelector() {
+ IncludeExcludeFileSelector fileSelector = new IncludeExcludeFileSelector();
+ fileSelector.setIncludes(new String[]{getOs().getAgentBinaryName()});
+ return new IncludeExcludeFileSelector[]{fileSelector};
+ }
+
+ private String getPluginVersion() {
+ try {
+ try (InputStream is = getClass().getResourceAsStream("/META-INF/maven/" + GROUP_ID + "/" + ARTIFACT_ID + "/pom.properties")) {
+ Properties properties = new Properties();
+ properties.load(is);
+ return properties.getProperty("version");
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String getAgentJvmArguments() {
+ return String.join(" ",
+ "-agentpath:" + new File(getTargetDirectory(), getOs().getAgentBinaryName()).getAbsolutePath(),
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:DisableIntrinsic=_currentTimeMillis",
+ "-XX:CompileCommand=quiet",
+ "-XX:CompileCommand=exclude,java/lang/System.currentTimeMillis",
+ "-XX:CompileCommand=exclude,jdk/internal/misc/VM.getNanoTimeAdjustment");
+ }
+
+ private Os getOs() {
+ return Stream.of(Os.values()).filter(Os::isCurrent).findFirst().orElse(null);
}
- }
-
- private String getAgentJvmArguments() {
- return String.join(" ",
- "-agentpath:" + new File(getTargetDirectory(), getOs().getAgentBinaryName()).getAbsolutePath(),
- "-XX:+UnlockDiagnosticVMOptions",
- "-XX:DisableIntrinsic=_currentTimeMillis",
- "-XX:CompileCommand=quiet",
- "-XX:CompileCommand=exclude,java/lang/System.currentTimeMillis",
- "-XX:CompileCommand=exclude,jdk/internal/misc/VM.getNanoTimeAdjustment");
- }
-
- private Os getOs() {
- return Stream.of(Os.values()).filter(Os::isCurrent).findFirst().orElse(null);
- }
}
diff --git a/modules/maven-plugin/src/main/java/io/github/faketime/Os.java b/modules/maven-plugin/src/main/java/io/github/faketime/Os.java
index e91e3c2..09daa45 100644
--- a/modules/maven-plugin/src/main/java/io/github/faketime/Os.java
+++ b/modules/maven-plugin/src/main/java/io/github/faketime/Os.java
@@ -1,63 +1,67 @@
package io.github.faketime;
+import java.util.List;
+
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.codehaus.plexus.util.Os.OS_ARCH;
import static org.codehaus.plexus.util.Os.OS_NAME;
-import java.util.List;
-
public enum Os {
- WINDOWS("windows", "windows", "faketime.dll"),
- LINUX("linux", "linux", "libfaketime"),
- MAC(asList("mac", "osx"), "mac", "libfaketime");
-
- private final List names;
- private final String classifierName;
- private final String agentBinaryName;
-
- Os(List names, String classifierName, String agentBinaryName) {
- this.names = names;
- this.classifierName = classifierName;
- this.agentBinaryName = agentBinaryName;
- }
-
- Os(String name, String classifierName, String agentBinaryName) {
- this(singletonList(name), classifierName, agentBinaryName);
- }
-
- public static String getBitness() {
- switch (OS_ARCH.replace("_", "")) {
- case "x8664":
- case "amd64":
- case "ia32e":
- case "em64t":
- case "x64":
- return "64";
- case "x8632":
- case "x86":
- case "i386":
- case "i486":
- case "i586":
- case "i686":
- case "ia32":
- case "x32":
- return "32";
- default:
- return null;
+ WINDOWS("windows", "windows", "faketime.dll"),
+ LINUX("linux", "linux", "libfaketime"),
+ MAC(asList("mac", "osx"), "mac", "libfaketime.dylib");
+
+ private final List names;
+ private final String classifierName;
+ private final String agentBinaryName;
+
+ Os(List names, String classifierName, String agentBinaryName) {
+ this.names = names;
+ this.classifierName = classifierName;
+ this.agentBinaryName = agentBinaryName;
}
- }
- public String getClassifierName() {
- return classifierName;
- }
+ Os(String name, String classifierName, String agentBinaryName) {
+ this(singletonList(name), classifierName, agentBinaryName);
+ }
- public String getAgentBinaryName() {
- return agentBinaryName;
- }
+ public static String getArch() {
+ switch (OS_ARCH.replace("_", "")) {
+ case "arm64":
+ return "arm64";
+ case "aarch64":
+ return "aarch64";
+ case "x8664":
+ case "amd64":
+ case "ia32e":
+ case "em64t":
+ case "x64":
+ return "x86_64";
+ case "x8632":
+ case "x86":
+ case "i386":
+ case "i486":
+ case "i586":
+ case "i686":
+ case "ia32":
+ case "x32":
+ return "x86_32";
+ default:
+ return null;
+ }
+ }
+
+ public String getClassifierName() {
+ return classifierName;
+ }
- public boolean isCurrent() {
- return names.stream().anyMatch(OS_NAME::contains);
- }
+ public String getAgentBinaryName() {
+ return agentBinaryName;
+ }
+
+ public boolean isCurrent() {
+ return names.stream().anyMatch(OS_NAME::contains);
+ }
}
diff --git a/mvnw b/mvnw
index 8dfad2c..19529dd 100755
--- a/mvnw
+++ b/mvnw
@@ -19,267 +19,241 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
-# Maven2 Start Up Batch script
-#
-# Required ENV vars:
-# ------------------
-# JAVA_HOME - location of a JDK home dir
+# Apache Maven Wrapper startup batch script, version 3.3.2
#
# Optional ENV vars
# -----------------
-# M2_HOME - location of maven2's installed home dir
-# MAVEN_OPTS - parameters passed to the Java VM when running Maven
-# e.g. to debug Maven itself, use
-# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
-# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# JAVA_HOME - location of a JDK home dir, required when download maven via java source
+# MVNW_REPOURL - repo url base for downloading maven distribution
+# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
# ----------------------------------------------------------------------------
-if [ -z "$MAVEN_SKIP_RC" ] ; then
-
- if [ -f /etc/mavenrc ] ; then
- . /etc/mavenrc
- fi
+set -euf
+[ "${MVNW_VERBOSE-}" != debug ] || set -x
- if [ -f "$HOME/.mavenrc" ] ; then
- . "$HOME/.mavenrc"
- fi
+# OS specific support.
+native_path() { printf %s\\n "$1"; }
+case "$(uname)" in
+CYGWIN* | MINGW*)
+ [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
+ native_path() { cygpath --path --windows "$1"; }
+ ;;
+esac
-fi
+# set JAVACMD and JAVACCMD
+set_java_home() {
+ # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
+ if [ -n "${JAVA_HOME-}" ]; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACCMD="$JAVA_HOME/jre/sh/javac"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ JAVACCMD="$JAVA_HOME/bin/javac"
-# OS specific support. $var _must_ be set to either true or false.
-cygwin=false;
-darwin=false;
-mingw=false
-case "`uname`" in
- CYGWIN*) cygwin=true ;;
- MINGW*) mingw=true;;
- Darwin*) darwin=true
- # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
- # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
- if [ -z "$JAVA_HOME" ]; then
- if [ -x "/usr/libexec/java_home" ]; then
- export JAVA_HOME="`/usr/libexec/java_home`"
- else
- export JAVA_HOME="/Library/Java/Home"
+ if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
+ echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
+ echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
+ return 1
fi
fi
- ;;
-esac
+ else
+ JAVACMD="$(
+ 'set' +e
+ 'unset' -f command 2>/dev/null
+ 'command' -v java
+ )" || :
+ JAVACCMD="$(
+ 'set' +e
+ 'unset' -f command 2>/dev/null
+ 'command' -v javac
+ )" || :
-if [ -z "$JAVA_HOME" ] ; then
- if [ -r /etc/gentoo-release ] ; then
- JAVA_HOME=`java-config --jre-home`
+ if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
+ echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
+ return 1
+ fi
fi
-fi
-
-if [ -z "$M2_HOME" ] ; then
- ## resolve links - $0 may be a link to maven's home
- PRG="$0"
+}
- # need this for relative symlinks
- while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG="`dirname "$PRG"`/$link"
- fi
+# hash string like Java String::hashCode
+hash_string() {
+ str="${1:-}" h=0
+ while [ -n "$str" ]; do
+ char="${str%"${str#?}"}"
+ h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
+ str="${str#?}"
done
+ printf %x\\n $h
+}
- saveddir=`pwd`
+verbose() { :; }
+[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
- M2_HOME=`dirname "$PRG"`/..
+die() {
+ printf %s\\n "$1" >&2
+ exit 1
+}
- # make it fully qualified
- M2_HOME=`cd "$M2_HOME" && pwd`
+trim() {
+ # MWRAPPER-139:
+ # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
+ # Needed for removing poorly interpreted newline sequences when running in more
+ # exotic environments such as mingw bash on Windows.
+ printf "%s" "${1}" | tr -d '[:space:]'
+}
- cd "$saveddir"
- # echo Using m2 at $M2_HOME
-fi
+# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
+while IFS="=" read -r key value; do
+ case "${key-}" in
+ distributionUrl) distributionUrl=$(trim "${value-}") ;;
+ distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
+ esac
+done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
+[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
-# For Cygwin, ensure paths are in UNIX format before anything is touched
-if $cygwin ; then
- [ -n "$M2_HOME" ] &&
- M2_HOME=`cygpath --unix "$M2_HOME"`
- [ -n "$JAVA_HOME" ] &&
- JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
- [ -n "$CLASSPATH" ] &&
- CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
-fi
+case "${distributionUrl##*/}" in
+maven-mvnd-*bin.*)
+ MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
+ case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
+ *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
+ :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
+ :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
+ :Linux*x86_64*) distributionPlatform=linux-amd64 ;;
+ *)
+ echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
+ distributionPlatform=linux-amd64
+ ;;
+ esac
+ distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
+ ;;
+maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
+*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
+esac
-# For Mingw, ensure paths are in UNIX format before anything is touched
-if $mingw ; then
- [ -n "$M2_HOME" ] &&
- M2_HOME="`(cd "$M2_HOME"; pwd)`"
- [ -n "$JAVA_HOME" ] &&
- JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
-fi
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
+[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
+distributionUrlName="${distributionUrl##*/}"
+distributionUrlNameMain="${distributionUrlName%.*}"
+distributionUrlNameMain="${distributionUrlNameMain%-bin}"
+MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
+MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
-if [ -z "$JAVA_HOME" ]; then
- javaExecutable="`which javac`"
- if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
- # readlink(1) is not available as standard on Solaris 10.
- readLink=`which readlink`
- if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
- if $darwin ; then
- javaHome="`dirname \"$javaExecutable\"`"
- javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
- else
- javaExecutable="`readlink -f \"$javaExecutable\"`"
- fi
- javaHome="`dirname \"$javaExecutable\"`"
- javaHome=`expr "$javaHome" : '\(.*\)/bin'`
- JAVA_HOME="$javaHome"
- export JAVA_HOME
- fi
- fi
-fi
+exec_maven() {
+ unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
+ exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
+}
-if [ -z "$JAVACMD" ] ; then
- if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- else
- JAVACMD="`which java`"
- fi
+if [ -d "$MAVEN_HOME" ]; then
+ verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+ exec_maven "$@"
fi
-if [ ! -x "$JAVACMD" ] ; then
- echo "Error: JAVA_HOME is not defined correctly." >&2
- echo " We cannot execute $JAVACMD" >&2
- exit 1
-fi
+case "${distributionUrl-}" in
+*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
+*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
+esac
-if [ -z "$JAVA_HOME" ] ; then
- echo "Warning: JAVA_HOME environment variable is not set."
+# prepare tmp dir
+if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
+ clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
+ trap clean HUP INT TERM EXIT
+else
+ die "cannot create temp dir"
fi
-CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+mkdir -p -- "${MAVEN_HOME%/*}"
-# traverses directory structure from process work directory to filesystem root
-# first directory with .mvn subdirectory is considered project base directory
-find_maven_basedir() {
+# Download and Install Apache Maven
+verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+verbose "Downloading from: $distributionUrl"
+verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
- if [ -z "$1" ]
- then
- echo "Path not specified to find_maven_basedir"
- return 1
- fi
+# select .zip or .tar.gz
+if ! command -v unzip >/dev/null; then
+ distributionUrl="${distributionUrl%.zip}.tar.gz"
+ distributionUrlName="${distributionUrl##*/}"
+fi
- basedir="$1"
- wdir="$1"
- while [ "$wdir" != '/' ] ; do
- if [ -d "$wdir"/.mvn ] ; then
- basedir=$wdir
- break
- fi
- # workaround for JBEAP-8937 (on Solaris 10/Sparc)
- if [ -d "${wdir}" ]; then
- wdir=`cd "$wdir/.."; pwd`
- fi
- # end of workaround
- done
- echo "${basedir}"
-}
+# verbose opt
+__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
+[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
-# concatenates all lines of a file
-concat_lines() {
- if [ -f "$1" ]; then
- echo "$(tr -s '\n' ' ' < "$1")"
- fi
-}
+# normalize http auth
+case "${MVNW_PASSWORD:+has-password}" in
+'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+esac
-BASE_DIR=`find_maven_basedir "$(pwd)"`
-if [ -z "$BASE_DIR" ]; then
- exit 1;
+if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
+ verbose "Found wget ... using wget"
+ wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
+elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
+ verbose "Found curl ... using curl"
+ curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
+elif set_java_home; then
+ verbose "Falling back to use Java to download"
+ javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
+ targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
+ cat >"$javaSource" <<-END
+ public class Downloader extends java.net.Authenticator
+ {
+ protected java.net.PasswordAuthentication getPasswordAuthentication()
+ {
+ return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
+ }
+ public static void main( String[] args ) throws Exception
+ {
+ setDefault( new Downloader() );
+ java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
+ }
+ }
+ END
+ # For Cygwin/MinGW, switch paths to Windows format before running javac and java
+ verbose " - Compiling Downloader.java ..."
+ "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
+ verbose " - Running Downloader.java ..."
+ "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
fi
-##########################################################################################
-# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
-# This allows using the maven wrapper in projects that prohibit checking in binary data.
-##########################################################################################
-if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
- if [ "$MVNW_VERBOSE" = true ]; then
- echo "Found .mvn/wrapper/maven-wrapper.jar"
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+if [ -n "${distributionSha256Sum-}" ]; then
+ distributionSha256Result=false
+ if [ "$MVN_CMD" = mvnd.sh ]; then
+ echo "Checksum validation is not supported for maven-mvnd." >&2
+ echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+ exit 1
+ elif command -v sha256sum >/dev/null; then
+ if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
+ distributionSha256Result=true
fi
-else
- if [ "$MVNW_VERBOSE" = true ]; then
- echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
- fi
- jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
- while IFS="=" read key value; do
- case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
- esac
- done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
- if [ "$MVNW_VERBOSE" = true ]; then
- echo "Downloading from: $jarUrl"
- fi
- wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
-
- if command -v wget > /dev/null; then
- if [ "$MVNW_VERBOSE" = true ]; then
- echo "Found wget ... using wget"
- fi
- wget "$jarUrl" -O "$wrapperJarPath"
- elif command -v curl > /dev/null; then
- if [ "$MVNW_VERBOSE" = true ]; then
- echo "Found curl ... using curl"
- fi
- curl -o "$wrapperJarPath" "$jarUrl"
- else
- if [ "$MVNW_VERBOSE" = true ]; then
- echo "Falling back to using Java to download"
- fi
- javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
- if [ -e "$javaClass" ]; then
- if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
- if [ "$MVNW_VERBOSE" = true ]; then
- echo " - Compiling MavenWrapperDownloader.java ..."
- fi
- # Compiling the Java class
- ("$JAVA_HOME/bin/javac" "$javaClass")
- fi
- if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
- # Running the downloader
- if [ "$MVNW_VERBOSE" = true ]; then
- echo " - Running MavenWrapperDownloader.java ..."
- fi
- ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
- fi
- fi
+ elif command -v shasum >/dev/null; then
+ if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
+ distributionSha256Result=true
fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
+ echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+ exit 1
+ fi
+ if [ $distributionSha256Result = false ]; then
+ echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
+ echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
+ exit 1
+ fi
fi
-##########################################################################################
-# End of extension
-##########################################################################################
-
-export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
-if [ "$MVNW_VERBOSE" = true ]; then
- echo $MAVEN_PROJECTBASEDIR
-fi
-MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin; then
- [ -n "$M2_HOME" ] &&
- M2_HOME=`cygpath --path --windows "$M2_HOME"`
- [ -n "$JAVA_HOME" ] &&
- JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
- [ -n "$CLASSPATH" ] &&
- CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
- [ -n "$MAVEN_PROJECTBASEDIR" ] &&
- MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+# unzip and move
+if command -v unzip >/dev/null; then
+ unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
+else
+ tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
fi
+printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
+mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
-WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
-
-exec "$JAVACMD" \
- $MAVEN_OPTS \
- -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
- "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
- ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
+clean || :
+exec_maven "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
index e5cfb0a..b150b91 100644
--- a/mvnw.cmd
+++ b/mvnw.cmd
@@ -1,161 +1,149 @@
-@REM ----------------------------------------------------------------------------
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM ----------------------------------------------------------------------------
-
-@REM ----------------------------------------------------------------------------
-@REM Maven2 Start Up Batch script
-@REM
-@REM Required ENV vars:
-@REM JAVA_HOME - location of a JDK home dir
-@REM
-@REM Optional ENV vars
-@REM M2_HOME - location of maven2's installed home dir
-@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
-@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
-@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
-@REM e.g. to debug Maven itself, use
-@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
-@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
-@REM ----------------------------------------------------------------------------
-
-@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
-@echo off
-@REM set title of command window
-title %0
-@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
-@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
-
-@REM set %HOME% to equivalent of $HOME
-if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
-
-@REM Execute a user defined script before this one
-if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
-@REM check for pre script, once with legacy .bat ending and once with .cmd ending
-if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
-if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
-:skipRcPre
-
-@setlocal
-
-set ERROR_CODE=0
-
-@REM To isolate internal variables from possible post scripts, we use another setlocal
-@setlocal
-
-@REM ==== START VALIDATION ====
-if not "%JAVA_HOME%" == "" goto OkJHome
-
-echo.
-echo Error: JAVA_HOME not found in your environment. >&2
-echo Please set the JAVA_HOME variable in your environment to match the >&2
-echo location of your Java installation. >&2
-echo.
-goto error
-
-:OkJHome
-if exist "%JAVA_HOME%\bin\java.exe" goto init
-
-echo.
-echo Error: JAVA_HOME is set to an invalid directory. >&2
-echo JAVA_HOME = "%JAVA_HOME%" >&2
-echo Please set the JAVA_HOME variable in your environment to match the >&2
-echo location of your Java installation. >&2
-echo.
-goto error
-
-@REM ==== END VALIDATION ====
-
-:init
-
-@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
-@REM Fallback to current working directory if not found.
-
-set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
-IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
-
-set EXEC_DIR=%CD%
-set WDIR=%EXEC_DIR%
-:findBaseDir
-IF EXIST "%WDIR%"\.mvn goto baseDirFound
-cd ..
-IF "%WDIR%"=="%CD%" goto baseDirNotFound
-set WDIR=%CD%
-goto findBaseDir
-
-:baseDirFound
-set MAVEN_PROJECTBASEDIR=%WDIR%
-cd "%EXEC_DIR%"
-goto endDetectBaseDir
-
-:baseDirNotFound
-set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
-cd "%EXEC_DIR%"
-
-:endDetectBaseDir
-
-IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
-
-@setlocal EnableExtensions EnableDelayedExpansion
-for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
-@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
-
-:endReadAdditionalConfig
-
-SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
-set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
-set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
-
-set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
-FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
- IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
-)
-
-@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
-@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
-if exist %WRAPPER_JAR% (
- echo Found %WRAPPER_JAR%
-) else (
- echo Couldn't find %WRAPPER_JAR%, downloading it ...
- echo Downloading from: %DOWNLOAD_URL%
- powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
- echo Finished downloading %WRAPPER_JAR%
-)
-@REM End of extension
-
-%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
-if ERRORLEVEL 1 goto error
-goto end
-
-:error
-set ERROR_CODE=1
-
-:end
-@endlocal & set ERROR_CODE=%ERROR_CODE%
-
-if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
-@REM check for post script, once with legacy .bat ending and once with .cmd ending
-if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
-if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
-:skipRcPost
-
-@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
-if "%MAVEN_BATCH_PAUSE%" == "on" pause
-
-if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
-
-exit /B %ERROR_CODE%
+<# : batch portion
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.3.2
+@REM
+@REM Optional ENV vars
+@REM MVNW_REPOURL - repo url base for downloading maven distribution
+@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
+@REM ----------------------------------------------------------------------------
+
+@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
+@SET __MVNW_CMD__=
+@SET __MVNW_ERROR__=
+@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
+@SET PSModulePath=
+@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
+ IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
+)
+@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
+@SET __MVNW_PSMODULEP_SAVE=
+@SET __MVNW_ARG0_NAME__=
+@SET MVNW_USERNAME=
+@SET MVNW_PASSWORD=
+@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
+@echo Cannot start maven from wrapper >&2 && exit /b 1
+@GOTO :EOF
+: end batch / begin powershell #>
+
+$ErrorActionPreference = "Stop"
+if ($env:MVNW_VERBOSE -eq "true") {
+ $VerbosePreference = "Continue"
+}
+
+# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
+$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
+if (!$distributionUrl) {
+ Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
+}
+
+switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
+ "maven-mvnd-*" {
+ $USE_MVND = $true
+ $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
+ $MVN_CMD = "mvnd.cmd"
+ break
+ }
+ default {
+ $USE_MVND = $false
+ $MVN_CMD = $script -replace '^mvnw','mvn'
+ break
+ }
+}
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
+if ($env:MVNW_REPOURL) {
+ $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
+ $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
+}
+$distributionUrlName = $distributionUrl -replace '^.*/',''
+$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
+$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
+if ($env:MAVEN_USER_HOME) {
+ $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
+}
+$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
+$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
+
+if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
+ Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+ Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
+ exit $?
+}
+
+if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
+ Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
+}
+
+# prepare tmp dir
+$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
+$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
+$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
+trap {
+ if ($TMP_DOWNLOAD_DIR.Exists) {
+ try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+ catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+ }
+}
+
+New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
+
+# Download and Install Apache Maven
+Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+Write-Verbose "Downloading from: $distributionUrl"
+Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+$webclient = New-Object System.Net.WebClient
+if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
+ $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
+}
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
+if ($distributionSha256Sum) {
+ if ($USE_MVND) {
+ Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
+ }
+ Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
+ if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
+ Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
+ }
+}
+
+# unzip and move
+Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
+Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
+try {
+ Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
+} catch {
+ if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
+ Write-Error "fail to move MAVEN_HOME"
+ }
+} finally {
+ try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+ catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+}
+
+Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
diff --git a/pom.xml b/pom.xml
index e94dd80..e0bf887 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,143 +2,169 @@
- 4.0.0
+ 4.0.0
- FakeTime Parent POM
- io.github.faketime-java
- faketime-parent
- pom
- 0-SNAPSHOT
+ FakeTime Parent POM
+ io.github.faketime-java
+ faketime-parent
+ pom
+ 0.9.0-SNAPSHOT
-
- FakeTime uses a native Java agent to replace System.currentTimeMillis() implementation with the one you can control using system properties
-
- https://github.com/faketime-java/faketime
-
-
- MIT
- http://opensource.org/licenses/MIT
-
-
-
-
- mihhail-lapushkin
- Mihhail Lapushkin
- mihhail.lapushkin@gmail.com
-
-
-
- scm:git:https://github.com/faketime-java/faketime.git
- scm:git:git@github.com:faketime-java/faketime.git
+
+ FakeTime uses a native Java agent to replace System.currentTimeMillis() implementation with the one you can control using system properties
+
https://github.com/faketime-java/faketime
- HEAD
-
+
+
+ MIT
+ http://opensource.org/licenses/MIT
+
+
+
+
+ mihhail-lapushkin
+ Mihhail Lapushkin
+ mihhail.lapushkin@gmail.com
+
+
+
+ scm:git:https://github.com/faketime-java/faketime.git
+ scm:git:git@github.com:faketime-java/faketime.git
+ https://github.com/faketime-java/faketime
+ HEAD
+
-
- UTF-8
- UTF-8
-
+
+ UTF-8
+ UTF-8
+
-
- modules/agent
- modules/api
- modules/junit
- modules/maven-plugin
-
+
+ modules/agent
+ modules/api
+ modules/junit
+ modules/maven-plugin
+
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.0
-
- 1.8
- 1.8
-
- -Xlint:all
-
-
-
+
+
+
+ io.github.faketime-java
+ faketime-api
+ ${project.version}
+
+
+ io.github.faketime-java
+ faketime-junit
+ ${project.version}
+
+
+ junit
+ junit
+ 4.12
+
+
+
-
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.8
- true
-
- ossrh
- https://oss.sonatype.org/
- true
-
-
-
-
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.14.0
+
+ 8
+
+ -Xlint:all
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+
-
-
- with-e2e-tests
-
- e2e-tests
-
-
+
+
+ with-e2e-tests
+
+ e2e-tests
+
+
-
- release
-
-
-
- org.apache.maven.plugins
- maven-gpg-plugin
- 1.6
-
-
- sign-artifacts
- verify
-
- sign
-
-
-
-
+
+ release
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 3.2.8
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
-
- org.apache.maven.plugins
- maven-source-plugin
- 3.0.1
-
-
- attach-sources
-
- jar-no-fork
-
-
-
-
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.3.1
+
+
+ attach-sources
+
+ jar-no-fork
+
+
+
+
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 3.0.0
-
-
- attach-javadocs
-
- jar
-
-
-
-
-
-
- threadSafe
- X
-
-
-
-
-
-
-
-
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.11.2
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+
+ threadSafe
+ X
+
+
+
+
+
+
+
+