Skip to content

Commit 71ea484

Browse files
committed
devenv: support containers on macos
1 parent f354b02 commit 71ea484

File tree

4 files changed

+180
-131
lines changed

4 files changed

+180
-131
lines changed

devenv/build.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
fn main() {
2+
println!(
3+
"cargo:rustc-env=TARGET_ARCH={}",
4+
std::env::var("CARGO_CFG_TARGET_ARCH").unwrap()
5+
);
6+
println!(
7+
"cargo:rustc-env=TARGET_OS={}",
8+
std::env::var("CARGO_CFG_TARGET_OS").unwrap()
9+
);
10+
}

devenv/src/devenv.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -474,10 +474,23 @@ impl Devenv {
474474
let gc_root = self
475475
.devenv_dot_gc
476476
.join(format!("container-{sanitized_name}-derivation"));
477+
let host_arch = env!("TARGET_ARCH");
478+
let host_os = env!("TARGET_OS");
479+
let target_system = if host_os == "macos" {
480+
match host_arch {
481+
"aarch64" => "aarch64-linux",
482+
"x86_64" => "x86_64-linux",
483+
_ => bail!("Unsupported container architecture for macOS: {host_arch}"),
484+
}
485+
} else {
486+
&self.global_options.system
487+
};
477488
let paths = self
478489
.nix
479490
.build(
480-
&[&format!("devenv.containers.{name}.derivation")],
491+
&[&format!(
492+
"devenv.perSystem.{target_system}.config.containers.{name}.derivation"
493+
)],
481494
None,
482495
Some(&gc_root),
483496
)
@@ -503,7 +516,7 @@ impl Devenv {
503516
let paths = self
504517
.nix
505518
.build(
506-
&[&format!("devenv.containers.{name}.copyScript")],
519+
&[&format!("devenv.config.containers.{name}.copyScript")],
507520
None,
508521
Some(&gc_root),
509522
)
@@ -558,7 +571,7 @@ impl Devenv {
558571
let paths = self
559572
.nix
560573
.build(
561-
&[&format!("devenv.containers.{name}.dockerRun")],
574+
&[&format!("devenv.config.containers.{name}.dockerRun")],
562575
None,
563576
Some(&gc_root),
564577
)
@@ -716,7 +729,7 @@ impl Devenv {
716729
let value = self
717730
.has_processes
718731
.get_or_try_init(|| async {
719-
let processes = self.nix.eval(&["devenv.processes"]).await?;
732+
let processes = self.nix.eval(&["devenv.config.processes"]).await?;
720733
Ok::<bool, miette::Report>(processes.trim() != "{}")
721734
})
722735
.await?;
@@ -728,7 +741,7 @@ impl Devenv {
728741
let span = info_span!("load_tasks", devenv.user_message = "Evaluating tasks");
729742
let gc_root = self.devenv_dot_gc.join("task-config");
730743
self.nix
731-
.build(&["devenv.task.config"], None, Some(&gc_root))
744+
.build(&["devenv.config.task.config"], None, Some(&gc_root))
732745
.instrument(span)
733746
.await?
734747
};
@@ -894,7 +907,7 @@ impl Devenv {
894907
let gc_root = self.devenv_dot_gc.join("test");
895908
let test_script = self
896909
.nix
897-
.build(&["devenv.test"], None, Some(&gc_root))
910+
.build(&["devenv.config.test"], None, Some(&gc_root))
898911
.instrument(span)
899912
.await?;
900913
test_script[0].to_string_lossy().to_string()
@@ -969,7 +982,7 @@ impl Devenv {
969982
flatten_object(&format!("{}.{}", prefix, k), v)
970983
})
971984
.collect(),
972-
_ => vec![format!("devenv.{}", prefix)],
985+
_ => vec![format!("devenv.config.{}", prefix)],
973986
}
974987
}
975988
flatten_object(key, value)
@@ -978,7 +991,7 @@ impl Devenv {
978991
} else {
979992
attributes
980993
.iter()
981-
.map(|attr| format!("devenv.{}", attr))
994+
.map(|attr| format!("devenv.config.{}", attr))
982995
.collect()
983996
};
984997
let paths = self

devenv/src/flake.tmpl.nix

Lines changed: 148 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -19,136 +19,162 @@
1919
if builtins.pathExists (devenv_dotfile_path + "/devenv.json")
2020
then builtins.fromJSON (builtins.readFile (devenv_dotfile_path + "/devenv.json"))
2121
else { };
22-
getOverlays = inputName: inputAttrs:
23-
map
24-
(overlay:
25-
let
26-
input = inputs.${inputName} or (throw "No such input `${inputName}` while trying to configure overlays.");
27-
in
28-
input.overlays.${overlay} or (throw "Input `${inputName}` has no overlay called `${overlay}`. Supported overlays: ${nixpkgs.lib.concatStringsSep ", " (builtins.attrNames input.overlays)}"))
29-
inputAttrs.overlays or [ ];
30-
overlays = nixpkgs.lib.flatten (nixpkgs.lib.mapAttrsToList getOverlays (devenv.inputs or { }));
31-
permittedUnfreePackages = devenv.nixpkgs.per-platform."${system}".permittedUnfreePackages or devenv.nixpkgs.permittedUnfreePackages or [ ];
32-
pkgs = import nixpkgs {
33-
inherit overlays system;
34-
config = {
35-
allowUnfree = devenv.nixpkgs.per-platform."${system}".allowUnfree or devenv.nixpkgs.allowUnfree or devenv.allowUnfree or false;
36-
allowBroken = devenv.nixpkgs.per-platform."${system}".allowBroken or devenv.nixpkgs.allowBroken or devenv.allowBroken or false;
37-
cudaSupport = devenv.nixpkgs.per-platform."${system}".cudaSupport or devenv.nixpkgs.cudaSupport or false;
38-
cudaCapabilities = devenv.nixpkgs.per-platform."${system}".cudaCapabilities or devenv.nixpkgs.cudaCapabilities or [ ];
39-
permittedInsecurePackages = devenv.nixpkgs.per-platform."${system}".permittedInsecurePackages or devenv.nixpkgs.permittedInsecurePackages or devenv.permittedInsecurePackages or [ ];
40-
allowUnfreePredicate = if (permittedUnfreePackages != [ ]) then (pkg: builtins.elem (nixpkgs.lib.getName pkg) permittedUnfreePackages) else (_: false);
41-
};
42-
};
43-
lib = pkgs.lib;
44-
importModule = path:
45-
if lib.hasPrefix "./" path
46-
then if lib.hasSuffix ".nix" path
47-
then ./. + (builtins.substring 1 255 path)
48-
else ./. + (builtins.substring 1 255 path) + "/devenv.nix"
49-
else if lib.hasPrefix "../" path
50-
then throw "devenv: ../ is not supported for imports"
51-
else
52-
let
53-
paths = lib.splitString "/" path;
54-
name = builtins.head paths;
55-
input = inputs.${name} or (throw "Unknown input ${name}");
56-
subpath = "/${lib.concatStringsSep "/" (builtins.tail paths)}";
57-
devenvpath = "${input}" + subpath;
58-
devenvdefaultpath = devenvpath + "/devenv.nix";
59-
in
60-
if lib.hasSuffix ".nix" devenvpath
61-
then devenvpath
62-
else if builtins.pathExists devenvdefaultpath
63-
then devenvdefaultpath
64-
else throw (devenvdefaultpath + " file does not exist for input ${name}.");
65-
project = pkgs.lib.evalModules {
66-
specialArgs = inputs // { inherit inputs; };
67-
modules = [
68-
({ config, ... }: {
69-
_module.args.pkgs = pkgs.appendOverlays (config.overlays or [ ]);
70-
})
71-
(inputs.devenv.modules + /top-level.nix)
72-
{
73-
devenv.cliVersion = version;
74-
devenv.root = devenv_root;
75-
devenv.dotfile = devenv_dotfile;
76-
}
77-
({ options, ... }: {
78-
config.devenv = lib.mkMerge [
79-
(pkgs.lib.optionalAttrs (builtins.hasAttr "tmpdir" options.devenv) {
80-
tmpdir = devenv_tmpdir;
81-
})
82-
(pkgs.lib.optionalAttrs (builtins.hasAttr "isTesting" options.devenv) {
83-
isTesting = devenv_istesting;
22+
23+
systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
24+
25+
# Function to create devenv configuration for a specific system
26+
mkDevenvForSystem = targetSystem:
27+
let
28+
getOverlays = inputName: inputAttrs:
29+
map
30+
(overlay:
31+
let
32+
input = inputs.${inputName} or (throw "No such input `${inputName}` while trying to configure overlays.");
33+
in
34+
input.overlays.${overlay} or (throw "Input `${inputName}` has no overlay called `${overlay}`. Supported overlays: ${nixpkgs.lib.concatStringsSep ", " (builtins.attrNames input.overlays)}"))
35+
inputAttrs.overlays or [ ];
36+
overlays = nixpkgs.lib.flatten (nixpkgs.lib.mapAttrsToList getOverlays (devenv.inputs or { }));
37+
permittedUnfreePackages = devenv.nixpkgs.per-platform."${targetSystem}".permittedUnfreePackages or devenv.nixpkgs.permittedUnfreePackages or [ ];
38+
pkgs = import nixpkgs {
39+
system = targetSystem;
40+
config = {
41+
allowUnfree = devenv.nixpkgs.per-platform."${targetSystem}".allowUnfree or devenv.nixpkgs.allowUnfree or devenv.allowUnfree or false;
42+
allowBroken = devenv.nixpkgs.per-platform."${targetSystem}".allowBroken or devenv.nixpkgs.allowBroken or devenv.allowBroken or false;
43+
cudaSupport = devenv.nixpkgs.per-platform."${targetSystem}".cudaSupport or devenv.nixpkgs.cudaSupport or false;
44+
cudaCapabilities = devenv.nixpkgs.per-platform."${targetSystem}".cudaCapabilities or devenv.nixpkgs.cudaCapabilities or [ ];
45+
permittedInsecurePackages = devenv.nixpkgs.per-platform."${targetSystem}".permittedInsecurePackages or devenv.nixpkgs.permittedInsecurePackages or devenv.permittedInsecurePackages or [ ];
46+
allowUnfreePredicate = if (permittedUnfreePackages != [ ]) then (pkg: builtins.elem (nixpkgs.lib.getName pkg) permittedUnfreePackages) else (_: false);
47+
};
48+
inherit overlays;
49+
};
50+
lib = pkgs.lib;
51+
importModule = path:
52+
if lib.hasPrefix "./" path
53+
then if lib.hasSuffix ".nix" path
54+
then ./. + (builtins.substring 1 255 path)
55+
else ./. + (builtins.substring 1 255 path) + "/devenv.nix"
56+
else if lib.hasPrefix "../" path
57+
then throw "devenv: ../ is not supported for imports"
58+
else
59+
let
60+
paths = lib.splitString "/" path;
61+
name = builtins.head paths;
62+
input = inputs.${name} or (throw "Unknown input ${name}");
63+
subpath = "/${lib.concatStringsSep "/" (builtins.tail paths)}";
64+
devenvpath = "${input}" + subpath;
65+
devenvdefaultpath = devenvpath + "/devenv.nix";
66+
in
67+
if lib.hasSuffix ".nix" devenvpath
68+
then devenvpath
69+
else if builtins.pathExists devenvdefaultpath
70+
then devenvdefaultpath
71+
else throw (devenvdefaultpath + " file does not exist for input ${name}.");
72+
project = pkgs.lib.evalModules {
73+
specialArgs = inputs // { inherit inputs; };
74+
modules = [
75+
({ config, ... }: {
76+
_module.args.pkgs = pkgs.appendOverlays (config.overlays or [ ]);
8477
})
85-
(pkgs.lib.optionalAttrs (builtins.hasAttr "runtime" options.devenv) {
86-
runtime = devenv_runtime;
78+
(inputs.devenv.modules + /top-level.nix)
79+
{
80+
devenv.cliVersion = version;
81+
devenv.root = devenv_root;
82+
devenv.dotfile = devenv_dotfile;
83+
}
84+
({ options, ... }: {
85+
config.devenv = lib.mkMerge [
86+
(pkgs.lib.optionalAttrs (builtins.hasAttr "tmpdir" options.devenv) {
87+
tmpdir = devenv_tmpdir;
88+
})
89+
(pkgs.lib.optionalAttrs (builtins.hasAttr "isTesting" options.devenv) {
90+
isTesting = devenv_istesting;
91+
})
92+
(pkgs.lib.optionalAttrs (builtins.hasAttr "runtime" options.devenv) {
93+
runtime = devenv_runtime;
94+
})
95+
(pkgs.lib.optionalAttrs (builtins.hasAttr "direnvrcLatestVersion" options.devenv) {
96+
direnvrcLatestVersion = devenv_direnvrc_latest_version;
97+
})
98+
];
8799
})
88-
(pkgs.lib.optionalAttrs (builtins.hasAttr "direnvrcLatestVersion" options.devenv) {
89-
direnvrcLatestVersion = devenv_direnvrc_latest_version;
100+
(pkgs.lib.optionalAttrs (container_name != null) {
101+
container.isBuilding = pkgs.lib.mkForce true;
102+
containers.${container_name}.isBuilding = true;
90103
})
104+
] ++ (map importModule (devenv.imports or [ ])) ++ [
105+
(if builtins.pathExists ./devenv.nix then ./devenv.nix else { })
106+
(devenv.devenv or { })
107+
(if builtins.pathExists ./devenv.local.nix then ./devenv.local.nix else { })
108+
(if builtins.pathExists (devenv_dotfile_path + "/cli-options.nix") then import (devenv_dotfile_path + "/cli-options.nix") else { })
91109
];
92-
})
93-
(pkgs.lib.optionalAttrs (container_name != null) {
94-
container.isBuilding = pkgs.lib.mkForce true;
95-
containers.${container_name}.isBuilding = true;
96-
})
97-
] ++ (map importModule (devenv.imports or [ ])) ++ [
98-
(if builtins.pathExists ./devenv.nix then ./devenv.nix else { })
99-
(devenv.devenv or { })
100-
(if builtins.pathExists ./devenv.local.nix then ./devenv.local.nix else { })
101-
(if builtins.pathExists (devenv_dotfile_path + "/cli-options.nix") then import (devenv_dotfile_path + "/cli-options.nix") else { })
102-
];
103-
};
104-
config = project.config;
110+
};
111+
config = project.config;
105112

106-
options = pkgs.nixosOptionsDoc {
107-
options = builtins.removeAttrs project.options [ "_module" ];
108-
warningsAreErrors = false;
109-
# Unpack Nix types, e.g. literalExpression, mDoc.
110-
transformOptions =
111-
let isDocType = v: builtins.elem v [ "literalDocBook" "literalExpression" "literalMD" "mdDoc" ];
112-
in lib.attrsets.mapAttrs (_: v:
113-
if v ? _type && isDocType v._type then
114-
v.text
115-
else if v ? _type && v._type == "derivation" then
116-
v.name
117-
else
118-
v
119-
);
120-
};
113+
options = pkgs.nixosOptionsDoc {
114+
options = builtins.removeAttrs project.options [ "_module" ];
115+
warningsAreErrors = false;
116+
# Unpack Nix types, e.g. literalExpression, mDoc.
117+
transformOptions =
118+
let isDocType = v: builtins.elem v [ "literalDocBook" "literalExpression" "literalMD" "mdDoc" ];
119+
in lib.attrsets.mapAttrs (_: v:
120+
if v ? _type && isDocType v._type then
121+
v.text
122+
else if v ? _type && v._type == "derivation" then
123+
v.name
124+
else
125+
v
126+
);
127+
};
121128

122-
# Recursively search for outputs in the config.
123-
# This is used when not building a specific output by attrpath.
124-
build = options: config:
125-
lib.concatMapAttrs
126-
(name: option:
127-
if lib.isOption option then
128-
let typeName = option.type.name or "";
129-
in
130-
if builtins.elem typeName [ "output" "outputOf" ] then
131-
{ ${name} = config.${name}; }
132-
else { }
133-
else
134-
let v = build option config.${name};
135-
in if v != { } then {
136-
${name} = v;
137-
} else { }
138-
)
139-
options;
129+
# Recursively search for outputs in the config.
130+
# This is used when not building a specific output by attrpath.
131+
build = options: config:
132+
lib.concatMapAttrs
133+
(name: option:
134+
if lib.isOption option then
135+
let typeName = option.type.name or "";
136+
in
137+
if builtins.elem typeName [ "output" "outputOf" ] then
138+
{ ${name} = config.${name}; }
139+
else { }
140+
else
141+
let v = build option config.${name};
142+
in if v != { } then {
143+
${name} = v;
144+
} else { }
145+
)
146+
options;
147+
in
148+
{
149+
inherit config options build;
150+
shell = config.shell;
151+
packages = {
152+
optionsJSON = options.optionsJSON;
153+
# deprecated
154+
inherit (config) info procfileScript procfileEnv procfile;
155+
ci = config.ciDerivation;
156+
};
157+
};
140158

141-
systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
159+
# Generate per-system devenv configurations
160+
perSystem = nixpkgs.lib.genAttrs systems mkDevenvForSystem;
161+
162+
# Default devenv for the current system
163+
currentSystemDevenv = perSystem.${system};
142164
in
143165
{
144-
devShell = lib.genAttrs systems (system: config.shell);
145-
packages = lib.genAttrs systems (system: {
146-
optionsJSON = options.optionsJSON;
147-
# deprecated
148-
inherit (config) info procfileScript procfileEnv procfile;
149-
ci = config.ciDerivation;
150-
});
151-
devenv = config;
152-
build = build project.options project.config;
166+
devShell = nixpkgs.lib.genAttrs systems (s: perSystem.${s}.shell);
167+
packages = nixpkgs.lib.genAttrs systems (s: perSystem.${s}.packages);
168+
169+
# Per-system devenv configurations
170+
devenv = {
171+
# Default devenv for the current system
172+
inherit (currentSystemDevenv) config options build shell packages;
173+
# Per-system devenv configurations
174+
inherit perSystem;
175+
};
176+
177+
# Legacy build output
178+
build = currentSystemDevenv.build currentSystemDevenv.options currentSystemDevenv.config;
153179
};
154180
}

devenv/src/nix.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ impl Nix {
743743
};
744744

745745
// Run Nix evaluation and file I/O concurrently
746-
let cachix_eval_future = self.eval(&["devenv.cachix"]);
746+
let cachix_eval_future = self.eval(&["devenv.config.cachix"]);
747747
let trusted_keys_path = self.paths.cachix_trusted_keys.clone();
748748
let known_keys_future = tokio::fs::read_to_string(&trusted_keys_path);
749749

0 commit comments

Comments
 (0)