Set up the flake repo directory.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
/target
|
||||
/work
|
||||
|
||||
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -1023,6 +1023,15 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.11"
|
||||
@@ -1149,6 +1158,7 @@ dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2 0.6.1",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
|
||||
@@ -14,7 +14,7 @@ opentelemetry-otlp = { version = "0.13.0", optional = true }
|
||||
opentelemetry-semantic-conventions = { version = "0.12.0", optional = true }
|
||||
serde = { version = "1.0.228", default-features = false, features = ["std", "derive"] }
|
||||
serde_json = { version = "1.0.149", default-features = false, features = ["std"] }
|
||||
tokio = { version = "1.49.0", default-features = false, features = ["rt", "rt-multi-thread", "fs", "io-util"] }
|
||||
tokio = { version = "1.49.0", default-features = false, features = ["rt", "rt-multi-thread", "fs", "io-util", "process"] }
|
||||
toml = { version = "0.9.11", default-features = false, features = ["display", "parse", "serde", "std"] }
|
||||
tracing = { version = "0.1.37", optional = true }
|
||||
tracing-opentelemetry = { version = "0.20.0", optional = true }
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
work_directory = "/home/nixworker/persist/nix_builder"
|
||||
# work_directory = "/home/nixworker/persist/nix_builder"
|
||||
|
||||
[[targets]]
|
||||
name = "odo"
|
||||
repo = "https://code.fizz.buzz/talexander/machine_setup.git"
|
||||
branch = "nix"
|
||||
path = "nix/configuration"
|
||||
attr = "odo"
|
||||
name = "odo"
|
||||
repo = "https://code.fizz.buzz/talexander/machine_setup.git"
|
||||
branch = "nix"
|
||||
path = "nix/configuration"
|
||||
attr = "odo"
|
||||
|
||||
[[targets]]
|
||||
name = "odo_update"
|
||||
repo = "https://code.fizz.buzz/talexander/machine_setup.git"
|
||||
branch = "nix"
|
||||
path = "nix/configuration"
|
||||
attr = "odo"
|
||||
update = true
|
||||
update_branch = "nix_update"
|
||||
name = "odo_update"
|
||||
repo = "https://code.fizz.buzz/talexander/machine_setup.git"
|
||||
branch = "nix"
|
||||
path = "nix/configuration"
|
||||
attr = "odo"
|
||||
update = true
|
||||
update_branch = "nix_update"
|
||||
|
||||
@@ -2,6 +2,10 @@ use crate::cli::parameters::BuildArgs;
|
||||
use crate::config::Config;
|
||||
use crate::config::TargetConfig;
|
||||
use crate::error::CustomError;
|
||||
use crate::fs_util::assert_directory;
|
||||
use crate::fs_util::is_git_repo;
|
||||
use crate::git_util::git_force_into_state;
|
||||
use crate::git_util::git_init_at_rev;
|
||||
|
||||
pub(crate) async fn run_build(args: BuildArgs) -> Result<(), CustomError> {
|
||||
println!("{:?}", args);
|
||||
@@ -18,12 +22,41 @@ pub(crate) async fn run_build(args: BuildArgs) -> Result<(), CustomError> {
|
||||
}
|
||||
};
|
||||
|
||||
prepare_flake_repo(target_config).await?;
|
||||
prepare_flake_repo(&config, target_config).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn prepare_flake_repo(target_config: &TargetConfig) -> Result<(), CustomError> {
|
||||
todo!()
|
||||
async fn prepare_flake_repo(
|
||||
config_root: &Config,
|
||||
target_config: &TargetConfig,
|
||||
) -> Result<(), CustomError> {
|
||||
let flake_directory = target_config.get_flake_directory(config_root)?;
|
||||
assert_directory!(
|
||||
&flake_directory,
|
||||
"Creating flake directory {}",
|
||||
(&flake_directory).to_string_lossy()
|
||||
);
|
||||
|
||||
if is_git_repo(&flake_directory).await? {
|
||||
// Clean up the existing clone
|
||||
git_force_into_state(
|
||||
&flake_directory,
|
||||
target_config.get_branch()?,
|
||||
"origin",
|
||||
target_config.get_repo()?,
|
||||
target_config.get_revision()?,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
git_init_at_rev(
|
||||
&flake_directory,
|
||||
target_config.get_branch()?,
|
||||
target_config.get_repo()?,
|
||||
target_config.get_revision()?,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -12,16 +12,23 @@ use super::Config;
|
||||
pub(crate) struct TargetConfig {
|
||||
pub(super) name: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub(super) repo: Option<String>,
|
||||
pub(super) repo: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub(super) branch: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub(super) revision: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub(super) path: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub(super) attr: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub(super) update: Option<bool>,
|
||||
|
||||
#[serde(default)]
|
||||
pub(super) update_branch: Option<String>,
|
||||
}
|
||||
@@ -42,4 +49,20 @@ impl TargetConfig {
|
||||
let target_directory = self.get_target_directory(config_root)?;
|
||||
Ok(Cow::Owned(target_directory.join("flake")))
|
||||
}
|
||||
|
||||
pub(crate) fn get_repo(&'_ self) -> Result<&String, CustomError> {
|
||||
Ok(&self.repo)
|
||||
}
|
||||
|
||||
pub(crate) fn get_branch(&'_ self) -> Result<Cow<'_, str>, CustomError> {
|
||||
if let Some(b) = &self.branch {
|
||||
Ok(Cow::Borrowed(b))
|
||||
} else {
|
||||
Ok(Cow::Borrowed("main"))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_revision(&self) -> Result<&Option<String>, CustomError> {
|
||||
Ok(&self.revision)
|
||||
}
|
||||
}
|
||||
|
||||
36
src/fs_util.rs
Normal file
36
src/fs_util.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
macro_rules! assert_directory {
|
||||
($dir:expr, $($params:tt)*) => {{
|
||||
let dir = $dir;
|
||||
let metadata = tokio::fs::metadata(&dir).await;
|
||||
match metadata {
|
||||
Ok(metadata) if !metadata.is_dir() => {
|
||||
tracing::info!($($params)*);
|
||||
tokio::fs::create_dir_all(dir).await?;
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::info!($($params)*);
|
||||
tokio::fs::create_dir_all(dir).await?;
|
||||
}
|
||||
Ok(_) => {}
|
||||
};
|
||||
}};
|
||||
}
|
||||
use std::path::Path;
|
||||
|
||||
pub(crate) use assert_directory;
|
||||
|
||||
use crate::error::CustomError;
|
||||
|
||||
pub(crate) async fn is_directory<D: AsRef<Path>>(dir: D) -> Result<bool, CustomError> {
|
||||
let metadata = tokio::fs::metadata(dir).await;
|
||||
let result = match metadata {
|
||||
Ok(metadata) if metadata.is_dir() => true,
|
||||
_ => false,
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub(crate) async fn is_git_repo<D: AsRef<Path>>(dir: D) -> Result<bool, CustomError> {
|
||||
let dot_git = dir.as_ref().join(".git");
|
||||
is_directory(dot_git).await
|
||||
}
|
||||
236
src/git_util/core.rs
Normal file
236
src/git_util/core.rs
Normal file
@@ -0,0 +1,236 @@
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::error::CustomError;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
pub(crate) async fn git_init<P, B>(dest: P, branch: B) -> Result<(), CustomError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
B: AsRef<str>,
|
||||
{
|
||||
// git -C $dest init --initial-branch=$branch
|
||||
|
||||
let mut command = Command::new("git");
|
||||
let dest = AsRef::<OsStr>::as_ref(dest.as_ref());
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["init"]);
|
||||
command.arg(format!("--initial-branch={}", branch.as_ref()));
|
||||
command.kill_on_drop(true);
|
||||
let output = command.output().await?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"Failing to init git repository: {}",
|
||||
String::from_utf8(output.stderr)?
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn git_remote_add<P, N, U>(dest: P, name: N, url: U) -> Result<(), CustomError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
N: AsRef<str>,
|
||||
U: AsRef<str>,
|
||||
{
|
||||
// git -C $dest remote add $name $url
|
||||
|
||||
let dest = AsRef::<OsStr>::as_ref(dest.as_ref());
|
||||
let name = name.as_ref();
|
||||
let url = url.as_ref();
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["remote", "add"]);
|
||||
command.arg(name);
|
||||
command.arg(url);
|
||||
command.kill_on_drop(true);
|
||||
let output = command.output().await?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"Failing to add remote to git repo: {}",
|
||||
String::from_utf8(output.stderr)?
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn git_fetch<P, N, R>(
|
||||
dest: P,
|
||||
name: N,
|
||||
rev: R,
|
||||
depth: Option<usize>,
|
||||
blobless: bool,
|
||||
treeless: bool,
|
||||
) -> Result<(), CustomError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
N: AsRef<str>,
|
||||
R: AsRef<str>,
|
||||
{
|
||||
// git -C $dest fetch [--depth=$depth] [--filter=blob:none] [--filter=tree:0] $name $rev
|
||||
|
||||
let dest = AsRef::<OsStr>::as_ref(dest.as_ref());
|
||||
let name = name.as_ref();
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["fetch"]);
|
||||
if let Some(d) = depth {
|
||||
command.arg(format!("--depth={}", d));
|
||||
}
|
||||
if blobless {
|
||||
command.arg("--filter=blob:none");
|
||||
}
|
||||
if treeless {
|
||||
command.arg("--filter=tree:0");
|
||||
}
|
||||
command.arg(name);
|
||||
command.arg(rev.as_ref());
|
||||
command.kill_on_drop(true);
|
||||
let output = command.output().await?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"Failing to git fetch: {}",
|
||||
String::from_utf8(output.stderr)?
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn git_checkout<P, R>(
|
||||
dest: P,
|
||||
rev: R,
|
||||
force: bool,
|
||||
detach: bool,
|
||||
) -> Result<(), CustomError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
R: AsRef<str>,
|
||||
{
|
||||
// git -C $dest checkout [--force] [--detach] $rev
|
||||
|
||||
let dest = AsRef::<OsStr>::as_ref(dest.as_ref());
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["checkout"]);
|
||||
if force {
|
||||
command.arg("--force");
|
||||
}
|
||||
if detach {
|
||||
command.arg("--detach");
|
||||
}
|
||||
command.arg(rev.as_ref());
|
||||
command.kill_on_drop(true);
|
||||
let output = command.output().await?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"Failing to git checkout: {}",
|
||||
String::from_utf8(output.stderr)?
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn git_get_remote<P, R>(dest: P, remote: R) -> Result<String, CustomError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
R: AsRef<str>,
|
||||
{
|
||||
// git -C $dest remote get-url $remote
|
||||
|
||||
let dest = AsRef::<OsStr>::as_ref(dest.as_ref());
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["remote", "get-url"]);
|
||||
command.arg(remote.as_ref());
|
||||
command.kill_on_drop(true);
|
||||
let output = command.output().await?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"Failing to get git remote: {}",
|
||||
String::from_utf8(output.stderr)?
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let url = {
|
||||
let mut url = String::from_utf8(output.stdout)?;
|
||||
url.truncate(url.trim_ascii_end().len());
|
||||
url
|
||||
};
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn git_reset<P, R>(dest: P, hard: bool, rev: R) -> Result<(), CustomError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
R: AsRef<str>,
|
||||
{
|
||||
// git -C $dest reset [--hard] $rev
|
||||
|
||||
let dest = AsRef::<OsStr>::as_ref(dest.as_ref());
|
||||
let rev = rev.as_ref();
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["reset"]);
|
||||
if hard {
|
||||
command.arg("--hard");
|
||||
}
|
||||
command.arg(rev);
|
||||
command.kill_on_drop(true);
|
||||
let output = command.output().await?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"Failing to git reset: {}",
|
||||
String::from_utf8(output.stderr)?
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn git_clean<P>(
|
||||
dest: P,
|
||||
recurse_into_untracked_directories: bool, // -d
|
||||
force: bool, // -f
|
||||
dont_use_ignore_rules: bool, // -x
|
||||
) -> Result<(), CustomError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
// git -C $dest clean [-dfx]
|
||||
|
||||
let dest = AsRef::<OsStr>::as_ref(dest.as_ref());
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C");
|
||||
command.arg(dest);
|
||||
command.args(&["clean"]);
|
||||
if recurse_into_untracked_directories {
|
||||
command.arg("-d");
|
||||
}
|
||||
if force {
|
||||
command.arg("--force");
|
||||
}
|
||||
if dont_use_ignore_rules {
|
||||
command.arg("-x");
|
||||
}
|
||||
command.kill_on_drop(true);
|
||||
let output = command.output().await?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"Failing to git clean: {}",
|
||||
String::from_utf8(output.stderr)?
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
85
src/git_util/high_level.rs
Normal file
85
src/git_util/high_level.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use crate::error::CustomError;
|
||||
use crate::fs_util::assert_directory;
|
||||
use crate::git_util::git_checkout;
|
||||
use crate::git_util::git_clean;
|
||||
use crate::git_util::git_fetch;
|
||||
use crate::git_util::git_get_remote;
|
||||
use crate::git_util::git_init;
|
||||
use crate::git_util::git_remote_add;
|
||||
use std::path::Path;
|
||||
|
||||
pub(crate) async fn git_init_at_rev<P, B, U>(
|
||||
dest: P,
|
||||
branch: B,
|
||||
url: U,
|
||||
rev: &Option<String>,
|
||||
) -> Result<(), CustomError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
B: AsRef<str>,
|
||||
U: AsRef<str>,
|
||||
{
|
||||
// mkdir -p $dest
|
||||
// git -C $dest init --initial-branch=main
|
||||
// git -C $dest remote add origin $url
|
||||
// git -C $dest fetch --depth 1 origin ($rev|$branch)
|
||||
// git -C $dest checkout FETCH_HEAD
|
||||
|
||||
assert_directory!(&dest, "Cloning git repo into {}", dest.as_ref().display());
|
||||
|
||||
let fetch_target = rev.as_deref().unwrap_or(branch.as_ref());
|
||||
|
||||
git_init(&dest, "main").await?;
|
||||
git_remote_add(&dest, "origin", url).await?;
|
||||
git_fetch(&dest, "origin", fetch_target, Some(1), false, false).await?;
|
||||
git_checkout(&dest, "FETCH_HEAD", false, false).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn git_force_into_state<P, B, R, U>(
|
||||
dest: P,
|
||||
branch: B,
|
||||
remote: R,
|
||||
url: U,
|
||||
rev: &Option<String>,
|
||||
) -> Result<(), CustomError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
B: AsRef<str>,
|
||||
R: AsRef<str>,
|
||||
U: AsRef<str>,
|
||||
{
|
||||
// Maybe instead
|
||||
// git -C $dest fetch --depth 1 $remote ($rev|$branch)
|
||||
// git -C $dest checkout --detach --force FETCH_HEAD
|
||||
// git -C $dest clean -dfx
|
||||
|
||||
let fetch_target = rev.as_deref().unwrap_or(branch.as_ref());
|
||||
|
||||
check_remote_correct(&dest, &remote, url).await?;
|
||||
git_fetch(&dest, &remote, fetch_target, Some(1), false, false).await?;
|
||||
git_checkout(&dest, "FETCH_HEAD", true, true).await?;
|
||||
git_clean(&dest, true, true, true).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn check_remote_correct<F, R, U>(folder: F, remote: R, url: U) -> Result<(), CustomError>
|
||||
where
|
||||
F: AsRef<Path>,
|
||||
R: AsRef<str>,
|
||||
U: AsRef<str>,
|
||||
{
|
||||
let existing_remote = git_get_remote(folder, &remote).await?;
|
||||
if existing_remote != url.as_ref() {
|
||||
return Err(format!(
|
||||
"Existing remote {} does not have the expected URL {} != {}",
|
||||
remote.as_ref(),
|
||||
existing_remote,
|
||||
url.as_ref()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
4
src/git_util/mod.rs
Normal file
4
src/git_util/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod core;
|
||||
mod high_level;
|
||||
pub(crate) use core::*;
|
||||
pub(crate) use high_level::*;
|
||||
@@ -13,6 +13,8 @@ mod cli;
|
||||
mod command;
|
||||
mod config;
|
||||
mod error;
|
||||
mod fs_util;
|
||||
mod git_util;
|
||||
mod init_tracing;
|
||||
|
||||
fn main() -> Result<ExitCode, CustomError> {
|
||||
|
||||
Reference in New Issue
Block a user