commit 3d1bb2dafe3d5e1841235a0a60d21756f6ba8cac Author: Michal Date: Wed Aug 3 23:07:08 2022 +0100 Made the thing diff --git a/.env b/.env new file mode 100644 index 0000000..c1f877e --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +PKG_WARNER_PACKAGES="test1,test2" +PKG_WARNER_DISTRO="Crystal" +PKG_WARNER_PMAN="ame" \ No newline at end of file diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..0b1a02d --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +dotenv +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7500a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.direnv/ +.idea/ +target/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..10d47e0 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,229 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "clap" +version = "3.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "os_str_bytes" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4" + +[[package]] +name = "pkg-warner" +version = "0.1.0" +dependencies = [ + "clap", + "colored", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0944c3d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "pkg-warner" +version = "0.1.0" +authors = ["Michal S. "] +edition = "2021" +description = "A simple, OS-agnostic package manager warner" +repository = "https://github.com/crystal-linux/pkg-warner" +license-file = "LICENSE" +keywords = ["package", "manager", "warner"] +categories = ["command-line-utilities"] + +[dependencies] +clap = { version = "3.2.16", default-features = false, features = ["std", "derive"] } +colored = { version = "2.0.0", default-features = false } \ No newline at end of file diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 0000000..9fe21a3 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,36 @@ +# Maintainer: Michal S +# Developer: Michal S + +pkgname=pkg-warner +pkgver=0.1.0 +pkgrel=1 +pkgdesc="Simple package manager warner tool for distribution developers" +arch=('x86_64') +url="https://github.com/crystal-linux/pkg-warner" +license=('GPL3') +source=("git+$url?rev=0.1.0") +sha256sums=('SKIP') +makedepends=('cargo') + +prepare() { + cd "$srcdir/$pkgname" + cargo fetch --locked --target "$CARCH-unknown-linux-gnu" +} + +build() { + cd "$srcdir/$pkgname" + export RUSTUP_TOOLCHAIN=stable + export CARGO_TARGET_DIR=target + + # These following envvars are Crystal-specific, please adjust for your own distro! + export PKG_WARNER_PACKAGES="" + export PKG_WARNER_DISTRO="Crystal" + export PKG_WARNER_PMAN="ame/pacman" + + cargo build --frozen --release +} + +package() { + cd "$srcdir/$pkgname" + cargo run --frozen --release -- -ivd "${pkgdir}/usr/bin" +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e787184 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +

+ + Logo + +

+ +

Package Warner

+ +

+ License + GitHub isses + GitHub pull requests
+ Discord + The maintainer of this repository
+ Mastodon Follow + Twitter Follow +

+ + + +

pkg-warner is a simple and configurable package warner tool for distribution packagers.

+ + +## Configuration + +`pkg-warner` is configured at build time using three environment variables: +- `PKG_WARNER_PACKAGES`: a comma-separated list of **incorrect** package managers to warn about. +- `PKG_WARNER_DISTRO`: the distribution name to use in the warning. +- `PKG_WARNER_PMAN`: the **correct** package manager name to use in the warning. + +Then, in the packaging process you can run `pkg-warner -id "${dest_dir}"` to copy itself to `${dest_dir}/` under the destination directory. (e.g., `./pkg/usr/bin/apt`) + +If no `-d/--dest-dir` id provided, it'll install to `/usr/bin` by default. + +If you want an example of how to adapt this to your own distribution/packaging process, see the provided [PKGBUILD](PKGBUILD) + +## How to build: + +Tested on latest Cargo (1.60.0-nightly) + +### Debug/development builds + +- `cargo build` + +### Optimised/release builds + +- `cargo build --release` diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3bd7ef1 --- /dev/null +++ b/flake.lock @@ -0,0 +1,64 @@ +{ + "nodes": { + "naersk": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1655042882, + "narHash": "sha256-9BX8Fuez5YJlN7cdPO63InoyBy7dm3VlJkkmTt6fS1A=", + "owner": "nix-community", + "repo": "naersk", + "rev": "cddffb5aa211f50c4b8750adbec0bbbdfb26bb9f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "naersk", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1659494082, + "narHash": "sha256-XRwMisQY/BcvDMDRVkd4n3/CT89HOtlPgWIQUNPvWSc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "8c7576622aeb4707351a17e83429667f42e7d910", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "naersk": "naersk", + "nixpkgs": "nixpkgs", + "utils": "utils" + } + }, + "utils": { + "locked": { + "lastModified": 1656928814, + "narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..c2d052c --- /dev/null +++ b/flake.nix @@ -0,0 +1,53 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + utils.url = "github:numtide/flake-utils"; + naersk = { + url = "github:nix-community/naersk"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { + self, + nixpkgs, + utils, + naersk, + }: + utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacyPackages."${system}"; + naersk-lib = naersk.lib."${system}"; + in rec + { + packages.pkg-warner = naersk-lib.buildPackage { + pname = "pkg-warner"; + root = ./.; + + PKG_WARNER_PACKAGES = "test1,test2,test3"; + PKG_WARNER_DISTRO = "Test Linux"; + PKG_WARNER_PMAN = "test4"; + }; + + packages.default = packages.pkg-warner; + + apps.pkg-warner = utils.lib.mkApp { + drv = packages.pkg-warner; + }; + + apps.default = apps.pkg-warner; + + devShells.default = pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + rustc + cargo + cargo-audit + rustfmt + clippy + + just + ]; + }; + + formatter = pkgs.alejandra; + }); +} diff --git a/justfile b/justfile new file mode 100644 index 0000000..426044c --- /dev/null +++ b/justfile @@ -0,0 +1,14 @@ +set dotenv-load := true + +# Run all checks and tests +check *FLAGS: + cargo clippy --all {{FLAGS}} -- -D warnings + cargo fmt --all --check {{FLAGS}} + +# Test the warner +test *FLAGS: + cargo run {{FLAGS}} -- --test + +# Test using Nix +test-nix: + nix run .# -- --test diff --git a/src/args.rs b/src/args.rs new file mode 100644 index 0000000..7d035d3 --- /dev/null +++ b/src/args.rs @@ -0,0 +1,17 @@ +use clap::{ArgAction, Parser}; + +#[derive(Debug, Clone, Parser)] +#[clap(name=env!("CARGO_PKG_NAME"), version=env!("CARGO_PKG_VERSION"), about=env!("CARGO_PKG_DESCRIPTION"))] +pub struct Args { + #[clap(long, short, action=ArgAction::SetTrue)] + pub init: bool, + + #[clap(long = "dest-dir", short)] + pub dest_dir: Option, + + #[clap(long, action=ArgAction::SetTrue)] + pub test: bool, + + #[clap(long, short, action=ArgAction::SetTrue)] + pub verbose: bool, +} diff --git a/src/internal/mod.rs b/src/internal/mod.rs new file mode 100644 index 0000000..11fd7a6 --- /dev/null +++ b/src/internal/mod.rs @@ -0,0 +1,5 @@ +mod strings; +mod structs; + +pub use strings::*; +pub use structs::*; diff --git a/src/internal/strings.rs b/src/internal/strings.rs new file mode 100644 index 0000000..c821ef4 --- /dev/null +++ b/src/internal/strings.rs @@ -0,0 +1,53 @@ +use std::process::exit; +use std::time::{SystemTime, UNIX_EPOCH}; + +use clap::Parser; +use colored::Colorize; + +use crate::internal::AppExitCode; + +const ERR_SYMBOL: &str = "✘"; +const WARN_SYMBOL: &str = "⚠"; + +#[macro_export] +macro_rules! log { + ($($arg:tt)+) => { + $crate::internal::log_fn(&format!("[{}:{}] {}", file!(), line!(), format!($($arg)+))); + } +} + +pub fn log_fn(msg: &str) { + if crate::args::Args::parse().verbose { + eprintln!( + "{} {}", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(), + msg + ); + } +} + +#[macro_export] +macro_rules! crash { + ($exit_code:expr, $($arg:tt)+) => { + $crate::internal::crash_fn($exit_code, &format!("[{}:{}] {}", file!(), line!(), format!($($arg)+))); + } +} + +pub fn crash_fn(exit_code: AppExitCode, msg: &str) { + println!("{} {}", ERR_SYMBOL.bold().red(), msg.bold().bright_red()); + exit(exit_code as i32); +} + +pub fn warn(bin: &str, dist: &str, pman: &str) { + println!( + "{} {} is not supported on {}. Please use {} instead!", + WARN_SYMBOL.bold().yellow(), + bin.bold().yellow(), + dist.bold(), + pman.bold(), + ); + exit(AppExitCode::Success as i32); +} diff --git a/src/internal/structs.rs b/src/internal/structs.rs new file mode 100644 index 0000000..6403b52 --- /dev/null +++ b/src/internal/structs.rs @@ -0,0 +1,4 @@ +pub enum AppExitCode { + Success = 1, // the correct package manager + CalledDirectly = 2, +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..bc7d8da --- /dev/null +++ b/src/main.rs @@ -0,0 +1,69 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)] + +use clap::Parser; +use std::{env, ops::Deref, process::Command}; + +mod args; +mod internal; + +use args::Args; +use internal::{warn, AppExitCode}; + +fn main() { + // Parse CLI arguments + let args = Args::parse(); + + // Get the current executable name as a String + let bin = env::current_exe() + .unwrap() + .as_path() + .file_name() + .unwrap() + .deref() + .to_string_lossy() + .to_string(); + + // Get variables from the environment at build time to simplify the code + let pkgs = env!("PKG_WARNER_PACKAGES") + .split(',') + .collect::>(); + let pman = env!("PKG_WARNER_PMAN").to_string(); + let dist = env!("PKG_WARNER_DISTRO").to_string(); + + // If --test is specified, print the warn message and exit + if args.test { + warn(&bin, &dist, &pman); + } + + // Check if the binary is called directly by the user, if so tell them off + if bin == "pkg-warner" { + if args.init { + init(&pkgs, args.dest_dir); + } else { + crash!( + AppExitCode::CalledDirectly, + "`pkg-warner` is not meant to be called directly by the user" + ); + } + } else { + warn(&bin, &dist, &pman); + } +} + +fn init(pkgs: &[&str], dest_dir: Option) { + log!("Initializing: {}", pkgs.join(", ")); + + // Either unwrap the dest_dir if present or use /usr/bin + let dest_dir = dest_dir.unwrap_or_else(|| "/usr/bin".to_string()); + + for pkg in pkgs { + log!("Installing \"{}\"", pkg); + + Command::new("install") + .arg("-Dm0755") + .arg(format!("{}", env::current_exe().unwrap().display())) + .arg(format!("{}/{}", dest_dir, pkg)) + .spawn() + .unwrap(); + } +}