Revert to v0.6

This commit is contained in:
Breadway 2026-05-17 08:33:00 +08:00
parent 3a46f0ac7c
commit 918045695d
6 changed files with 93 additions and 64 deletions

6
Cargo.lock generated
View file

@ -293,7 +293,7 @@ dependencies = [
[[package]] [[package]]
name = "bread-cli" name = "bread-cli"
version = "1.0.0" version = "0.6.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bread-shared", "bread-shared",
@ -311,7 +311,7 @@ dependencies = [
[[package]] [[package]]
name = "bread-shared" name = "bread-shared"
version = "1.0.0" version = "0.6.0"
dependencies = [ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
@ -319,7 +319,7 @@ dependencies = [
[[package]] [[package]]
name = "breadd" name = "breadd"
version = "1.0.0" version = "0.6.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "bread-cli" name = "bread-cli"
version = "1.0.0" version = "0.6.0"
edition = "2021" edition = "2021"
[[bin]] [[bin]]

View file

@ -1,6 +1,6 @@
[package] [package]
name = "bread-shared" name = "bread-shared"
version = "1.0.0" version = "0.6.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]

View file

@ -120,18 +120,22 @@ static DEFAULT_EXCLUDES: &[&str] = &[
/// Directories skipped when searching for git repos. /// Directories skipped when searching for git repos.
static GIT_SKIP_DIRS: &[&str] = &[ static GIT_SKIP_DIRS: &[&str] = &[
".local", "Nextcloud", "target", "node_modules", "__pycache__", ".local",
".cache", "snap", "flatpak", "@girs", "Steam", "Nextcloud",
"target",
"node_modules",
"__pycache__",
".cache",
"snap",
"flatpak",
"@girs",
"Steam",
]; ];
// ── stage_export ──────────────────────────────────────────────────────────── // ── stage_export ────────────────────────────────────────────────────────────
/// Build a self-contained snapshot directory at `staging`. /// Build a self-contained snapshot directory at `staging`.
pub fn stage_export( pub fn stage_export(cfg_dir: &Path, config: &SyncConfig, staging: &Path) -> Result<ExportManifest> {
cfg_dir: &Path,
config: &SyncConfig,
staging: &Path,
) -> Result<ExportManifest> {
fs::create_dir_all(staging)?; fs::create_dir_all(staging)?;
let excludes: Vec<String> = DEFAULT_EXCLUDES.iter().map(|s| s.to_string()).collect(); let excludes: Vec<String> = DEFAULT_EXCLUDES.iter().map(|s| s.to_string()).collect();
@ -238,8 +242,7 @@ pub fn stage_export(
let fonts_src = expand_path("~/.local/share/fonts"); let fonts_src = expand_path("~/.local/share/fonts");
let fonts_dst = staging.join("local-fonts"); let fonts_dst = staging.join("local-fonts");
if fonts_src.exists() { if fonts_src.exists() {
sync_dir(&fonts_src, &fonts_dst, &excludes) sync_dir(&fonts_src, &fonts_dst, &excludes).context("failed to snapshot fonts")?;
.context("failed to snapshot fonts")?;
path_map.push(PathRecord { path_map.push(PathRecord {
staging: "local-fonts".to_string(), staging: "local-fonts".to_string(),
original: "~/.local/share/fonts".to_string(), original: "~/.local/share/fonts".to_string(),
@ -292,9 +295,7 @@ pub fn stage_export(
match packages::snapshot(manager, &dest_file) { match packages::snapshot(manager, &dest_file) {
Ok(true) => included_managers.push(manager.clone()), Ok(true) => included_managers.push(manager.clone()),
Ok(false) => {} Ok(false) => {}
Err(e) => eprintln!( Err(e) => eprintln!("bread: warning: package snapshot for {manager} failed: {e}"),
"bread: warning: package snapshot for {manager} failed: {e}"
),
} }
} }
} }
@ -307,10 +308,18 @@ pub fn stage_export(
// 11. Git repositories — find all repos with a remote, commit+push each // 11. Git repositories — find all repos with a remote, commit+push each
let nc_dirs = nextcloud_sync_dirs(&home); let nc_dirs = nextcloud_sync_dirs(&home);
if !nc_dirs.is_empty() { if !nc_dirs.is_empty() {
let labels: Vec<_> = nc_dirs.iter() let labels: Vec<_> = nc_dirs
.map(|p| p.strip_prefix(&home).map(|r| format!("~/{}", r.display())).unwrap_or_else(|_| p.display().to_string())) .iter()
.map(|p| {
p.strip_prefix(&home)
.map(|r| format!("~/{}", r.display()))
.unwrap_or_else(|_| p.display().to_string())
})
.collect(); .collect();
eprintln!("bread: skipping Nextcloud-tracked folders: {}", labels.join(", ")); eprintln!(
"bread: skipping Nextcloud-tracked folders: {}",
labels.join(", ")
);
} }
let repos = find_git_repos(&home); let repos = find_git_repos(&home);
commit_and_push_repos(&repos, &home); commit_and_push_repos(&repos, &home);
@ -565,10 +574,7 @@ fn commit_and_push_repos(repos: &[GitRepoRecord], home: &Path) {
.output(); .output();
match push { match push {
Ok(o) if o.status.success() => eprintln!("ok"), Ok(o) if o.status.success() => eprintln!("ok"),
Ok(o) => eprintln!( Ok(o) => eprintln!("failed: {}", String::from_utf8_lossy(&o.stderr).trim()),
"failed: {}",
String::from_utf8_lossy(&o.stderr).trim()
),
Err(e) => eprintln!("failed: {}", e), Err(e) => eprintln!("failed: {}", e),
} }
} }
@ -611,7 +617,15 @@ fn find_git_repos(home: &Path) -> Vec<GitRepoRecord> {
walk_repos(home, home, 0, 1, &mut repos, &nc_dirs); walk_repos(home, home, 0, 1, &mut repos, &nc_dirs);
// Deeper search in common project directories // Deeper search in common project directories
for subdir in &["Projects", "Documents", "src", "dev", "code", "repos", "builds"] { for subdir in &[
"Projects",
"Documents",
"src",
"dev",
"code",
"repos",
"builds",
] {
let p = home.join(subdir); let p = home.join(subdir);
if p.exists() { if p.exists() {
walk_repos(&p, home, 0, 3, &mut repos, &nc_dirs); walk_repos(&p, home, 0, 3, &mut repos, &nc_dirs);
@ -630,7 +644,14 @@ fn find_git_repos(home: &Path) -> Vec<GitRepoRecord> {
repos repos
} }
fn walk_repos(dir: &Path, home: &Path, depth: u32, max_depth: u32, repos: &mut Vec<GitRepoRecord>, nc_dirs: &[PathBuf]) { fn walk_repos(
dir: &Path,
home: &Path,
depth: u32,
max_depth: u32,
repos: &mut Vec<GitRepoRecord>,
nc_dirs: &[PathBuf],
) {
// Skip anything inside a Nextcloud sync root // Skip anything inside a Nextcloud sync root
if nc_dirs.iter().any(|nc| dir.starts_with(nc)) { if nc_dirs.iter().any(|nc| dir.starts_with(nc)) {
return; return;
@ -655,7 +676,11 @@ fn walk_repos(dir: &Path, home: &Path, depth: u32, max_depth: u32, repos: &mut V
.map(|p| p.to_string_lossy().to_string()) .map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|_| dir.to_string_lossy().to_string()); .unwrap_or_else(|_| dir.to_string_lossy().to_string());
repos.push(GitRepoRecord { path: rel, remote, branch }); repos.push(GitRepoRecord {
path: rel,
remote,
branch,
});
} }
} }
return; // don't recurse into git repos (skip submodules) return; // don't recurse into git repos (skip submodules)
@ -700,7 +725,9 @@ fn install_packages_from(packages_dir: &Path) -> Result<()> {
let cargo_file = packages_dir.join("cargo.txt"); let cargo_file = packages_dir.join("cargo.txt");
if cargo_file.exists() { if cargo_file.exists() {
for pkg in packages::parse_cargo(&fs::read_to_string(&cargo_file)?) { for pkg in packages::parse_cargo(&fs::read_to_string(&cargo_file)?) {
let _ = std::process::Command::new("cargo").args(["install", &pkg]).status(); let _ = std::process::Command::new("cargo")
.args(["install", &pkg])
.status();
} }
} }
let pip_file = packages_dir.join("pip.txt"); let pip_file = packages_dir.join("pip.txt");
@ -713,7 +740,9 @@ fn install_packages_from(packages_dir: &Path) -> Result<()> {
let npm_file = packages_dir.join("npm.txt"); let npm_file = packages_dir.join("npm.txt");
if npm_file.exists() { if npm_file.exists() {
for pkg in packages::parse_npm(&fs::read_to_string(&npm_file)?) { for pkg in packages::parse_npm(&fs::read_to_string(&npm_file)?) {
let _ = std::process::Command::new("npm").args(["install", "-g", &pkg]).status(); let _ = std::process::Command::new("npm")
.args(["install", "-g", &pkg])
.status();
} }
} }
Ok(()) Ok(())
@ -787,7 +816,9 @@ fn generate_restore_sh(manifest: &ExportManifest) -> String {
s.push_str("echo \" cargo: grep -v '^ ' \\\"$RESTORE_DIR/packages/cargo.txt\\\" | awk '{print \\$1}' | xargs -I{} cargo install {}\"\n"); s.push_str("echo \" cargo: grep -v '^ ' \\\"$RESTORE_DIR/packages/cargo.txt\\\" | awk '{print \\$1}' | xargs -I{} cargo install {}\"\n");
} }
if manifest.packages.contains(&"pip".to_string()) { if manifest.packages.contains(&"pip".to_string()) {
s.push_str("echo \" pip: pip install --user -r \\\"$RESTORE_DIR/packages/pip.txt\\\"\"\n"); s.push_str(
"echo \" pip: pip install --user -r \\\"$RESTORE_DIR/packages/pip.txt\\\"\"\n",
);
} }
if manifest.packages.contains(&"npm".to_string()) { if manifest.packages.contains(&"npm".to_string()) {
s.push_str("echo \" npm: awk -F/ '{print \\$NF}' \\\"$RESTORE_DIR/packages/npm.txt\\\" | xargs npm install -g\"\n"); s.push_str("echo \" npm: awk -F/ '{print \\$NF}' \\\"$RESTORE_DIR/packages/npm.txt\\\" | xargs npm install -g\"\n");
@ -832,9 +863,7 @@ fn generate_restore_sh(manifest: &ExportManifest) -> String {
if !parent.is_empty() { if !parent.is_empty() {
s.push_str(&format!("mkdir -p \"$HOME/{parent}\"\n")); s.push_str(&format!("mkdir -p \"$HOME/{parent}\"\n"));
} }
s.push_str(&format!( s.push_str(&format!("if [ ! -d \"{dest}/.git\" ]; then\n"));
"if [ ! -d \"{dest}/.git\" ]; then\n"
));
s.push_str(&format!( s.push_str(&format!(
" git clone --branch {branch} {remote} \"{dest}\" && echo \"[OK] ~/{}\"\n", " git clone --branch {branch} {remote} \"{dest}\" && echo \"[OK] ~/{}\"\n",
repo.path repo.path

View file

@ -1,6 +1,6 @@
[package] [package]
name = "breadd" name = "breadd"
version = "1.0.0" version = "0.6.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]

View file

@ -1,7 +1,7 @@
# Maintainer: Breadway <rileyhorsham@gmail.com> # Maintainer: Breadway <rileyhorsham@gmail.com>
pkgname=bread pkgname=bread
pkgver=1.0.0 pkgver=0.6.0
pkgrel=1 pkgrel=1
pkgdesc="A reactive automation fabric for Linux desktops" pkgdesc="A reactive automation fabric for Linux desktops"
arch=('x86_64') arch=('x86_64')