1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
use std::process::Stdio;
use tokio::process::Command;
use std::path::Path;
pub async fn activate(
profile_path: String,
closure: String,
activate_cmd: Option<String>,
bootstrap_cmd: Option<String>,
auto_rollback: bool,
) -> Result<(), Box<dyn std::error::Error>> {
info!("Activating profile");
Command::new("nix-env")
.arg("-p")
.arg(&profile_path)
.arg("--set")
.arg(&closure)
.stdout(Stdio::null())
.spawn()?
.await?;
if let (Some(bootstrap_cmd), false) = (bootstrap_cmd, !Path::new(&profile_path).exists()) {
let bootstrap_status = Command::new("bash")
.arg("-c")
.arg(&bootstrap_cmd)
.env("PROFILE", &profile_path)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.await;
match bootstrap_status {
Ok(s) if s.success() => (),
_ => {
tokio::fs::remove_file(&profile_path).await?;
good_panic!("Failed to execute bootstrap command");
}
}
}
if let Some(activate_cmd) = activate_cmd {
let activate_status = Command::new("bash")
.arg("-c")
.arg(&activate_cmd)
.env("PROFILE", &profile_path)
.status()
.await;
match activate_status {
Ok(s) if s.success() => (),
_ if auto_rollback => {
Command::new("nix-env")
.arg("-p")
.arg(&profile_path)
.arg("--rollback")
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()?
.await?;
let c = Command::new("nix-env")
.arg("-p")
.arg(&profile_path)
.arg("--list-generations")
.output()
.await?;
let generations_list = String::from_utf8(c.stdout)?;
let last_generation_line = generations_list
.lines()
.last()
.expect("Expected to find a generation in list");
let last_generation_id = last_generation_line
.split_whitespace()
.next()
.expect("Expected to get ID from generation entry");
debug!("Removing generation entry {}", last_generation_line);
warn!("Removing generation by ID {}", last_generation_id);
Command::new("nix-env")
.arg("-p")
.arg(&profile_path)
.arg("--delete-generations")
.arg(last_generation_id)
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()?
.await?;
// TODO: Find some way to make sure this command never changes, otherwise this will not work
Command::new("bash")
.arg("-c")
.arg(&activate_cmd)
.spawn()?
.await?;
good_panic!("Failed to execute activation command");
}
_ => {}
}
}
Ok(())
}
|