diff --git a/.gitignore b/.gitignore index 7c9f50c..be024c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -**/dist/ **/target **/Cargo.lock *.pkg \ No newline at end of file diff --git a/.idea/jsonSchemas.xml b/.idea/jsonSchemas.xml deleted file mode 100644 index f5ad76c..0000000 --- a/.idea/jsonSchemas.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.woodpecker.yml b/.woodpecker.yml index 068cb06..620c2bd 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -8,24 +8,20 @@ when: - "pkgr/**" - "bootpkg/**" - "pkgfile/**" + - "pkg/**" - "manifest/**" steps: - clippy: # check if the code compiles + check: # check if the code compiles image: rust commands: - - rustup component add clippy - - cargo clippy --release --no-deps --manifest-path bootpkg/Cargo.toml - - cargo clippy --release --no-deps --manifest-path pkgr/Cargo.toml - pull: true - failure: ignore + - cargo check --release --manifest-path bootpkg/Cargo.toml --all + - cargo check --release --manifest-path pkgr/Cargo.toml --all build: image: rust commands: - cargo build --release --manifest-path bootpkg/Cargo.toml --all - cargo build --release --manifest-path pkgr/Cargo.toml --all - pull: true - failure: fail publish: image: woodpeckerci/plugin-gitea-release settings: @@ -36,6 +32,5 @@ steps: api_key: from_secret: gitea_access_token target: main - failure: ignore when: event: tag \ No newline at end of file diff --git a/README.md b/README.md index 42323c9..7e24755 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,8 @@ # Packager -[![CI Status](https://ci.ixvd.net/api/badges/2/status.svg)](https://ci.ixvd.net/repos/2) - > "A package manager and builder but like rust." > -- Gandhi (2050) -> ***Almost to a point you can use it*** :) - -Packager is a simple yet powerful package manager - -## Install a package -pkgr supports fetching packages with a: -- path -- url (http/https) -- package locator - -```shell -# example with path -pkgr install ./foxy/snek.pkg -# example with url -pkgr install https://example.com/doggo.pkg -# example with package locator -pkgr install foo:stable,bar -``` - -## Composing a package -Right now, pkgr does not have a compose/package command. (it's in the works dw!) -You can create a package with `pkg.py`! - -```shell -# Usage: pkg.py [ ...] -# example: -python pkg.py manifest.toml example.pkg root/ source/ scripts/ -# this will create a package with an archive that look like this: -# [header+manifest] -# ... -# [archive: -# root/ -# source/ -# scripts/ -# ] -``` - -It's not perfect, but it'll get the job done :) - +> ***not even close to done*** :) +Packager is a simple yet powerful package manager \ No newline at end of file diff --git a/bodge-pkg.py b/bodge-pkg.py new file mode 100644 index 0000000..cca3307 --- /dev/null +++ b/bodge-pkg.py @@ -0,0 +1,31 @@ +import os +import tarfile + +with open("./package.toml", mode='r') as mani: + data = mani.read() + with open("./sample.pkg", mode='wb') as pkg: + print("building header...") + pkg.write(bytes([0x01, (len(data) >> 8) & 0xFF, len(data) & 0xFF])) + print("writing manifest into pkg...") + pkg.write(data.encode("utf-8")) + with tarfile.TarFile("/tmp/pkgtar", 'w') as pkgtar: + print("tarring ./pkg...") + os.chdir("pkg") + for root, dirs, files in os.walk("."): + for file in files: + print(f"\33[2Kadd: {os.path.join(root, file)}", end="\r", flush=True) + pkgtar.add(os.path.join(root, file)) + os.chdir("..") + for root, dirs, files in os.walk("pkgr"): + for file in files: + print(f"\33[2Kadd: {os.path.join(root, file)}", end="\r", flush=True) + pkgtar.add(os.path.join(root, file)) + print("\33[2K", end="\r", flush=True) + with open("/tmp/pkgtar", 'rb') as pkgtar: + print("appending pkgtar to pkg...") + pkg.write(pkgtar.read()) + print("deleting /tmp/pkgtar...") + os.unlink("/tmp/pkgtar") + print("closing write stream") + pkg.close() + \ No newline at end of file diff --git a/bootpkg/Cargo.toml b/bootpkg/Cargo.toml index 5530ce3..d6c3186 100644 --- a/bootpkg/Cargo.toml +++ b/bootpkg/Cargo.toml @@ -14,4 +14,3 @@ regex = "1.9.1" reqwest = { version = "0.11.18", features = ["blocking"] } uuid = { version = "1.4.0", features = ["serde", "v4"] } tar = "0.4.39" -libc = "0.2.80" diff --git a/bootpkg/package.toml b/bootpkg/package.toml deleted file mode 100644 index c272a08..0000000 --- a/bootpkg/package.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "bootpkg" #* -description = "A tool to strap pkgs" #* -version = 1 -tags = [] -type = "application" -arch = "x86_64" - -[bin] -root = "/root" \ No newline at end of file diff --git a/bootpkg/src/args.rs b/bootpkg/src/args.rs index 373830b..0df76c9 100644 --- a/bootpkg/src/args.rs +++ b/bootpkg/src/args.rs @@ -18,20 +18,9 @@ pub struct Args { impl From> for Args { fn from(value: Vec) -> Self { - if value.len() == 0 { - return Args { - command: Command::from(String::default()), - args: vec![], - } - } - Args { command: Command::from(value[0].to_owned()), - args: if value.len() > 1 { - value[1..].to_owned() - } else { - vec![] - }, + args: value[1..].to_owned(), } } } diff --git a/bootpkg/src/main.rs b/bootpkg/src/main.rs index 65037f3..ffd4338 100644 --- a/bootpkg/src/main.rs +++ b/bootpkg/src/main.rs @@ -15,14 +15,6 @@ mod args; mod prelude; fn main() { - #[cfg(not(debug_assertions))] - { - if unsafe { libc::getuid() } != 0 { - println!("bootpkg must be run as root."); - std::process::exit(1); - } - } - let args = Args::from(env::args().collect::>()[1..].to_owned()); match args.command { Command::Strap => { diff --git a/bootpkg/src/prelude.rs b/bootpkg/src/prelude.rs index b5ec6fe..9406cdb 100644 --- a/bootpkg/src/prelude.rs +++ b/bootpkg/src/prelude.rs @@ -30,12 +30,12 @@ pub fn mani_from_str(s: &str) -> Manifest> { fs: mani.fs, bin: mani.bin, build: mani.build, - ext: bmani.pkgr, + pkgr: bmani.pkgr, } } pub fn run_bootstrap(mani: Manifest>) -> bool { - if let Some(pkgr) = mani.ext { + if let Some(pkgr) = mani.pkgr { if let Some(bootstrap) = pkgr.bootstrap { fn run_command>(s: S) -> i32 { std::process::Command::new("sh") diff --git a/build b/build deleted file mode 100755 index c245f7a..0000000 --- a/build +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -build_pkgr() { - cd pkgr - mkdir -p dist/root/{usr/bin,etc/pkgr} - echo -e "You can't use pkgr to update pkgr because the file will be in use while updating.\nuse bootpkg" > dist/root/etc/pkgr.d/YOU-CAN-NOT-USE-PKGR-TO-UPDATE-PKGR.txt - - # for bin - cargo build -r - cp target/release/pkgr dist/root/usr/bin/pkgr - - # for build - mkdir -p dist/pkgr - cp -r src/ Cargo.toml dist/pkgr - cp -r ../manifest dist/manifest - cp -r ../pkgfile dist/pkgfile - - cd dist - python ../../pkg.py ../package.toml pkgr.pkg "*" - cd ../.. -} - -build_bootpkg() { - cd bootpkg - mkdir -p dist/root/usr/bin - - cargo build -r - cp target/release/bootpkg dist/root/usr/bin/bootpkg - - - cd dist - python ../../pkg.py ../package.toml bootpkg.pkg "*" - cd ../.. -} - -set -e - -build_bootpkg -build_pkgr diff --git a/docs/README.md b/docs/README.md index 5b84964..0e9b295 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,9 +9,7 @@ pkgr is the main tool for the packager. Because this tool is so feature rich, it has its own [README](./pkgr/README.md). ## bootpkg -`bootpkg` is a simple pkgr variant. -It doesn't contain anything fancy and is only used to install and update pkgr. -Using it for anything other than pkgr is not recommended. +bootpkg is a tool primariliy used to bootstrap the packager. ### Usage @@ -19,4 +17,4 @@ Using it for anything other than pkgr is not recommended. bootpkg strap ./pkgr.pkg ``` -This will extract the pkgfile and read the `[pkgr.bootstrap]` section to bootstrap the packager or any other package. +This will extract the pkgfile and read the `[pkgr.bootstrap]` section to bootstrap the packager or any other package. \ No newline at end of file diff --git a/docs/manifest.md b/docs/manifest.md deleted file mode 100644 index d6f7f14..0000000 --- a/docs/manifest.md +++ /dev/null @@ -1,5 +0,0 @@ -# Manifest - ---- - -The manifest spec is located in `/package.example.toml` as an example. \ No newline at end of file diff --git a/docs/pkgfile.md b/docs/pkgfile.md new file mode 100644 index 0000000..4b2b81a --- /dev/null +++ b/docs/pkgfile.md @@ -0,0 +1,24 @@ +# PKGFILE +This file is essentially a tar with the manifest in the header. + +## Format +The format is as follows: +``` +[PKGFILE version (1 byte)][manifest length x 256 (1 byte)][manifest length (1 byte)] +[manifest (manifest length bytes)] +[archive] +``` + +The file is Big Endian. + +## Unpacking +To unpack a PKGFILE, you can use the following command: +```bash +pkgr unpack +``` + +## Packing +You can write your own packer, or use the following command: +```bash +pkgr pack +``` diff --git a/docs/pkgfiles/current.md b/docs/pkgfiles/current.md deleted file mode 100644 index e5cd8cc..0000000 --- a/docs/pkgfiles/current.md +++ /dev/null @@ -1,25 +0,0 @@ -# PKGFILE - -version 1 - ---- -PKGFiles are an all-in-one solution to install a package. - -## Overhead - -Because pkgfiles include everything, many times you're downloading more than what is needed. -This may seem stupid but pkgfiles are *not* meant to stay on your system. - -## Format - -The format is as follows: - -``` -[PKGFILE version (1 byte)][manifest length x 256 (1 byte)][manifest length (1 byte)] -[manifest (manifest length bytes)] -[archive] -``` - -### Endianness - -The file is Big Endian. diff --git a/docs/pkgfiles/planned.md b/docs/pkgfiles/planned.md deleted file mode 100644 index 398f8da..0000000 --- a/docs/pkgfiles/planned.md +++ /dev/null @@ -1,22 +0,0 @@ -# Planned PKGFILE features. - ---- - -### Compression - -> Planned for next PKGFILE version. - -Currently, compression is not supported, since PKGFILE is an all-in-one solution this is very unpleasant. -When compression will be implemented, there is a big possibility that the manifest won't be compressed. -This is done to allow servers to easily parse and inspect manifests. -The compression will likely be versatile in the way that the format will be stated in the header and the pkgr -implementation can work it out by itself. -There will be a default compression format, likely gzip. - -### Compact Manifest - -> Not planned yet. - -Right now, the manifest is an utf-8 blob sandwiched between the header and the archive. -This also requires a fixed max size for the manifest which is unfavourable. -In the future, the manifest may turn into a versatile binary blob with no size limitations. \ No newline at end of file diff --git a/manifest/src/bin.rs b/manifest/src/bin.rs index 5142d99..f55a8e5 100644 --- a/manifest/src/bin.rs +++ b/manifest/src/bin.rs @@ -5,15 +5,5 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Bin { pub root: String, - #[serde(default)] pub checksums: HashMap, } - -impl Default for Bin { - fn default() -> Self { - Bin { - root: String::default(), - checksums: HashMap::default(), - } - } -} diff --git a/manifest/src/build.rs b/manifest/src/build.rs index 6d406b1..1879710 100644 --- a/manifest/src/build.rs +++ b/manifest/src/build.rs @@ -8,13 +8,3 @@ pub struct Build { pub install_script: String, pub dependencies: HashMap, } - -impl Default for Build { - fn default() -> Self { - Build { - dependencies: HashMap::default(), - build_script: String::default(), - install_script: String::default() - } - } -} \ No newline at end of file diff --git a/manifest/src/lib.rs b/manifest/src/lib.rs index 89526f2..0d52840 100644 --- a/manifest/src/lib.rs +++ b/manifest/src/lib.rs @@ -6,17 +6,17 @@ pub mod bin; pub mod build; pub mod fs; pub mod package; -pub mod ext; +pub mod pkgr; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(default)] -pub struct Manifest> { +pub struct Manifest> { pub package: package::Package, pub dependencies: HashMap, pub fs: fs::FS, pub bin: Option, pub build: Option, - pub ext: E, + pub pkgr: P, } impl Manifest

