deploy script
This commit is contained in:
parent
ac55ccd2f5
commit
0cd8406ba5
1294
Cargo.lock
generated
1294
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -4,11 +4,13 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
async-trait = "0.1.83"
|
||||||
clap = { version = "4.5.20", features = ["derive"] }
|
clap = { version = "4.5.20", features = ["derive"] }
|
||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
|
futures = "0.3.31"
|
||||||
|
openssh = "0.11.4"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
reqwest = "0.12.9"
|
reqwest = "0.12.9"
|
||||||
russh = "0.46.0"
|
|
||||||
serde = { version = "1.0.214", features = ["derive"] }
|
serde = { version = "1.0.214", features = ["derive"] }
|
||||||
serde_json = "1.0.132"
|
serde_json = "1.0.132"
|
||||||
tokio = { version = "1.41.1", features = ["full"] }
|
tokio = { version = "1.41.1", features = ["full"] }
|
||||||
|
|
119
src/deploy.rs
Normal file
119
src/deploy.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
use color_eyre::{eyre::Result, owo_colors::OwoColorize};
|
||||||
|
use futures::future::join_all;
|
||||||
|
use openssh::{KnownHosts, Session};
|
||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
path::PathBuf,
|
||||||
|
process::{Command, Stdio},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn gen_systems_path(system: &str) -> String {
|
||||||
|
format!(
|
||||||
|
".#nixosConfigurations.{}.config.system.build.toplevel",
|
||||||
|
system
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(systems: &[String], show_trace: bool) -> Result<()> {
|
||||||
|
if systems.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let dir = env::var("PRJ_ROOT")
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.or_else(|_| env::current_dir())?;
|
||||||
|
let mut configs = Vec::new();
|
||||||
|
for s in systems.iter().map(|x| gen_systems_path(x)) {
|
||||||
|
configs.push(format!(
|
||||||
|
".#nixosConfigurations.{}.config.system.build.toplevel",
|
||||||
|
s
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let mut cmd = Command::new("nom");
|
||||||
|
let mut cmd = if cmd
|
||||||
|
.arg("--version")
|
||||||
|
.current_dir(dir)
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.spawn()
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
Command::new("nix")
|
||||||
|
} else {
|
||||||
|
Command::new("nom")
|
||||||
|
};
|
||||||
|
if show_trace {
|
||||||
|
cmd.arg("--show-trace");
|
||||||
|
};
|
||||||
|
let cmd = cmd
|
||||||
|
.arg("build")
|
||||||
|
.arg("--print-out-paths")
|
||||||
|
.arg("--no-link")
|
||||||
|
.args(configs);
|
||||||
|
cmd.spawn()?.wait()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn deploy(systems: &[String], show_trace: bool, mode: &str) -> Result<()> {
|
||||||
|
let (systems, hosts): (Vec<_>, Vec<_>) = systems
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.split_once('@').unwrap_or((x, x)))
|
||||||
|
.unzip();
|
||||||
|
|
||||||
|
println!("Opening ssh connection for {} hosts.", hosts.len().blue());
|
||||||
|
let connections = hosts
|
||||||
|
.iter()
|
||||||
|
.map(|x| Session::connect(x, KnownHosts::Strict));
|
||||||
|
let connections = join_all(connections)
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.collect::<std::result::Result<Vec<_>, openssh::Error>>()?;
|
||||||
|
build(
|
||||||
|
&systems.iter().map(|x| x.to_string()).collect::<Vec<_>>(),
|
||||||
|
show_trace,
|
||||||
|
)?;
|
||||||
|
for (system, (con, host)) in systems.into_iter().zip(connections.into_iter().zip(hosts)) {
|
||||||
|
let path = gen_systems_path(system);
|
||||||
|
let mut cmd = Command::new("nix");
|
||||||
|
let cmd = cmd.arg("eval").arg("--read-only").arg("--raw").arg(path);
|
||||||
|
let toplevel = String::from_utf8(cmd.output()?.stdout)?;
|
||||||
|
println!("Copyings toplevel for {}", system.blue());
|
||||||
|
let mut cmd = Command::new("nix");
|
||||||
|
let cmd = cmd
|
||||||
|
.arg("copy")
|
||||||
|
.arg("--to")
|
||||||
|
.arg(format!("ssh://{}", host))
|
||||||
|
.arg(&toplevel);
|
||||||
|
cmd.spawn()?.wait()?;
|
||||||
|
let prev_system = con
|
||||||
|
.command("readlink")
|
||||||
|
.arg("-e")
|
||||||
|
.arg("/nix/var/nix/profiles/system")
|
||||||
|
.output()
|
||||||
|
.await?
|
||||||
|
.stdout;
|
||||||
|
// register toplevel
|
||||||
|
con.command("nix-env")
|
||||||
|
.arg("--profile")
|
||||||
|
.arg("/nix/var/nix/profiles/system")
|
||||||
|
.arg("--set")
|
||||||
|
.arg(&toplevel)
|
||||||
|
.spawn()
|
||||||
|
.await?;
|
||||||
|
con.command(format!("{}/bin/switch-to-configuration", toplevel))
|
||||||
|
.arg(mode)
|
||||||
|
.spawn()
|
||||||
|
.await?;
|
||||||
|
if !prev_system.is_empty() {
|
||||||
|
con.command("nvd")
|
||||||
|
.arg("--color")
|
||||||
|
.arg("--always")
|
||||||
|
.arg("diff")
|
||||||
|
.arg(String::from_utf8(prev_system)?)
|
||||||
|
.arg(toplevel)
|
||||||
|
.spawn()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
59
src/main.rs
59
src/main.rs
|
@ -1,16 +1,18 @@
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
fs::{self, read_dir},
|
fs::{self, read_dir},
|
||||||
io::Error,
|
|
||||||
path::PathBuf,
|
|
||||||
process::{Command, Stdio},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::{error::ErrorKind, Args, CommandFactory, Parser, Subcommand};
|
use clap::{error::ErrorKind, Args, CommandFactory, Parser, Subcommand};
|
||||||
use color_eyre::eyre::{bail, Result};
|
use color_eyre::{
|
||||||
|
eyre::{bail, Result},
|
||||||
|
owo_colors::OwoColorize,
|
||||||
|
};
|
||||||
|
use deploy::*;
|
||||||
use pr::*;
|
use pr::*;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::{header, Client};
|
use reqwest::{header, Client};
|
||||||
|
mod deploy;
|
||||||
mod pr;
|
mod pr;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
@ -51,6 +53,10 @@ struct AddPR {
|
||||||
#[derive(Args, Debug, Default)]
|
#[derive(Args, Debug, Default)]
|
||||||
struct Deploy {
|
struct Deploy {
|
||||||
systems: Vec<String>,
|
systems: Vec<String>,
|
||||||
|
#[arg(long, default_value_t = false)]
|
||||||
|
show_trace: bool,
|
||||||
|
#[arg(long, default_value_t = ("switch".to_string()))]
|
||||||
|
mode: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args, Debug, Default)]
|
#[derive(Args, Debug, Default)]
|
||||||
|
@ -82,7 +88,12 @@ async fn main() -> Result<()> {
|
||||||
let nix_rev = get_local_nixp_rev()?;
|
let nix_rev = get_local_nixp_rev()?;
|
||||||
println!("Local nixpkgs: {}", contains(&nix_rev, &pr, &client).await?);
|
println!("Local nixpkgs: {}", contains(&nix_rev, &pr, &client).await?);
|
||||||
for &i in BRANCHES {
|
for &i in BRANCHES {
|
||||||
println!("{}: {}", i, contains(i, &pr, &client).await?);
|
let t = contains(i, &pr, &client).await?;
|
||||||
|
if t {
|
||||||
|
println!("{:<25}: {}", i, "contained".green());
|
||||||
|
} else {
|
||||||
|
println!("{:<25}: {}", i, "not contained".red());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CliCommands::UpdatePrs(opts) => {
|
CliCommands::UpdatePrs(opts) => {
|
||||||
|
@ -107,10 +118,10 @@ async fn main() -> Result<()> {
|
||||||
bail!("This shouldn't happen")
|
bail!("This shouldn't happen")
|
||||||
};
|
};
|
||||||
let pr = get_pr(l, &client).await?;
|
let pr = get_pr(l, &client).await?;
|
||||||
println!("Fetching diff for PR #{}: {}", l, pr.title);
|
println!("Fetching diff for PR #{:<6}: {}", l, pr.title);
|
||||||
let branch = get_local_nixp_rev()?;
|
let branch = get_local_nixp_rev()?;
|
||||||
if contains(&branch, &pr, &client).await? {
|
if contains(&branch, &pr, &client).await? {
|
||||||
println!("PR is contained in your local nixpkgs, removing diff");
|
println!("\t↪ PR is contained in your local nixpkgs, removing diff");
|
||||||
fs::remove_file(format!("{}/{}.diff", opts.path, l))?;
|
fs::remove_file(format!("{}/{}.diff", opts.path, l))?;
|
||||||
} else {
|
} else {
|
||||||
get_diff(l, &opts.path, &client).await?;
|
get_diff(l, &opts.path, &client).await?;
|
||||||
|
@ -123,9 +134,6 @@ async fn main() -> Result<()> {
|
||||||
get_diff(pr, &opts.path, &client).await?;
|
get_diff(pr, &opts.path, &client).await?;
|
||||||
}
|
}
|
||||||
CliCommands::Build(opts) => {
|
CliCommands::Build(opts) => {
|
||||||
let dir = env::var("PRJ_ROOT")
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.or_else(|_| env::current_dir())?;
|
|
||||||
if opts.systems.is_empty() {
|
if opts.systems.is_empty() {
|
||||||
let mut cmd = Cli::command();
|
let mut cmd = Cli::command();
|
||||||
cmd.error(
|
cmd.error(
|
||||||
|
@ -134,35 +142,7 @@ async fn main() -> Result<()> {
|
||||||
)
|
)
|
||||||
.exit()
|
.exit()
|
||||||
}
|
}
|
||||||
let mut configs = Vec::new();
|
build(&opts.systems, opts.show_trace)?;
|
||||||
for s in &opts.systems {
|
|
||||||
configs.push(format!(
|
|
||||||
".#nixosConfigurations.{}.config.system.build.toplevel",
|
|
||||||
s
|
|
||||||
));
|
|
||||||
}
|
|
||||||
println!("{:?}", configs);
|
|
||||||
let mut cmd = Command::new("nom");
|
|
||||||
let mut cmd = if cmd
|
|
||||||
.arg("--version")
|
|
||||||
.current_dir(dir)
|
|
||||||
.stdin(Stdio::null())
|
|
||||||
.stdout(Stdio::null())
|
|
||||||
.stderr(Stdio::null())
|
|
||||||
.spawn()
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
Command::new("nix")
|
|
||||||
} else {
|
|
||||||
Command::new("nom")
|
|
||||||
};
|
|
||||||
let cmd = cmd
|
|
||||||
.arg("build")
|
|
||||||
.arg("--print-out-paths")
|
|
||||||
.arg("--no-link")
|
|
||||||
.args(configs);
|
|
||||||
cmd.spawn()?.wait()?;
|
|
||||||
println!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CliCommands::Deploy(opts) => {
|
CliCommands::Deploy(opts) => {
|
||||||
|
@ -174,6 +154,7 @@ async fn main() -> Result<()> {
|
||||||
)
|
)
|
||||||
.exit()
|
.exit()
|
||||||
}
|
}
|
||||||
|
deploy(&opts.systems, opts.show_trace, &opts.mode).await?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue