diff --git a/Cargo.toml b/Cargo.toml index 8008536..82ec16e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,28 @@ [package] -name = "pt" +name = "libpt" version = "0.1.0" edition = "2021" +authors = ["Christoph J. Scherr "] +license = "GPL3" +description = "my personal multitool" +readme = "README.md" +homepage = "https://git.cscherr.de/PlexSheep/pt" +repository = "https://git.cscherr.de/PlexSheep/pt" +keywords = ["cli", "python", "scriptable", "pyo3", "library"] +categories = ["command-line-utilities"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + [lib] +name = "libpt" +crate-type = ["cdylib", "rlib"] + +[[bin]] name = "pt" -crate-type = ["cdylib"] +path = "src/bin/mod.rs" [dependencies] +clap = "4.3.11" +env_logger = "0.10.0" +log = { version = "0.4.19", features = ["max_level_debug", "release_max_level_info"] } pyo3 = "0.18.1" diff --git a/README.md b/README.md index bd0016b..71eb267 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,28 @@ -# baserepo +# pt / libpt +`pt` stands for either one of "personal tool", "plex tool", "pete" or something among those lines. +It is a collection of tools that i might or might not use. The intended purpose of this repo is that +I program whatever i feel is worth having in a personal thing into it, then use it as either a lib, +crate, python module or executable. + +Let's see if I make it a bloated mess or stop committing after 30 hello worlds. + +#### But the name `pt` / `libpt` already exists! +So what? I don't care. Besides, there is not enough names to name everything unique. + +# compiling +TBD + +# Documentation +TBD + +# Mirrored +The origin of this repository is [git.cscherr.de](https://git.cscherr.de/PlexSheep/pt) + +It is mirrored to: +- [GitHub](https://github.com/PlexSheep/pt) +- [Codeberg](https://codeberg.org/PlexSheep/pt) + + +# License +GPL-3 or newer. diff --git a/pyproject.toml b/pyproject.toml index cf5ea9c..18e52f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["maturin>=0.14,<0.15"] build-backend = "maturin" [project] -name = "pt" +name = "libtp" requires-python = ">=3.7" classifiers = [ "Programming Language :: Rust", diff --git a/src/bin/args/mod.rs b/src/bin/args/mod.rs new file mode 100644 index 0000000..0fae719 --- /dev/null +++ b/src/bin/args/mod.rs @@ -0,0 +1,4 @@ +//! # args module +//! +//! The args module of pt is used to parse commandline arguments. Fot this, it makes use of +//! [`clap`]. diff --git a/src/bin/mod.rs b/src/bin/mod.rs new file mode 100644 index 0000000..ce1f868 --- /dev/null +++ b/src/bin/mod.rs @@ -0,0 +1,9 @@ +//! # Main executable of pt +//! +//! This module contains all code specific to the executable version of `libpt`: `pt`. +mod args; + +/// ## Main function of the `pt` binary +pub fn main() { + println!("hello world"); +} diff --git a/src/lib.rs b/src/lib.rs index 507231b..190a9ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,63 @@ +//! # root module of `libpt` +//! +//! [`libpt`](crate) contains my personal code. It is compiled as all of the following: +//! +//! - dynamic library (`cdylib`, `.so` file on Linux) +//! - rust library crate (`rlib`, usable as ) +//! - python module (with [`PyO3`](pyo3)) +//! - executable (as `pt`) +//! +//! For more info on the linkage types, please refer to the +//! [rust reference](https://doc.rust-lang.org/reference/linkage.html). + +//// ATTRIBUTES //////////////////////////////////////////////////////////////////////////////////// +// we want docs +#![warn(missing_docs)] +#![warn(rustdoc::missing_crate_level_docs)] + +// we want Debug everywhere. This is a library and there will be many bugs. +#![warn(missing_debug_implementations)] + +// enable clippy's extra lints, the pedantic version +#![warn(clippy::pedantic)] + +//// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// +/// contains code specific to the executable +pub mod bin; +/// logger used by libpt +pub mod logger; +use crate::logger::Logger; + use pyo3::prelude::*; -/// Formats the sum of two numbers as string. +//// PUBLIC FUNCTIONS ////////////////////////////////////////////////////////////////////////////// +/// ## Check if [`libpt`](crate) has been loaded +/// +/// Always returns `true` if you can execute it. #[pyfunction] -fn sum_as_string(a: usize, b: usize) -> PyResult { - Ok((a + b).to_string()) +pub fn libpt_loaded() -> bool { + true } -/// A Python module implemented in Rust. +//// PRIVATE FUNCTIONS ///////////////////////////////////////////////////////////////////////////// +/// ## Python module: logger #[pymodule] -fn pt(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; +fn py_logger(py: Python, m: &PyModule) -> PyResult<()> { + let logger_module = PyModule::new(py, "logger")?; + logger_module.add_class::()?; + + m.add_submodule(logger_module)?; Ok(()) -} \ No newline at end of file +} + +/// ## Python module: root +/// +/// This function is the entry point of [`PyO3`](pyo3). This is where the main module is built. +#[pymodule] +fn libpt(py: Python, m: &PyModule) -> PyResult<()> { + m.add_function(wrap_pyfunction!(libpt_loaded, m)?)?; + + // load logger module + py_logger(py, m)?; + Ok(()) +} diff --git a/src/logger/mod.rs b/src/logger/mod.rs new file mode 100644 index 0000000..b6937e0 --- /dev/null +++ b/src/logger/mod.rs @@ -0,0 +1,151 @@ +//! # A specialized Logger for [`libpt`](crate) +//! +//! For the library version, only the basic [`log`](crate::log) is used, so that it is possible for +//! the end user to use the [`log`](crate::log) frontend they desire. +//! +//! I did however decide to create a [`Logger`] struct. This struct is mainly intended to be used +//! with the python module of [`libpt`], but is still just as usable in other contexts. +//! +//! ## Technologies used for logging: +//! - [`log`](crate::log): base logging crate +//! - [`env_logger`](crate::env_logger): used for the executable + +//// ATTRIBUTES //////////////////////////////////////////////////////////////////////////////////// + +//// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// +use std::{fmt, str::FromStr}; + +use log::{debug, error, info, trace, warn}; + +use env_logger; + +use pyo3::prelude::*; +//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////// +/// The log level used when none is specified +const DEFAULT_LOG_LEVEL: log::Level = log::Level::Info; + +//// STRUCTS /////////////////////////////////////////////////////////////////////////////////////// +/// ## Logger for [`libpt`](crate::libpt) +/// +/// This struct exists mainly for the python module, so that we can use the same logger with both +/// python and rust. +#[pyclass] +pub struct Logger { + /// keeps track of if the logger was initialized + pub initialized: bool, +} + +//// IMPLEMENTATION //////////////////////////////////////////////////////////////////////////////// +impl Logger { + /// ## create a `Logger` + pub fn new(level: log::Level) -> Self { + let mut l = Logger { initialized: false }; + l.init(level); + l + } + pub fn init(&mut self, level: log::Level) { + // only init if no init has been performed yet + if self.initialized { + self.warn("trying to reinitialize the logger, ignoring"); + return; + } + #[allow(unused_imports)] + use log::log_enabled; + // TODO check if level is valid! + std::env::set_var("RUST_LOG", level.as_str()); + env_logger::init(); + self.initialized = true; + } + + /// ## logging at [`Level::Error`] + pub fn error(&self, printable: T) + where + T: fmt::Display, + { + error!("{}", printable) + } + /// ## logging at [`Level::Warn`] + pub fn warn(&self, printable: T) + where + T: fmt::Display, + { + warn!("{}", printable) + } + /// ## logging at [`Level::Info`] + pub fn info(&self, printable: T) + where + T: fmt::Display, + { + info!("{}", printable) + } + /// ## logging at [`Level::Debug`] + pub fn debug(&self, printable: T) + where + T: fmt::Display, + { + debug!("{}", printable) + } + /// ## logging at [`Level::Trace`] + pub fn trace(&self, printable: T) + where + T: fmt::Display, + { + trace!("{}", printable) + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +#[pymethods] +impl Logger { + /// ## Python version of [`new()`](Logger::new) + #[new] + pub fn py_new(level: String) -> PyResult { + Ok(Self::new(log::Level::from_str(level.as_str()).expect( + format!("could not get log level for '{}'", level).as_str(), + ))) + } + /// ## Python version of [`init()`](Logger::init) + #[pyo3(name = "init")] + pub fn py_init(&mut self, level: String) { + Self::init(self, log::Level::from_str(level.as_str()).expect( + format!("could not get log level for '{}'", level).as_str(), + )) + } + /// ## Python version of [`error()`](Logger::error) + #[pyo3(name = "error")] + pub fn py_error(&self, printable: String) { + self.error(printable) + } + /// ## Python version of [`warn()`](Logger::warn) + #[pyo3(name = "warn")] + pub fn py_warn(&self, printable: String) { + self.warn(printable) + } + /// ## Python version of [`info()`](Logger::info) + #[pyo3(name = "info")] + pub fn py_info(&self, printable: String) { + self.info(printable) + } + /// ## Python version of [`debug()`](Logger::debug) + #[pyo3(name = "debug")] + pub fn py_debug(&self, printable: String) { + self.debug(printable) + } + /// ## Python version of [`trace()`](Logger::trace) + #[pyo3(name = "trace")] + pub fn py_trace(&self, printable: String) { + self.trace(printable) + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +impl fmt::Debug for Logger { + /// ## Debug representation for [`Logger`] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Logger") + } +} + +//// PUBLIC FUNCTIONS ////////////////////////////////////////////////////////////////////////////// + +//// PRIVATE FUNCTIONS ///////////////////////////////////////////////////////////////////////////// diff --git a/tests/bin.rs b/tests/bin.rs new file mode 100644 index 0000000..e69de29 diff --git a/tests/lib.rs b/tests/lib.rs new file mode 100644 index 0000000..91cf5df --- /dev/null +++ b/tests/lib.rs @@ -0,0 +1,11 @@ +/// # tests for the general behaviour of the libraries availability +/// +/// These tests will not go very in depth + +// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////// +use libpt; + +#[test] +fn loaded_libpt() { + assert!(libpt::libpt_loaded()) +} diff --git a/tests/logger.rs b/tests/logger.rs new file mode 100644 index 0000000..e69de29