From 3d1bb2dafe3d5e1841235a0a60d21756f6ba8cac Mon Sep 17 00:00:00 2001 From: Michal Date: Wed, 3 Aug 2022 23:07:08 +0100 Subject: [PATCH] Made the thing --- .env | 3 + .envrc | 2 + .gitignore | 3 + Cargo.lock | 229 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 14 +++ PKGBUILD | 36 +++++++ README.md | 47 +++++++++ flake.lock | 64 +++++++++++ flake.nix | 53 ++++++++++ justfile | 14 +++ src/args.rs | 17 +++ src/internal/mod.rs | 5 + src/internal/strings.rs | 53 ++++++++++ src/internal/structs.rs | 4 + src/main.rs | 69 ++++++++++++ 15 files changed, 613 insertions(+) create mode 100644 .env create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 PKGBUILD create mode 100644 README.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 justfile create mode 100644 src/args.rs create mode 100644 src/internal/mod.rs create mode 100644 src/internal/strings.rs create mode 100644 src/internal/structs.rs create mode 100644 src/main.rs 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(); + } +}