From 57f56aff0e0c3b294348b1596fae31e5946bfb3b Mon Sep 17 00:00:00 2001 From: Michal S Date: Sat, 20 Aug 2022 21:54:47 +0100 Subject: [PATCH] Added PKGBUILD editing and saving --- Cargo.lock | 143 ++++++++++++++++++++++++++++++++++ Cargo.toml | 3 +- src/main.rs | 58 +++++++------- src/operations/aur_install.rs | 131 ++++++++++++++++++++----------- src/operations/upgrade.rs | 2 +- 5 files changed, 262 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb77f6b..8934e77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,7 @@ version = 3 name = "Amethyst" version = "3.5.0" dependencies = [ + "chrono", "clap", "colored", "libc", @@ -18,6 +19,15 @@ dependencies = [ "ureq", ] +[[package]] +name = "android_system_properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" +dependencies = [ + "libc", +] + [[package]] name = "atty" version = "0.2.14" @@ -47,6 +57,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + [[package]] name = "cc" version = "1.0.73" @@ -59,6 +75,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time", + "wasm-bindgen", + "winapi", +] + [[package]] name = "chunked_transfer" version = "1.4.0" @@ -187,6 +218,19 @@ dependencies = [ "libc", ] +[[package]] +name = "iana-time-zone" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "js-sys", + "wasm-bindgen", + "winapi", +] + [[package]] name = "idna" version = "0.2.3" @@ -223,6 +267,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +[[package]] +name = "js-sys" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -292,6 +345,25 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "once_cell" version = "1.13.1" @@ -636,6 +708,17 @@ dependencies = [ "terminal_size", ] +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -712,6 +795,66 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index b1af406..55869e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,4 +27,5 @@ serde = { version = "1.0.138", default-features = false, features = [ "derive", native-tls = { version = "0.2.10", default-features = false } libc = { version = "0.2.126", default-features = false } rm_rf = { version = "0.6.2", default-features = false } -spinoff = { version = "0.5.2", default-features = false } \ No newline at end of file +spinoff = { version = "0.5.2", default-features = false } +chrono = "0.4.22" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index b972a23..49ad31b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -89,42 +89,44 @@ fn cmd_install(args: InstallArgs, options: Options) { } if !sorted.aur.is_empty() { // If AUR packages found, install them - operations::aur_install(sorted.aur.clone(), options); + operations::aur_install(sorted.aur.clone(), options, "".to_string()); } // Show optional dependencies for installed packages - info!("Showing optional dependencies for installed packages"); - for r in sorted.repo { - info!("{}:", r); - std::process::Command::new("expac") - .args(&["-S", "-l", "\n ", " %O", &r]) - .spawn() - .unwrap() - .wait() - .unwrap(); - } - for a in sorted.aur { - info!("{}:", a); - let dir_bytes = std::process::Command::new("mktemp") - .arg("-d") - .output() - .unwrap() - .stdout; - let dir = String::from_utf8(dir_bytes).unwrap(); - std::process::Command::new("bash") - .arg("-c") - .arg(format!("\ + if packages.len() > 1 { + info!("Showing optional dependencies for installed packages"); + for r in sorted.repo { + info!("{}:", r); + std::process::Command::new("expac") + .args(&["-S", "-l", "\n ", " %O", &r]) + .spawn() + .unwrap() + .wait() + .unwrap(); + } + for a in sorted.aur { + info!("{}:", a); + let dir_bytes = std::process::Command::new("mktemp") + .arg("-d") + .output() + .unwrap() + .stdout; + let dir = String::from_utf8(dir_bytes).unwrap(); + std::process::Command::new("bash") + .arg("-c") + .arg(format!("\ cd {} curl -L https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h={} -o PKGBUILD -s source PKGBUILD printf ' %s\\n' \"${{optdepends[@]}}\"\ ", dir, a)) - .stderr(std::process::Stdio::piped()) - .spawn() - .unwrap() - .wait() - .unwrap(); - std::fs::remove_dir_all(&std::path::Path::new(&dir.trim())).unwrap(); + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap() + .wait() + .unwrap(); + std::fs::remove_dir_all(&std::path::Path::new(&dir.trim())).unwrap(); + } } } diff --git a/src/operations/aur_install.rs b/src/operations/aur_install.rs index d012ac5..dfe9b16 100644 --- a/src/operations/aur_install.rs +++ b/src/operations/aur_install.rs @@ -28,10 +28,24 @@ fn list(dir: &str) -> Vec { dirs } -pub fn aur_install(a: Vec, options: Options) { +fn mktemp() -> String { + let tempdir = Command::new("mktemp") + .args(&["-d", "/tmp/ame.XXXXXX.tmp"]) + .output() + .unwrap() + .stdout; + + String::from_utf8(tempdir).unwrap().trim().to_string() +} + +pub fn aur_install(a: Vec, options: Options, cachedir: String) { // Initialise variables let url = crate::internal::rpc::URL; - let cachedir = format!("{}/.cache/ame/", env::var("HOME").unwrap()); + let cachedir = if !options.toplevel { + cachedir + } else { + mktemp() + }; let verbosity = options.verbosity; let noconfirm = options.noconfirm; @@ -155,43 +169,59 @@ pub fn aur_install(a: Vec, options: Options) { if !noconfirm { // Prompt user to view PKGBUILD - let p1 = prompt!(default false, - "Would you like to review {}'s PKGBUILD (and any .install files if present)?", - pkg - ); - let editor: &str = &env::var("PAGER").unwrap_or_else(|_| "less".parse().unwrap()); - - if p1 { - // Open PKGBUILD in pager - Command::new(editor) - .arg(format!("{}/PKGBUILD", pkg)) - .spawn() - .unwrap() - .wait() - .unwrap(); - - // Check if any .install files are present - let status = ShellCommand::bash() - .arg("-c") - .arg(format!("ls {}/*.install &> /dev/null", pkg)) - .wait() - .silent_unwrap(AppExitCode::Other); - - if status.success() { - // If so, open them too - ShellCommand::bash() - .arg("-c") - .arg(format!("{} {}/*.install", editor, pkg)) - .wait() - .silent_unwrap(AppExitCode::Other); - } - - // Prompt user to continue - let p2 = prompt!(default true, "Would you still like to install {}?", pkg); - if !p2 { - // If not, crash - fs::remove_dir_all(format!("{}/{}", cachedir, pkg)).unwrap(); - crash!(AppExitCode::UserCancellation, "Not proceeding"); + let p0 = prompt!(default false, "Would you like to review and/or edit {}'s PKGBUILD (and any adjacent build files if present)?", pkg); + if p0 { + info!("This will drop you into a standard `bash` shell in the package's cache directory. If any changes are made, you will be prompted whether to save them to your home directory. To stop reviewing/editing, just run `exit`"); + let p1 = prompt!(default true, + "Continue?" + ); + + if p1 { + let cdir = env::current_dir().unwrap().to_str().unwrap().to_string(); + set_current_dir(Path::new(&format!("{}/{}", &cachedir, pkg))).unwrap(); + + Command::new("bash").spawn().unwrap().wait().unwrap(); + + set_current_dir(Path::new(&cdir)).unwrap(); + + // Prompt user to save changes + let p2 = prompt!(default false, + "Save changes to package {}?", + pkg + ); + if p2 { + // Save changes to ~/.local/share + let dest = format!( + "{}-saved-{}", + pkg, + chrono::Local::now() + .naive_local() + .format("%Y-%m-%d_%H-%M-%S") + ); + Command::new("cp") + .arg("-r") + .arg(format!("{}/{}", cachedir, pkg)) + .arg(format!( + "{}/.local/share/ame/{}", + env::var("HOME").unwrap(), + dest + )) + .spawn() + .unwrap() + .wait() + .unwrap(); + + // Alert user + info!("Saved changes to ~/.local/share/ame/{}", dest); + }; + + // Prompt user to continue + let p3 = prompt!(default true, "Would you still like to install {}?", pkg); + if !p3 { + // If not, crash + fs::remove_dir_all(format!("{}/{}", cachedir, pkg)).unwrap(); + crash!(AppExitCode::UserCancellation, "Not proceeding"); + }; } } } @@ -203,13 +233,13 @@ pub fn aur_install(a: Vec, options: Options) { crate::operations::install(sorted.repo, newopts); } if !sorted.aur.is_empty() { - crate::operations::aur_install(sorted.aur, newopts); + crate::operations::aur_install(sorted.aur, newopts, cachedir.clone()); } if !md_sorted.repo.is_empty() { crate::operations::install(md_sorted.repo, newopts); } if !md_sorted.aur.is_empty() { - crate::operations::aur_install(md_sorted.aur, newopts); + crate::operations::aur_install(md_sorted.aur, newopts, cachedir.clone()); } // Build makepkg args @@ -270,14 +300,25 @@ pub fn aur_install(a: Vec, options: Options) { .unwrap() .wait() .unwrap(); - - // Remove everything from cachedir - crate::init(options); } } // If any packages failed to build, warn user with failed packages if !failed.is_empty() { - warn!("Failed to build packages {}", failed.join(", ")); + warn!( + "Failed to build packages {}, keeping cache directory at {} for manual inspection", + failed.join(", "), + cachedir + ); + Command::new("mv") + .args(&[&cachedir, &format!("{}.failed", cachedir)]) + .spawn() + .unwrap() + .wait() + .unwrap(); + } else if options.toplevel { + rm_rf::remove(&cachedir).unwrap_or_else(|e| + crash!(AppExitCode::Other, "Could not remove cache directory at {}: {}. This could be a permissions issue with fakeroot, try running `sudo rm -rf {}`", cachedir, e, cachedir) + ); } } diff --git a/src/operations/upgrade.rs b/src/operations/upgrade.rs index b24c106..dcd901f 100644 --- a/src/operations/upgrade.rs +++ b/src/operations/upgrade.rs @@ -128,7 +128,7 @@ pub fn upgrade(options: Options, args: UpgradeArgs) { aur_upgrades.join(", "), ); if cont { - aur_install(aur_upgrades, options); + aur_install(aur_upgrades, options, "".to_string()); }; } else { info!("No upgrades available for installed AUR packages");