Skip to content

Commit 06011ec

Browse files
committed
devenv: support containers on macos
1 parent 05b2f39 commit 06011ec

File tree

4 files changed

+181
-133
lines changed

4 files changed

+181
-133
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
@@ -473,10 +473,23 @@ impl Devenv {
473473
let gc_root = self
474474
.devenv_dot_gc
475475
.join(format!("container-{sanitized_name}-derivation"));
476+
let host_arch = env!("TARGET_ARCH");
477+
let host_os = env!("TARGET_OS");
478+
let target_system = if host_os == "macos" {
479+
match host_arch {
480+
"aarch64" => "aarch64-linux",
481+
"x86_64" => "x86_64-linux",
482+
_ => bail!("Unsupported container architecture for macOS: {host_arch}"),
483+
}
484+
} else {
485+
&self.global_options.system
486+
};
476487
let paths = self
477488
.nix
478489
.build(
479-
&[&format!("devenv.containers.{name}.derivation")],
490+
&[&format!(
491+
"devenv.perSystem.{target_system}.config.containers.{name}.derivation"
492+
)],
480493
None,
481494
Some(&gc_root),
482495
)
@@ -502,7 +515,7 @@ impl Devenv {
502515
let paths = self
503516
.nix
504517
.build(
505-
&[&format!("devenv.containers.{name}.copyScript")],
518+
&[&format!("devenv.config.containers.{name}.copyScript")],
506519
None,
507520
Some(&gc_root),
508521
)
@@ -557,7 +570,7 @@ impl Devenv {
557570
let paths = self
558571
.nix
559572
.build(
560-
&[&format!("devenv.containers.{name}.dockerRun")],
573+
&[&format!("devenv.config.containers.{name}.dockerRun")],
561574
None,
562575
Some(&gc_root),
563576
)
@@ -715,7 +728,7 @@ impl Devenv {
715728
let value = self
716729
.has_processes
717730
.get_or_try_init(|| async {
718-
let processes = self.nix.eval(&["devenv.processes"]).await?;
731+
let processes = self.nix.eval(&["devenv.config.processes"]).await?;
719732
Ok::<bool, miette::Report>(processes.trim() != "{}")
720733
})
721734
.await?;
@@ -727,7 +740,7 @@ impl Devenv {
727740
let span = info_span!("load_tasks", devenv.user_message = "Evaluating tasks");
728741
let gc_root = self.devenv_dot_gc.join("task-config");
729742
self.nix
730-
.build(&["devenv.task.config"], None, Some(&gc_root))
743+
.build(&["devenv.config.task.config"], None, Some(&gc_root))
731744
.instrument(span)
732745
.await?
733746
};
@@ -894,7 +907,7 @@ impl Devenv {
894907
let span = info_span!("test", devenv.user_message = "Building tests");
895908
let gc_root = self.devenv_dot_gc.join("test");
896909
self.nix
897-
.build(&["devenv.test"], None, Some(&gc_root))
910+
.build(&["devenv.config.test"], None, Some(&gc_root))
898911
.instrument(span)
899912
.await?
900913
};
@@ -974,7 +987,7 @@ impl Devenv {
974987
flatten_object(&format!("{}.{}", prefix, k), v)
975988
})
976989
.collect(),
977-
_ => vec![format!("devenv.{}", prefix)],
990+
_ => vec![format!("devenv.config.{}", prefix)],
978991
}
979992
}
980993
flatten_object(key, value)
@@ -983,7 +996,7 @@ impl Devenv {
983996
} else {
984997
attributes
985998
.iter()
986-
.map(|attr| format!("devenv.{}", attr))
999+
.map(|attr| format!("devenv.config.{}", attr))
9871000
.collect()
9881001
};
9891002
let paths = self

devenv/src/flake.tmpl.nix

Lines changed: 149 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
inputs =
33
let
44
__DEVENV_VARS__
5-
in {
6-
git-hooks.url = "github:cachix/git-hooks.nix";
5+
in {
6+
git-hooks.url = "github:cachix/git-hooks.nix";
77
git-hooks.inputs.nixpkgs.follows = "nixpkgs";
88
pre-commit-hooks.follows = "git-hooks";
99
nixpkgs.url = "github:cachix/devenv-nixpkgs/rolling";
@@ -15,139 +15,164 @@
1515
outputs = { nixpkgs, ... }@inputs:
1616
let
1717
__DEVENV_VARS__
18-
devenv =
18+
devenv =
1919
if builtins.pathExists (devenv_dotfile + "/devenv.json")
2020
then builtins.fromJSON (builtins.readFile (devenv_dotfile + "/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-
pkgs = import nixpkgs {
32-
inherit system;
33-
config = {
34-
allowUnfree = devenv.nixpkgs.per-platform."${system}".allowUnfree or devenv.nixpkgs.allowUnfree or devenv.allowUnfree or false;
35-
allowBroken = devenv.nixpkgs.per-platform."${system}".allowBroken or devenv.nixpkgs.allowBroken or devenv.allowBroken or false;
36-
cudaSupport = devenv.nixpkgs.per-platform."${system}".cudaSupport or devenv.nixpkgs.cudaSupport or false;
37-
cudaCapabilities = devenv.nixpkgs.per-platform."${system}".cudaCapabilities or devenv.nixpkgs.cudaCapabilities or [ ];
38-
permittedInsecurePackages = devenv.nixpkgs.per-platform."${system}".permittedInsecurePackages or devenv.nixpkgs.permittedInsecurePackages or devenv.permittedInsecurePackages or [ ];
39-
};
40-
inherit overlays;
41-
};
42-
lib = pkgs.lib;
43-
importModule = path:
44-
if lib.hasPrefix "./" path
45-
then if lib.hasSuffix ".nix" path
46-
then ./. + (builtins.substring 1 255 path)
47-
else ./. + (builtins.substring 1 255 path) + "/devenv.nix"
48-
else if lib.hasPrefix "../" path
49-
then throw "devenv: ../ is not supported for imports"
50-
else
51-
let
52-
paths = lib.splitString "/" path;
53-
name = builtins.head paths;
54-
input = inputs.${name} or (throw "Unknown input ${name}");
55-
subpath = "/${lib.concatStringsSep "/" (builtins.tail paths)}";
56-
devenvpath = "${input}" + subpath;
57-
devenvdefaultpath = devenvpath + "/devenv.nix";
58-
in
59-
if lib.hasSuffix ".nix" devenvpath
60-
then devenvpath
61-
else if builtins.pathExists devenvdefaultpath
62-
then devenvdefaultpath
63-
else throw (devenvdefaultpath + " file does not exist for input ${name}.");
64-
project = pkgs.lib.evalModules {
65-
specialArgs = inputs // { inherit inputs; };
66-
modules = [
67-
({ config, ... }: {
68-
_module.args.pkgs = pkgs.appendOverlays (config.overlays or [ ]);
69-
})
70-
(inputs.devenv.modules + /top-level.nix)
71-
{
72-
devenv.cliVersion = version;
73-
devenv.root = devenv_root;
74-
devenv.dotfile = devenv_root + "/" + devenv_dotfile_string;
75-
}
76-
({ options, ... }: {
77-
config.devenv = lib.mkMerge [
78-
(pkgs.lib.optionalAttrs (builtins.hasAttr "tmpdir" options.devenv) {
79-
tmpdir = devenv_tmpdir;
80-
})
81-
(pkgs.lib.optionalAttrs (builtins.hasAttr "isTesting" options.devenv) {
82-
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+
pkgs = import nixpkgs {
38+
system = targetSystem;
39+
config = {
40+
allowUnfree = devenv.nixpkgs.per-platform."${targetSystem}".allowUnfree or devenv.nixpkgs.allowUnfree or devenv.allowUnfree or false;
41+
allowBroken = devenv.nixpkgs.per-platform."${targetSystem}".allowBroken or devenv.nixpkgs.allowBroken or devenv.allowBroken or false;
42+
cudaSupport = devenv.nixpkgs.per-platform."${targetSystem}".cudaSupport or devenv.nixpkgs.cudaSupport or false;
43+
cudaCapabilities = devenv.nixpkgs.per-platform."${targetSystem}".cudaCapabilities or devenv.nixpkgs.cudaCapabilities or [ ];
44+
permittedInsecurePackages = devenv.nixpkgs.per-platform."${targetSystem}".permittedInsecurePackages or devenv.nixpkgs.permittedInsecurePackages or devenv.permittedInsecurePackages or [ ];
45+
};
46+
inherit overlays;
47+
};
48+
lib = pkgs.lib;
49+
importModule = path:
50+
if lib.hasPrefix "./" path
51+
then if lib.hasSuffix ".nix" path
52+
then ./. + (builtins.substring 1 255 path)
53+
else ./. + (builtins.substring 1 255 path) + "/devenv.nix"
54+
else if lib.hasPrefix "../" path
55+
then throw "devenv: ../ is not supported for imports"
56+
else
57+
let
58+
paths = lib.splitString "/" path;
59+
name = builtins.head paths;
60+
input = inputs.${name} or (throw "Unknown input ${name}");
61+
subpath = "/${lib.concatStringsSep "/" (builtins.tail paths)}";
62+
devenvpath = "${input}" + subpath;
63+
devenvdefaultpath = devenvpath + "/devenv.nix";
64+
in
65+
if lib.hasSuffix ".nix" devenvpath
66+
then devenvpath
67+
else if builtins.pathExists devenvdefaultpath
68+
then devenvdefaultpath
69+
else throw (devenvdefaultpath + " file does not exist for input ${name}.");
70+
project = pkgs.lib.evalModules {
71+
specialArgs = inputs // { inherit inputs; };
72+
modules = [
73+
({ config, ... }: {
74+
_module.args.pkgs = pkgs.appendOverlays (config.overlays or [ ]);
8375
})
84-
(pkgs.lib.optionalAttrs (builtins.hasAttr "runtime" options.devenv) {
85-
runtime = devenv_runtime;
76+
(inputs.devenv.modules + /top-level.nix)
77+
{
78+
devenv.cliVersion = version;
79+
devenv.root = devenv_root;
80+
devenv.dotfile = devenv_root + "/" + devenv_dotfile_string;
81+
}
82+
({ options, ... }: {
83+
config.devenv = lib.mkMerge [
84+
(pkgs.lib.optionalAttrs (builtins.hasAttr "tmpdir" options.devenv) {
85+
tmpdir = devenv_tmpdir;
86+
})
87+
(pkgs.lib.optionalAttrs (builtins.hasAttr "isTesting" options.devenv) {
88+
isTesting = devenv_istesting;
89+
})
90+
(pkgs.lib.optionalAttrs (builtins.hasAttr "runtime" options.devenv) {
91+
runtime = devenv_runtime;
92+
})
93+
(pkgs.lib.optionalAttrs (builtins.hasAttr "direnvrcLatestVersion" options.devenv) {
94+
direnvrcLatestVersion = devenv_direnvrc_latest_version;
95+
})
96+
];
8697
})
87-
(pkgs.lib.optionalAttrs (builtins.hasAttr "direnvrcLatestVersion" options.devenv) {
88-
direnvrcLatestVersion = devenv_direnvrc_latest_version;
98+
(pkgs.lib.optionalAttrs (container_name != null) {
99+
container.isBuilding = pkgs.lib.mkForce true;
100+
containers.${container_name}.isBuilding = true;
89101
})
102+
] ++ (map importModule (devenv.imports or [ ])) ++ [
103+
(if builtins.pathExists ./devenv.nix then ./devenv.nix else { })
104+
(devenv.devenv or { })
105+
(if builtins.pathExists ./devenv.local.nix then ./devenv.local.nix else { })
106+
(if builtins.pathExists (devenv_dotfile + "/cli-options.nix") then import (devenv_dotfile + "/cli-options.nix") else { })
90107
];
91-
})
92-
(pkgs.lib.optionalAttrs (container_name != null) {
93-
container.isBuilding = pkgs.lib.mkForce true;
94-
containers.${container_name}.isBuilding = true;
95-
})
96-
] ++ (map importModule (devenv.imports or [ ])) ++ [
97-
(if builtins.pathExists ./devenv.nix then ./devenv.nix else { })
98-
(devenv.devenv or { })
99-
(if builtins.pathExists ./devenv.local.nix then ./devenv.local.nix else { })
100-
(if builtins.pathExists (devenv_dotfile + "/cli-options.nix") then import (devenv_dotfile + "/cli-options.nix") else { })
101-
];
102-
};
103-
config = project.config;
108+
};
109+
config = project.config;
104110

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

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

140-
systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
157+
# Generate per-system devenv configurations
158+
perSystem = nixpkgs.lib.genAttrs systems mkDevenvForSystem;
159+
160+
# Default devenv for the current system
161+
currentSystemDevenv = perSystem.${system};
141162
in
142163
{
143-
devShell = lib.genAttrs systems (system: config.shell);
144-
packages = lib.genAttrs systems (system: {
145-
optionsJSON = options.optionsJSON;
146-
# deprecated
147-
inherit (config) info procfileScript procfileEnv procfile;
148-
ci = config.ciDerivation;
149-
});
150-
devenv = config;
151-
build = build project.options project.config;
164+
devShell = nixpkgs.lib.genAttrs systems (s: perSystem.${s}.shell);
165+
packages = nixpkgs.lib.genAttrs systems (s: perSystem.${s}.packages);
166+
167+
# Per-system devenv configurations
168+
devenv = {
169+
# Default devenv for the current system
170+
inherit (currentSystemDevenv) config options build shell packages;
171+
# Per-system devenv configurations
172+
inherit perSystem;
173+
};
174+
175+
# Legacy build output
176+
build = currentSystemDevenv.build currentSystemDevenv.options currentSystemDevenv.config;
152177
};
153178
}

0 commit comments

Comments
 (0)