Skip to content

Commit b9ed7d5

Browse files
DerGuteMoritzwhentze
authored andcommitted
Add :deps/prep-lib support for git dependencies
Source dependencies may require a "prep" step e.g. to compile Java source[1]. This patch adds support for this but only for git dependencies since that's the only dependency type which implements this at the moment anyway[2]. This is achieved by extracing the necessary info from `deps.edn` to the lockfile. A second pass over the constructed Clojure home derived from the lockfile then picks out all the git libs which need prepping, runs the respective command for them and finally constructs a new home with the prepped libs. 1: See https://clojure.org/guides/deps_and_cli#prep_libs 2: Technically, :local/root dependencies also implement it but `clojure-nix-locker` doesn't have to handle these.
1 parent a5e03fb commit b9ed7d5

File tree

4 files changed

+95
-44
lines changed

4 files changed

+95
-44
lines changed

createHome.nix

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ let
2222
};
2323
};
2424

25-
handleGit = path: { url, rev, sha256, common_dir }: {
25+
handleGit = path: { url, rev, sha256, common_dir, ... }: {
2626
name = path;
2727
path = pkgs.fetchgit {
2828
inherit url rev sha256;
@@ -32,8 +32,10 @@ let
3232
# Corresponds to the ~/.m2/repository directory
3333
mavenRepoCache = pkgs.linkFarm "maven-repo-cache" (lib.mapAttrsToList fetchMaven contents.maven);
3434

35+
unpreppedGitWorkTrees = lib.mapAttrsToList handleGit contents.git;
36+
3537
# This corresponds to the ~/.gitlibs/libs directory, containing git worktrees
36-
gitWorktreeCache = pkgs.linkFarm "git-worktree-cache" (lib.mapAttrsToList handleGit contents.git);
38+
gitWorktreeCache = gitWorkTrees: pkgs.linkFarm "git-worktree-cache" gitWorkTrees;
3739

3840
# This corresponds to the ~/.gitlibs/_repos directory, containing git directories for the above worktrees
3941
gitFakeRepoCache = pkgs.runCommandNoCC "git-fake-repo-cache" {}
@@ -56,24 +58,53 @@ let
5658
echo '{}' > $out/tools/tools.edn
5759
'';
5860

59-
# Creates the final home directory, combining all parts together
60-
result = pkgs.linkFarm "clojure-home" [
61-
{
62-
name = ".m2/repository";
63-
path = mavenRepoCache;
64-
}
65-
{
66-
name = ".gitlibs/libs";
67-
path = gitWorktreeCache;
68-
}
69-
{
70-
name = ".gitlibs/_repos";
71-
path = gitFakeRepoCache;
72-
}
61+
# Creates a home directory for Clojure, combining all parts together
62+
clojureHome = gitWorkTrees:
63+
pkgs.linkFarm "clojure-home" [
64+
{
65+
name = ".m2/repository";
66+
path = mavenRepoCache;
67+
}
68+
{
69+
name = ".gitlibs/libs";
70+
path = gitWorktreeCache gitWorkTrees;
71+
}
72+
{
73+
name = ".gitlibs/_repos";
74+
path = gitFakeRepoCache;
75+
}
76+
{
77+
name = ".clojure";
78+
path = configDir;
79+
}
80+
];
81+
82+
unpreppedHome = clojureHome unpreppedGitWorkTrees;
83+
84+
utils = import ./utils.nix { inherit pkgs; };
85+
86+
prepLib = { path, name }: spec:
87+
if spec ? prep then
88+
let prep = spec.prep; in
89+
pkgs.runCommand "${name}-prepped"
90+
{ nativeBuildInputs = [ (utils.wrapClojure unpreppedHome pkgs.clojure) ]; }
91+
''
92+
cp -r ${path} $out
93+
chmod -R +w $out
94+
cd $out
95+
clojure -X:${prep.alias} ${prep.fn}
96+
''
97+
else
98+
path;
99+
100+
prepGitWorkTree = { name, ... }@wt:
73101
{
74-
name = ".clojure";
75-
path = configDir;
76-
}
77-
];
102+
inherit name;
103+
path = prepLib wt (lib.getAttr name contents.git);
104+
};
105+
106+
preppedGitWorkTrees = builtins.map prepGitWorkTree unpreppedGitWorkTrees;
107+
108+
preppedHome = clojureHome preppedGitWorkTrees;
78109

79-
in result
110+
in preppedHome

default.nix

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ let
88
# We don't care about lines being too long
99
flakeIgnore = [ "E501" ];
1010
} ./locker.py;
11+
12+
utils = import ./utils.nix { inherit pkgs; };
1113
in {
1214
inherit standaloneLocker;
1315

@@ -28,6 +30,7 @@ in {
2830
commandLocker = command: pkgs.writeShellApplication {
2931
name = "clojure-nix-locker";
3032
runtimeInputs = [
33+
pkgs.babashka
3134
pkgs.coreutils
3235
pkgs.git
3336
pkgs.gnutar
@@ -70,26 +73,7 @@ in {
7073
homeDirectory = import ./createHome.nix {
7174
inherit pkgs src lockfile mavenRepos;
7275
};
73-
shellEnv = pkgs.writeTextFile {
74-
name = "clojure-nix-locker.shell-env";
75-
text = ''
76-
export HOME="${homeDirectory}"
77-
export JAVA_TOOL_OPTIONS="-Duser.home=${homeDirectory}"
78-
'';
79-
meta = {
80-
description = ''
81-
Can be sourced in shell scripts to export environment
82-
variables so that `clojure` uses the locked dependencies.
83-
'';
84-
};
85-
};
86-
wrapClojure = clojure:
87-
(pkgs.runCommandNoCC "locked-clojure" { buildInputs = [ pkgs.makeWrapper ]; } ''
88-
mkdir -p $out/bin
89-
makeWrapper ${clojure}/bin/clojure $out/bin/clojure \
90-
--run "source ${shellEnv}"
91-
makeWrapper ${clojure}/bin/clj $out/bin/clj \
92-
--run "source ${shellEnv}"
93-
'');
94-
};
76+
shellEnv = utils.shellEnv homeDirectory;
77+
wrapClojure = utils.wrapClojure homeDirectory;
78+
};
9579
}

locker.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,31 @@
2929

3030
gitlibsDir = args.home.joinpath('.gitlibs').resolve()
3131

32+
extractPrepLibInfo = '''
33+
(some-> *input*
34+
:deps/prep-lib
35+
(select-keys [:alias :fn])
36+
cheshire.core/generate-string
37+
println)
38+
'''
39+
3240
if gitlibsDir.exists():
3341
for namespace_path in gitlibsDir.joinpath('libs').iterdir():
3442
for name_path in namespace_path.iterdir():
3543
for rev_path in name_path.iterdir():
3644
path = rev_path.relative_to(gitlibsDir, "libs").as_posix()
3745
repo = Repo(rev_path)
3846
prefetch = subprocess.run(["nix-prefetch-git", rev_path], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=True)
39-
47+
with open(rev_path / "deps.edn") as deps_edn:
48+
prep = subprocess.run(["bb", "-I", "--stream", extractPrepLibInfo], stdin=deps_edn, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=True)
4049
result['git'][path] = {
4150
# This is the path to the corresponding bare repository in ~/.gitlibs/_repos
4251
"common_dir": Path(repo.common_dir).resolve().relative_to(gitlibsDir, "_repos").as_posix(),
4352
"url": repo.remotes.origin.url,
4453
"rev": repo.head.commit.hexsha,
4554
"sha256": json.loads(prefetch.stdout)['sha256'],
4655
}
56+
if preps := prep.stdout:
57+
result['git'][path]['prep'] = json.loads(preps)
4758

4859
print(json.dumps(result, indent=2, sort_keys=True))

utils.nix

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{ pkgs }:
2+
3+
rec {
4+
shellEnv = homeDirectory: pkgs.writeTextFile {
5+
name = "clojure-nix-locker.shell-env";
6+
text = ''
7+
export HOME="${homeDirectory}"
8+
export JAVA_TOOL_OPTIONS="-Duser.home=${homeDirectory}"
9+
'';
10+
meta = {
11+
description = ''
12+
Can be sourced in shell scripts to export environment
13+
variables so that `clojure` uses the locked dependencies.
14+
'';
15+
};
16+
};
17+
wrapClojure = homeDirectory: clojure:
18+
(pkgs.runCommandNoCC "locked-clojure" { buildInputs = [ pkgs.makeWrapper ]; } ''
19+
mkdir -p $out/bin
20+
makeWrapper ${clojure}/bin/clojure $out/bin/clojure \
21+
--run "source ${shellEnv homeDirectory}"
22+
makeWrapper ${clojure}/bin/clj $out/bin/clj \
23+
--run "source ${shellEnv homeDirectory}"
24+
'');
25+
}

0 commit comments

Comments
 (0)