generated from PlexSheep/baserepo
Compare commits
No commits in common. "master" and "feat/cli" have entirely different histories.
|
@ -21,6 +21,8 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
rustup component add rustfmt
|
rustup component add rustfmt
|
||||||
rustup component add clippy
|
rustup component add clippy
|
||||||
|
- name: install python
|
||||||
|
run: apt update && apt install libpython3-dev -y
|
||||||
- name: config custom registry
|
- name: config custom registry
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/.cargo/
|
mkdir -p ~/.cargo/
|
||||||
|
@ -43,4 +45,4 @@ jobs:
|
||||||
with:
|
with:
|
||||||
# Optional. Commit message for the created commit.
|
# Optional. Commit message for the created commit.
|
||||||
# Defaults to "Apply automatic changes"
|
# Defaults to "Apply automatic changes"
|
||||||
commit_message: "ci: automatic cargo CI changes"
|
commit_message: automatic cargo CI changes
|
|
@ -1,7 +0,0 @@
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
# Check for updates every Monday
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
|
@ -1,16 +1,10 @@
|
||||||
name: Rust CI
|
name: cargo devel CI
|
||||||
on:
|
on:
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- '**'
|
- '**'
|
||||||
# - '!master'
|
# - '!master'
|
||||||
|
|
||||||
env:
|
|
||||||
CARGO_TERM_COLOR: always
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CI:
|
CI:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -48,10 +42,10 @@ jobs:
|
||||||
- name: cargo fmt
|
- name: cargo fmt
|
||||||
run: cargo fmt --all
|
run: cargo fmt --all
|
||||||
- name: cargo test
|
- name: cargo test
|
||||||
run: cargo test --all-features --all-targets --workspace
|
run: cargo test --all-features --all-targets --workspace && cargo test --all-features --workspace --doc
|
||||||
- name: commit back to repository
|
- name: commit back to repository
|
||||||
uses: stefanzweifel/git-auto-commit-action@v5
|
uses: stefanzweifel/git-auto-commit-action@v5
|
||||||
with:
|
with:
|
||||||
# Optional. Commit message for the created commit.
|
# Optional. Commit message for the created commit.
|
||||||
# Defaults to "Apply automatic changes"
|
# Defaults to "Apply automatic changes"
|
||||||
commit_message: "ci: automatic Rust CI changes"
|
commit_message: automatic cargo CI changes
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
name: Release-plz
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
# Release unpublished packages.
|
|
||||||
release-plz-release:
|
|
||||||
name: Release-plz release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Install Rust toolchain
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
- name: Run release-plz
|
|
||||||
uses: MarcoIeni/release-plz-action@v0.5
|
|
||||||
with:
|
|
||||||
command: release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
||||||
|
|
||||||
# Create a PR with the new versions and changelog, preparing the next release.
|
|
||||||
release-plz-pr:
|
|
||||||
name: Release-plz PR
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
concurrency:
|
|
||||||
group: release-plz-${{ github.ref }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Install Rust toolchain
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
- name: Run release-plz
|
|
||||||
uses: MarcoIeni/release-plz-action@v0.5
|
|
||||||
with:
|
|
||||||
command: release-pr
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
32
Cargo.toml
32
Cargo.toml
|
@ -1,11 +1,17 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [".", "members/libpt-core", "members/libpt-log", "members/libpt-cli"]
|
members = [
|
||||||
|
".",
|
||||||
|
"members/libpt-core",
|
||||||
|
"members/libpt-log",
|
||||||
|
"members/libpt-py",
|
||||||
|
"members/libpt-cli",
|
||||||
|
]
|
||||||
default-members = [".", "members/libpt-core"]
|
default-members = [".", "members/libpt-core"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
publish = true
|
publish = true
|
||||||
version = "0.7.3-alpha.2"
|
version = "0.6.0-alpha.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
|
@ -14,15 +20,19 @@ readme = "README.md"
|
||||||
homepage = "https://git.cscherr.de/PlexSheep/pt"
|
homepage = "https://git.cscherr.de/PlexSheep/pt"
|
||||||
repository = "https://git.cscherr.de/PlexSheep/pt"
|
repository = "https://git.cscherr.de/PlexSheep/pt"
|
||||||
keywords = ["library"]
|
keywords = ["library"]
|
||||||
categories = ["command-line-utilities", "development-tools"]
|
categories = [
|
||||||
|
"command-line-utilities",
|
||||||
|
"development-tools",
|
||||||
|
"development-tools::ffi",
|
||||||
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = "1.0.79"
|
anyhow = "1.0.79"
|
||||||
thiserror = "1.0.56"
|
thiserror = "1.0.56"
|
||||||
libpt-core = { version = "0.5.0", path = "members/libpt-core" }
|
libpt-core = { version = "0.4.0", path = "members/libpt-core" }
|
||||||
libpt-bintols = { version = "0.5.1", path = "members/libpt-bintols" }
|
libpt-bintols = { version = "0.5.1", path = "members/libpt-bintols" }
|
||||||
libpt-log = { version = "0.6.2-alpha.1", path = "members/libpt-log" }
|
libpt-log = { version = "0.4.2", path = "members/libpt-log" }
|
||||||
libpt-cli = { version = "0.2.2-alpha.1", path = "members/libpt-cli" }
|
libpt-cli = { version = "0.1.0", path = "members/libpt-cli" }
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "libpt"
|
name = "libpt"
|
||||||
|
@ -41,11 +51,11 @@ categories.workspace = true
|
||||||
[features]
|
[features]
|
||||||
default = ["log", "core"]
|
default = ["log", "core"]
|
||||||
core = []
|
core = []
|
||||||
full = ["default", "core", "log", "bintols", "libpt-cli/full"]
|
full = ["default", "core", "log", "bintols"]
|
||||||
log = ["dep:libpt-log"]
|
log = ["dep:libpt-log"]
|
||||||
log-crate = ["libpt-cli/log"]
|
|
||||||
bintols = ["dep:libpt-bintols", "log"]
|
bintols = ["dep:libpt-bintols", "log"]
|
||||||
cli = ["dep:libpt-cli", "core", "log"]
|
cli = ["dep:libpt-cli", "core", "log"]
|
||||||
|
# py = ["dep:libpt-py"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "libpt"
|
name = "libpt"
|
||||||
|
@ -59,8 +69,4 @@ crate-type = [
|
||||||
libpt-core = { workspace = true }
|
libpt-core = { workspace = true }
|
||||||
libpt-bintols = { workspace = true, optional = true }
|
libpt-bintols = { workspace = true, optional = true }
|
||||||
libpt-log = { workspace = true, optional = true }
|
libpt-log = { workspace = true, optional = true }
|
||||||
libpt-cli = { workspace = true, optional = true, features = ["log"] }
|
libpt-cli = { workspace = true, optional = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
|
11
README.md
11
README.md
|
@ -40,19 +40,12 @@ If you want to use the python variant too, you need to compile with maturing.
|
||||||
|
|
||||||
## Installing from [pypi](https://pypi.org)
|
## Installing from [pypi](https://pypi.org)
|
||||||
|
|
||||||
The Python interface of `libpt` is currently not implemented, but it is planned
|
`libpt` has been packaged for [pypi.org](https://pypi.org/project/libpt/).
|
||||||
to eventually re add it. Meanwhile, you can use a much older version if you
|
|
||||||
really want.
|
|
||||||
|
|
||||||
> :warning: **This will install a very old version**
|
You can install it with `pip install libpt`
|
||||||
>
|
|
||||||
> `libpt` has been packaged for [pypi.org](https://pypi.org/project/libpt/).
|
|
||||||
>
|
|
||||||
> You can install it with `pip install libpt`
|
|
||||||
|
|
||||||
## Installing from [crates.io](https://crates.io)
|
## Installing from [crates.io](https://crates.io)
|
||||||
|
|
||||||
|
|
||||||
`libpt` has been packaged for [crates.io](https://crates.io/crates/libpt).
|
`libpt` has been packaged for [crates.io](https://crates.io/crates/libpt).
|
||||||
|
|
||||||
You can add the library to your project with `cargo add libpt`.
|
You can add the library to your project with `cargo add libpt`.
|
||||||
|
|
|
@ -20,7 +20,3 @@ libpt-core = { workspace = true }
|
||||||
libpt-log = { workspace = true }
|
libpt-log = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libpt-cli"
|
name = "libpt-cli"
|
||||||
publish.workspace = true
|
publish.workspace = true
|
||||||
version = "0.2.2-alpha.2"
|
version = "0.1.0"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
@ -12,9 +12,11 @@ repository.workspace = true
|
||||||
keywords.workspace = true
|
keywords.workspace = true
|
||||||
categories.workspace = true
|
categories.workspace = true
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
full = ["log"]
|
|
||||||
log = ["dep:log"]
|
log = ["dep:log"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -24,14 +26,11 @@ comfy-table = "7.1.1"
|
||||||
console = "0.15.8"
|
console = "0.15.8"
|
||||||
dialoguer = { version = "0.11.0", features = ["completion", "history"] }
|
dialoguer = { version = "0.11.0", features = ["completion", "history"] }
|
||||||
embed-doc-image = "0.1.4"
|
embed-doc-image = "0.1.4"
|
||||||
|
exitcode = "1.1.2"
|
||||||
|
human-panic = "2.0.0"
|
||||||
indicatif = "0.17.8"
|
indicatif = "0.17.8"
|
||||||
libpt-log = { workspace = true, optional = false }
|
libpt-log = { workspace = true, optional = false }
|
||||||
log = { version = "0.4.21", optional = true }
|
log = { version = "0.4.21", optional = true }
|
||||||
serde = { version = "1.0.209", features = ["derive"] }
|
|
||||||
shlex = "1.3.0"
|
shlex = "1.3.0"
|
||||||
strum = { version = "0.26.3", features = ["derive"] }
|
strum = { version = "0.26.3", features = ["derive"] }
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use libpt_cli::args::VerbosityLevel;
|
use libpt_cli::args::VerbosityLevel;
|
||||||
use libpt_cli::printing;
|
use libpt_cli::{clap, printing};
|
||||||
use libpt_log::{debug, Logger};
|
use libpt_log::{debug, Logger};
|
||||||
|
|
||||||
/// This is the help
|
/// This is the help
|
||||||
|
@ -23,7 +23,10 @@ struct Cli {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
let _logger = Logger::builder().set_level(cli.verbosity.level()).build();
|
let _logger = Logger::builder()
|
||||||
|
.max_level(cli.verbosity.level())
|
||||||
|
.show_time(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
debug!("logger initialized with level: {}", cli.verbosity.level());
|
debug!("logger initialized with level: {}", cli.verbosity.level());
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use console::style;
|
use console::style;
|
||||||
use libpt_cli::printing;
|
|
||||||
use libpt_cli::repl::{DefaultRepl, Repl};
|
use libpt_cli::repl::{DefaultRepl, Repl};
|
||||||
use libpt_log::{debug, Logger};
|
use libpt_cli::{clap, printing, strum};
|
||||||
|
use libpt_log::{debug, Level, Logger};
|
||||||
|
|
||||||
use clap::Subcommand;
|
use clap::Subcommand;
|
||||||
use strum::EnumIter;
|
use strum::EnumIter;
|
||||||
|
@ -31,7 +31,10 @@ enum ReplCommand {
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
// You would normally make a proper cli interface with clap before entering the repl. This is
|
// You would normally make a proper cli interface with clap before entering the repl. This is
|
||||||
// omitted here for brevity
|
// omitted here for brevity
|
||||||
let _logger = Logger::builder().display_time(false).build();
|
let _logger = Logger::builder()
|
||||||
|
.show_time(false)
|
||||||
|
.max_level(Level::INFO)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
// the compiler can infer that we want to use the ReplCommand enum.
|
// the compiler can infer that we want to use the ReplCommand enum.
|
||||||
let mut repl = DefaultRepl::<ReplCommand>::default();
|
let mut repl = DefaultRepl::<ReplCommand>::default();
|
||||||
|
@ -73,7 +76,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
if !fancy {
|
if !fancy {
|
||||||
println!("{}", text.join(" "))
|
println!("{}", text.join(" "))
|
||||||
} else {
|
} else {
|
||||||
printing::blockprint(text.join(" "), console::Color::Cyan)
|
printing::blockprint(&text.join(" "), console::Color::Cyan)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ use clap::Parser;
|
||||||
use libpt_log::Level;
|
use libpt_log::Level;
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
use log;
|
use log;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// Custom help template for displaying command-line usage information
|
/// Custom help template for displaying command-line usage information
|
||||||
///
|
///
|
||||||
|
@ -19,7 +18,7 @@ use serde::{Deserialize, Serialize};
|
||||||
/// # use libpt_cli::args::HELP_TEMPLATE;
|
/// # use libpt_cli::args::HELP_TEMPLATE;
|
||||||
/// use clap::Parser;
|
/// use clap::Parser;
|
||||||
/// #[derive(Parser, Debug, Clone, PartialEq, Eq, Hash)]
|
/// #[derive(Parser, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
/// #[command(help_template = HELP_TEMPLATE, author, version)]
|
/// #[command(help_template = HELP_TEMPLATE)]
|
||||||
/// pub struct MyArgs {
|
/// pub struct MyArgs {
|
||||||
/// /// show more details
|
/// /// show more details
|
||||||
/// #[arg(short, long)]
|
/// #[arg(short, long)]
|
||||||
|
@ -78,9 +77,9 @@ Author: {author-with-newline}
|
||||||
/// Get the loglevel like this:
|
/// Get the loglevel like this:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use libpt_cli::args::VerbosityLevel;
|
/// # use libpt_cli::args::VerbosityLevel;
|
||||||
/// use libpt_log::Level;
|
/// use libpt_log::Level;
|
||||||
/// use clap::Parser;
|
/// # use clap::Parser;
|
||||||
///
|
///
|
||||||
/// # #[derive(Parser, Debug)]
|
/// # #[derive(Parser, Debug)]
|
||||||
/// # pub struct Opts {
|
/// # pub struct Opts {
|
||||||
|
@ -96,18 +95,18 @@ Author: {author-with-newline}
|
||||||
/// let level: Level = opts.verbose.level();
|
/// let level: Level = opts.verbose.level();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Parser, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Parser, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct VerbosityLevel {
|
pub struct VerbosityLevel {
|
||||||
/// make the output more verbose
|
/// make the output more verbose
|
||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
short = 'v',
|
short = 'v',
|
||||||
action = clap::ArgAction::Count, // NOTE: this forces u8 type for some reason
|
action = clap::ArgAction::Count,
|
||||||
global = true,
|
global = true,
|
||||||
// help = L::verbose_help(),
|
// help = L::verbose_help(),
|
||||||
// long_help = L::verbose_long_help(),
|
// long_help = L::verbose_long_help(),
|
||||||
)]
|
)]
|
||||||
verbose: u8,
|
verbose: i8,
|
||||||
|
|
||||||
/// make the output less verbose
|
/// make the output less verbose
|
||||||
///
|
///
|
||||||
|
@ -119,7 +118,7 @@ pub struct VerbosityLevel {
|
||||||
global = true,
|
global = true,
|
||||||
conflicts_with = "verbose",
|
conflicts_with = "verbose",
|
||||||
)]
|
)]
|
||||||
quiet: u8,
|
quiet: i8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerbosityLevel {
|
impl VerbosityLevel {
|
||||||
|
@ -132,7 +131,7 @@ impl VerbosityLevel {
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn value(&self) -> u8 {
|
fn value(&self) -> i8 {
|
||||||
Self::level_value(Level::INFO)
|
Self::level_value(Level::INFO)
|
||||||
.saturating_sub((self.quiet).min(10))
|
.saturating_sub((self.quiet).min(10))
|
||||||
.saturating_add((self.verbose).min(10))
|
.saturating_add((self.verbose).min(10))
|
||||||
|
@ -190,7 +189,7 @@ impl VerbosityLevel {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
const fn level_value(level: Level) -> u8 {
|
const fn level_value(level: Level) -> i8 {
|
||||||
match level {
|
match level {
|
||||||
Level::TRACE => 4,
|
Level::TRACE => 4,
|
||||||
Level::DEBUG => 3,
|
Level::DEBUG => 3,
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
//! This module bundles a lot of good CLI tools, and adds some of it's own, to make development of
|
|
||||||
//! CLI apps easier and more ergonomic.
|
|
||||||
#![warn(clippy::pedantic, clippy::style, clippy::nursery)]
|
#![warn(clippy::pedantic, clippy::style, clippy::nursery)]
|
||||||
pub mod args;
|
pub mod args;
|
||||||
pub mod printing;
|
pub mod printing;
|
||||||
pub mod repl;
|
pub mod repl;
|
||||||
|
|
||||||
|
pub use clap;
|
||||||
|
pub use comfy_table;
|
||||||
|
pub use console;
|
||||||
|
pub use dialoguer;
|
||||||
|
pub use exitcode;
|
||||||
|
pub use human_panic;
|
||||||
|
pub use indicatif;
|
||||||
|
pub use shlex;
|
||||||
|
pub use strum;
|
||||||
|
|
|
@ -42,7 +42,7 @@ use console::{style, Color};
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use console::Color;
|
/// use libpt_cli::console::Color;
|
||||||
/// use libpt_cli::printing::blockprint;
|
/// use libpt_cli::printing::blockprint;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// blockprint("Hello world!", Color::Blue);
|
/// blockprint("Hello world!", Color::Blue);
|
||||||
|
@ -64,7 +64,7 @@ pub fn blockprint(content: impl ToString, color: Color) {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use console::Color;
|
/// use libpt_cli::console::Color;
|
||||||
/// use libpt_cli::printing::blockfmt;
|
/// use libpt_cli::printing::blockfmt;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let formatted_content = blockfmt("Hello world!", Color::Blue);
|
/// let formatted_content = blockfmt("Hello world!", Color::Blue);
|
||||||
|
@ -93,8 +93,8 @@ pub fn blockfmt(content: impl ToString, color: Color) -> String {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// use comfy_table::{presets, CellAlignment, ContentArrangement};
|
/// use libpt_cli::comfy_table::{presets, CellAlignment, ContentArrangement};
|
||||||
/// use console::Color;
|
/// use libpt_cli::console::Color;
|
||||||
/// use libpt_cli::printing::blockfmt_advanced;
|
/// use libpt_cli::printing::blockfmt_advanced;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// println!(
|
/// println!(
|
||||||
|
|
|
@ -27,8 +27,8 @@ use libpt_log::trace;
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use libpt_cli::repl::{DefaultRepl, Repl};
|
/// use libpt_cli::repl::{DefaultRepl, Repl};
|
||||||
/// use clap::Subcommand;
|
/// use libpt_cli::clap::Subcommand;
|
||||||
/// use strum::EnumIter;
|
/// use libpt_cli::strum::EnumIter;
|
||||||
///
|
///
|
||||||
/// #[derive(Subcommand, Debug, EnumIter, Clone)]
|
/// #[derive(Subcommand, Debug, EnumIter, Clone)]
|
||||||
/// enum ReplCommand {
|
/// enum ReplCommand {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libpt-core"
|
name = "libpt-core"
|
||||||
publish.workspace = true
|
publish.workspace = true
|
||||||
version = "0.5.0"
|
version = "0.4.0"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
@ -14,9 +14,6 @@ categories.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.79"
|
anyhow = "1.0.79"
|
||||||
|
libpt-log = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
|
|
@ -8,16 +8,3 @@
|
||||||
|
|
||||||
/// macros to make things faster in your code
|
/// macros to make things faster in your code
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
/// ## Get the name of the crate that uses your library
|
|
||||||
///
|
|
||||||
/// Let's say you're writing the library `foo` and need the name of the crate that uses `foo`. With
|
|
||||||
/// this function, you can get the name of the crate that uses `foo`.
|
|
||||||
///
|
|
||||||
/// Will return [None] if [`std::env::current_exe()`] errors or if conversion to [String] from [std::ffi::OsStr] fails.
|
|
||||||
pub fn get_crate_name() -> Option<String> {
|
|
||||||
if let Ok(exe) = std::env::current_exe() {
|
|
||||||
return Some(exe.file_stem()?.to_str()?.to_string());
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libpt-log"
|
name = "libpt-log"
|
||||||
publish.workspace = true
|
publish.workspace = true
|
||||||
version = "0.6.2-alpha.2"
|
version = "0.4.3"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
@ -13,17 +13,11 @@ keywords.workspace = true
|
||||||
categories.workspace = true
|
categories.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.37"
|
||||||
tracing-appender = "0.2.3"
|
tracing-appender = "0.2.2"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = "0.3.17"
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
libpt-core = { workspace = true, optional = false }
|
|
||||||
chrono = "0.4.38"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
gag = "1.0.0"
|
gag = "1.0.0"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
use libpt_log::Logger;
|
|
||||||
use tracing::info;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let _logger = Logger::builder()
|
|
||||||
.log_to_file(true)
|
|
||||||
.log_dir("/tmp/llll".into())
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
info!("foo bar qux");
|
|
||||||
}
|
|
|
@ -17,9 +17,7 @@ pub enum Error {
|
||||||
/// Could not assign logger as the global default
|
/// Could not assign logger as the global default
|
||||||
#[error("Could not assign logger as global default")]
|
#[error("Could not assign logger as global default")]
|
||||||
SetGlobalDefaultFail(#[from] SetGlobalDefaultError),
|
SetGlobalDefaultFail(#[from] SetGlobalDefaultError),
|
||||||
/// any other error type, wrapped in [`anyhow::Error`]
|
/// any other error type, wrapped in [anyhow::Error](anyhow::Error)
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Other(#[from] anyhow::Error),
|
Other(#[from] anyhow::Error),
|
||||||
#[error("Tried to open the logfile, but logging to file was not requested")]
|
|
||||||
LogfileButNoFilelog,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,34 +6,27 @@
|
||||||
//! For the library version, only the basic [`tracing`] is used, so that it is possible for
|
//! For the library version, only the basic [`tracing`] is used, so that it is possible for
|
||||||
//! the end user to use the [`tracing`] frontend they desire.
|
//! the end user to use the [`tracing`] frontend they desire.
|
||||||
//!
|
//!
|
||||||
//! I did decide to create a [`Logger`] struct. This struct is mainly intended to be used with the
|
//! I did however decide to create a [`Logger`] struct. This struct is mainly intended to be used
|
||||||
//! python module of [`pt`](../libpt/index.html), but is still just as usable in other contexts.
|
//! with the python module of [`pt`](../libpt/index.html), but is still just as usable in other contexts.
|
||||||
//! You can use this struct when use of the macros is not possible, but the macros should generally
|
|
||||||
//! be preferred.
|
|
||||||
//!
|
//!
|
||||||
//! ## Technologies used for logging:
|
//! ## Technologies used for logging:
|
||||||
//! - [`tracing`]: base logging crate
|
//! - [`tracing`]: base logging crate
|
||||||
//! - [`tracing_appender`]: Used to log to files
|
//! - [`tracing_appender`]: Used to log to files
|
||||||
//! - [`tracing_subscriber`]: Used to do actual logging, formatting, to stdout
|
//! - [`tracing_subscriber`]: Used to do actual logging, formatting, to stdout
|
||||||
#![warn(clippy::pedantic, clippy::style, clippy::nursery)]
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Debug},
|
fmt,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
use error::Error;
|
use error::*;
|
||||||
|
|
||||||
/// This is the magic dependency where the cool stuff happens
|
|
||||||
///
|
|
||||||
/// I'm just repackaging it a little to make it more ergonomic
|
|
||||||
pub use tracing;
|
pub use tracing;
|
||||||
pub use tracing::{debug, error, info, trace, warn, Level};
|
pub use tracing::{debug, error, info, trace, warn, Level};
|
||||||
use tracing_subscriber::{
|
use tracing_appender::{self, non_blocking::NonBlocking};
|
||||||
fmt::format::FmtSpan, layer::SubscriberExt as _, util::SubscriberInitExt, Layer,
|
use tracing_subscriber::fmt::{format::FmtSpan, time};
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
/// The log level used when none is specified
|
/// The log level used when none is specified
|
||||||
|
@ -62,9 +55,7 @@ static INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||||
/// # }
|
/// # }
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
#[allow(clippy::struct_excessive_bools)] // it's just true/false values, not states, and I don't
|
|
||||||
// need to reinvent the wheel
|
|
||||||
pub struct LoggerBuilder {
|
pub struct LoggerBuilder {
|
||||||
/// create and log to logfiles
|
/// create and log to logfiles
|
||||||
log_to_file: bool,
|
log_to_file: bool,
|
||||||
|
@ -95,8 +86,6 @@ pub struct LoggerBuilder {
|
||||||
show_time: bool,
|
show_time: bool,
|
||||||
/// show timestamps as uptime (duration since the logger was initialized)
|
/// show timestamps as uptime (duration since the logger was initialized)
|
||||||
uptime: bool,
|
uptime: bool,
|
||||||
/// log when span things happen
|
|
||||||
span_events: FmtSpan,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoggerBuilder {
|
impl LoggerBuilder {
|
||||||
|
@ -131,89 +120,110 @@ impl LoggerBuilder {
|
||||||
/// This function will return an error if a global Logger was aready initialized. This module
|
/// This function will return an error if a global Logger was aready initialized. This module
|
||||||
/// uses the [tracing] crate for logging, so if a [tracing] logger is initialized elsewhere,
|
/// uses the [tracing] crate for logging, so if a [tracing] logger is initialized elsewhere,
|
||||||
/// this method will error.
|
/// this method will error.
|
||||||
#[allow(clippy::missing_panics_doc)]
|
|
||||||
pub fn build(self) -> Result<Logger> {
|
pub fn build(self) -> Result<Logger> {
|
||||||
// only init if no init has been performed yet
|
// only init if no init has been performed yet
|
||||||
if INITIALIZED.load(Ordering::Relaxed) {
|
if INITIALIZED.load(Ordering::Relaxed) {
|
||||||
warn!("trying to reinitialize the logger, ignoring");
|
warn!("trying to reinitialize the logger, ignoring");
|
||||||
bail!(Error::Usage("logging is already initialized".to_string()));
|
bail!(Error::Usage("logging is already initialized".to_string()));
|
||||||
}
|
}
|
||||||
let layer = tracing_subscriber::fmt::layer()
|
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
|
||||||
|
.with_level(self.display_level)
|
||||||
|
.with_max_level(self.max_level)
|
||||||
.with_ansi(self.ansi)
|
.with_ansi(self.ansi)
|
||||||
.with_target(self.display_target)
|
.with_target(self.display_target)
|
||||||
.with_file(self.display_filename)
|
.with_file(self.display_filename)
|
||||||
.with_thread_ids(self.display_thread_ids)
|
.with_thread_ids(self.display_thread_ids)
|
||||||
.with_line_number(self.display_line_number)
|
.with_line_number(self.display_line_number)
|
||||||
.with_thread_names(self.display_thread_names)
|
.with_thread_names(self.display_thread_names)
|
||||||
.with_span_events(self.span_events.clone())
|
.with_span_events(FmtSpan::FULL);
|
||||||
.with_filter(tracing::level_filters::LevelFilter::from_level(
|
// I know this is hacky, but I couldn't get it any other way. I couldn't even find a
|
||||||
self.max_level,
|
// project that could do it any other way. You can't apply one after another, because the
|
||||||
));
|
// type is changed every time. When using `Box<dyn Whatever>`, some methods complain about
|
||||||
if self.log_to_file {
|
// not being in trait bounds.
|
||||||
tracing_subscriber::registry()
|
// TODO: somehow find a better solution for this
|
||||||
.with(layer.and_then({
|
match (self.log_to_file, self.show_time, self.pretty, self.uptime) {
|
||||||
tracing_subscriber::fmt::layer()
|
(true, true, true, true) => {
|
||||||
.with_writer(
|
let subscriber = subscriber
|
||||||
self.logfile()?
|
.with_writer(new_file_appender(self.log_dir))
|
||||||
.expect("logging to file is requested but logfile returned None"),
|
.with_timer(time::uptime())
|
||||||
)
|
.pretty()
|
||||||
.with_ansi(self.ansi)
|
.finish();
|
||||||
.with_target(self.display_target)
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
.with_file(self.display_filename)
|
}
|
||||||
.with_thread_ids(self.display_thread_ids)
|
(true, true, true, false) => {
|
||||||
.with_line_number(self.display_line_number)
|
let subscriber = subscriber
|
||||||
.with_thread_names(self.display_thread_names)
|
.with_writer(new_file_appender(self.log_dir))
|
||||||
.with_span_events(self.span_events.clone())
|
.pretty()
|
||||||
.with_filter(tracing::level_filters::LevelFilter::from_level(
|
.finish();
|
||||||
self.max_level,
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
))
|
}
|
||||||
}))
|
(true, false, true, _) => {
|
||||||
.init();
|
let subscriber = subscriber
|
||||||
} else {
|
.with_writer(new_file_appender(self.log_dir))
|
||||||
tracing_subscriber::registry().with(layer).init();
|
.without_time()
|
||||||
|
.pretty()
|
||||||
|
.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(true, true, false, true) => {
|
||||||
|
let subscriber = subscriber
|
||||||
|
.with_writer(new_file_appender(self.log_dir))
|
||||||
|
.with_timer(time::uptime())
|
||||||
|
.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(true, true, false, false) => {
|
||||||
|
let subscriber = subscriber
|
||||||
|
.with_writer(new_file_appender(self.log_dir))
|
||||||
|
.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(true, false, false, _) => {
|
||||||
|
let file_appender = tracing_appender::rolling::daily(self.log_dir.clone(), "log");
|
||||||
|
let (file_writer, _guard) = tracing_appender::non_blocking(file_appender);
|
||||||
|
let subscriber = subscriber.with_writer(file_writer).without_time().finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, true, true, true) => {
|
||||||
|
let subscriber = subscriber.pretty().with_timer(time::uptime()).finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, true, true, false) => {
|
||||||
|
let subscriber = subscriber.pretty().with_timer(time::uptime()).finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, false, true, _) => {
|
||||||
|
let subscriber = subscriber.without_time().pretty().finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, true, false, true) => {
|
||||||
|
let subscriber = subscriber.with_timer(time::uptime()).finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, true, false, false) => {
|
||||||
|
let subscriber = subscriber.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, false, false, _) => {
|
||||||
|
let subscriber = subscriber.without_time().finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INITIALIZED.store(true, Ordering::Relaxed);
|
INITIALIZED.store(true, Ordering::Relaxed);
|
||||||
Ok(Logger {})
|
Ok(Logger {})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opens a new file for logging to.
|
|
||||||
///
|
|
||||||
/// Format: `{log_dir}/{consumer_name}_2024-09-01.log`
|
|
||||||
///
|
|
||||||
/// Will be none if [`Self::log_to_file`] is [false].
|
|
||||||
fn logfile(&self) -> Result<Option<std::fs::File>> {
|
|
||||||
if !self.log_to_file {
|
|
||||||
return Err(Error::LogfileButNoFilelog.into());
|
|
||||||
}
|
|
||||||
let mut path = self.log_dir.clone();
|
|
||||||
std::fs::create_dir_all(&path)?;
|
|
||||||
path.push(format!(
|
|
||||||
"{}_{}.log",
|
|
||||||
libpt_core::get_crate_name().unwrap_or_else(|| "logfile".to_string()),
|
|
||||||
chrono::Local::now().date_naive()
|
|
||||||
));
|
|
||||||
let file = std::fs::File::create(path)?;
|
|
||||||
Ok(Some(file))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// enable or disable logging to and creating of logfiles
|
/// enable or disable logging to and creating of logfiles
|
||||||
///
|
pub fn log_to_file(mut self, log_to_file: bool) -> Self {
|
||||||
/// If you want to log to a file, don't forget to set [`Self::log_dir`]!
|
|
||||||
///
|
|
||||||
/// Default: false
|
|
||||||
#[must_use]
|
|
||||||
pub const fn log_to_file(mut self, log_to_file: bool) -> Self {
|
|
||||||
self.log_to_file = log_to_file;
|
self.log_to_file = log_to_file;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// set a directory where logfiles would be created in
|
/// set a directory where logfiles would be created in
|
||||||
///
|
///
|
||||||
/// Enable or disable creation and logging to logfiles with [`log_to_file`](Self::log_to_file).
|
/// Enable or disable creation and logging to logfiles with [log_to_file](Self::log_to_file).
|
||||||
///
|
///
|
||||||
/// Default: [`DEFAULT_LOG_DIR`] (/dev/null)
|
/// The default logdir is [DEFAULT_LOG_DIR].
|
||||||
#[must_use]
|
|
||||||
pub fn log_dir(mut self, log_dir: PathBuf) -> Self {
|
pub fn log_dir(mut self, log_dir: PathBuf) -> Self {
|
||||||
self.log_dir = log_dir;
|
self.log_dir = log_dir;
|
||||||
self
|
self
|
||||||
|
@ -225,112 +235,70 @@ impl LoggerBuilder {
|
||||||
/// are displayed by a program that does not interpret them.
|
/// are displayed by a program that does not interpret them.
|
||||||
///
|
///
|
||||||
/// Keeping ANSI control sequences enabled has the disadvantage of added colors for the logs.
|
/// Keeping ANSI control sequences enabled has the disadvantage of added colors for the logs.
|
||||||
///
|
pub fn ansi(mut self, ansi: bool) -> Self {
|
||||||
/// Default: true
|
|
||||||
#[must_use]
|
|
||||||
pub const fn ansi(mut self, ansi: bool) -> Self {
|
|
||||||
self.ansi = ansi;
|
self.ansi = ansi;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// when making a log, display the source file in which a log was crated in
|
/// when making a log, display the source file in which a log was crated in
|
||||||
///
|
pub fn display_filename(mut self, display_filename: bool) -> Self {
|
||||||
/// Default: false
|
|
||||||
#[must_use]
|
|
||||||
pub const fn display_filename(mut self, display_filename: bool) -> Self {
|
|
||||||
self.display_filename = display_filename;
|
self.display_filename = display_filename;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// when making a log, display the time of the message
|
|
||||||
///
|
|
||||||
/// Default: true
|
|
||||||
#[must_use]
|
|
||||||
pub const fn display_time(mut self, show_time: bool) -> Self {
|
|
||||||
self.show_time = show_time;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// when making a log, display the log level of the message
|
/// when making a log, display the log level of the message
|
||||||
///
|
pub fn display_level(mut self, display_level: bool) -> Self {
|
||||||
/// Default: true
|
|
||||||
#[must_use]
|
|
||||||
pub const fn display_level(mut self, display_level: bool) -> Self {
|
|
||||||
self.display_level = display_level;
|
self.display_level = display_level;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// show target context
|
/// show target context
|
||||||
///
|
pub fn display_target(mut self, display_target: bool) -> Self {
|
||||||
/// Default: false
|
|
||||||
#[must_use]
|
|
||||||
pub const fn display_target(mut self, display_target: bool) -> Self {
|
|
||||||
self.display_target = display_target;
|
self.display_target = display_target;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// set the maximum verbosity level.
|
||||||
|
pub fn max_level(mut self, max_level: Level) -> Self {
|
||||||
|
self.max_level = max_level;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// show the id of the thread that created this message
|
/// show the id of the thread that created this message
|
||||||
///
|
pub fn display_thread_ids(mut self, display_thread_ids: bool) -> Self {
|
||||||
/// Default: false
|
|
||||||
#[must_use]
|
|
||||||
pub const fn display_thread_ids(mut self, display_thread_ids: bool) -> Self {
|
|
||||||
self.display_thread_ids = display_thread_ids;
|
self.display_thread_ids = display_thread_ids;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// show the name of the thread that created this message
|
/// show the name of the thread that created this message
|
||||||
///
|
pub fn display_thread_names(mut self, display_thread_names: bool) -> Self {
|
||||||
/// Default: false
|
|
||||||
#[must_use]
|
|
||||||
pub const fn display_thread_names(mut self, display_thread_names: bool) -> Self {
|
|
||||||
self.display_thread_names = display_thread_names;
|
self.display_thread_names = display_thread_names;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// show which line in the source file produces a log
|
/// show which line in the source file produces a log
|
||||||
///
|
pub fn display_line_number(mut self, display_line_number: bool) -> Self {
|
||||||
/// Default: false
|
|
||||||
#[must_use]
|
|
||||||
pub const fn display_line_number(mut self, display_line_number: bool) -> Self {
|
|
||||||
self.display_line_number = display_line_number;
|
self.display_line_number = display_line_number;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// splits a log over multiple lines, looks like a python traceback
|
/// splits a log over multiple lines, looks like a python traceback
|
||||||
///
|
pub fn pretty(mut self, pretty: bool) -> Self {
|
||||||
/// Default: false
|
|
||||||
#[must_use]
|
|
||||||
pub const fn pretty(mut self, pretty: bool) -> Self {
|
|
||||||
self.pretty = pretty;
|
self.pretty = pretty;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// show a timestamp describing when the log was created
|
||||||
|
pub fn show_time(mut self, show_time: bool) -> Self {
|
||||||
|
self.show_time = show_time;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// show timestamps as uptime (duration since the logger was initialized)
|
/// show timestamps as uptime (duration since the logger was initialized)
|
||||||
///
|
pub fn uptime(mut self, uptime: bool) -> Self {
|
||||||
/// Default: false
|
|
||||||
#[must_use]
|
|
||||||
pub const fn uptime(mut self, uptime: bool) -> Self {
|
|
||||||
self.uptime = uptime;
|
self.uptime = uptime;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// set the lowest loglevel to be displayed
|
|
||||||
///
|
|
||||||
/// Default: [`Level::INFO`]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn set_level(mut self, max_level: Level) -> Self {
|
|
||||||
self.max_level = max_level;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// set how span events are handled
|
|
||||||
///
|
|
||||||
/// Default: [`FmtSpan::NONE`]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn span_events(mut self, span_events: FmtSpan) -> Self {
|
|
||||||
self.span_events = span_events;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LoggerBuilder {
|
impl Default for LoggerBuilder {
|
||||||
|
@ -349,12 +317,11 @@ impl Default for LoggerBuilder {
|
||||||
pretty: false,
|
pretty: false,
|
||||||
show_time: true,
|
show_time: true,
|
||||||
uptime: false,
|
uptime: false,
|
||||||
span_events: FmtSpan::NONE,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## Logger for `libpt`
|
/// ## Logger for [`pt`](libpt)
|
||||||
///
|
///
|
||||||
/// A logger is generally a functionality that let's you write information from your library or
|
/// A logger is generally a functionality that let's you write information from your library or
|
||||||
/// application in a more structured manner than if you just wrote all information to `stdout` or
|
/// application in a more structured manner than if you just wrote all information to `stdout` or
|
||||||
|
@ -366,23 +333,19 @@ impl Default for LoggerBuilder {
|
||||||
///
|
///
|
||||||
/// ## Levels
|
/// ## Levels
|
||||||
///
|
///
|
||||||
/// * [ERROR](Level::ERROR) – Something broke
|
/// TODO: add levels desc and ascii art
|
||||||
/// * [WARN](Level::WARN) – Something is bad
|
|
||||||
/// * [INFO](Level::INFO) – Useful information for users
|
|
||||||
/// * [DEBUG](Level::DEBUG) – Useful information for developers
|
|
||||||
/// * [TRACE](Level::TRACE) – Very verbose information for developers (often for libraries)
|
|
||||||
///
|
///
|
||||||
/// ## Usage
|
/// ## Usage
|
||||||
///
|
///
|
||||||
/// You don't need to use the [Logger] struct, it's better to use the macros instead:
|
/// You don't need to use the [Logger] struct, it's better to use the macros instead:
|
||||||
///
|
///
|
||||||
/// * [`error!`]
|
/// * `error!`
|
||||||
/// * [`warn!`]
|
/// * `warn!`
|
||||||
/// * [`info!`]
|
/// * `info!`
|
||||||
/// * [`debug!`]
|
/// * `debug!`
|
||||||
/// * [`trace!`]
|
/// * `trace!`
|
||||||
///
|
///
|
||||||
/// You can however use the [Logger] struct in cases where usage of a macro is impossible or
|
/// You can however use the [Logger] struct in cases where usage of a macro is bad or
|
||||||
/// you are somehow working with multiple loggers. The macros offer additional functionalities,
|
/// you are somehow working with multiple loggers. The macros offer additional functionalities,
|
||||||
/// suck as full `format!` support and context, see [`tracing`], which we use as backend.
|
/// suck as full `format!` support and context, see [`tracing`], which we use as backend.
|
||||||
///
|
///
|
||||||
|
@ -402,46 +365,206 @@ pub struct Logger;
|
||||||
|
|
||||||
/// ## Main implementation
|
/// ## Main implementation
|
||||||
impl Logger {
|
impl Logger {
|
||||||
/// Get a new [`LoggerBuilder`]
|
/// Get a new [LoggerBuilder]
|
||||||
#[must_use]
|
|
||||||
pub fn builder() -> LoggerBuilder {
|
pub fn builder() -> LoggerBuilder {
|
||||||
LoggerBuilder::default()
|
LoggerBuilder::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ## initializes the logger
|
||||||
|
///
|
||||||
|
/// Will enable the logger to be used.
|
||||||
|
///
|
||||||
|
/// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control
|
||||||
|
#[deprecated(since = "0.4.1", note = "use Logger::builder() instead")]
|
||||||
|
pub fn build(log_dir: Option<PathBuf>, max_level: Option<Level>, uptime: bool) -> Result<Self> {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
Self::build_customized(
|
||||||
|
log_dir.is_some(),
|
||||||
|
log_dir.unwrap_or(PathBuf::from(DEFAULT_LOG_DIR)),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
max_level.unwrap_or(DEFAULT_LOG_LEVEL),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
uptime,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## initializes the logger
|
||||||
|
///
|
||||||
|
/// Will enable the logger to be used. This is a version that shows less information,
|
||||||
|
/// useful in cases with only one sender to the logging framework.
|
||||||
|
///
|
||||||
|
/// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control
|
||||||
|
#[deprecated(since = "0.4.1", note = "use Logger::builder() instead")]
|
||||||
|
pub fn build_mini(max_level: Option<Level>) -> Result<Self> {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
Self::build_customized(
|
||||||
|
false,
|
||||||
|
PathBuf::from(DEFAULT_LOG_DIR),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
max_level.unwrap_or(DEFAULT_LOG_LEVEL),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## initializes the logger
|
||||||
|
///
|
||||||
|
/// Will enable the logger to be used.
|
||||||
|
#[deprecated(since = "0.4.1", note = "use Logger::builder() instead")]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn build_customized(
|
||||||
|
log_to_file: bool,
|
||||||
|
log_dir: PathBuf,
|
||||||
|
ansi: bool,
|
||||||
|
display_filename: bool,
|
||||||
|
display_level: bool,
|
||||||
|
display_target: bool,
|
||||||
|
max_level: Level,
|
||||||
|
display_thread_ids: bool,
|
||||||
|
display_thread_names: bool,
|
||||||
|
display_line_number: bool,
|
||||||
|
pretty: bool,
|
||||||
|
show_time: bool,
|
||||||
|
uptime: bool, // uptime instead of system time
|
||||||
|
) -> Result<Self> {
|
||||||
|
// only init if no init has been performed yet
|
||||||
|
if INITIALIZED.load(Ordering::Relaxed) {
|
||||||
|
warn!("trying to reinitialize the logger, ignoring");
|
||||||
|
bail!(Error::Usage("logging is already initialized".to_string()));
|
||||||
|
}
|
||||||
|
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
|
||||||
|
.with_level(display_level)
|
||||||
|
.with_max_level(max_level)
|
||||||
|
.with_ansi(ansi)
|
||||||
|
.with_target(display_target)
|
||||||
|
.with_file(display_filename)
|
||||||
|
.with_thread_ids(display_thread_ids)
|
||||||
|
.with_line_number(display_line_number)
|
||||||
|
.with_thread_names(display_thread_names)
|
||||||
|
.with_span_events(FmtSpan::FULL);
|
||||||
|
// I know this is hacky, but I couldn't get it any other way. I couldn't even find a
|
||||||
|
// project that could do it any other way. You can't apply one after another, because the
|
||||||
|
// type is changed every time. When using Box<dyn Whatever>, some methods complain about
|
||||||
|
// not being in trait bounds.
|
||||||
|
// TODO: somehow find a better solution for this
|
||||||
|
match (log_to_file, show_time, pretty, uptime) {
|
||||||
|
(true, true, true, true) => {
|
||||||
|
let subscriber = subscriber
|
||||||
|
.with_writer(new_file_appender(log_dir))
|
||||||
|
.with_timer(time::uptime())
|
||||||
|
.pretty()
|
||||||
|
.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(true, true, true, false) => {
|
||||||
|
let subscriber = subscriber
|
||||||
|
.with_writer(new_file_appender(log_dir))
|
||||||
|
.pretty()
|
||||||
|
.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(true, false, true, _) => {
|
||||||
|
let subscriber = subscriber
|
||||||
|
.with_writer(new_file_appender(log_dir))
|
||||||
|
.without_time()
|
||||||
|
.pretty()
|
||||||
|
.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(true, true, false, true) => {
|
||||||
|
let subscriber = subscriber
|
||||||
|
.with_writer(new_file_appender(log_dir))
|
||||||
|
.with_timer(time::uptime())
|
||||||
|
.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(true, true, false, false) => {
|
||||||
|
let subscriber = subscriber.with_writer(new_file_appender(log_dir)).finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(true, false, false, _) => {
|
||||||
|
let file_appender = tracing_appender::rolling::daily(log_dir.clone(), "log");
|
||||||
|
let (file_writer, _guard) = tracing_appender::non_blocking(file_appender);
|
||||||
|
let subscriber = subscriber.with_writer(file_writer).without_time().finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, true, true, true) => {
|
||||||
|
let subscriber = subscriber.pretty().with_timer(time::uptime()).finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, true, true, false) => {
|
||||||
|
let subscriber = subscriber.pretty().with_timer(time::uptime()).finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, false, true, _) => {
|
||||||
|
let subscriber = subscriber.without_time().pretty().finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, true, false, true) => {
|
||||||
|
let subscriber = subscriber.with_timer(time::uptime()).finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, true, false, false) => {
|
||||||
|
let subscriber = subscriber.finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
(false, false, false, _) => {
|
||||||
|
let subscriber = subscriber.without_time().finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
INITIALIZED.store(true, Ordering::Relaxed);
|
||||||
|
Ok(Logger {})
|
||||||
|
}
|
||||||
|
|
||||||
/// ## logging at [`Level::ERROR`]
|
/// ## logging at [`Level::ERROR`]
|
||||||
pub fn error<T>(&self, printable: T)
|
pub fn error<T>(&self, printable: T)
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
{
|
{
|
||||||
error!("{}", printable);
|
error!("{}", printable)
|
||||||
}
|
}
|
||||||
/// ## logging at [`Level::WARN`]
|
/// ## logging at [`Level::WARN`]
|
||||||
pub fn warn<T>(&self, printable: T)
|
pub fn warn<T>(&self, printable: T)
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
{
|
{
|
||||||
warn!("{}", printable);
|
warn!("{}", printable)
|
||||||
}
|
}
|
||||||
/// ## logging at [`Level::INFO`]
|
/// ## logging at [`Level::INFO`]
|
||||||
pub fn info<T>(&self, printable: T)
|
pub fn info<T>(&self, printable: T)
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
{
|
{
|
||||||
info!("{}", printable);
|
info!("{}", printable)
|
||||||
}
|
}
|
||||||
/// ## logging at [`Level::DEBUG`]
|
/// ## logging at [`Level::DEBUG`]
|
||||||
pub fn debug<T>(&self, printable: T)
|
pub fn debug<T>(&self, printable: T)
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
{
|
{
|
||||||
debug!("{}", printable);
|
debug!("{}", printable)
|
||||||
}
|
}
|
||||||
/// ## logging at [`Level::TRACE`]
|
/// ## logging at [`Level::TRACE`]
|
||||||
pub fn trace<T>(&self, printable: T)
|
pub fn trace<T>(&self, printable: T)
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
{
|
{
|
||||||
trace!("{}", printable);
|
trace!("{}", printable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,3 +586,8 @@ impl Default for Logger {
|
||||||
.expect("building a Logger failed")
|
.expect("building a Logger failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_file_appender(log_dir: PathBuf) -> NonBlocking {
|
||||||
|
let file_appender = tracing_appender::rolling::daily(log_dir.clone(), "log");
|
||||||
|
tracing_appender::non_blocking(file_appender).0
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/target
|
||||||
|
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
.pytest_cache/
|
||||||
|
*.py[cod]
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
.venv/
|
||||||
|
env/
|
||||||
|
bin/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
include/
|
||||||
|
man/
|
||||||
|
venv/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
pip-selfcheck.json
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
|
||||||
|
# Mr Developer
|
||||||
|
.mr.developer.cfg
|
||||||
|
.project
|
||||||
|
.pydevproject
|
||||||
|
|
||||||
|
# Rope
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# VSCode
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Pyenv
|
||||||
|
.python-version
|
|
@ -0,0 +1,31 @@
|
||||||
|
[package]
|
||||||
|
name = "libpt-py"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
description.workspace = true
|
||||||
|
readme.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
keywords.workspace = true
|
||||||
|
categories.workspace = true
|
||||||
|
|
||||||
|
[package.metadata.maturin]
|
||||||
|
name = "libpt"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libpt = { version = "0.5.0"}
|
||||||
|
pyo3 = { version = "0.19.0", features = ["full"] }
|
||||||
|
anyhow.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["log", "core", "full"]
|
||||||
|
core = []
|
||||||
|
full = ["default", "core", "log", "bintols"]
|
||||||
|
log = ["libpt/log"]
|
||||||
|
bintols = ["libpt/bintols", "log"]
|
|
@ -0,0 +1,16 @@
|
||||||
|
[build-system]
|
||||||
|
requires = ["maturin>=1.4,<2.0"]
|
||||||
|
build-backend = "maturin"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "libpt"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
classifiers = [
|
||||||
|
"Programming Language :: Rust",
|
||||||
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
|
]
|
||||||
|
dynamic = ["version"]
|
||||||
|
|
||||||
|
[tool.maturin]
|
||||||
|
features = ["pyo3/extension-module"]
|
|
@ -0,0 +1,76 @@
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
use libpt::bintols as origin;
|
||||||
|
|
||||||
|
mod split {
|
||||||
|
use libpt::bintols::split as origin;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
pub fn split_int(data: u128) -> Vec<u8> {
|
||||||
|
origin::unsigned_to_vec(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// implement a python module in Rust
|
||||||
|
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||||
|
let module = PyModule::new(py, "split")?;
|
||||||
|
|
||||||
|
module.add_function(wrap_pyfunction!(split_int, module)?)?;
|
||||||
|
|
||||||
|
parent.add_submodule(module)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod display {
|
||||||
|
use libpt::bintols::display as origin;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
pub fn bytes_to_bin(data: &[u8]) -> String {
|
||||||
|
origin::bytes_to_bin(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
pub fn byte_bit_display(data: usize) -> String {
|
||||||
|
origin::byte_bit_display(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
pub fn humanbytes(total: u128) -> String {
|
||||||
|
origin::humanbytes(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// implement a python module in Rust
|
||||||
|
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||||
|
let module = PyModule::new(py, "display")?;
|
||||||
|
|
||||||
|
module.add_function(wrap_pyfunction!(bytes_to_bin, module)?)?;
|
||||||
|
module.add_function(wrap_pyfunction!(byte_bit_display, module)?)?;
|
||||||
|
module.add_function(wrap_pyfunction!(humanbytes, module)?)?;
|
||||||
|
|
||||||
|
parent.add_submodule(module)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// implement a python module in Rust
|
||||||
|
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||||
|
let module = PyModule::new(py, "bintols")?;
|
||||||
|
|
||||||
|
// binary constants
|
||||||
|
module.add("KIBI", origin::KIBI)?;
|
||||||
|
module.add("MEBI", origin::MEBI)?;
|
||||||
|
module.add("GIBI", origin::GIBI)?;
|
||||||
|
module.add("TEBI", origin::TEBI)?;
|
||||||
|
module.add("PEBI", origin::PEBI)?;
|
||||||
|
module.add("EXBI", origin::EXBI)?;
|
||||||
|
module.add("ZEBI", origin::ZEBI)?;
|
||||||
|
module.add("YOBI", origin::YOBI)?;
|
||||||
|
|
||||||
|
display::submodule(py, module)?;
|
||||||
|
split::submodule(py, module)?;
|
||||||
|
|
||||||
|
parent.add_submodule(module)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
mod printing;
|
||||||
|
|
||||||
|
/// implement a python module in Rust
|
||||||
|
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||||
|
let module = PyModule::new(py, "core")?;
|
||||||
|
printing::submodule(py, module)?;
|
||||||
|
parent.add_submodule(module)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
use libpt::core::printing as origin;
|
||||||
|
|
||||||
|
/// Quickly get a one line visual divider
|
||||||
|
#[pyfunction]
|
||||||
|
pub fn divider() -> String {
|
||||||
|
origin::divider()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Quickly print a one line visual divider
|
||||||
|
#[pyfunction]
|
||||||
|
pub fn print_divider() {
|
||||||
|
origin::print_divider()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// implement a python module in Rust
|
||||||
|
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||||
|
let module = PyModule::new(py, "printing")?;
|
||||||
|
module.add_function(wrap_pyfunction!(divider, module)?)?;
|
||||||
|
module.add_function(wrap_pyfunction!(print_divider, module)?)?;
|
||||||
|
parent.add_submodule(module)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
//! Python bindings for [`libpt`]
|
||||||
|
|
||||||
|
#[cfg(feature = "bintols")]
|
||||||
|
mod bintols;
|
||||||
|
#[cfg(feature = "core")]
|
||||||
|
mod core;
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
mod log;
|
||||||
|
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
/// return the version of libpt
|
||||||
|
#[pyfunction]
|
||||||
|
fn version() -> String {
|
||||||
|
env!("CARGO_PKG_VERSION").to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// implement a python module in Rust
|
||||||
|
#[pymodule]
|
||||||
|
#[pyo3(name = "libpt")]
|
||||||
|
fn libpt_py(py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_function(wrap_pyfunction!(version, m)?)?;
|
||||||
|
#[cfg(feature = "core")]
|
||||||
|
core::submodule(py, m)?;
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
log::submodule(py, m)?;
|
||||||
|
#[cfg(feature = "bintols")]
|
||||||
|
bintols::submodule(py, m)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
use libpt::log as origin;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[pyclass]
|
||||||
|
pub enum Level {
|
||||||
|
Error,
|
||||||
|
Warn,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
Trace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Level> for origin::Level {
|
||||||
|
fn from(value: Level) -> Self {
|
||||||
|
match value {
|
||||||
|
Level::Error => origin::Level::ERROR,
|
||||||
|
Level::Warn => origin::Level::WARN,
|
||||||
|
Level::Info => origin::Level::INFO,
|
||||||
|
Level::Debug => origin::Level::DEBUG,
|
||||||
|
Level::Trace => origin::Level::TRACE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
pub struct Logger {
|
||||||
|
inner: origin::Logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<origin::Logger> for Logger {
|
||||||
|
fn from(inner: origin::Logger) -> Self {
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl Logger {
|
||||||
|
#[new]
|
||||||
|
pub fn build(
|
||||||
|
log_dir: Option<PathBuf>,
|
||||||
|
max_level: Option<Level>,
|
||||||
|
uptime: Option<bool>,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
// concert our wrapper type
|
||||||
|
let max_level = max_level.map(origin::Level::from);
|
||||||
|
let mut builder = origin::Logger::builder();
|
||||||
|
if log_dir.is_some() {
|
||||||
|
builder = builder.log_dir(log_dir.unwrap());
|
||||||
|
}
|
||||||
|
if max_level.is_some() {
|
||||||
|
builder = builder.max_level(max_level.unwrap());
|
||||||
|
}
|
||||||
|
if uptime.is_some() {
|
||||||
|
builder = builder.uptime(uptime.unwrap());
|
||||||
|
}
|
||||||
|
Ok(builder.build()?.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## logging at [`Level::ERROR`]
|
||||||
|
pub fn error(&self, printable: String) {
|
||||||
|
self.inner.error(printable)
|
||||||
|
}
|
||||||
|
/// ## logging at [`Level::WARN`]
|
||||||
|
pub fn warn(&self, printable: String) {
|
||||||
|
self.inner.warn(printable)
|
||||||
|
}
|
||||||
|
/// ## logging at [`Level::INFO`]
|
||||||
|
pub fn info(&self, printable: String) {
|
||||||
|
self.inner.info(printable)
|
||||||
|
}
|
||||||
|
/// ## logging at [`Level::DEBUG`]
|
||||||
|
pub fn debug(&self, printable: String) {
|
||||||
|
self.inner.debug(printable)
|
||||||
|
}
|
||||||
|
/// ## logging at [`Level::StringRACE`]
|
||||||
|
pub fn trace(&self, printable: String) {
|
||||||
|
self.inner.trace(printable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// implement a python module in Rust
|
||||||
|
pub fn submodule(py: Python, parent: &PyModule) -> PyResult<()> {
|
||||||
|
let module = PyModule::new(py, "log")?;
|
||||||
|
module.add_class::<Logger>()?;
|
||||||
|
parent.add_submodule(module)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
cargo check --all-features --workspace
|
cargo check --all-features
|
||||||
echo ">>>>>>>> SELECT A NEW VERSION"
|
echo ">>>>>>>> SELECT A NEW VERSION"
|
||||||
cargo ws version
|
cargo ws version
|
||||||
NEW_VERSION=$(cat Cargo.toml | rg '^\s*version\s*=\s*"([^"]*)"\s*$' -or '$1')
|
NEW_VERSION=$(cat Cargo.toml | rg '^\s*version\s*=\s*"([^"]*)"\s*$' -or '$1')
|
||||||
|
|
Reference in New Issue