├── .gitignore ├── README.md ├── UNLICENSE ├── default.nix ├── flake.lock ├── flake.nix ├── mavenix.nix ├── mvnix-init ├── mvnix-update ├── overlay.nix └── release.nix /.gitignore: -------------------------------------------------------------------------------- 1 | result* 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mavenix 2 | 3 | Deterministic Maven builds using Nix? 4 | 5 | ## Install 6 | 7 | First you need to install the [Nix package manager](https://nixos.org/nix/), if 8 | you already haven't. 9 | 10 | ```sh 11 | nix-env -i -f https://github.com/nix-community/mavenix/tarball/master 12 | ``` 13 | 14 | ## Usage 15 | 16 | ### Create stub files 17 | 18 | First we need to create some stub Nix expression files. `cd` into your maven 19 | project directory and run: 20 | 21 | ```sh 22 | mvnix-init 23 | ``` 24 | 25 | Follow the instructions displayed. 26 | 27 | ### Generate lock file 28 | 29 | The `mvnix-update` script generates a `mavenix.lock` file: 30 | 31 | ```sh 32 | mvnix-update 33 | ``` 34 | 35 | Note the `mvnix-update` script expects a `default.nix` that evaluates to the derivation, 36 | just as is generated by `mvnix-init`. It is possible however to pass in a custom expression 37 | in order to update the derivation. E.g., if the derivation is the attribute `pkgset.pkg`: 38 | 39 | ```sh 40 | mvnix-update -E "(import ./. {}).pkgset.pkg" 41 | ``` 42 | 43 | ### Packaging third-party projects 44 | 45 | If you are packaging a third-party Maven project you can specify a Nix 46 | expression that returns the source of that project. 47 | 48 | This makes it possible to generate a lock file without having to first 49 | manually clone the target project repository. 50 | 51 | E.g. generate and build a Nix package for Traccar v4.2: 52 | 53 | ```sh 54 | mvnix-init -S 'fetchTarball "http://github.com/traccar/traccar/tarball/v4.2"' 55 | mvnix-update 56 | nix-build 57 | ``` 58 | 59 | Or a Spring Boot application: 60 | 61 | ```sh 62 | mvnix-init -S 'fetchTarball https://github.com/Gerschtli/spring-rest-api/tarball/master' 63 | mvnix-update 64 | nix-build 65 | ``` 66 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs ? (import (fetchTarball "https://github.com/NixOS/nixpkgs-channels/tarball/c75de8bc12cc7e713206199e5ca30b224e295041") {}), 3 | mavenixLib ? import ./mavenix.nix { inherit pkgs; }, 4 | }: with pkgs; 5 | 6 | let 7 | inherit (mavenixLib) name version; 8 | homepage = "https://github.com/nix-community/mavenix"; 9 | download = "${homepage}/tarball/v${version}"; 10 | gen-header = "# This file has been generated by ${name}."; 11 | 12 | default-tmpl = writeText "default-tmpl.nix" '' 13 | ${gen-header} Configure the build here! 14 | let 15 | mavenix-src = %%env%%; 16 | in { 17 | # pkgs is pinned to 19.09 in mavenix-src, 18 | # replace/invoke with or /path/to/your/nixpkgs_checkout 19 | pkgs ? (import mavenix-src {}).pkgs, 20 | mavenix ? import mavenix-src { inherit pkgs; }, 21 | src ? %%src%%, 22 | doCheck ? false, 23 | }: mavenix.buildMaven { 24 | inherit src doCheck; 25 | infoFile = ./mavenix.lock; 26 | 27 | # Add build dependencies 28 | # 29 | #buildInputs = with pkgs; [ git makeWrapper ]; 30 | 31 | # Set build environment variables 32 | # 33 | #MAVEN_OPTS = "-Dfile.encoding=UTF-8"; 34 | 35 | # Attributes are passed to the underlying `stdenv.mkDerivation`, so build 36 | # hooks can be set here also. 37 | # 38 | #postInstall = ''' 39 | # makeWrapper ''${pkgs.jre8_headless}/bin/java $out/bin/my-bin \ 40 | # --add-flags "-jar $out/share/java/my-proj.jar" 41 | #'''; 42 | 43 | # Add extra maven dependencies which might not have been picked up 44 | # automatically 45 | # 46 | #deps = [ 47 | # { path = "org/group-id/artifactId/version/file.jar"; sha1 = "0123456789abcdef"; } 48 | # { path = "org/group-id/artifactId/version/file.pom"; sha1 = "123456789abcdef0"; } 49 | #]; 50 | 51 | # Add dependencies on other mavenix derivations 52 | # 53 | #drvs = [ (import ../other/mavenix/derivation {}) ]; 54 | 55 | # Override which maven package to build with 56 | # 57 | #maven = maven.overrideAttrs (_: { jdk = pkgs.oraclejdk10; }); 58 | 59 | # Override remote repository URLs and settings.xml 60 | # 61 | #remotes = { central = "https://repo.maven.apache.org/maven2"; }; 62 | #settings = ./settings.xml; 63 | } 64 | ''; 65 | in mavenixLib // { 66 | cli = stdenv.mkDerivation { 67 | inherit name; 68 | src = lib.cleanSource ./.; 69 | 70 | buildInputs = [ makeWrapper ]; 71 | 72 | phases = [ "unpackPhase" "installPhase" "fixupPhase" ]; 73 | installPhase = '' 74 | mkdir -p $out/bin 75 | cp mvnix-init mvnix-update $out/bin 76 | wrapProgram $out/bin/mvnix-init \ 77 | --set CONFIG_TEMPLATE ${default-tmpl} \ 78 | --set MAVENIX_SCRIPT ${./mavenix.nix} \ 79 | --set MAVENIX_DOWNLOAD ${download} \ 80 | --set MAVENIX_VERSION ${version} \ 81 | --prefix PATH : ${lib.makeBinPath [ nix coreutils yq ]} 82 | wrapProgram $out/bin/mvnix-update \ 83 | --set MAVENIX_VERSION ${version} \ 84 | --prefix PATH : ${lib.makeBinPath [ nix coreutils jq yq mktemp ]} 85 | ''; 86 | 87 | meta = with lib; { 88 | inherit homepage; 89 | description = "Mavenix: deterministic builds for Maven using Nix?"; 90 | license = licenses.unlicense; 91 | maintainers = [ { email = "me@icetan.org"; github = "icetan"; name = "Christopher Fredén"; } ]; 92 | }; 93 | }; 94 | } 95 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1621552131, 6 | "narHash": "sha256-AD/AEXv+QOYAg0PIqMYv2nbGOGTIwfOGKtz3rE+y+Tc=", 7 | "owner": "NixOS", 8 | "repo": "nixpkgs", 9 | "rev": "d42cd445dde587e9a993cd9434cb43da07c4c5de", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "id": "nixpkgs", 14 | "type": "indirect" 15 | } 16 | }, 17 | "root": { 18 | "inputs": { 19 | "nixpkgs": "nixpkgs", 20 | "utils": "utils" 21 | } 22 | }, 23 | "utils": { 24 | "locked": { 25 | "lastModified": 1620759905, 26 | "narHash": "sha256-WiyWawrgmyN0EdmiHyG2V+fqReiVi8bM9cRdMaKQOFg=", 27 | "owner": "numtide", 28 | "repo": "flake-utils", 29 | "rev": "b543720b25df6ffdfcf9227afafc5b8c1fabfae8", 30 | "type": "github" 31 | }, 32 | "original": { 33 | "owner": "numtide", 34 | "repo": "flake-utils", 35 | "type": "github" 36 | } 37 | } 38 | }, 39 | "root": "root", 40 | "version": 7 41 | } 42 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Mavenix"; 3 | 4 | inputs.utils.url = "github:numtide/flake-utils"; 5 | 6 | outputs = { self, nixpkgs, utils }: 7 | utils.lib.eachSystem utils.lib.allSystems (system: 8 | let 9 | pkgs = import nixpkgs { inherit system; }; 10 | mavenix = import ./. { inherit pkgs; }; 11 | in rec { 12 | packages = utils.lib.flattenTree { 13 | mavenix-cli = mavenix.cli; 14 | }; 15 | defaultPackage = packages.mavenix-cli; 16 | apps.mavenix-cli = utils.lib.mkApp { drv = packages.mavenix-cli; }; 17 | defaultApp = apps.mavenix-cli; 18 | }) // { 19 | overlay = final: prev: { 20 | inherit (import ./mavenix.nix { pkgs = prev; }) buildMaven; 21 | mavenix-cli = (import ./. { pkgs = prev; }).cli; 22 | }; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /mavenix.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: 2 | 3 | let 4 | inherit (builtins) attrNames attrValues pathExists toJSON foldl' elemAt; 5 | inherit (pkgs) stdenv runCommand fetchurl makeWrapper maven writeText 6 | requireFile yq; 7 | inherit (pkgs.lib) concatLists concatStrings importJSON strings 8 | optionalAttrs optionalString; 9 | 10 | maven' = maven; 11 | settings' = writeText "settings.xml" '' 12 | 16 | 17 | ''; 18 | 19 | mapmap = fs: ls: concatLists (map (v: map (f: f v) fs) ls); 20 | 21 | urlToScript = remoteList: dep: 22 | let 23 | inherit (dep) path sha1; 24 | authenticated = if (dep?authenticated) then dep.authenticated else false; 25 | 26 | fetch = if authenticated then (requireFile { 27 | inherit sha1; 28 | url = "${elemAt remoteList 0}/${path}"; 29 | }) else (fetchurl { 30 | inherit sha1; 31 | urls = map (r: "${r}/${path}") remoteList; 32 | }); 33 | in '' 34 | mkdir -p "$(dirname ${path})" 35 | ln -sfv "${fetch}" "${path}" 36 | ''; 37 | 38 | metadataToScript = remote: meta: 39 | let 40 | inherit (meta) path content; 41 | name = "maven-metadata-${remote}.xml"; 42 | in '' 43 | mkdir -p "${path}" 44 | ( cd "${path}" 45 | ln -sfv "${writeText "maven-metadata.xml" content}" "${name}" 46 | linkSnapshot "${name}" ) 47 | ''; 48 | 49 | drvToScript = drv: '' 50 | echo >&2 === building mavenix drvs: ${drv.name} === 51 | props="${drv}/share/java/*.properties" 52 | for prop in $props; do getMavenPathFromProperties $prop; done 53 | ''; 54 | 55 | transInfo = map (drv: importJSON "${drv}/share/mavenix/mavenix.lock"); 56 | 57 | transDeps = tinfo: concatLists (map (info: info.deps) tinfo); 58 | transMetas = tinfo: concatLists (map (info: info.metas) tinfo); 59 | transRemotes = foldl' (acc: info: acc // info.remotes) {}; 60 | 61 | mkRepo = { 62 | deps ? [], 63 | metas ? [], 64 | remotes ? {}, 65 | drvs ? [], 66 | drvsInfo ? [], 67 | postHook ? "", 68 | }: let 69 | deps' = deps ++ (transDeps drvsInfo); 70 | metas' = metas ++ (transMetas drvsInfo); 71 | remotes' = (transRemotes drvsInfo) // remotes; 72 | remoteList = attrValues remotes'; 73 | in runCommand "mk-repo" {} '' 74 | set -e 75 | 76 | getMavenPath() { 77 | local version=$(sed -n 's|^version=||p' "$1") 78 | local groupId=$(sed -n 's|^groupId=||p' "$1") 79 | local artifactId=$(sed -n 's|^artifactId=||p' "$1") 80 | echo "''${groupId//.//}/$artifactId/$version/$artifactId-$version" 81 | } 82 | 83 | linkSnapshot() { 84 | [ "$(${yq}/bin/xq '.metadata.versioning.snapshotVersions' "$1")" == "null" ] \ 85 | && return 86 | ${yq}/bin/xq -r ' 87 | .metadata as $o 88 | | [.metadata.versioning.snapshotVersions.snapshotVersion] | flatten | .[] 89 | | ((if .classifier? then ("-" + .classifier) else "" end) + "." + .extension) as $e 90 | | $o.artifactId + "-" + .value + $e + " " + $o.artifactId + "-" + $o.version + $e 91 | ' "$1" | xargs -L1 ln -sfv 92 | } 93 | 94 | getMavenPathFromProperties() { 95 | local path="$(getMavenPath "$1")" 96 | local bpath="$(dirname $path)" 97 | local basefilename="''${1%%.properties}" 98 | 99 | if test "$bpath"; then 100 | mkdir -p "$bpath" 101 | for fn in $basefilename-* $basefilename.{pom,jar}; do 102 | test ! -f $fn || ln -sfv "$fn" "$bpath" 103 | done 104 | ln -sfv "$basefilename.metadata.xml" "$bpath/maven-metadata-local.xml" 105 | fi 106 | } 107 | 108 | mkdir -p "$out" 109 | (cd $out 110 | ${concatStrings (map (urlToScript remoteList) deps')} 111 | ${concatStrings (mapmap 112 | (map metadataToScript (attrNames remotes')) metas')} 113 | ${concatStrings (map drvToScript drvs)} 114 | ) 115 | 116 | ${postHook} 117 | ''; 118 | 119 | cp-artifact = submod: '' 120 | find . -type f \ 121 | -regex "${submod.path}/target/[^/]*\.\(jar\|war\)$" ! -name "*-sources.jar" \ 122 | -exec cp -v {} $dir \; 123 | ''; 124 | 125 | cp-pom = submod: '' 126 | cp -v ${submod.path}/pom.xml $dir/${submod.name}.pom 127 | ''; 128 | 129 | mk-properties = submod: '' 130 | echo 'groupId=${submod.groupId} 131 | artifactId=${submod.artifactId} 132 | version=${submod.version} 133 | ' > $dir/${submod.name}.properties 134 | ''; 135 | 136 | mk-maven-metadata = submod: '' 137 | echo ' 138 | ${submod.groupId} 139 | ${submod.artifactId} 140 | ${submod.version} 141 | 142 | ' > $dir/${submod.name}.metadata.xml 143 | ''; 144 | 145 | overrideOverrideAttrs = f: attrs: (f attrs) // { 146 | overrideAttrs = f_: overrideOverrideAttrs f (attrs // (f_ attrs)); 147 | }; 148 | 149 | buildMaven = overrideOverrideAttrs ({ 150 | src, 151 | infoFile, 152 | deps ? [], 153 | drvs ? [], 154 | settings ? settings', 155 | maven ? maven', 156 | 157 | nativeBuildInputs ? [], 158 | passthru ? {}, 159 | 160 | remotes ? {}, 161 | 162 | postMkRepoHook ? "", 163 | 164 | doCheck ? true, 165 | debug ? false, 166 | build ? true, 167 | ... 168 | }@config: 169 | let 170 | dummy-info = { name = "update"; deps = []; metas = []; }; 171 | 172 | info = if (build && pathExists infoFile) then importJSON infoFile else dummy-info; 173 | remotes' = (optionalAttrs (info?remotes) info.remotes) // remotes; 174 | drvsInfo = transInfo drvs; 175 | 176 | emptyRepo = mkRepo { 177 | inherit drvs drvsInfo; 178 | remotes = remotes'; 179 | }; 180 | 181 | repo = mkRepo { 182 | inherit (info) deps metas; 183 | inherit drvs drvsInfo; 184 | remotes = remotes'; 185 | postHook = postMkRepoHook; 186 | }; 187 | 188 | # Wrap mvn with settings to improve the nix-shell experience 189 | maven' = runCommand "mvn" { 190 | nativeBuildInputs = [ makeWrapper ]; 191 | } '' 192 | mkdir -p $out/bin 193 | makeWrapper ${maven}/bin/mvn $out/bin/mvn --add-flags "--settings ${settings}" 194 | ''; 195 | 196 | mvn = "${maven'}/bin/mvn --offline --batch-mode -Dmaven.repo.local=${repo} -nsu "; 197 | 198 | in 199 | stdenv.mkDerivation ({ 200 | name = info.name; 201 | 202 | nativeBuildInputs = nativeBuildInputs ++ [ 203 | maven' maven.jdk 204 | (pkgs.ensureNewerSourcesHook { year = "1980"; }) 205 | ]; 206 | 207 | # Export as environment variable to make it possible to reuse default flags in other phases/hooks 208 | inherit mvn; 209 | 210 | postPhases = [ "mavenixDistPhase" ]; 211 | 212 | checkPhase = optionalString build '' 213 | runHook preCheck 214 | 215 | $mvn test 216 | 217 | runHook postCheck 218 | ''; 219 | 220 | buildPhase = optionalString build '' 221 | runHook preBuild 222 | 223 | $mvn --version 224 | $mvn package -DskipTests=true -Dmaven.test.skip.exec=true 225 | 226 | runHook postBuild 227 | ''; 228 | 229 | installPhase = optionalString build '' 230 | runHook preInstall 231 | 232 | dir="$out/share/java" 233 | mkdir -p $dir 234 | 235 | ${optionalString (info?submodules) (concatStrings (mapmap 236 | [ cp-artifact cp-pom mk-properties mk-maven-metadata ] 237 | info.submodules 238 | ))} 239 | 240 | runHook postInstall 241 | ''; 242 | 243 | mavenixDistPhase = optionalString build '' 244 | mkdir -p $out/share/mavenix 245 | echo copying lock file 246 | cp -v ${infoFile} $out/share/mavenix/mavenix.lock 247 | ''; 248 | 249 | passthru = passthru // { 250 | mavenixMeta = { 251 | inherit deps emptyRepo settings; 252 | infoFile = toString infoFile; 253 | srcPath = toString src; 254 | }; 255 | }; 256 | } // ( 257 | removeAttrs config [ 258 | "deps" "drvs" "remotes" "infoFile" 259 | "nativeBuildInputs" "passthru" 260 | ] 261 | )) 262 | ); 263 | in rec { 264 | version = "2.3.3"; 265 | name = "mavenix-${version}"; 266 | updateInfo = f: infoFile: 267 | writeText "updated-lock" ( 268 | toJSON ((x: x // f x) (importJSON infoFile)) 269 | ); 270 | inherit buildMaven pkgs; 271 | } 272 | -------------------------------------------------------------------------------- /mvnix-init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | usage() { 5 | # shellcheck disable=SC2015 6 | test "$1" && echo -e Error: "$1"\\n || true 7 | cat >&2 <] 9 | 10 | Options: 11 | -S, --src A Nix expression to use as 'src' for derivation 12 | -o, --output Output directory for generated files 13 | -s, --standalone Include 'mavenix.nix' file 14 | -f, --force Overwrite output file if exists 15 | -v, --verbose Verbose output 16 | -h, --help Print usage 17 | 18 | Version: $MAVENIX_VERSION 19 | EOF 20 | exit 1 21 | } 22 | 23 | tmpl() { sed "s|%%$1%%|$2|g"; } 24 | 25 | # Default values 26 | outputDir="." 27 | 28 | # Parse CLI arguments 29 | while test "$1";do 30 | case "$1" in 31 | -S|--src) shift;srcExpr="($1)";; 32 | -o|--output) shift;outputDir="$1";; 33 | -s|--standalone) standalone=1;; 34 | -f|--force) forceOverwrite=1;; 35 | -v|--verbose) set -x;; 36 | -h|--help) usage;; 37 | -*) usage "no option \"$1\"";; 38 | *) config="$1";; 39 | esac 40 | shift 41 | done 42 | 43 | mkdir -p "$outputDir" 44 | config="${config-$outputDir/default.nix}" 45 | [[ -n "$forceOverwrite" || ! -e "$config" ]] || usage "\"$config\" already exists" 46 | 47 | srcExpr="${srcExpr-./$(realpath --relative-to="$(dirname "$config")" ".")}" 48 | 49 | copy() { cp "$1" "$2"; echo "$2"; } 50 | echo >&2 " 51 | Creating files: 52 | " 53 | 54 | if test "$standalone"; then 55 | relEnv="./$(realpath --relative-to="$(dirname "$config")" "$outputDir/mavenix.nix")" 56 | copy "$MAVENIX_SCRIPT" "$outputDir/mavenix.nix" 57 | chmod u+w "$outputDir/mavenix.nix" 58 | else 59 | relEnv="fetchTarball { url = \"$MAVENIX_DOWNLOAD\"; sha256 = \"$(nix-prefetch-url "$MAVENIX_DOWNLOAD" --unpack 2>&-)\"; }" 60 | fi 61 | 62 | # shellcheck disable=SC2002 63 | cat "$CONFIG_TEMPLATE" \ 64 | | tmpl src "$srcExpr" \ 65 | | tmpl env "$relEnv" \ 66 | > "$config" 67 | echo "$config" 68 | 69 | echo >&2 " 70 | 1. Configure by editing '$config' 71 | 2. Create a lock file by running 'mvnix-update \"$config\"' 72 | 3. Build your project 'nix-build \"$config\"' 73 | " 74 | -------------------------------------------------------------------------------- /mvnix-update: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | usage() { 5 | # shellcheck disable=SC2015 6 | test "$1" && echo -e Error: "$1"\\n || true 7 | cat >&2 <] 9 | 10 | Options: 11 | -E, --exp Pass in a Nix expression that represents the 12 | derivation to be updated. 13 | -s, --save-repo Specify path to save maven repo to. This will 14 | speed up consecutive runs, but might affect 15 | lock file if POM is changed in between. 16 | -n, --no-add Don't add dependencies to nix store 17 | -v, --verbose Verbose output 18 | -h, --help Print usage 19 | 20 | Version: $MAVENIX_VERSION 21 | EOF 22 | exit 1 23 | } 24 | 25 | # Setup work dir and cleanup 26 | WORK_DIR=$(mktemp -d --tmpdir mvnix-update.XXXXXX) 27 | cleanup() { { chmod -R +w "$WORK_DIR"; rm -rf "$WORK_DIR"; } || true; } 28 | trap 'trap - EXIT; cleanup; kill -- $$' EXIT 29 | 30 | # Default values 31 | tmp_repo="$WORK_DIR/m2-repo" 32 | 33 | # Parse CLI arguments 34 | while test "$1";do 35 | case "$1" in 36 | -E|--exp) shift;expression="$1";; 37 | -s|--save-repo) shift;tmp_repo="$1";; 38 | -n|--no-add) no_add=1;; 39 | -v|--verbose) verbose=1;set -x;; 40 | -h|--help) usage;; 41 | -*) usage "no option \"$1\"";; 42 | *) config="$1";; 43 | esac 44 | shift 45 | done 46 | 47 | die() { echo >&2 "$@"; exit 1;} 48 | 49 | nix_flags=$(test "$verbose" && printf %s "--verbose" || true) 50 | 51 | if [[ "$expression" && "$config" ]]; then 52 | die "Expression and file arguments are mutually exclusive" 53 | elif [[ "$config" ]]; then 54 | expression="import \"$(realpath "$config")\" {}" 55 | elif [[ ! "$expression" ]]; then 56 | expression="import ./. {}" 57 | fi 58 | 59 | tmp_repo=$(realpath "$tmp_repo") 60 | mkdir -p "$tmp_repo" 61 | 62 | ns_() { 63 | local ns_wd="$1";shift 64 | HOME="/tmp/nowhere" nix-shell $nix_flags --show-trace --pure \ 65 | --run "cd \"$ns_wd\"; $*" -E "($expression).overrideAttrs (_: { build = false; })"; 66 | } 67 | 68 | echo >&2 " 69 | Getting mavenix meta data... 70 | " 71 | 72 | realiseStorePath() { 73 | # Check if $1 is a store path (similar to lib.isStorePath) and realize only 74 | # if it is. 75 | if [[ $1 =~ ^/nix/store/ ]]; then 76 | nix-store --realise "$1" >/dev/null 77 | fi 78 | } 79 | mavenixMeta=$(nix-instantiate $nix_flags --eval --strict --json -E "($expression).mavenixMeta" | jq -rc .) 80 | mq() { jq -rc "$1" <<<"$mavenixMeta"; } 81 | 82 | test "$mavenixMeta" || die "Nix expression is not a mavenix derivation" 83 | 84 | nix-build --no-out-link -E "{ inherit (($expression).mavenixMeta) emptyRepo settings infoFile; }" 85 | 86 | src_path=$(mq .srcPath) 87 | realiseStorePath "$src_path" 88 | 89 | settings=$(mq .settings) 90 | empty_repo=$(mq .emptyRepo) 91 | 92 | if test -d "$empty_repo"; then 93 | cp -rf -t "$tmp_repo" "$empty_repo"/* >/dev/null 2>&1 || true 94 | chmod -R u+w "$tmp_repo" || true 95 | fi 96 | 97 | src_wd="$src_path" 98 | if test ! -w "$src_wd"; then 99 | src_wd="$WORK_DIR/src" 100 | cp -r "$src_path" "$src_wd" 101 | chmod -R u+w "$src_wd" || true #echo >&2 Failed to set chmod on temp repo dir. 102 | fi 103 | 104 | # shellcheck disable=SC2015 105 | mvn_flags=$(test "$verbose" && printf %s "-e -X" || true) 106 | # shellcheck disable=SC2086 107 | mvn_() { ns_ "$src_wd" mvn $mvn_flags -B -nsu --settings "$settings" "$@"; } 108 | mvn_out() { ns_ "$src_wd" mvn -B -nsu --settings "$settings" "$@"; } 109 | 110 | echo >&2 " 111 | Running mvn package... 112 | " 113 | mvn_ >&2 install -Dmaven.test.skip.exec=true -DskipTests -Dmaven.repo.local="$tmp_repo" 114 | 115 | echo >&2 " 116 | Getting project info... 117 | " 118 | pom=$(mvn_out help:effective-pom | grep -v '^\[\|^Effective \|^$' | xq -c .) 119 | projects=$(jq -c '.projects.project // [.project]' <<<"$pom") 120 | pq() { jq -rc "$1" <<<"$projects"; } 121 | export -f pq 122 | 123 | groupId=$(pq .[0].groupId) 124 | artifactId=$(pq .[0].artifactId) 125 | version=$(pq .[0].version) 126 | 127 | modules=$(pq ' 128 | [ .[] 129 | | { 130 | name: (.artifactId + "-" + .version), 131 | groupId, artifactId, version, 132 | path: (.build.directory | sub("^'"$src_wd"'/"; "./") | sub("/target"; "")) 133 | } 134 | ] 135 | ') 136 | 137 | remotes_repos=$(pq ' 138 | [ [.[].repositories.repository, .[].pluginRepositories.pluginRepository] 139 | | flatten | .[] 140 | | {(.id):.url} 141 | ] | add 142 | ') 143 | 144 | tmp_lock_file="$WORK_DIR/tmp-mavenix.lock" 145 | lock_file="$(mq .infoFile)" 146 | 147 | echo >&2 " 148 | Resolving maven dependencies... 149 | " 150 | mvn_ >&2 dependency:go-offline -Dmaven.repo.local="$tmp_repo" 151 | 152 | echo >&2 " 153 | Creating lock file... 154 | " 155 | ( 156 | echo -n "{ 157 | \"name\": \"$artifactId-$version\", 158 | \"groupId\": \"$groupId\", 159 | \"artifactId\": \"$artifactId\", 160 | \"version\": \"$version\", 161 | \"submodules\": $modules, 162 | \"deps\": [ $(mq .deps[] | sed 's/\(.\)$/\1,/')" 163 | ( cd "$tmp_repo" 164 | remotes=$(find . -type f -name "*.repositories" | sed 's|^\./||' | sort) 165 | sep="" 166 | for remote in $remotes; do 167 | dir=$(dirname "$remote") 168 | files=$(find "$dir" -type f ! -name "*.repositories" ! -name "*.sha1" \ 169 | | grep -v '^#' "$remote" | sed "s|^|$dir/|" | sort) 170 | for file_ in $files; do 171 | file=$(echo "$file_" | cut -d '>' -f1) 172 | # Maven 3.0.5 for 3.3.9 use $file instead of $file_real 173 | # shellcheck disable=SC2116,SC2086 174 | file_real=$(echo ${file//-SNAPSHOT./-[0-9]*.}) 175 | repo=$(echo "$file_" | cut -d '>' -f2 | sed 's/=$//') 176 | test "$repo" || continue 177 | echo -n "$sep 178 | {\"path\":\"$file_real\",\"sha1\":\"$(grep -Eo '[0-9a-zA-Z]{40}' < "$file_real.sha1")\"}" 179 | sep="," 180 | 181 | test "$no_add" || nix-store --add-fixed sha1 "$file_real" >&2 182 | done 183 | done 184 | 185 | echo -n " 186 | ], 187 | \"metas\": [" 188 | metafiles=$(find . -type f -name "maven-metadata-*.xml" | sed 's|^\./||' | sort) 189 | sep="" 190 | for file in $metafiles; do 191 | repo=$(basename "$file" | sed 's/^maven-metadata-//;s/\.xml$//') 192 | [[ "$repo" && "$repo" != "local" ]] || continue 193 | echo -n "$sep{ 194 | \"path\": \"$(dirname "$file")\", 195 | \"content\": \"$(sed ':a;N;$!ba;s/\n/\\n/g;s/\"/\\\"/g' "$file")\" 196 | }" 197 | sep=", " 198 | done 199 | ) 200 | echo -n " 201 | ], 202 | \"remotes\": $remotes_repos 203 | } 204 | " 205 | ) > "$tmp_lock_file" 206 | 207 | 208 | echo >&2 " 209 | Sanity check... 210 | " 211 | jq -c . "$tmp_lock_file" > /dev/null 212 | jq -S . "$tmp_lock_file" > "$lock_file" 213 | 214 | echo >&2 " 215 | Lock file created at: $lock_file 216 | " 217 | -------------------------------------------------------------------------------- /overlay.nix: -------------------------------------------------------------------------------- 1 | final: prev: 2 | let 3 | mavenix = import ./. {}; 4 | in { 5 | inherit mavenix; 6 | mavenix-cli = mavenix.cli; 7 | } 8 | -------------------------------------------------------------------------------- /release.nix: -------------------------------------------------------------------------------- 1 | { 2 | mavenixSrc ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; } 3 | }: 4 | 5 | { 6 | build = { system ? builtins.currentSystem }: 7 | let 8 | pkgs = import { inherit system; }; 9 | in 10 | import mavenixSrc.outPath { inherit pkgs; }; 11 | } 12 | --------------------------------------------------------------------------------