please-pm 0.0.0

A Please Package Manager API
Documentation
//! # About
//!
//! Welcome to the documentation for the Please Package Manager client! This
//! documentation will provide all of the nessecary information to install, run
//! and prehaps contribute to this project (named `please-pm-client` from here
//! on).
//! # Examples
//!
//! ## As a library
//!
//! Install the official, dummy `test-package` and view the infomation for it:
//!
//! ```rust
//! use please_pm_client::{get_package_info, install_package};
//!
//! fn main() {
//!     println!(
//!         "NEW PACKAGE INSTALLED:\n\n{:?}",
//!         install_package("test-package".to_string(), false, false)
//!     );
//!     println!(
//!         "INFO:\n\n{:?}",
//!         get_package_info("test-package".to_string(), false)
//!     );
//! }
//! ```
//!
//! This will install a new package named "test-package" with only the required
//! dependencies and will print a fancy output (set `is_verbose` to `false` in
//! [install_package] if you want a more verbose output).
//!
//! This is a basic example and such, it does not implamented the proper
//! package checking (only debug prints `{:?}`).
//!
//! ## Config examples
//!
//! #### Basic `please.toml`:
//!
//! ```toml
//! [package] # Basic package metadata
//! name = "my-test-package" # Name of package (Not optional)
//! description = "This is a small test package. The name of this should be like-this" # Package description
//! icon = "logo.png" # The icon file
//! readme = "README.md" # The readme file
//!
//! [dependencies]
//!     [dependencies.required] # Required dependencies
//!     node = "4.6.3"
//!     flask = "2.0.4"
//!
//!     [dependencies.optional] # Optional dependencies that user can choose to install
//!     python3 = "9.4.2"
//!
//!     [dependencies.build] # Build dependencies. This will not be uploaded to the api but is a shortcut for a build script
//!     git = "1.0.2"
//!     docker = "5.7.2"
//!
//! [build]
//! build_script = "build.sh" # The bash build script (Not optional)
//! launch_script = "launch.sh" # The launch script that determines how it will run after building
//! binary_dir = "build/" # The directory where binaries are produced from build_script
//! binary_pattern = "a.out|my_build" # Regex parsing to get the proper files.
//! ```
//!
//! ##### `please.toml` notes
//!
//! - For `binary_pattern`, please see [here](#binary-pattern) for more
//! information for more complicated binary outputs.
//! - The only required parts of `please.toml` are the `name` in `[package]`
//! and the full `[build]` for your package.
//!
//! #### Basic `please.json`
//!
//! ```json
//! {
//!     "package": {
//!         "name": "my-test-package",
//!         "description": "This is a small test package. The name of this should be like-this",
//!         "icon": "logo.png",
//!         "readme": "README.md"
//!     },
//!     "dependencies": {
//!         "optional": {
//!             "python3": "9.4.2"
//!         },
//!         "build": {
//!             "git": "1.0.2",
//!             "docker": "5.7.2"
//!         },
//!         "required": {
//!             "node": "4.6.3",
//!             "flask": "2.0.4"
//!         }
//!     },
//!     "build": {
//!         "build_script": "build.sh",
//!         "launch_script": "launch.sh",
//!         "binary_dir": "build/",
//!         "binary_pattern": "a.out|my_build"
//!     }
//! }
//! ```
//!
//! ## Basic usage
//! ### Installing the Client
//!
//! #### From source
//!
//! 1. Clone the repository: `git clone https://gitlab.com/owez/please-pm-client`
//! 2. Build the package manager with `cargo build --release`
//! 3. Head to `please-pm-client/target/release/` and copy the executable named `client-backend`
//!
//! #### From [crates.io](https://crates.io/)
//!
//! As this repository is under heavy development, there is currently not a
//! stable *[crates.io]((https://crates.io/))* release. For now, please build
//! it from source using **[this](#from-source)** guide.
//!

use std::path::PathBuf;

/// A simple trait for allowing the use of representing something as a string
/// in an easy and extendible way.
pub trait StringRep {
    /// Basic `&str` representation of the generic implamented trait.
    fn str_rep(&self) -> &'static str;

    /// Customised representation addressing the individual part of the
    /// implamented trait. If there is none, it is allowed to fall back to
    /// [StringRep::str_rep].
    fn string_rep(&self) -> String;
}

/// Main error enum for Please Package Manager. For more infomation on each
/// type of Error, please view each of their individual docs.
///
/// To easily get a description of each error, please refer to the implament
/// method that's *coming soon*.
#[derive(Debug)]
pub enum ErrorKind {
    /// When the [publish_package] function didn't get a package path and could
    /// not determine the current running path. This commonly happens when it
    /// is being ran directly from functions instead of the API.
    NoUploadPath,

    /// When the `please.toml`/`please.json` file could not be decoded properly.
    /// This error should be raised if the toml/json file has incorrect syntax.
    MetadataDecodeError,
}

#[allow(non_snake_case, unreachable_patterns)]
impl StringRep for ErrorKind {
    /// Represent an error generically, allowing the use of a [str].
    fn str_rep(&self) -> &'static str {
        match self {
            NoUploadPath => "Could not determine what directory to upload!",
            MetadataDecodeError => "Could not decode the metadata (please.x)!",
        }
    }

    /// Represent the [ErrorKind] as a customised error, allowing more
    /// detailed responses at the cost of using a heap-allocated [String].
    fn string_rep(&self) -> String {
        match self {
            // Add more in this as more with names come
            _ => String::from(self.str_rep()), // No metadata, this is shortcut
        }
    }
}

/// Gets correctly-formatted infomation on a selected package by.
///
/// *NOTE: This function is a frontend and will therefore display a formatted
/// answer; no matter what*.
pub fn get_package_info(package_name: String, is_verbose: bool) -> Result<String, ErrorKind> {
    unimplemented!();
}

/// Installs a package with the given name (`package_name`).
///
/// *NOTE: This function is a frontend and will therefore display a formatted
/// answer; no matter what*.
///
/// # Arguments
///
/// - `package_name`: The unique package name.
/// - `is_verbose`: Should give a verbose/detailed output when installing.
/// - `install_optional`: If it should install requested optional packages.
pub fn install_package(
    package_name: String,
    is_verbose: bool,
    install_optional: bool,
) -> Result<String, ErrorKind> {
    unimplemented!();
}

/// Removes a given `package_name`. This function will not succeed if the
/// package is not installed or is a dependancy (optional or otherwise) to
/// another package.
///
/// `force_remove` foces the removal of a package. This should **not** be used
/// unless it is an emergency.
///
/// *NOTE: This function is a frontend and will therefore display a formatted
/// answer; no matter what*.
pub fn remove_package(package_name: String, force_remove: bool) -> Result<String, ErrorKind> {
    unimplemented!();
}

/// Publishes a given package path (must be package root & a valid package tree)
/// to the Please Package Manager API.
///
/// If a `path` [PathBuf] is not provided in [Option]<[PathBuf]> is not
/// provided, it will try to validate the directory the program is running from.
/// If it cannot find this file, it will return a special error message.
///
/// *NOTE: This function is a frontend and will therefore display a formatted
/// answer; no matter what*.
pub fn publish_package(path: Option<PathBuf>) -> Result<String, ErrorKind> {
    unimplemented!();
}