diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3a0068d..f4f67e33 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,21 +20,22 @@ env: CONTRIBUTORS_TOKEN: ${{ secrets.CONTRIBUTORS_TOKEN }} IS_CI: true IS_RELEASE: ${{ startsWith(github.ref, 'refs/tags/') }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_PUBLISH_TOKEN }} jobs: cargo-deny: runs-on: ubuntu-latest continue-on-error: true steps: - - uses: actions/checkout@v4 - - uses: EmbarkStudios/cargo-deny-action@v2 + - uses: actions/checkout@v4.2.2 + - uses: EmbarkStudios/cargo-deny-action@v2.0.4 clippy: name: Clippy runs-on: windows-latest steps: - - uses: actions/checkout@v4 - - uses: Swatinem/rust-cache@v2.7.3 + - uses: actions/checkout@v4.2.2 + - uses: Swatinem/rust-cache@v2.7.5 - name: Install Rust uses: dtolnay/rust-toolchain@stable @@ -49,7 +50,7 @@ jobs: name: Formatting runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.2.2 - name: Install Rust uses: dtolnay/rust-toolchain@stable @@ -64,11 +65,11 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v4 - - uses: Swatinem/rust-cache@v2.7.3 + - uses: actions/checkout@v4.2.2 + - uses: Swatinem/rust-cache@v2.7.5 - name: Install and setup Scoop - uses: MinoruSekine/setup-scoop@v4 + uses: MinoruSekine/setup-scoop@v4.0.1 with: buckets: extras java @@ -86,8 +87,8 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v4 - - uses: Swatinem/rust-cache@v2.7.3 + - uses: actions/checkout@v4.2.2 + - uses: Swatinem/rust-cache@v2.7.5 with: key: build-${{ matrix.arch }} - uses: extractions/setup-just@v2 @@ -105,12 +106,27 @@ jobs: needs: [cargo-deny, build, test, clippy, format] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.2.2 - uses: extractions/setup-just@v2 - name: Install Rust uses: dtolnay/rust-toolchain@stable + - name: Verify crate + run: cargo publish --dry-run + + - name: Check version matches tag + run: | + $version = (cargo metadata --format-version 1 | ConvertFrom-Json).packages[0].version + $tag = "${{ github.ref_name }}" + if ($tag -ne "v$version") { + throw "Version mismatch: tag=$tag, Cargo.toml=$version" + } + + - name: Publish to crates.io + if: ${{ !github.event.release.prerelease }} + run: cargo publish + - name: Build and Package if: ${{ !github.event.release.prerelease }} run: just release-all @@ -120,7 +136,7 @@ jobs: run: just beta-release-all - name: Upload a Build Artifact - uses: actions/upload-artifact@v4.4.0 + uses: actions/upload-artifact@v4.4.3 with: name: package.zip path: release/* @@ -133,7 +149,7 @@ jobs: release/*.exe.sha256 - name: VirusTotal Scan - uses: crazy-max/ghaction-virustotal@v4 + uses: crazy-max/ghaction-virustotal@v4.1.0 with: update_release_body: true vt_api_key: ${{ secrets.VT_API_KEY }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f78f190..b10915b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `json` flag from `app download` command - Download progress bars now show app name instead of url leaf - Download hash checks now report to a progress bar rather than a print message for each +- Logs will now go into `/logs` if running with debug assertions + +### Removed + +- `sfsu_macros` crate ## [1.15.0] - 2024-03-11 diff --git a/Cargo.lock b/Cargo.lock index 1c065c34..5074bff0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -384,9 +384,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1184,7 +1184,7 @@ dependencies = [ "regex", "signal-hook", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1212,7 +1212,7 @@ dependencies = [ "gix-object", "gix-worktree-stream", "jiff", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1292,7 +1292,7 @@ dependencies = [ "memchr", "once_cell", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", "unicode-bom", "winnow", ] @@ -1357,7 +1357,7 @@ dependencies = [ "gix-traverse", "gix-worktree", "imara-diff", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1377,7 +1377,7 @@ dependencies = [ "gix-trace", "gix-utils", "gix-worktree", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1393,7 +1393,7 @@ dependencies = [ "gix-path", "gix-ref", "gix-sec", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1437,7 +1437,7 @@ dependencies = [ "gix-trace", "gix-utils", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1522,7 +1522,7 @@ dependencies = [ "memmap2", "rustix", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1561,7 +1561,7 @@ dependencies = [ "gix-object", "gix-revwalk", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1580,7 +1580,7 @@ dependencies = [ "gix-validate", "itoa", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", "winnow", ] @@ -1602,7 +1602,7 @@ dependencies = [ "gix-quote", "parking_lot", "tempfile", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1622,7 +1622,7 @@ dependencies = [ "memmap2", "parking_lot", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", "uluru", ] @@ -1737,7 +1737,7 @@ dependencies = [ "gix-utils", "gix-validate", "memmap2", - "thiserror 2.0.4", + "thiserror 2.0.6", "winnow", ] @@ -1752,7 +1752,7 @@ dependencies = [ "gix-revision", "gix-validate", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1770,7 +1770,7 @@ dependencies = [ "gix-object", "gix-revwalk", "gix-trace", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1785,7 +1785,7 @@ dependencies = [ "gix-hashtable", "gix-object", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1820,7 +1820,7 @@ dependencies = [ "gix-pathspec", "gix-worktree", "portable-atomic", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1835,7 +1835,7 @@ dependencies = [ "gix-pathspec", "gix-refspec", "gix-url", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1893,7 +1893,7 @@ dependencies = [ "gix-object", "gix-revwalk", "smallvec", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1966,7 +1966,7 @@ dependencies = [ "gix-path", "gix-worktree", "io-close", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -1984,7 +1984,7 @@ dependencies = [ "gix-path", "gix-traverse", "parking_lot", - "thiserror 2.0.4", + "thiserror 2.0.6", ] [[package]] @@ -2453,14 +2453,6 @@ dependencies = [ "syn", ] -[[package]] -name = "instant" -version = "0.1.0" -dependencies = [ - "rightnow", - "web-time", -] - [[package]] name = "inventory" version = "0.3.15" @@ -2637,9 +2629,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libgit2-sys" @@ -3262,11 +3254,24 @@ dependencies = [ "cc", "cfg-if", "nix", - "quork-proc", + "quork-proc 0.3.2", "thiserror 1.0.69", "windows", ] +[[package]] +name = "quork" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4282adb2f46ab23e5e5c7540c5e91f71fb5cb00101a29280b1b77a6e9b2be33" +dependencies = [ + "cfg-if", + "nix", + "quork-proc 0.4.1", + "thiserror 2.0.6", + "windows", +] + [[package]] name = "quork-proc" version = "0.3.2" @@ -3280,6 +3285,19 @@ dependencies = [ "syn", ] +[[package]] +name = "quork-proc" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0386bc87f6a1770b849cd7b1127499d9fe6526ea24cc267e0c89874bc7ae5e0c" +dependencies = [ + "proc-macro-crate", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.37" @@ -3451,12 +3469,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "rightnow" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebea34613bff83746c6e173ca6259aa49771f928a73f416bc52560aab9703e82" - [[package]] name = "ring" version = "0.17.8" @@ -3770,14 +3782,13 @@ dependencies = [ "log", "open", "parking_lot", - "quork", + "quork 0.8.1", "ratatui", "rayon", "regex", "semver", "serde", "serde_json", - "sfsu-macros", "shadow-rs", "sprinkles-rs", "tokio", @@ -3790,22 +3801,6 @@ dependencies = [ "winres", ] -[[package]] -name = "sfsu-macros" -version = "0.1.0" -dependencies = [ - "anyhow", - "heck", - "proc-macro-crate", - "proc-macro-error2", - "proc-macro2", - "quork", - "quote", - "sprinkles-rs", - "strum", - "syn", -] - [[package]] name = "sha1" version = "0.10.6" @@ -3956,7 +3951,7 @@ dependencies = [ "phf", "phf_codegen", "quick-xml 0.37.1", - "quork", + "quork 0.7.2", "rayon", "regex", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index 8426a444..fc608785 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,37 +1,13 @@ [package] +authors = ["Juliette Cordor "] description = "Stupid Fast Scoop Utils" edition = "2021" -license = { workspace = true } +license = "MIT OR Apache-2.0" name = "sfsu" -publish = false +publish = true +repository = "https://github.com/winpax/sfsu" version = "1.15.0" -[workspace] -members = ["macros", "patches/*"] -package.authors = ["Juliette Cordor "] -package.homepage = "https://github.com/winpax/sfsu" -package.license = "MIT OR Apache-2.0" -package.publish = false -package.repository = "https://github.com/winpax/sfsu" - -[workspace.dependencies] -chrono = { version = "0.4", features = [ - "clock", - "serde", - "std", -], default-features = false } -console = { version = "0.15", features = ["windows-console-colors"] } -futures = "0.3" -git2 = "0.19" -heck = "0.5" -itertools = "0.13" -log = { version = "0.4", features = ["std"] } -quork = "0.7" -rayon = "1.10" -regex = "1.10" -serde = { version = "1.0", features = ["derive"] } -sprinkles-rs = { version = "0.19", features = ["clap"] } - [[bench]] harness = false name = "searching" @@ -69,7 +45,11 @@ v2 = [] anyhow = "1.0" bat = { version = "0.24", default-features = false, features = ["regex-onig"] } cfg-if = "1.0" -chrono.workspace = true +chrono = { version = "0.4", features = [ + "clock", + "serde", + "std", +], default-features = false } clap = { version = "4.5", features = [ "derive", "env", @@ -77,47 +57,42 @@ clap = { version = "4.5", features = [ "unicode", "wrap_help", ] } -console.workspace = true +console = { version = "0.15", features = ["windows-console-colors"] } crossterm = "0.28" -derive_more = { version = "1.0.0", features = ["deref_mut", "deref", "as_ref"] } +derive_more = { version = "1.0", features = ["deref_mut", "deref", "as_ref"] } dialoguer = "0.11" -futures.workspace = true -heck.workspace = true +futures = "0.3" +heck = "0.5" human-panic = "2.0" -itertools.workspace = true -konst = "0.3.9" -log = { workspace = true } +itertools = "0.13" +konst = "0.3" +log = { version = "0.4", features = ["std"] } open = "5.1" parking_lot = "0.12" -quork.workspace = true +quork = "0.8" ratatui = { version = "0.29", features = ["macros"] } -rayon.workspace = true -regex.workspace = true +rayon = "1.10" +regex = "1.10" semver = "1.0" -serde.workspace = true +serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } -sfsu-macros = { version = "0.1.0", path = "./macros" } shadow-rs = "0.36" -sprinkles-rs.workspace = true +sprinkles-rs = { version = "0.19", features = ["clap"] } tokio = { version = "1.37", features = ["full"] } -vt3 = "0.7.3" +vt3 = "0.7" which = "7.0" windows = { version = "0.58", features = ["Win32_Storage_FileSystem"] } windows-version = "0.1" winreg = "0.52" [dev-dependencies] -chrono.workspace = true criterion = { version = "0.5", features = ["async_tokio", "html_reports"] } [build-dependencies] contribs = { git = "https://github.com/winpax/contribs.git", version = "0.1" } dotenv = "0.15" -git2.workspace = true +git2 = "0.19" shadow-rs = "0.36" tokio = { version = "1.37", features = ["full"] } toml_edit = "0.22" winres = "0.1" - -[patch.crates-io] -instant = { path = "patches/instant" } diff --git a/macros/Cargo.toml b/macros/Cargo.toml deleted file mode 100644 index d330f833..00000000 --- a/macros/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -edition = "2021" -license = { workspace = true } -name = "sfsu-macros" -publish.workspace = true -rust-version = "1.69.0" -version = "0.1.0" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -proc-macro = true - -[dependencies] -heck.workspace = true -proc-macro-crate = "3.1" -proc-macro-error2 = "2.0" -proc-macro2 = "1.0" -quote = "1.0" -syn = { version = "2.0", features = ["full"] } - -[dev-dependencies] -anyhow = "1.0" -quork.workspace = true -sprinkles-rs.workspace = true -strum = { version = "0.26", features = ["derive"] } diff --git a/macros/src/hooks.rs b/macros/src/hooks.rs deleted file mode 100644 index 0b022469..00000000 --- a/macros/src/hooks.rs +++ /dev/null @@ -1,136 +0,0 @@ -use proc_macro2::{Ident, Span, TokenStream}; -use proc_macro_crate::{crate_name, FoundCrate}; -use proc_macro_error2::abort_call_site; -use quote::quote; -use syn::DeriveInput; - -pub struct Variant { - pub name: Ident, - pub command_name: String, - pub hook_name: String, -} - -impl Variant { - pub fn into_tuple(self) -> (Ident, String, String) { - (self.name, self.command_name, self.hook_name) - } - - pub fn unzip(variants: impl Iterator) -> (Vec, Vec, Vec) { - let mut names = Vec::new(); - let mut command_names = Vec::new(); - let mut hook_names = Vec::new(); - - for variant in variants { - let (name, command_name, hook_name) = variant.into_tuple(); - names.push(name); - command_names.push(command_name); - hook_names.push(hook_name); - } - - (names, command_names, hook_names) - } -} - -pub fn hook_enum(input: DeriveInput) -> TokenStream { - let struct_name = { - let original_ident = &input.ident; - let og_ident_span = original_ident.span(); - Ident::new(&format!("{}Hooks", original_ident), og_ident_span) - }; - - let data = &input.data; - - let variants = match data { - syn::Data::Enum(ref e) => e - .variants - .iter() - .filter_map(|variant| { - // TODO: Refactor this to use one attribute i.e #[hook(...)] - let attrs = &variant.attrs; - if attrs.iter().any(|attr| match attr.meta { - syn::Meta::Path(ref p) => p.is_ident("no_hook"), - _ => false, - }) { - None - } else { - let mut variant = Variant { - name: variant.ident.clone(), - command_name: heck::AsKebabCase(variant.ident.to_string()).to_string(), - hook_name: heck::AsKebabCase(variant.ident.to_string()).to_string(), - }; - - for attr in attrs.iter() { - if let syn::Meta::NameValue(ref nv) = attr.meta { - if nv.path.is_ident("hook_name") { - if let syn::Expr::Lit(syn::ExprLit { - lit: syn::Lit::Str(ref s), - .. - }) = nv.value - { - variant.hook_name = s.value(); - } - } - - if nv.path.is_ident("command_name") { - if let syn::Expr::Lit(syn::ExprLit { - lit: syn::Lit::Str(ref s), - .. - }) = nv.value - { - variant.command_name = s.value(); - } - } - } - } - - Some(variant) - } - }) - .collect::>(), - _ => abort_call_site!("Can only be derived for enums"), - }; - - let (variants, command_names, hook_names) = Variant::unzip(variants.into_iter()); - - let quork = match crate_name("quork").expect("quork is present in `Cargo.toml`") { - FoundCrate::Itself => Ident::new("quork", Span::call_site()), - FoundCrate::Name(name) => Ident::new(&name, Span::call_site()), - }; - - quote! { - // TODO: Better way of doing this? or add support for meta in proc macro - #[derive(Debug, Copy, Clone, #quork::macros::ListVariants, PartialEq, Eq)] - pub enum #struct_name { - #(#variants),* - } - - impl #struct_name { - pub const fn command<'a>(self) -> &'a str { - match self { - #(#struct_name::#variants => #command_names,)* - } - } - - pub const fn hook<'a>(self) -> &'a str { - match self { - #(#struct_name::#variants => #hook_names,)* - } - } - } - - // impl std::fmt::Display for #struct_name { - // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // write!(f, "{}", self.hook()) - // } - // } - - impl From for #struct_name { - fn from(string: String) -> Self { - match string.as_str() { - #(#hook_names => #struct_name::#variants,)* - _ => panic!("Invalid command name: {}", string), - } - } - } - } -} diff --git a/macros/src/inner.rs b/macros/src/inner.rs deleted file mode 100644 index 8f3ff9a6..00000000 --- a/macros/src/inner.rs +++ /dev/null @@ -1,31 +0,0 @@ -use proc_macro2::TokenStream; -use proc_macro_error2::abort_call_site; -use quote::quote; -use syn::DeriveInput; - -pub fn into_inner(ast: DeriveInput) -> TokenStream { - let input_name = &ast.ident; - - let data = &ast.data; - - let mut variants = vec![]; - - match data { - syn::Data::Enum(ref e) => { - for v in &e.variants { - variants.push(v.ident.clone()); - } - } - _ => abort_call_site!("Can only be derived for enums"), - }; - - quote! { - impl #input_name { - pub async fn run(self, ctx: &impl sprinkles::contexts::ScoopContext) -> anyhow::Result<()> { - match self { - #(Self::#variants (a) => a.run(ctx).await,)* - } - } - } - } -} diff --git a/macros/src/keyvalue.rs b/macros/src/keyvalue.rs deleted file mode 100644 index 1d86373e..00000000 --- a/macros/src/keyvalue.rs +++ /dev/null @@ -1,56 +0,0 @@ -use proc_macro2::TokenStream; -use proc_macro_error2::abort_call_site; -use quote::quote; -use syn::{DataStruct, DeriveInput}; - -pub fn keyvalue(input: DeriveInput) -> TokenStream { - let ident = input.ident; - let data = input.data; - - let fields = match data { - syn::Data::Struct(DataStruct { fields, .. }) => fields - .into_iter() - .map(|field| match field.ty.clone() { - syn::Type::Path(v) => { - let is_option = v - .path - .segments - .first() - .unwrap() - .ident - .to_string() - .starts_with("Option"); - - let ident = field.ident.unwrap(); - - if is_option { - quote! { - if let Some(data) = self.#ident { - keys.push(stringify!(#ident)); - values.push(data.to_string()); - } - } - } else { - quote! { - keys.push(stringify!(#ident)); - values.push(self.#ident.to_string()) - } - } - } - _ => unimplemented!(), - }) - .collect::>(), - _ => abort_call_site!("Can only be derived on structs with fields"), - }; - - quote! { - impl sprinkles::KeyValue for #ident { - fn into_pairs(self) -> (Vec<&'static str>, Vec) { - let mut keys = vec![]; - let mut values = vec![]; - #(#fields;)* - (keys, values) - } - } - } -} diff --git a/macros/src/lib.rs b/macros/src/lib.rs deleted file mode 100644 index c0074f44..00000000 --- a/macros/src/lib.rs +++ /dev/null @@ -1,25 +0,0 @@ -use proc_macro::TokenStream; -use proc_macro_error2::proc_macro_error; -use syn::{parse_macro_input, DeriveInput}; - -mod hooks; -mod inner; -mod keyvalue; - -#[proc_macro_derive(Runnable)] -#[proc_macro_error] -pub fn derive_into_inner(input: TokenStream) -> TokenStream { - inner::into_inner(parse_macro_input!(input as DeriveInput)).into() -} - -#[proc_macro_derive(Hooks, attributes(no_hook, hook_name, command_name))] -#[proc_macro_error] -pub fn derive_hook_enum(input: TokenStream) -> TokenStream { - hooks::hook_enum(parse_macro_input!(input as DeriveInput)).into() -} - -#[proc_macro_derive(KeyValue, attributes(deprecated))] -#[proc_macro_error] -pub fn derive_key_value(input: TokenStream) -> TokenStream { - keyvalue::keyvalue(parse_macro_input!(input as DeriveInput)).into() -} diff --git a/macros/tests/into_inner.rs b/macros/tests/into_inner.rs deleted file mode 100644 index 730bb7ac..00000000 --- a/macros/tests/into_inner.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![allow(dead_code)] - -struct DummyStruct; - -impl DummyStruct { - pub async fn run( - self, - _: &impl sprinkles::contexts::ScoopContext, - ) -> anyhow::Result<()> { - println!("Hello, world!"); - - Ok(()) - } -} - -#[derive(sfsu_macros::Runnable)] -enum MaybeIntoInner { - Test1(DummyStruct), - Test2(DummyStruct), -} diff --git a/macros/tests/raw_enum.rs b/macros/tests/raw_enum.rs deleted file mode 100644 index 149783b4..00000000 --- a/macros/tests/raw_enum.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![allow(dead_code)] - -use quork::traits::list::ListVariants; -use sfsu_macros::Hooks; - -struct DummyStruct; - -#[derive(Hooks)] -enum EnumWithData { - Test1(DummyStruct), - Test2(DummyStruct), -} - -#[test] -fn has_all_variants() { - let variants = EnumWithDataHooks::VARIANTS - .iter() - .map(|v| v.hook()) - .collect::(); - - assert_eq!(variants, "test1test2"); -} - -#[derive(Hooks)] -enum EnumExclude { - Test1(DummyStruct), - #[no_hook] - Test2(DummyStruct), - Test3(DummyStruct), -} - -#[test] -fn excludes_no_hook_variant() { - let variants = EnumExcludeHooks::VARIANTS - .iter() - .map(|v| v.hook()) - .collect::(); - - assert_eq!(variants, "test1test3"); -} diff --git a/patches/instant/Cargo.toml b/patches/instant/Cargo.toml deleted file mode 100644 index d0a14ff1..00000000 --- a/patches/instant/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "instant" -version = "0.1.0" -edition = "2021" -authors.workspace = true -homepage.workspace = true -license.workspace = true -publish.workspace = true -repository.workspace = true - -[dependencies] -rightnow = "0.1.0" -web-time = "1.1.0" diff --git a/patches/instant/src/lib.rs b/patches/instant/src/lib.rs deleted file mode 100644 index 96367739..00000000 --- a/patches/instant/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use web_time::*; - -pub fn now() -> f64 { - rightnow::RightNow::now().as_secs_f64() * 1000.0 -} diff --git a/src/commands.rs b/src/commands.rs index 42f19caf..b0b4cd27 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -17,7 +17,6 @@ mod virustotal; use clap::Subcommand; -use sfsu_macros::{Hooks, Runnable}; use sprinkles::{config, contexts::ScoopContext}; use crate::{abandon, output::colours::eprintln_yellow}; @@ -64,6 +63,16 @@ impl std::fmt::Display for DeprecationWarning { } } +pub trait Runnable +where + Self: Sized, +{ + async fn run( + self, + ctx: &impl sprinkles::contexts::ScoopContext, + ) -> anyhow::Result<()>; +} + // TODO: Run command could return `impl Display` and print that itself pub trait Command { const BETA: bool = false; @@ -99,26 +108,27 @@ pub trait CommandRunner: Command { impl CommandRunner for T {} -#[derive(Debug, Clone, Subcommand, Hooks, Runnable)] +// TODO: Replace strip macro with a custom enum +// Use match to ensure all variants are covered +// This will allow more flexibility with hooks in future +// as sfsu invocation deviates from scoop's +#[derive(Debug, Clone, Subcommand, quork::macros::Strip)] +#[stripped(ident = CommandHooks)] +#[stripped_meta(derive(Debug, Copy, Clone, quork::macros::ListVariants, PartialEq, Eq))] pub enum Commands { App(app::Args), #[cfg(not(feature = "v2"))] - #[command_name = "app cat"] Cat(app::cat::Args), #[cfg(all(feature = "download", not(feature = "v2")))] - #[command_name = "app download"] Download(app::download::Args), #[cfg(not(feature = "v2"))] - #[command_name = "app home"] Home(app::home::Args), #[cfg(not(feature = "v2"))] - #[command_name = "app info"] Info(app::info::Args), #[cfg(not(feature = "v2"))] - #[command_name = "app list"] List(app::list::Args), - #[no_hook] + #[stripped(ignore)] Hook(hook::Args), Search(search::Args), @@ -131,18 +141,119 @@ pub enum Commands { Outdated(outdated::Args), Depends(depends::Args), Status(status::Args), - #[cfg_attr(not(feature = "v2"), no_hook)] + #[cfg_attr(not(feature = "v2"), stripped(ignore))] Update(update::Args), Export(export::Args), Checkup(checkup::Args), #[cfg(feature = "download")] Cache(cache::Args), - #[hook_name = "virustotal"] #[clap(alias = "virustotal")] Scan(virustotal::Args), - #[no_hook] + #[stripped(ignore)] Credits(credits::Args), - #[no_hook] + #[stripped(ignore)] #[cfg(debug_assertions)] Debug(debug::Args), } + +impl Runnable for Commands { + async fn run( + self, + ctx: &impl sprinkles::contexts::ScoopContext, + ) -> anyhow::Result<()> { + match self { + Commands::App(args) => args.run(ctx).await, + Commands::Cat(args) => args.run(ctx).await, + Commands::Download(args) => args.run(ctx).await, + Commands::Home(args) => args.run(ctx).await, + Commands::Info(args) => args.run(ctx).await, + Commands::List(args) => args.run(ctx).await, + Commands::Hook(args) => args.run(ctx).await, + Commands::Search(args) => args.run(ctx).await, + Commands::UnusedBuckets(args) => args.run(ctx).await, + Commands::Bucket(args) => args.run(ctx).await, + Commands::Describe(args) => args.run(ctx).await, + Commands::Outdated(args) => args.run(ctx).await, + Commands::Depends(args) => args.run(ctx).await, + Commands::Status(args) => args.run(ctx).await, + Commands::Update(args) => args.run(ctx).await, + Commands::Export(args) => args.run(ctx).await, + Commands::Checkup(args) => args.run(ctx).await, + Commands::Cache(args) => args.run(ctx).await, + Commands::Scan(args) => args.run(ctx).await, + Commands::Credits(args) => args.run(ctx).await, + Commands::Debug(args) => args.run(ctx).await, + } + } +} + +impl CommandHooks { + pub const fn command<'a>(self) -> &'a str { + match self { + CommandHooks::App => "app", + CommandHooks::Cat => "app cat", + CommandHooks::Download => "app download", + CommandHooks::Home => "app home", + CommandHooks::Info => "app info", + CommandHooks::List => "app list", + CommandHooks::Search => "search", + CommandHooks::UnusedBuckets => "unused-buckets", + CommandHooks::Bucket => "bucket", + CommandHooks::Describe => "describe", + CommandHooks::Outdated => "outdated", + CommandHooks::Depends => "depends", + CommandHooks::Status => "status", + CommandHooks::Export => "export", + CommandHooks::Checkup => "checkup", + CommandHooks::Cache => "cache", + CommandHooks::Scan => "scan", + } + } + + pub const fn hook<'a>(self) -> &'a str { + match self { + CommandHooks::App => "app", + CommandHooks::Cat => "cat", + CommandHooks::Download => "download", + CommandHooks::Home => "home", + CommandHooks::Info => "info", + CommandHooks::List => "list", + CommandHooks::Search => "search", + CommandHooks::UnusedBuckets => "unused-buckets", + CommandHooks::Bucket => "bucket", + CommandHooks::Describe => "describe", + CommandHooks::Outdated => "outdated", + CommandHooks::Depends => "depends", + CommandHooks::Status => "status", + CommandHooks::Export => "export", + CommandHooks::Checkup => "checkup", + CommandHooks::Cache => "cache", + CommandHooks::Scan => "virustotal", + } + } +} + +impl From for CommandHooks { + fn from(string: String) -> Self { + match string.as_str() { + "app" => CommandHooks::App, + "cat" => CommandHooks::Cat, + "download" => CommandHooks::Download, + "home" => CommandHooks::Home, + "info" => CommandHooks::Info, + "list" => CommandHooks::List, + "search" => CommandHooks::Search, + "unused-buckets" => CommandHooks::UnusedBuckets, + "bucket" => CommandHooks::Bucket, + "describe" => CommandHooks::Describe, + "outdated" => CommandHooks::Outdated, + "depends" => CommandHooks::Depends, + "status" => CommandHooks::Status, + "export" => CommandHooks::Export, + "checkup" => CommandHooks::Checkup, + "cache" => CommandHooks::Cache, + "virustotal" => CommandHooks::Scan, + _ => panic!("Invalid command name: {string}"), + } + } +} diff --git a/src/commands/app.rs b/src/commands/app.rs index 6be811c0..fefa3070 100644 --- a/src/commands/app.rs +++ b/src/commands/app.rs @@ -8,12 +8,11 @@ pub mod purge; use clap::{Parser, Subcommand}; -use sfsu_macros::Runnable; use sprinkles::{config, contexts::ScoopContext}; -use super::{Command, CommandRunner}; +use super::{Command, CommandRunner, Runnable}; -#[derive(Debug, Clone, Subcommand, Runnable)] +#[derive(Debug, Clone, Subcommand)] pub enum Commands { Cat(cat::Args), #[cfg(feature = "download")] @@ -24,6 +23,22 @@ pub enum Commands { Purge(purge::Args), } +impl Runnable for Commands { + async fn run( + self, + ctx: &impl sprinkles::contexts::ScoopContext, + ) -> anyhow::Result<()> { + match self { + Commands::Cat(args) => args.run(ctx).await, + Commands::Download(args) => args.run(ctx).await, + Commands::Home(args) => args.run(ctx).await, + Commands::Info(args) => args.run(ctx).await, + Commands::List(args) => args.run(ctx).await, + Commands::Purge(args) => args.run(ctx).await, + } + } +} + #[derive(Debug, Clone, Parser)] /// Commands for managing apps pub struct Args { diff --git a/src/commands/bucket.rs b/src/commands/bucket.rs index 2fb74359..7a78ae3d 100644 --- a/src/commands/bucket.rs +++ b/src/commands/bucket.rs @@ -7,12 +7,11 @@ pub mod unused; use clap::{Parser, Subcommand}; -use sfsu_macros::Runnable; use sprinkles::{config, contexts::ScoopContext}; -use super::{Command, CommandRunner}; +use super::{Command, CommandRunner, Runnable}; -#[derive(Debug, Clone, Subcommand, Runnable)] +#[derive(Debug, Clone, Subcommand)] pub enum Commands { Add(add::Args), #[clap(alias = "rm")] @@ -24,6 +23,22 @@ pub enum Commands { Outdated(outdated::Args), } +impl Runnable for Commands { + async fn run( + self, + ctx: &impl sprinkles::contexts::ScoopContext, + ) -> anyhow::Result<()> { + match self { + Commands::Add(args) => args.run(ctx).await, + Commands::Remove(args) => args.run(ctx).await, + Commands::List(args) => args.run(ctx).await, + Commands::Known(args) => args.run(ctx).await, + Commands::Unused(args) => args.run(ctx).await, + Commands::Outdated(args) => args.run(ctx).await, + } + } +} + #[derive(Debug, Clone, Parser)] /// Commands for managing buckets pub struct Args { diff --git a/src/commands/cache.rs b/src/commands/cache.rs index a8e7fece..7ab8e6cf 100644 --- a/src/commands/cache.rs +++ b/src/commands/cache.rs @@ -4,7 +4,6 @@ use anyhow::Context; use clap::{Parser, Subcommand}; use regex::Regex; use serde::Serialize; -use sfsu_macros::Runnable; use sprinkles::{config, contexts::ScoopContext}; use tokio::task::JoinSet; @@ -13,6 +12,8 @@ mod remove; use crate::{abandon, commands::CommandRunner, wrappers::sizes::Size}; +use super::Runnable; + #[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)] struct CacheEntry { #[serde(skip)] @@ -93,7 +94,7 @@ impl CacheEntry { } } -#[derive(Debug, Clone, Subcommand, Runnable)] +#[derive(Debug, Clone, Subcommand)] enum Commands { #[clap(alias = "show", alias = "ls")] List(list::Args), @@ -101,6 +102,18 @@ enum Commands { Remove(remove::Args), } +impl Runnable for Commands { + async fn run( + self, + ctx: &impl sprinkles::contexts::ScoopContext, + ) -> anyhow::Result<()> { + match self { + Commands::List(args) => args.run(ctx).await, + Commands::Remove(args) => args.run(ctx).await, + } + } +} + #[derive(Debug, Clone, Parser)] /// Show or clear the download cache pub struct Args { diff --git a/src/commands/debug.rs b/src/commands/debug.rs index a687e798..af82d682 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -1,16 +1,25 @@ use clap::{Parser, Subcommand}; -use sfsu_macros::{Hooks, Runnable}; use sprinkles::{config, contexts::ScoopContext}; -use super::{Command, CommandRunner}; +use super::{Command, CommandRunner, Runnable}; mod save; -#[derive(Debug, Hooks, Clone, Subcommand, Runnable)] +#[derive(Debug, Clone, Subcommand)] pub enum Commands { Save(save::Args), } +impl Runnable for Commands { + async fn run( + self, + ctx: &impl sprinkles::contexts::ScoopContext, + ) -> anyhow::Result<()> { + match self { + Commands::Save(args) => args.run(ctx).await, + } + } +} #[derive(Debug, Clone, Parser)] /// Debugging commands pub struct Args { diff --git a/src/commands/hook.rs b/src/commands/hook.rs index f48032e7..8bb7705a 100644 --- a/src/commands/hook.rs +++ b/src/commands/hook.rs @@ -2,7 +2,7 @@ use clap::Parser; use quork::traits::list::ListVariants; use sprinkles::{contexts::ScoopContext, shell::Shell}; -use super::CommandsHooks; +use super::CommandHooks as CommandsHooks; #[derive(Debug, Clone, Parser)] /// Generate hooks for the given shell diff --git a/src/commands/outdated.rs b/src/commands/outdated.rs index 8faa5d00..e096e407 100644 --- a/src/commands/outdated.rs +++ b/src/commands/outdated.rs @@ -1,19 +1,30 @@ use clap::{Parser, Subcommand}; use serde_json::Map; -use sfsu_macros::Runnable; use sprinkles::{config, contexts::ScoopContext}; -use super::{Command, CommandRunner, DeprecationMessage, DeprecationWarning}; +use super::{Command, CommandRunner, DeprecationMessage, DeprecationWarning, Runnable}; pub mod apps; pub mod buckets; -#[derive(Debug, Clone, Subcommand, Runnable)] +#[derive(Debug, Clone, Subcommand)] pub enum Commands { Apps(apps::Args), Buckets(buckets::Args), } +impl Runnable for Commands { + async fn run( + self, + ctx: &impl sprinkles::contexts::ScoopContext, + ) -> anyhow::Result<()> { + match self { + Commands::Apps(args) => args.run(ctx).await, + Commands::Buckets(args) => args.run(ctx).await, + } + } +} + #[derive(Debug, Clone, Parser)] /// List outdated buckets and/or packages pub struct Args { diff --git a/src/main.rs b/src/main.rs index 22cb3efd..86476a97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ use std::{ use clap::Parser; -use commands::Commands; +use commands::{Commands, Runnable}; use logging::Logger; use sprinkles::contexts::{AnyContext, ScoopContext, User};