{ @@ -50,7 +50,7 @@ impl Default for Manifest { fs: fs::FS::default(), bin: None, build: None, - ext: None, + pkgr: None, } } } diff --git a/manifest/src/package.rs b/manifest/src/package.rs index d7c126c..233206d 100644 --- a/manifest/src/package.rs +++ b/manifest/src/package.rs @@ -12,16 +12,6 @@ pub enum PackageType { Meta, } -impl ToString for PackageType { - fn to_string(&self) -> String { - match &self { - PackageType::Application => "application", - PackageType::Library => "library", - PackageType::Meta => "meta" - }.to_string() - } -} - #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(default)] pub struct Package { diff --git a/manifest/src/ext.rs b/manifest/src/pkgr.rs similarity index 80% rename from manifest/src/ext.rs rename to manifest/src/pkgr.rs index b47a60c..530a37c 100644 --- a/manifest/src/ext.rs +++ b/manifest/src/pkgr.rs @@ -2,9 +2,9 @@ use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Extension {} +pub struct PKGR {} -impl Display for Extension { +impl Display for PKGR { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "") } diff --git a/package.example.toml b/package.example.toml index c20aabb..c99108d 100644 --- a/package.example.toml +++ b/package.example.toml @@ -84,16 +84,16 @@ install_script = "scripts/install" # relative to pkg [build.dependencies] base = "latest,stable" # selected by default -## ext.* +## pkgr.* # packager is the official client but you may use other clients supporting the "pkgr v1 spec". -# other clients may offer extra functionality this must be put under "ext.*" -[ext] +# other clients may offer extra functionality this must be put under "pkgr.*" +[pkgr] -## ext.bootstrap +## pkgr.bootstrap # This section is used for bootpkg. An edition of packager that bootstraps the full version. # This exists so that packager is easy to install on anything! # and only 1 release channel for pkgr -[ext.bootstrap] +[pkgr.bootstrap] ## any non-zero = installed check_installed_commands = [ "sh scripts/check_installed" diff --git a/package.toml b/package.toml new file mode 100644 index 0000000..81240ab --- /dev/null +++ b/package.toml @@ -0,0 +1,69 @@ +[package] +name = "packager" #* +description = "A package installation tool" #* +version = 1 # this can automatically be incremented when publishing by running `pkgr publish -i ...` +tags = [ "prod", "pkgr-spec-1" ] +type = "application" + +arch = "x86_64" # this is automatically filled by `pkgr publish ...` + +## dependencies +# you may use the following syntax +# "" or ",,..." +[dependencies] + +## bin +# Used for systems that don't want to build pkgs. +[bin] # binary files root + +## bin.root +# ** RELATIVE TO PACKAGE ROOT ** +# bin.root specifies the root of the installed tree. +# anything in here will be overlayed on top of the system. +root = "/root" #* + +## bin.checksums +# ** KEYS are relative to BIN.ROOT ** +# ** VALUES are relative to PKG ROOT ** +# checksums is used to perform checksums before install +# values may be paths or a uri. You may include variables. +# supported variables: +# - @name +# - @version +# - @display_version +[bin.checksums] +"/usr/bin/pkgr" = "https://ixvd.net/checksums/packager/@version" + +## build +# Scripts will be copied to a custom root. +# After the pacakge is built, the install script is ran. +# After the install script the build directory will be deleted and an CTREE (changed tree) will be generated. +# Then the CTREE will be used to copy the files over. +[build] +build_script = "scripts/build" # relative to pkg +install_script = "scripts/install" # relative to pkg + +[build.dependencies] +base = "latest,stable" # selected by default + +## pkgr.* +# packager is the official client but you may use other clients supporting the "pkgr v1 spec". +# other clients may offer extra functionality this must be put under "pkgr.*" +[pkgr] + +## pkgr.bootstrap +# This section is used for bootpkg. An edition of packager that bootstraps the full version. +# This exists so that packager is easy to install on anything! +# and only 1 release channel for pkgr +[pkgr.bootstrap] +## any non-zero = installed +check_installed_commands = [ + "sh scripts/check_installed" +] + +# any non-zero = fail +commands = [ + "sh scripts/bootstrap/download_latest @version /tmp/pkgr.pkg", + "sh scripts/bootstrap/dirty_install /tmp/pkgr.pkg", + "sh scripts/check_installed" +] diff --git a/pkg.py b/pkg.py deleted file mode 100644 index 03e20ab..0000000 --- a/pkg.py +++ /dev/null @@ -1,79 +0,0 @@ -import glob -import os -import sys -import tarfile - - -def build_package(package_toml_path, output_path, directories_to_include): - data = read_package_toml(package_toml_path) - header = build_header(data) - pkg_path = output_path - - with open(pkg_path, mode='wb') as pkg: - pkg.write(header) - write_manifest(pkg, data) - build_tarball(pkg, directories_to_include) - - return pkg_path - - -def read_package_toml(package_toml_path): - with open(package_toml_path, mode='r') as mani: - return mani.read() - - -def build_header(data): - header = bytes([0x01, (len(data) >> 8) & 0xFF, len(data) & 0xFF]) - return header - - -def write_manifest(pkg, data): - pkg.write(data.encode("utf-8")) - - -def build_tarball(pkg, directories_to_include): - with tarfile.TarFile("/tmp/pkgtar", 'w') as pkgtar: - for directory in directories_to_include: - add_files_to_tar(pkgtar, directory, True) - - append_tar_to_pkg(pkg) - cleanup_tmp_files() - - -def add_files_to_tar(pkgtar, directory, skip_target=False): - for root, dirs, files in os.walk(directory): - for file in files: - if skip_target and "target" in root: - continue - print(f"\33[2Kadd: {os.path.join(root, file)}", end="\r", flush=True) - # print() - pkgtar.add(os.path.join(root, file)) - print("\33[2K", end="\r", flush=True) - - -def append_tar_to_pkg(pkg): - with open("/tmp/pkgtar", 'rb') as pkgtar: - pkg.write(pkgtar.read()) - - -def cleanup_tmp_files(): - print("deleting /tmp/pkgtar...") - os.unlink("/tmp/pkgtar") - - -if __name__ == '__main__': - if len(sys.argv) < 3: - print("Usage: pkg.py [ ...]") - sys.exit(1) - - package_toml_path = sys.argv[1] - output_path = sys.argv[2] - directories_to_include = glob.glob(sys.argv[3]) if len(sys.argv) == 4 else sys.argv[3:] - - try: - pkg_path = build_package(package_toml_path, output_path, directories_to_include) - print(f"Package created: {pkg_path}") - except FileNotFoundError: - print("Error: File not found.") - except Exception as e: - print(f"Error occurred: {e}") diff --git a/pkg/scripts/bootstrap/dirty_install b/pkg/scripts/bootstrap/dirty_install new file mode 100644 index 0000000..41d3f5d --- /dev/null +++ b/pkg/scripts/bootstrap/dirty_install @@ -0,0 +1,3 @@ +#!/bin/sh + +printf "" \ No newline at end of file diff --git a/pkg/scripts/bootstrap/download_latest b/pkg/scripts/bootstrap/download_latest new file mode 100644 index 0000000..178bd4e --- /dev/null +++ b/pkg/scripts/bootstrap/download_latest @@ -0,0 +1,9 @@ +#!/bin/sh + +fetch_latest_version() { + printf "" +} + +download_file() { + printf "" +} \ No newline at end of file diff --git a/pkg/scripts/check_installed b/pkg/scripts/check_installed new file mode 100644 index 0000000..41d3f5d --- /dev/null +++ b/pkg/scripts/check_installed @@ -0,0 +1,3 @@ +#!/bin/sh + +printf "" \ No newline at end of file diff --git a/pkgfile/src/lib.rs b/pkgfile/src/lib.rs index 6a9457d..407055c 100644 --- a/pkgfile/src/lib.rs +++ b/pkgfile/src/lib.rs @@ -1,9 +1,4 @@ -use std::error::Error; -use std::fmt::{Display, Formatter}; -use std::io; -use std::path::Path; - -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone)] pub struct PKGFile { pub manifest: String, pub data: Vec, @@ -28,56 +23,28 @@ impl Default for PKGFile { } } -#[derive(Debug)] -pub enum PKGFileError { - IOError(io::Error), - ParsingError(String) -} - -impl Display for PKGFileError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - PKGFileError::IOError(e) => write!(f, "IOError: {}", e), - PKGFileError::ParsingError(s) => write!(f, "ParsingError: {}", s) - } - } -} - -impl Error for PKGFileError {} - -impl<'a> TryFrom<&'a Path> for PKGFile { - type Error = PKGFileError; - fn try_from(path: &'a Path) -> Result { - let d = match std::fs::read(path) { - Ok(d) => d, - Err(e) => return Err(PKGFileError::IOError(e)) - }; - PKGFile::try_from(d) - } -} - impl TryFrom> for PKGFile { - type Error = PKGFileError; + type Error = (); - fn try_from(value: Vec) -> Result { + fn try_from(value: Vec) -> Result { match value[0] { 1 => { let header: Vec = value[..3].iter().map(|v| u32::from(*v)).collect(); let manifest_size: u32 = (header[1] << 8) | header[2]; if manifest_size > value.len() as u32 { - return Err(PKGFileError::ParsingError("Invalid header length".into())); + return Err(()); } Ok(PKGFile { manifest: match String::from_utf8( value[3..(manifest_size as usize + 3)].to_vec(), ) { Ok(s) => s, - _ => return Err(PKGFileError::ParsingError("Could not parse manifest".into())), + _ => return Err(()), }, data: value[(manifest_size as usize + 3)..].to_vec(), }) } - _ => Err(PKGFileError::ParsingError("Unknown pkgfile version".into())), + _ => Err(()), } } } diff --git a/pkgr/Cargo.toml b/pkgr/Cargo.toml index e43b436..cc6e55b 100644 --- a/pkgr/Cargo.toml +++ b/pkgr/Cargo.toml @@ -23,7 +23,3 @@ serde = { version = "1.0.171", features = ["derive"] } libc = "0.2.80" reqwest = { version = "0.11.18", features = ["blocking"] } tar = "0.4.39" -humantime = "2.1.0" -expanduser = "1.2.2" -url = { version = "2.4.0", features = ["serde"] } -dns-lookup = "2.0.3" diff --git a/pkgr/package.toml b/pkgr/package.toml deleted file mode 100644 index fa95cd9..0000000 --- a/pkgr/package.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "packager" -description = "A package installation tool" -version = 1 -tags = [ "prod", "pkgr-spec-1" ] -type = "application" -arch = "x86_64" - -[dependencies] - -[bin] -root = "/root" - -[bin.checksums] -"/usr/bin/pkgr" = "https://ixvd.net/checksums/packager/@version" - -[build] -build_script = "scripts/build" -install_script = "scripts/install" - -[build.dependencies] - -[ext] - -[ext.bootstrap] -check_installed_commands = [ - "file /usr/bin/pkgr" -] - -commands = [ - "cp root/usr/bin/pkgr /usr/bin/pkgr" -] diff --git a/pkgr/skel/etc/pkgr.d/repos.toml b/pkgr/skel/etc/pkgr.d/repos.toml deleted file mode 100644 index 2723e7b..0000000 --- a/pkgr/skel/etc/pkgr.d/repos.toml +++ /dev/null @@ -1,4 +0,0 @@ -[repo.main] -name = "Main" -url = "tcp://pkgs.ixvd.net:1050" - diff --git a/pkgr/skel/etc/pkgr.toml b/pkgr/skel/etc/pkgr.toml deleted file mode 100644 index 2ee5004..0000000 --- a/pkgr/skel/etc/pkgr.toml +++ /dev/null @@ -1,7 +0,0 @@ -build_by_default = false -tmp_dir = "/tmp/pkgr" - -[storage] -repo_file = "/etc/pkgr.d/repos.toml" -data_dir = "/var/lib/pkgr/packages" -index_dir = "/var/lib/pkgr/indexes" \ No newline at end of file diff --git a/pkgr/skel/var/lib/pkgr/indexes/repo.toml b/pkgr/skel/var/lib/pkgr/indexes/repo.toml deleted file mode 100644 index 47fa234..0000000 --- a/pkgr/skel/var/lib/pkgr/indexes/repo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[index.main] -last_update = "1610219288" -[index.main.packager] -versions = [1, 2, 3] -tags = ["tag"] - -## rust -# IndexedPackage -# - name -> packager -# - origin_repo -> main -# - versions -> [1,2,3] -# - tags -> ["tag"] -# - get_package() -> Package - -## rust -# Repo -# - name -> main -# - last_update -> 1610219288 -# - update_repo() -> io::Result<()> -# - searchIndex(p: PackageIdentifier) -> IndexedPackage \ No newline at end of file diff --git a/pkgr/src/api/client.rs b/pkgr/src/api/client.rs deleted file mode 100644 index e69de29..0000000 diff --git a/pkgr/src/api/mod.rs b/pkgr/src/api/mod.rs deleted file mode 100644 index 1ed3d70..0000000 --- a/pkgr/src/api/mod.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::collections::HashMap; -use serde; -use serde::{Deserialize, Serialize}; - -pub mod client; - -#[derive(Serialize, Deserialize)] -pub enum Query { - #[serde(rename = "pull")] - Pull { - name: String, - version: Option, - tags: Vec - }, - #[serde(rename = "push")] - Push { - // todo: review me pls - _data: Vec - }, - #[serde(rename = "index")] - Index { - request_update: bool, - fetch: bool - } -} - -#[derive(Serialize, Deserialize)] -pub struct Request { - version: u32, - id: String, - token: Option, - query: HashMap -} - -#[derive(Serialize, Deserialize)] -pub struct DataErrorDetails { - actor: String, - detailed_cause: String, - recovery_options: Vec, -} - -#[derive(Serialize, Deserialize)] -pub struct DataError { - name: String, - cause: Option, - details: Option -} - -#[derive(Serialize, Deserialize)] -pub enum Data { - Pull { - _data: Option>, - } -} - -#[derive(Serialize, Deserialize)] -pub struct Response { - version: u32, - id: String, - reply_to: String, - errors: HashMap, - data: HashMap -} \ No newline at end of file diff --git a/pkgr/src/commands.rs b/pkgr/src/commands.rs index 80e9448..4393869 100644 --- a/pkgr/src/commands.rs +++ b/pkgr/src/commands.rs @@ -1,17 +1,12 @@ -use std::process::exit; - -use clap::{Parser, Subcommand}; -use colored::Colorize; -use log::{debug, error, info, trace, warn}; - -use manifest::package::PackageType; - use crate::package::identifier::PackageIdentifier; +use crate::package::installer::{InstallType, PackageInstaller}; use crate::package::Package; -use crate::package::queue::PackageQueue; +use clap::{Parser, Subcommand}; +use log::{debug, error, info, trace, warn}; +use manifest::Manifest; +use std::process::exit; +use crate::CONFIG; use crate::process::Process; -use crate::types::fetch::TryFetch; -use crate::util::prompts::prompt_bool; #[derive(Parser, Debug)] #[clap(name = "pkgr", version)] @@ -26,8 +21,6 @@ pub enum Command { Install { #[arg(short, long, default_value_t = false)] build: bool, - #[arg(short, long, default_value_t = false)] - ask: bool, package_identifier: PackageIdentifier, }, /// Remove a package from the system @@ -45,11 +38,7 @@ pub enum Command { }, /// Update packages on the system Update, - /// Get info about a package - Info { - package_identifier: Option - }, - #[cfg(debug_assertions)] + #[command(hide = true)] Debug, #[command(hide = true)] None, @@ -60,18 +49,18 @@ impl Command { match self { Command::Install { build, - ask, package_identifier, } => { warn!("Installer does not run in isolation."); let start = std::time::Instant::now(); - let _unix_start = std::time::SystemTime::now() + let unix_start = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap(); info!("Parsing package..."); - let mut pkg = Package::try_fetch(package_identifier.clone()).unwrap(); + trace!("Fetching package: {}", package_identifier); + let mut pkg = Package::fetch(package_identifier.clone()).unwrap(); debug!("manifest size: {}kb", pkg.pkgfile.manifest.len() / 1024); debug!("files size: {}kb", pkg.pkgfile.data.len() / 1024); @@ -81,29 +70,24 @@ impl Command { exit(1); } - let mut queue = PackageQueue::new(); - queue.add_package(pkg, *build); - trace!("Installing queue..."); - { - if *ask { - info!("Install following packages?"); - info!(target: "item", "{}", queue); - if !prompt_bool("Continue?", false) { - return; - } + trace!("Starting install..."); + match pkg.install(CONFIG.with(|c| if !*build { c.build_by_default } else { *build })) { + Ok(_) => (), + Err(e) => { + error!("Install failed: {}", e.to_string()); + exit(1); } } - queue.install(*build); let end = std::time::Instant::now(); - let _unix_end = std::time::SystemTime::now() + let unix_end = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap(); let duration = end.duration_since(start); info!("Install complete."); - info!("Install took {}.", humantime::format_duration(duration)); + info!("Install took {}ms.", duration.as_nanos() as f64 / 1000000.0); } Command::Remove { package_identifier, @@ -122,74 +106,6 @@ impl Command { Command::Update => { error!("Update is not yet implemented."); } - Command::Info { - package_identifier - } => { - if let Some(p) = package_identifier { - if let Ok(mut pkg) = Package::try_fetch(p.clone()) { - trace!("{}", pkg.pkgfile.manifest); - info!(target: "item", "Identifier: {:?}", pkg.identifier); - info!(target: "item", ""); - let mani = pkg.manifest(); - info!(target: "item", "Package name: {}", mani.package.name); - info!(target: "item", "Package description: {}", mani.package.description); - info!(target: "item", "Package version: {}", mani.package.version); - info!(target: "item", "Package tags: {}", mani.package.tags.join(", ")); - info!(target: "item", "Package type: {}", mani.package.package_type.to_string()); - info!(target: "item", ""); - info!(target: "item", "Supported install types: {}", { - let mut types = vec![]; - if let Some(_) = mani.bin { types.push("bin") } - if let Some(_) = mani.build { types.push("build") } - if let PackageType::Meta = mani.package.package_type { types.push("meta") } - types.join(", ") - }); - info!(target: "item", ""); - info!(target: "item", "Dependencies: {}", { - let deps = pkg.dependencies(); - if deps.len() == 0 { - String::from("None") - } else { - deps - .iter() - .map(|p| { - p.identifier.to_string() - }) - .collect::>() - .join(", ") - } - }); - info!(target: "item", "Build Dependencies: {}", { - let deps = pkg.build_dependencies(); - if deps.len() == 0 { - String::from("None") - } else { - deps - .iter() - .map(|p| { - p.identifier.to_string() - }) - .collect::>() - .join(", ") - } - }); - } else { - error!("Could not find {p}"); - } - } else { - info!("Welcome to pkgr!\n\ - {}\n\ - To get help please run \"{} -h\"", env!("CARGO_PKG_DESCRIPTION"), std::env::args().nth(0).unwrap()); - info!(""); - info!("version: {}", env!("CARGO_PKG_VERSION")); - info!("authors: {}", env!("CARGO_PKG_AUTHORS")); - - info!(""); - info!("If you can't seem to figure something out, use environment variable: PKGR_LOG_LEVEL=debug"); - trace!("{}", "The trace log level should really only be used by PKGR devs.".red()); - } - } - #[cfg(debug_assertions)] Command::Debug => { trace!("Trace message.\nWith newline."); debug!("Debug message.\nWith newline."); @@ -201,12 +117,16 @@ impl Command { Process::command(vec!["sh", "-c", "echo whoami: $(whoami)"]) .spawn() .unwrap(); - if let Ok(_user) = std::env::var("SUDO_USER") { + if let Ok(user) = std::env::var("SUDO_USER") { Process::command(vec!["sh", "-c", "echo sudo_user: $SUDO_USER"]) .spawn() .unwrap(); } + info!(""); + info!("PKGR VERSION: {}", env!("CARGO_PKG_VERSION")); + info!("PKGR AUTHORS: {}", env!("CARGO_PKG_AUTHORS")); + info!("PKGR DESCRIPTION: {}", env!("CARGO_PKG_DESCRIPTION")); info!(""); info!( "PKGR_LOG_LEVEL: {}", diff --git a/pkgr/src/config/mod.rs b/pkgr/src/config/mod.rs index 4c6876e..9a932d2 100644 --- a/pkgr/src/config/mod.rs +++ b/pkgr/src/config/mod.rs @@ -1,8 +1,4 @@ use serde::{Deserialize, Serialize}; -use storage::Storage; - -mod storage; -pub mod repos; #[derive(Debug, Serialize, Deserialize)] pub struct Config { @@ -10,16 +6,13 @@ pub struct Config { pub build_by_default: bool, #[serde(default)] pub tmp_dir: Option, - #[serde(default)] - pub storage: Storage } impl Default for Config { fn default() -> Config { Config { build_by_default: false, - tmp_dir: Some(String::from("/tmp/pkgr")), - storage: Storage::default() + tmp_dir: Some(String::from("/tmp/pkgr")) } } } diff --git a/pkgr/src/config/repos.rs b/pkgr/src/config/repos.rs deleted file mode 100644 index 8594a25..0000000 --- a/pkgr/src/config/repos.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::collections::HashMap; -use std::str::FromStr; -use serde::{Deserialize, Serialize}; -use url::Url; - -#[derive(Clone, Serialize, Deserialize)] -pub struct Repo { - #[serde(default)] - pub name: String, - pub uri: Url -} - -impl Default for Repo { - fn default() -> Self { - Repo { - name: String::from("Repo"), - uri: Url::parse("tcp://0.0.0.0:0000").unwrap() - } - } -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct RepoFile { - pub repos: HashMap -} - -impl RepoFile { - pub fn from_path(path: &str) -> Result { - match std::fs::read_to_string(path) { - Ok(s) => match toml::from_str(&s) { - Ok(c) => Ok(c), - Err(e) => Err(format!("failed to parse config: {}", e)), - }, - Err(e) => Err(format!("failed to read config: {}", e)), - } - } -} \ No newline at end of file diff --git a/pkgr/src/config/storage.rs b/pkgr/src/config/storage.rs deleted file mode 100644 index 5fa8fa1..0000000 --- a/pkgr/src/config/storage.rs +++ /dev/null @@ -1,24 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Serialize, Deserialize)] -pub struct Storage { - /// Where the repositories are defined. - #[serde(default)] - pub repo_file: String, - /// Where to store pkgs data - #[serde(default)] - pub data_dir: String, - /// Where to store repo indexes - #[serde(default)] - pub index_dir: String, -} - -impl Default for Storage { - fn default() -> Self { - Storage { - repo_file: String::from("/etc/pkgr.d/repos.toml"), - data_dir: String::from("/var/lib/pkgr/packages"), - index_dir: String::from("/var/lib/pkgr/indexes"), - } - } -} diff --git a/pkgr/src/logging.rs b/pkgr/src/logging.rs index daef3eb..5e32d9d 100644 --- a/pkgr/src/logging.rs +++ b/pkgr/src/logging.rs @@ -1,19 +1,18 @@ -use std::env; - use colored::Colorize; use fern::Dispatch; use log::{Record, SetLoggerError}; +use std::env; fn format_regular>(log: S, record: &Record) -> String { let log = log.into(); let line_prefix = |line: String, extend: bool| { let prefix = if extend { match record.level() { - log::Level::Trace => " ]".bright_blue(), - log::Level::Debug => " ?".green(), - log::Level::Info => " >".blue(), - log::Level::Warn => " #".yellow(), - log::Level::Error => " !".red(), + log::Level::Trace => " :".bright_blue(), + log::Level::Debug => " :".green(), + log::Level::Info => " :".blue(), + log::Level::Warn => " :".yellow(), + log::Level::Error => " :".red(), }.to_string() } else { match record.level() { @@ -29,7 +28,7 @@ fn format_regular>(log: S, record: &Record) -> String { let mut lines = log.lines().peekable(); let mut output = match lines.peek() { - Some(_line) => line_prefix(lines.next().unwrap().to_string(), false), + Some(line) => line_prefix(lines.next().unwrap().to_string(), false), None => return "".to_string(), }; @@ -44,12 +43,14 @@ pub fn setup_logger() -> Result<(), SetLoggerError> { Dispatch::new() .format(|out, message, record| { match record.metadata().target() { - // command output logging - "command:stdout" => out.finish(format_args!("{} {}", ">>".cyan(), message.to_string())), - "command:stderr" => out.finish(format_args!("{} {}", ">>".red(), message.to_string())), - // this target means, it's an item and not a log. - "item" => out.finish(format_args!("{} {}", "*".blue(), message.to_string())), - // default logging + "command:stdout" => { + out.finish(format_args!("{} {}", ">>".cyan(), message.to_string())); + return; + } + "command:stderr" => { + out.finish(format_args!("{} {}", ">>".red(), message.to_string())); + return; + } _ => out.finish(format_args!("{}", format_regular(message.to_string(), record))), } }) diff --git a/pkgr/src/main.rs b/pkgr/src/main.rs index 3aff896..97f721f 100644 --- a/pkgr/src/main.rs +++ b/pkgr/src/main.rs @@ -1,27 +1,16 @@ -use clap::Parser; -use log::trace; - use crate::commands::Cli; +use crate::process::Process; +use clap::Parser; +use colored::Colorize; +use log::trace; +use std::process::Command; -/// pkgr's commands. mod commands; -/// Logging implementations for pkgr. mod logging; -/// Package and helpers. mod package; -/// Repo and helpers -mod repo; -/// Process wrapper with logging wrapper. mod process; -/// tmpfs wrapper. mod tmpfs; -/// pkgr's optional config. mod config; -/// custom types used by pkgr -mod types; -/// utils -mod util; -mod api; thread_local! { static CONFIG: config::Config = config::Config::from_path("/etc/pkgr.toml") @@ -29,8 +18,7 @@ thread_local! { } fn main() { - logging::setup_logger() - .expect("unable to set logger."); + logging::setup_logger().expect("Unable to setup logger."); #[cfg(not(debug_assertions))] { diff --git a/pkgr/src/package/fetch.rs b/pkgr/src/package/fetch.rs new file mode 100644 index 0000000..a97dfb6 --- /dev/null +++ b/pkgr/src/package/fetch.rs @@ -0,0 +1,55 @@ +use crate::package::identifier::PackageLocator; +use pkgfile::PKGFile; +use reqwest::blocking::get; +use std::error::Error; +use std::fmt::Display; +use std::io::Read; + +#[derive(Debug)] +pub enum FetchError { + HTTPError(reqwest::Error), + IOError(std::io::Error), + ParseError, +} + +impl Display for FetchError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + FetchError::HTTPError(e) => write!(f, "HTTP Error: {}", e), + FetchError::IOError(e) => write!(f, "IO Error: {}", e), + FetchError::ParseError => write!(f, "Parse Error"), + } + } +} + +impl Error for FetchError {} + +pub fn fetch_by_path>(path: S) -> Result { + std::fs::read(path.into()) + .map_err(|e| FetchError::IOError(e)) + .and_then(|bytes| PKGFile::try_from(bytes).map_err(|_| FetchError::ParseError)) +} + +pub fn fetch_by_uri>(uri: S) -> Result { + // get file contents as bytes + let mut bytes = Vec::new(); + match get(uri.into()) { + Ok(mut response) => { + match response.take(1024 * 1024).read_to_end(&mut bytes) { + Ok(_) => (), + Err(e) => return Err(FetchError::IOError(e)), + }; + } + Err(e) => return Err(FetchError::HTTPError(e)), + }; + // parse bytes as PKGFile + match PKGFile::try_from(bytes) { + Ok(pkgfile) => Ok(pkgfile), + Err(e) => Err(FetchError::ParseError), + } +} + +pub fn fetch_by_package_locator(package_locator: PackageLocator) -> Result { + // TODO: search index for package locator + Ok(PKGFile::default()) +} diff --git a/pkgr/src/package/identifier.rs b/pkgr/src/package/identifier.rs index e39ac87..3fde5e7 100644 --- a/pkgr/src/package/identifier.rs +++ b/pkgr/src/package/identifier.rs @@ -1,9 +1,7 @@ use std::error::Error; -use std::fmt::Formatter; use std::str::FromStr; use regex::Regex; -use serde::Serializer; #[derive(Debug, Clone)] pub enum PackageIdentifierError { @@ -24,29 +22,11 @@ impl std::fmt::Display for PackageIdentifierError { impl Error for PackageIdentifierError {} -#[derive(Clone, Eq, PartialEq)] +#[derive(Debug, Clone)] pub enum PackageIdentifier { PackageLocator(PackageLocator), URI(String), - Path(String) -} - -impl std::fmt::Debug for PackageIdentifier { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - if f.alternate() { - match self { - PackageIdentifier::PackageLocator(pl) => write!(f, "PackageLocator({:#?})", pl), - PackageIdentifier::URI(uri) => write!(f, "URI({:?})", uri), - PackageIdentifier::Path(path) => write!(f, "Path({:?})", path), - } - } else { - match self { - PackageIdentifier::PackageLocator(pl) => write!(f, "PL: {:?}", pl), - PackageIdentifier::URI(uri) => write!(f, "URI: {:?}", uri), - PackageIdentifier::Path(path) => write!(f, "Path: {:?}", path), - } - } - } + Path(String), } impl std::fmt::Display for PackageIdentifier { @@ -59,7 +39,7 @@ impl std::fmt::Display for PackageIdentifier { } } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone)] pub struct PackageLocator { pub name: String, pub version: Option, @@ -160,9 +140,8 @@ impl FromStr for PackageLocator { } } -impl TryFrom<(String, String)> for PackageLocator { - type Error = PackageIdentifierError; - fn try_from((name, locate_str): (String, String)) -> Result { +impl From<(String, String)> for PackageLocator { + fn from((name, locate_str): (String, String)) -> Self { // name = "pkg" // locate_str = "1.0.0:tag1,tag2" or "1.0.0" or "tag1,tag2" let mut version = None; @@ -186,10 +165,10 @@ impl TryFrom<(String, String)> for PackageLocator { ); } - Ok(PackageLocator { + PackageLocator { name, version, tags, - }) + } } } diff --git a/pkgr/src/package/installer/errors.rs b/pkgr/src/package/installer/errors.rs index 332a06f..9e86f1b 100644 --- a/pkgr/src/package/installer/errors.rs +++ b/pkgr/src/package/installer/errors.rs @@ -1,26 +1,21 @@ use std::fmt::Display; -use std::io; #[derive(Debug)] pub enum BinError { UnpackError(String), - IOError(io::Error), - Cancelled, } impl Display for BinError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { BinError::UnpackError(e) => write!(f, "Unpack error: {}", e), - BinError::IOError(e) => write!(f, "IO error: {}", e), - BinError::Cancelled => write!(f, "Cancelled by user"), } } } #[derive(Debug)] pub enum BuildError { - InvalidManifest(String), + InvalidManifest, } impl Display for BuildError { @@ -35,15 +30,17 @@ impl Display for BuildError { pub enum InstallError { BuildError(BuildError), BinError(BinError), - InvalidManifest(String), + InvalidManifest, + Generic, } impl ToString for InstallError { fn to_string(&self) -> String { match self { - InstallError::BuildError(e) => format!("{}", e), - InstallError::BinError(e) => format!("{}", e), - InstallError::InvalidManifest(s) => format!("{}", s), + InstallError::BuildError(e) => format!("Build error: \n{}", e), + InstallError::BinError(e) => format!("Bin error: \n{}", e), + InstallError::InvalidManifest => "Invalid manifest".to_string(), + InstallError::Generic => "Install error".to_string(), } } } diff --git a/pkgr/src/package/installer/mod.rs b/pkgr/src/package/installer/mod.rs index 4dbeab0..5da81f9 100644 --- a/pkgr/src/package/installer/mod.rs +++ b/pkgr/src/package/installer/mod.rs @@ -1,17 +1,13 @@ -use std::io; -use std::fs::remove_dir_all; -use std::path::Path; - -use log::{debug, trace}; - +use crate::tmpfs::TempDir; use errors::{BinError, BuildError, InstallError}; +use log::{debug, error, info, trace}; use manifest::Manifest; use pkgfile::PKGFile; +use std::fmt::Display; +use std::process::exit; use crate::CONFIG; - -use crate::tmpfs::TempDir; -use crate::types::fetch::TryFetch; -use crate::util::fs::copy_recursively; +use crate::package::identifier::{PackageIdentifier, PackageLocator}; +use crate::package::Package; pub mod errors; @@ -41,14 +37,11 @@ impl PackageInstaller { if !self.pkgfile.has_data() { return Err(BinError::UnpackError("package has no data".to_string())); } - let path = std::path::Path::new(&path); - if path.exists() { - trace!("cache already exists.."); - debug!("removing cache dir..."); - match remove_dir_all(path) { - Ok(_) => debug!("removed cache directory"), - Err(e) => return Err(BinError::UnpackError(format!("unable to remove directory ({}): {}", path.to_str().unwrap_or("unknown"), e.to_string()))) - } + if std::path::Path::new(&path).exists() { + return Err(BinError::UnpackError(format!( + "path already exists: {}", + path + ))); } tar::Archive::new(self.pkgfile.data.as_slice()) .unpack(&path) @@ -59,32 +52,39 @@ impl PackageInstaller { let mut tmpdir = TempDir::default(); tmpdir.push(&self.manifest.package.name); trace!("extracting package into: {}", tmpdir.to_string()); - if let Err(e) = self.extract_to(tmpdir.to_string()) { - return Err(e); + match self.extract_to(tmpdir.to_string()) { + Ok(_) => {} + Err(e) => return Err(e), } debug!("extracted package in: {}", tmpdir.to_string()); - match self.apply_overlay() { - Ok(_) => Ok(()), - Err(e) => Err(BinError::IOError(e)) - } - } - - fn apply_overlay(&self) -> Result<(), io::Error> { - let mut tmpdir = TempDir::default(); - tmpdir.push(&self.manifest.package.name); - tmpdir.push(&self.manifest.bin.clone().unwrap().root); - if let Err(e) = copy_recursively(&tmpdir.path(), Path::new("/")) { - return Err(e); - } Ok(()) } fn build(&self) -> Result<(), BuildError> { if let None = self.manifest.build.clone() { - return Err(BuildError::InvalidManifest(String::from("No build manifest"))); + return Err(BuildError::InvalidManifest); } let build_manifest = self.manifest.build.clone().unwrap(); // TODO: Check dependencies + for pkg_tuple in build_manifest.dependencies { + let mut pkg = Package::fetch( + PackageIdentifier::PackageLocator( + PackageLocator::from(pkg_tuple) + ) + ).expect("no pkg"); + + if !pkg.is_installed() { + match pkg.install(CONFIG.with(|c| { + c.build_by_default + })) { + Ok(_) => { info!("Installed dependency: \"{}\"", pkg.manifest().package.name) }, + Err(_) => { + error!("Could not install dependency: \"{}\"", pkg.identifier); + exit(1); + } + } + } + } Ok(()) } @@ -95,7 +95,7 @@ impl PackageInstaller { if let None = self.manifest.bin { self.install_type = InstallType::Build; if let None = self.manifest.build { - return Err(InstallError::InvalidManifest(String::from("no bin or build manifest"))); + return Err(InstallError::InvalidManifest); } } } @@ -103,23 +103,17 @@ impl PackageInstaller { if let None = self.manifest.build { self.install_type = InstallType::Bin; if let None = self.manifest.bin { - return Err(InstallError::InvalidManifest(String::from("no build or bin manifest"))); + return Err(InstallError::InvalidManifest); } } } } - let r = match self.install_type { + match self.install_type { InstallType::Bin => self.bin() .map_err(|e| InstallError::BinError(e)), InstallType::Build => self.build() .map_err(|e| InstallError::BuildError(e)), - }; - - if let Err(e) = r { - return Err(e); } - - Ok(()) } } diff --git a/pkgr/src/package/mod.rs b/pkgr/src/package/mod.rs index 6378cef..79de18d 100644 --- a/pkgr/src/package/mod.rs +++ b/pkgr/src/package/mod.rs @@ -1,31 +1,19 @@ -use std::fmt::Display; -use std::path::Path; -use std::process::exit; - -use log::{debug, error, info, trace}; -use reqwest::blocking::get; - -use manifest::build::Build; -use pkgfile::PKGFile; - -use crate::package::identifier::{PackageIdentifier, PackageLocator}; -use crate::types::fetch::TryFetch; +use log::{info, trace}; +pub mod fetch; pub mod identifier; pub mod installer; -pub mod queue; -#[derive(Eq, PartialEq)] pub struct Package { - pub identifier: PackageIdentifier, - pub pkgfile: PKGFile, + pub identifier: identifier::PackageIdentifier, + pub pkgfile: pkgfile::PKGFile, is_installed: bool, is_indexed: bool, } impl Package { /// Create a new package from a package identifier and a package file. - pub fn new(identifier: PackageIdentifier, pkgfile: PKGFile) -> Package { + pub fn new(identifier: identifier::PackageIdentifier, pkgfile: pkgfile::PKGFile) -> Package { Package { identifier, pkgfile, @@ -34,60 +22,34 @@ impl Package { } } + /// Fetch a package from a package identifier. + pub fn fetch( + package_identifier: identifier::PackageIdentifier, + ) -> Result { + match &package_identifier { + identifier::PackageIdentifier::Path(path) => { + trace!("fetching package from path: {}", path); + let pkgfile = fetch::fetch_by_path(path).unwrap(); + Ok(Package::new(package_identifier, pkgfile)) + } + identifier::PackageIdentifier::URI(url) => { + trace!("fetching package from uri: {}", url); + let pkgfile = fetch::fetch_by_uri(url).unwrap(); + Ok(Package::new(package_identifier, pkgfile)) + } + identifier::PackageIdentifier::PackageLocator(locator) => { + trace!("fetching package from locator: {}", locator); + let pkgfile = fetch::fetch_by_package_locator(locator.clone()).unwrap(); + Ok(Package::new(package_identifier, pkgfile)) + } + } + } + /// Get the package manifest. pub fn manifest(&self) -> manifest::Manifest { manifest::Manifest::try_from(self.pkgfile.manifest.clone()).unwrap() } - /// Get package dependencies - pub fn dependencies(&self) -> Vec { - let mut dependencies = vec![]; - for dependency in self.manifest().dependencies { - let pkglocate = if let Ok(pl) = PackageLocator::try_from(dependency.clone()) { - trace!("parsed pl successfully..."); - pl - } else { - error!("Could not parse package locator: {:?} in dependencies.", &dependency); - exit(1); - }; - let pkg = match Package::try_fetch(PackageIdentifier::PackageLocator(pkglocate)) { - Ok(p) => p, - Err(e) => { - error!("Could not fetch dependency: {}", e); - exit(1); - } - }; - dependencies.push(pkg); - } - dependencies - } - - pub fn build_dependencies(&self) -> Vec { - let mut dependencies = vec![]; - for dependency in self - .manifest() - .build - .unwrap_or(Build::default()) - .dependencies { - let pkglocate = if let Ok(pl) = PackageLocator::try_from(dependency.clone()) { - trace!("parsed pl successfully..."); - pl - } else { - error!("Could not parse package locator: {:?} in dependencies.", &dependency); - exit(1); - }; - let pkg = match Package::try_fetch(PackageIdentifier::PackageLocator(pkglocate)) { - Ok(p) => p, - Err(e) => { - error!("Could not fetch dependency: {}", e); - exit(1); - } - }; - dependencies.push(pkg); - } - dependencies - } - /// Install the package. pub fn install(&mut self, build: bool) -> Result<(), installer::errors::InstallError> { let manifest = self.manifest(); @@ -134,57 +96,3 @@ impl Package { unimplemented!(); } } - -#[derive(Debug)] -pub enum FetchError { - HTTPError(reqwest::Error), - IOError(std::io::Error), - ParseError, -} - -impl Display for FetchError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - FetchError::HTTPError(e) => write!(f, "HTTP Error: {}", e), - FetchError::IOError(e) => write!(f, "IO Error: {}", e), - FetchError::ParseError => write!(f, "Parse Error"), - } - } -} - -impl TryFetch for Package { - type Error = FetchError; - - /// Fetch a package from a package identifier. - fn try_fetch(query: PackageIdentifier) -> Result { - trace!("Fetching: {query:#?}"); - let pkgfile = match &query { - PackageIdentifier::Path(s) => match PKGFile::try_from(Path::new(&s)) { - Ok(p) => Ok(p), - Err(e) => Err(FetchError::ParseError) - }, - PackageIdentifier::URI(s) => { - let mut bytes = Vec::new(); - debug!("sending GET request..."); - match get::(s.into()) { - Ok(response) => { - debug!("Got response!"); - if let Ok(b) = response.bytes() { - bytes.extend(b); - } - } - Err(e) => return Err(FetchError::HTTPError(e)), - }; - // parse bytes as PKGFile - match PKGFile::try_from(bytes) { - Ok(pkgfile) => Ok(pkgfile), - Err(_e) => Err(FetchError::ParseError), - } - } - PackageIdentifier::PackageLocator(l) => unimplemented!() - }; - - pkgfile - .map(|p| Package::new(query, p)) - } -} \ No newline at end of file diff --git a/pkgr/src/package/queue.rs b/pkgr/src/package/queue.rs deleted file mode 100644 index 601d8da..0000000 --- a/pkgr/src/package/queue.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::fmt::{Display, Formatter}; - -use log::trace; - -use crate::package::Package; - -pub struct PackageQueue { - packages: Vec, -} - -impl PackageQueue { - pub fn new() -> Self { - PackageQueue { - packages: vec![] - } - } - - pub fn add_package(&mut self, package: Package, build: bool) { - let dependencies = package.dependencies(); - for dependency in dependencies { - trace!("Checking package: {}", &dependency.identifier); - if self.packages.contains(&dependency) { - continue; - } - trace!("Adding package: {}", &dependency.identifier); - self.packages.push(dependency); - } - if !self.packages.contains(&package) { - self.packages.push(package); - } - } - - pub fn install(&mut self, build: bool) { - self.packages - .iter_mut() - .for_each(|pkg| { - pkg.install(build).expect("TODO: panic message"); - }); - } -} - -impl Display for PackageQueue { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - for pkg in &self.packages { - if let Err(e) = write!(f, "{}", pkg.identifier) { - return Err(e); - } - } - write!(f, "") - } -} \ No newline at end of file diff --git a/pkgr/src/process.rs b/pkgr/src/process.rs index fbaf567..f6f4e21 100644 --- a/pkgr/src/process.rs +++ b/pkgr/src/process.rs @@ -1,8 +1,8 @@ use std::io::{BufRead, BufReader}; use std::process::Command; - use log::{info, trace}; + pub struct Process { pub command: Vec, pub cwd: Option, diff --git a/pkgr/src/repo/index/index_package.rs b/pkgr/src/repo/index/index_package.rs deleted file mode 100644 index ca60160..0000000 --- a/pkgr/src/repo/index/index_package.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::io; -use std::path::Path; -use serde::{Deserialize, Serialize}; -use url::Url; -use pkgfile::PKGFile; -use crate::api::Query; -use crate::CONFIG; -use crate::package::Package; -use crate::repo::index::RepoIndex; - -/// This struct solely exists for indexing and has no real functionality. -#[derive(Serialize, Deserialize)] -pub struct IndexPackage { - name: String, - versions: Vec, - tags: Vec, - uri: Url -} \ No newline at end of file diff --git a/pkgr/src/repo/index/mod.rs b/pkgr/src/repo/index/mod.rs deleted file mode 100644 index fc516b6..0000000 --- a/pkgr/src/repo/index/mod.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::collections::HashMap; -use std::io; -use std::path::Path; -use serde::{Deserialize, Serialize}; -use crate::api::Request; -use crate::CONFIG; -use crate::repo::index::index_package::IndexPackage; -use crate::repo::Repo; -use crate::types::fetch::{Fetch, TryFetch}; -use crate::util::create_uuid; - -pub mod index_package; - -#[derive(Serialize, Deserialize)] -pub struct RepoIndex { - origin_repo: String, - packages: HashMap -} - -impl RepoIndex { - // /// Fetch existing index or create a new one. - // pub fn from_repo(repo: Repo) -> Self { - // - // } - // - // /// Create new index. - // pub fn create_with_repo(repo: Repo) -> Self { - // } - - /// Get repo - pub fn get_repo(&self) -> io::Result { - Ok(Repo::from_name(&self.origin_repo)?) - } - - pub fn from_path(path: &str) -> Result { - match std::fs::read_to_string(path) { - Ok(s) => match toml::from_str(&s) { - Ok(c) => Ok(c), - Err(e) => Err(format!("failed to parse config: {}", e)), - }, - Err(e) => Err(format!("failed to read config: {}", e)), - } - } -} - -impl TryFetch for RepoIndex { - type Error = (); - /// Fetch - fn try_fetch(query: Repo) -> Result { - let path = CONFIG.with(|c| c.storage.index_dir.clone()) + query.uri.as_str() + ".toml"; - if Path::new(path.as_str()).exists() { - RepoIndex::from_path(path.as_str()) - .map_err(|_| ()) - } else { - Err(()) - } - } -} \ No newline at end of file diff --git a/pkgr/src/repo/mod.rs b/pkgr/src/repo/mod.rs deleted file mode 100644 index d0c3e88..0000000 --- a/pkgr/src/repo/mod.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::io; -use std::io::{Error, ErrorKind}; -use std::path::Path; -use url::Url; -use crate::CONFIG; -use crate::config::repos::RepoFile; - -/// Indexed repos -pub mod index; - -pub struct Repo { - name: String, - uri: Url, -} - -impl Repo { - pub fn from_name(name: &String) -> io::Result { - let r = RepoFile::from_path(CONFIG.with(|c| c.storage.repo_file.clone()).as_str()) - .map_err(|e| Error::new(ErrorKind::Other, e))?; - let r = r - .repos - .get(name) - .ok_or(Error::new(ErrorKind::InvalidData, "Could not get repo"))?; - Ok(Repo { - name: r.name.clone(), - uri: r.uri.clone() - }) - } - - pub fn get_name(&self) -> String { - self.name.clone() - } - - pub fn get_uri(&self) -> Url { - self.uri.clone() - } - - /// Fetch indexed repo - pub fn get_index(&self) { - - } -} \ No newline at end of file diff --git a/pkgr/src/tmpfs.rs b/pkgr/src/tmpfs.rs index 7d68892..d21aff7 100644 --- a/pkgr/src/tmpfs.rs +++ b/pkgr/src/tmpfs.rs @@ -1,32 +1,20 @@ use std::path::PathBuf; - use crate::CONFIG; -#[derive(Clone)] pub struct TempDir { path: PathBuf, } impl TempDir { pub fn new(path: PathBuf) -> TempDir { - let pbs: String = path.to_str().unwrap().into(); - let path = expanduser::expanduser(&pbs).unwrap(); if !path.exists() { std::fs::create_dir_all(&path).unwrap(); } TempDir { path } } - pub fn path(&self) -> PathBuf { - self.path.clone() - } - pub fn push>(&mut self, path: S) { - let mut path_str = path.into(); - if path_str.starts_with('/') { - path_str = path_str[1..].to_string(); - } - self.path.push(path_str); + self.path.push(path.into()); } } diff --git a/pkgr/src/types/fetch.rs b/pkgr/src/types/fetch.rs deleted file mode 100644 index d3b7eac..0000000 --- a/pkgr/src/types/fetch.rs +++ /dev/null @@ -1,10 +0,0 @@ -/// Get a result from an external source -pub trait Fetch { - fn fetch(query: Q) -> R; -} - -/// Try to get a result from an external source -pub trait TryFetch { - type Error; - fn try_fetch(query: Q) -> Result; -} \ No newline at end of file diff --git a/pkgr/src/types/mod.rs b/pkgr/src/types/mod.rs deleted file mode 100644 index c798af5..0000000 --- a/pkgr/src/types/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod fetch; \ No newline at end of file diff --git a/pkgr/src/util/fs.rs b/pkgr/src/util/fs.rs deleted file mode 100644 index 815b950..0000000 --- a/pkgr/src/util/fs.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::{fs, io}; -use std::fs::DirEntry; -use std::path::Path; - -use log::trace; - -pub fn visit_dirs(dir: &Path, cb: &dyn Fn(&DirEntry)) -> std::io::Result<()> { - if dir.is_dir() { - for entry in std::fs::read_dir(dir)? { - let entry = entry?; - let path = entry.path(); - if path.is_dir() { - visit_dirs(&path, cb)?; - } else { - cb(&entry); - } - } - } - Ok(()) -} - -pub fn copy_recursively(source: &Path, target: &Path) -> io::Result<()> { - if source.is_file() { - trace!("source: {:?}, target: {:?}", source, target); - fs::copy(source, target)?; - } else if source.is_dir() { - if !target.exists() { - fs::create_dir(target)?; - } - - for entry in fs::read_dir(source)? { - let entry = entry?; - let file_name = entry.file_name(); - let source_path = entry.path(); - let target_path = target.join(&file_name); - - copy_recursively(&source_path, &target_path)?; - } - } - Ok(()) -} \ No newline at end of file diff --git a/pkgr/src/util/mod.rs b/pkgr/src/util/mod.rs deleted file mode 100644 index 25c313c..0000000 --- a/pkgr/src/util/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod prompts; -/// Helpers for fs -pub mod fs; - -/// Create a UUID -pub fn create_uuid() -> String { - // TODO - String::from("rand") -} \ No newline at end of file diff --git a/pkgr/src/util/prompts.rs b/pkgr/src/util/prompts.rs deleted file mode 100644 index 9dcae5d..0000000 --- a/pkgr/src/util/prompts.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::io::Write; - -use log::trace; - -pub fn is_noninteractive() -> bool { - if let Ok(v) = std::env::var("PKGR_NON_INTERACTIVE") { - trace!("PKGR_NON_INTERACTIVE={}", v); - match v.as_str() { - "1" => true, - "true" => true, - _ => false - } - } else { false } -} - -pub fn prompt_bool>(prompt: S, default: bool) -> bool { - if is_noninteractive() { return default; } - print!("{} [{}]: ", prompt.into(), if default { "Y/n" } else { "y/N" }); - match std::io::stdout().flush() { - Ok(_) => (), - _ => println!() - }; - - let mut input = String::new(); - std::io::stdin().read_line(&mut input).expect("Failed to read input."); - let answer = input.trim().to_lowercase(); - - if answer.is_empty() { - default - } else { - answer == "y" || answer == "yes" - } -} \ No newline at end of file