mirror of
https://codeberg.org/icewind/haze.git
synced 2026-06-03 09:04:12 +02:00
git pull command
This commit is contained in:
parent
d86ee53f66
commit
1804a7fd93
7 changed files with 121 additions and 37 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1011,7 +1011,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.5.2",
|
"hermit-abi 0.5.2",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
30
flake.lock
generated
30
flake.lock
generated
|
|
@ -22,11 +22,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1748868585,
|
"lastModified": 1763383859,
|
||||||
"narHash": "sha256-DrrbahOQAwvNM8l5EuGxxkVS7X5/S59zcG0N9ZWQFhk=",
|
"narHash": "sha256-f4sICqPgoDv4yMYOt5j7UikDoqYtt1DgR5ECxpitUHI=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "flakelight",
|
"repo": "flakelight",
|
||||||
"rev": "dfbecd12d99c1bf82906521a6a7d5b75d2aa1ca2",
|
"rev": "3cea16878d9e296da0c40e2cc22ebcd15696e70c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -44,26 +44,26 @@
|
||||||
"rust-overlay": "rust-overlay"
|
"rust-overlay": "rust-overlay"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1747926214,
|
"lastModified": 1763591898,
|
||||||
"narHash": "sha256-e/7klyoQpe9wsYeQIUfm/9Yqa78et24L+nSpsCz937k=",
|
"narHash": "sha256-aHSMj7CIa9EJYxdf05wOWRGp0KRsT/TAox7uwVSdDb8=",
|
||||||
"owner": "icewind1991",
|
"ref": "refs/heads/main",
|
||||||
"repo": "mill-scale",
|
"rev": "2d9b2da2c9f384f93ef977c48f8ee35ce586529b",
|
||||||
"rev": "394979573123e5d4762d29cc78b5e11b3d35cc6b",
|
"revCount": 66,
|
||||||
"type": "github"
|
"type": "git",
|
||||||
|
"url": "https://codeberg.org/icewind/mill-scale.git"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "icewind1991",
|
"type": "git",
|
||||||
"repo": "mill-scale",
|
"url": "https://codeberg.org/icewind/mill-scale.git"
|
||||||
"type": "github"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1749086602,
|
"lastModified": 1763622513,
|
||||||
"narHash": "sha256-DJcgJMekoxVesl9kKjfLPix2Nbr42i7cpEHJiTnBUwU=",
|
"narHash": "sha256-1jQnuyu82FpiSxowrF/iFK6Toh9BYprfDqfs4BB+19M=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "4792576cb003c994bd7cc1edada3129def20b27d",
|
"rev": "c58bc7f5459328e4afac201c5c4feb7c818d604b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
mill-scale = {
|
mill-scale = {
|
||||||
url = "github:icewind1991/mill-scale";
|
url = "git+https://codeberg.org/icewind/mill-scale.git";
|
||||||
inputs.flakelight.follows = "flakelight";
|
inputs.flakelight.follows = "flakelight";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
rustPlatform,
|
rustPlatform,
|
||||||
pkg-config,
|
pkg-config,
|
||||||
lib,
|
lib,
|
||||||
|
git,
|
||||||
}: let
|
}: let
|
||||||
|
inherit (lib) getExe;
|
||||||
inherit (lib.sources) sourceByRegex;
|
inherit (lib.sources) sourceByRegex;
|
||||||
inherit (builtins) fromTOML readFile;
|
inherit (builtins) fromTOML readFile;
|
||||||
src = sourceByRegex ../. ["Cargo.*" "(src|redis-certificates)(/.*)?"];
|
src = sourceByRegex ../. ["Cargo.*" "(src|redis-certificates)(/.*)?"];
|
||||||
|
|
@ -13,6 +15,8 @@ in
|
||||||
|
|
||||||
inherit src version;
|
inherit src version;
|
||||||
|
|
||||||
|
GIT_BINARY = getExe git;
|
||||||
|
|
||||||
cargoLock = {
|
cargoLock = {
|
||||||
lockFile = ../Cargo.lock;
|
lockFile = ../Cargo.lock;
|
||||||
outputHashes = {
|
outputHashes = {
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,8 @@ pub enum HazeArgs {
|
||||||
)]
|
)]
|
||||||
#[strum(serialize_all = "lowercase")]
|
#[strum(serialize_all = "lowercase")]
|
||||||
pub enum GitOperation {
|
pub enum GitOperation {
|
||||||
|
/// Pull the active branch in all apps
|
||||||
|
Pull,
|
||||||
/// Checkout a branch in all apps
|
/// Checkout a branch in all apps
|
||||||
///
|
///
|
||||||
/// "main" and "master" can be used interchangeably.
|
/// "main" and "master" can be used interchangeably.
|
||||||
|
|
@ -333,6 +335,9 @@ impl HazeArgs {
|
||||||
operation: GitOperation::Checkout { branch },
|
operation: GitOperation::Checkout { branch },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
"pull" => Ok(HazeArgs::Git {
|
||||||
|
operation: GitOperation::Pull,
|
||||||
|
}),
|
||||||
operation => Err(Report::msg(format!("Unknown git operation {operation}"))),
|
operation => Err(Report::msg(format!("Unknown git operation {operation}"))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
110
src/git.rs
110
src/git.rs
|
|
@ -1,33 +1,105 @@
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use git2::build::CheckoutBuilder;
|
use git2::build::CheckoutBuilder;
|
||||||
use git2::{Branch, BranchType, ObjectType, Repository};
|
use git2::{Branch, BranchType, ObjectType, Repository, RepositoryState};
|
||||||
use miette::{Context, IntoDiagnostic};
|
use miette::{Context, IntoDiagnostic};
|
||||||
use std::fs::read_dir;
|
use std::fs::read_dir;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
fn find_app_repos(root: impl AsRef<Path>) -> Result<impl Iterator<Item = PathBuf>> {
|
||||||
|
let apps_dir = root.as_ref().join("apps");
|
||||||
|
Ok(read_dir(apps_dir)
|
||||||
|
.into_diagnostic()?
|
||||||
|
.flatten()
|
||||||
|
.filter(|app| app.path().join(".git").is_dir())
|
||||||
|
.map(|app| app.path()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn longest_app_branch(root: impl AsRef<Path>) -> Result<(usize, usize)> {
|
||||||
|
Ok(find_app_repos(root)?
|
||||||
|
.filter_map(|app_dir| {
|
||||||
|
let app_name = app_dir.file_name()?.to_str()?;
|
||||||
|
let repo = Repository::init(&app_dir).ok()?;
|
||||||
|
let branch_name = current_branch_name(&repo)?;
|
||||||
|
Some((app_name.len(), branch_name.len()))
|
||||||
|
})
|
||||||
|
.max()
|
||||||
|
.unwrap_or_default())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn checkout_all<P: AsRef<Path>>(sources_root: P, mut name: &str) -> Result<()> {
|
pub fn checkout_all<P: AsRef<Path>>(sources_root: P, mut name: &str) -> Result<()> {
|
||||||
// "main" and "master" are interchangeable
|
// "main" and "master" are interchangeable
|
||||||
if name == "main" {
|
if name == "main" {
|
||||||
name = "master";
|
name = "master";
|
||||||
}
|
}
|
||||||
let apps_dir = sources_root.as_ref().join("apps");
|
|
||||||
for app in read_dir(apps_dir).into_diagnostic()? {
|
for app_dir in find_app_repos(sources_root)? {
|
||||||
let app = app.into_diagnostic()?;
|
let repo = Repository::init(&app_dir)
|
||||||
if app.metadata().into_diagnostic()?.is_dir() && app.path().join(".git").is_dir() {
|
.into_diagnostic()
|
||||||
let app_dir = app.path();
|
.wrap_err_with(|| format!("Failed to open repository {}", app_dir.display()))?;
|
||||||
let repo = Repository::init(&app_dir)
|
if let Some(branch) = get_branch(&repo, name)? {
|
||||||
.into_diagnostic()
|
if !branch.is_head() {
|
||||||
.wrap_err_with(|| format!("Failed to open repository {}", app_dir.display()))?;
|
print!("{}", app_dir.file_name().unwrap().to_string_lossy());
|
||||||
if let Some(branch) = get_branch(&repo, name)? {
|
if let Err(e) = checkout(&repo, branch) {
|
||||||
if !branch.is_head() {
|
println!(": {:#} ❌", e);
|
||||||
print!("{}", app.file_name().to_string_lossy());
|
} else {
|
||||||
if let Err(e) = checkout(&repo, branch) {
|
println!(" ✓");
|
||||||
println!(": {:#} ❌", e);
|
|
||||||
} else {
|
|
||||||
println!(" ✓");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_branch_name(repo: &Repository) -> Option<String> {
|
||||||
|
let (branch, _) = repo
|
||||||
|
.branches(None)
|
||||||
|
.ok()?
|
||||||
|
.flatten()
|
||||||
|
.find(|(b, _)| b.is_head())?;
|
||||||
|
|
||||||
|
branch.name().ok().flatten().map(String::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
const GIT_BINARY: &str = match option_env!("GIT_BINARY") {
|
||||||
|
Some(git) => git,
|
||||||
|
None => "git",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn pull_all<P: AsRef<Path>>(sources_root: P) -> Result<()> {
|
||||||
|
let sources_root = sources_root.as_ref();
|
||||||
|
let (max_app, max_branch) = longest_app_branch(sources_root)?;
|
||||||
|
|
||||||
|
for app_dir in find_app_repos(sources_root)? {
|
||||||
|
let app_name = app_dir.file_name().unwrap().to_string_lossy();
|
||||||
|
let repo = Repository::init(&app_dir)
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err_with(|| format!("Failed to open repository {}", app_dir.display()))?;
|
||||||
|
let branch_name = current_branch_name(&repo).unwrap_or("unknown".into());
|
||||||
|
|
||||||
|
print!(
|
||||||
|
"{app_name:<app_width$} - {branch_name:<branch_width$}",
|
||||||
|
app_width = max_app,
|
||||||
|
branch_width = max_branch
|
||||||
|
);
|
||||||
|
|
||||||
|
if repo.state() != RepositoryState::Clean {
|
||||||
|
println!(": repository not clean ❌");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = Command::new(GIT_BINARY)
|
||||||
|
.arg("pull")
|
||||||
|
.current_dir(&app_dir)
|
||||||
|
.output()
|
||||||
|
.into_diagnostic()
|
||||||
|
.wrap_err_with(|| format!("Failed to run git pull for {}", app_dir.display()))?;
|
||||||
|
|
||||||
|
if output.status.success() {
|
||||||
|
println!(" ✓");
|
||||||
|
} else {
|
||||||
|
println!(" ❌");
|
||||||
|
eprintln!("{}", String::from_utf8_lossy(&output.stderr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::cloud::{Cloud, CloudOptions};
|
||||||
use crate::config::HazeConfig;
|
use crate::config::HazeConfig;
|
||||||
use crate::database::DatabaseFamily;
|
use crate::database::DatabaseFamily;
|
||||||
use crate::exec::{container_logs, exec, exec_tty};
|
use crate::exec::{container_logs, exec, exec_tty};
|
||||||
use crate::git::checkout_all;
|
use crate::git::{checkout_all, pull_all};
|
||||||
use crate::help::help;
|
use crate::help::help;
|
||||||
use crate::image::update_image;
|
use crate::image::update_image;
|
||||||
use crate::network::clear_networks;
|
use crate::network::clear_networks;
|
||||||
|
|
@ -366,6 +366,9 @@ async fn main() -> Result<ExitCode> {
|
||||||
GitOperation::Checkout { branch } => {
|
GitOperation::Checkout { branch } => {
|
||||||
checkout_all(&config.sources_root, &branch)?;
|
checkout_all(&config.sources_root, &branch)?;
|
||||||
}
|
}
|
||||||
|
GitOperation::Pull => {
|
||||||
|
pull_all(&config.sources_root)?;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
HazeArgs::Env {
|
HazeArgs::Env {
|
||||||
filter,
|
filter,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue