Giter Site home page Giter Site logo

iqlusioninc / abscissa Goto Github PK

View Code? Open in Web Editor NEW
571.0 571.0 39.0 1.16 MB

Application microframework with command-line option parsing, configuration, error handling, logging, and shell interactions

License: Apache License 2.0

Rust 90.87% Handlebars 9.13%

abscissa's People

Contributors

adizere avatar alex avatar c410-f3r avatar dependabot-preview[bot] avatar dependabot[bot] avatar hannydevelop avatar hawkw avatar hdevalence avatar jarrodldavis avatar jzelinskie avatar lberezy avatar leotaku avatar rsdy avatar shella avatar shnatsel avatar simonsan avatar tarcieri avatar tony-iqlusion avatar zerokarmaleft avatar zmanian avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

abscissa's Issues

crates: Consider `err-derive`

Presently Abscissa uses the failure as its error handling abstraction, and uses the following features:

  • failure_derive proc macro "DSL" for describing errors
  • cause support for capturing error causes (and potentially downcasting them)
  • backtrace support

In the intervening time since we selected failure std::error:Error got a new Error::source method which supports downcasting.

My understanding is there's also some work underway to consume the backtrace crate as part of std, however I can't find references to it. That said, Abscissa uses a generic abscissa_core::error::Error<Kind> type, so capturing and storing backtraces directly is potentially doable.

That leaves the error-handling DSL as the main compelling reason to continue using failure. The err-derive crate seems like a popular new alternative to failure_derive.

I think failure had good goals when it started, like unifying error handling for std and no_std programs, and addressing shortcomings of std::error::Error in a third party crate. But because Abscissa is very much std dependent, and because std::error::Error has improved, failure is less compelling, and the schism between std::error::Error and failure::Fail is somewhat problematic.

I think the main compelling reason to switch would be if std::error::Error ever gets first-class backtrace support, but it's something we can also consider doing earlier.

It appears err-derive adds one additional transitive compile time dependency (rustc_version) but otherwise has the same dependencies as failure.

Doc String in lib.rs inaccurate or out-of-date

I was following these instructions:

//! $ cargo run -- hello world

I ran the below (in an abscissa new generated directory):

abscissa --verbose
Sep 02 03:41:31.306 DEBUG abscissa_core::component::registry: registered component: abscissa_core::terminal::component::Terminal (v0.5.2)
Sep 02 03:41:31.306 DEBUG abscissa_core::component::registry: registered component: abscissa_core::trace::component::Tracing (v0.5.2)
abscissa 0.5.1
Tony Arcieri <[email protected]>
Application microframework with support for command-line option parsing, configuration, error handling, logging, and terminal interactions. This crate contains a CLI utility for generating new applications.

USAGE:
    abscissa <SUBCOMMAND>

SUBCOMMANDS:
    gen        generate a new module in an existing app
    help       show help for a command
    new        create a new Abscissa application from a template
    version    display version information

cargo run -- hello world
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
     Running `target/debug/quizface hello world`
error: unrecognized command `hello`

quizface 0.1.0


FLAGS:
    -c, --config CONFIG       path to configuration file
    -h, --help                print help message
    -v, --verbose             be verbose

I didn't really expect "hello" to be a subcommand because it's not among the constructor-variants of the commands::QuizfaceCmd enum that abscissa generated for me.

Replace `gumdrop` with `clap` v3?

There were two primary reasons why Abscissa used gumdrop over clap v2 originally:

  • Previously clap had an excessively large number of dependencies, whereas gumdrop had no dependencies other than proc-macro2, quote, and syn for its proc macro. It seems clap-v3 has done a good job of addressing this (see below).
  • Custom derive support: clap's previous custom derive crate structopt was added as something of an afterthought, had a clunky attribute syntax, and generally felt pretty low quality, whereas gumdrop was effectively a "custom derive first" crate and in that regard felt much more cohesive. That said, clap-v3 now features clap_derive which largely addresses these concerns.

We're now at a crossroads where we can either upgrade to gumdrop v0.8 or consider migrating to clap-v3. Either approach seems a bit difficult as gumdrop v0.8 contains a number of API changes.

The current beta release is clap-v3 3.0.0-beta.2. They warn against depending on the API until it's stable, however.

Tracking issue for clap v3 is here: clap-rs/clap#1037

Dependencies

Here are the transitive dependencies of clap-v3 3.0.0-beta.1 (I haven't fully cross-referenced these with our current ones yet, but I see a lot of commonality):

  • ansi_term 0.12.1
  • atty 0.2.14
  • autocfg 1.0.0
  • bitflags 1.2.1
  • clap-v3 3.0.0-beta.1
  • clap_derive-v3 3.0.0-beta.1
  • heck 0.3.1
  • hermit-abi 0.1.13
  • indexmap 1.4.0
  • lazy_static 1.4.0
  • libc 0.2.71
  • proc-macro-error 0.4.12
  • proc-macro-error-attr 0.4.12
  • proc-macro2 1.0.18
  • quote 1.0.7
  • strsim 0.9.3
  • syn 1.0.31
  • syn-mid 0.5.0
  • textwrap 0.11.0
  • unicode-segmentation 1.6.0
  • unicode-width 0.1.7
  • unicode-xid 0.2.0
  • vec_map 0.8.2
  • version_check 0.9.2
  • winapi 0.3.8
  • winapi-i686-pc-windows-gnu 0.4.0
  • winapi-x86_64-pc-windows-gnu 0.4.0

Unable to compile crate with dash in name

If I try to create an Abscissa crate that has a dash in the name, then it will create invalid code. Since in the code the crate name has to replace dashes with underscores.

How to reproduce:

$ abscissa new abscissa-test
...

$ cd abscissa-test/

$ cargo build
   Compiling abscissa-test v0.1.0 (/home/user/src/abscissa-test)
error: expected one of `::`, `;`, or `as`, found `-`
 --> src/bin/abscissa-test/main.rs:6:13
  |
6 | use abscissa-test::application::APPLICATION;
  |             ^ expected one of `::`, `;`, or `as` here

abscissa_core v0.6.0-pre.2 based apps fail to build because of the Clap dependency

It looks like the recent move to Clap has had some side effects.

The error that I am seeing when compiling apps generated with the CLI is below:

error[E0432]: unresolved import `clap::Clap`
   --> /home/ctrauma/.cargo/registry/src/github.com-1ecc6299db9ec823/abscissa_core-0.6.0-pre.2/src/lib.rs:141:9
    |
141 | pub use clap::Clap;
    |         ^^^^^^^^^^ no `Clap` in the root
% abscissa --version
abscissa 0.6.0-pre.2
% abscissa new test
     Created `test` (application directory)
     Created new file: .gitignore
     Created new file: Cargo.toml
     Created new file: README.md
     Created new file: src/application.rs
     Created new file: src/bin/test/main.rs
     Created new file: src/commands.rs
     Created new file: src/commands/start.rs
     Created new file: src/config.rs
     Created new file: src/error.rs
     Created new file: src/lib.rs
     Created new file: src/prelude.rs
     Created new file: tests/acceptance.rs
     Running git init test
     Running cargo generate-lockfile
    Finished `test` generated in 0.14s
% cargo build --release
   Compiling proc-macro2 v1.0.30
   Compiling unicode-xid v0.2.2
   Compiling syn v1.0.80
   Compiling autocfg v1.0.1
   Compiling version_check v0.9.3
   Compiling memchr v2.4.1
   Compiling libc v0.2.104
   Compiling serde_derive v1.0.130
   Compiling cfg-if v1.0.0
   Compiling serde v1.0.130
   Compiling lazy_static v1.4.0
   Compiling regex-syntax v0.6.25
   Compiling fnv v1.0.7
   Compiling strsim v0.10.0
   Compiling cc v1.0.71
   Compiling ident_case v1.0.1
   Compiling once_cell v1.8.0
   Compiling log v0.4.14
   Compiling eyre v0.6.5
   Compiling adler v1.0.2
   Compiling gimli v0.25.0
   Compiling unicode-segmentation v1.8.0
   Compiling semver v1.0.4
   Compiling pin-project-lite v0.2.7
   Compiling hashbrown v0.11.2
   Compiling unicode-width v0.1.9
   Compiling rustc-demangle v0.1.21
   Compiling indenter v0.3.3
   Compiling smallvec v1.7.0
   Compiling bitflags v1.3.2
   Compiling zeroize v1.4.2
   Compiling ansi_term v0.12.1
   Compiling termcolor v1.1.2
   Compiling owo-colors v1.3.0
   Compiling canonical-path v2.0.2
   Compiling fs-err v2.6.0
   Compiling arc-swap v1.4.0
   Compiling proc-macro-error-attr v1.0.4
   Compiling proc-macro-error v1.0.4
   Compiling unicase v2.6.0
   Compiling tracing-core v0.1.21
   Compiling sharded-slab v0.1.4
   Compiling num-traits v0.2.14
   Compiling miniz_oxide v0.4.4
   Compiling num-integer v0.1.44
   Compiling indexmap v1.7.0
   Compiling thread_local v1.1.3
   Compiling textwrap v0.14.2
   Compiling heck v0.3.3
   Compiling backtrace v0.3.61
   Compiling regex-automata v0.1.10
   Compiling addr2line v0.16.0
   Compiling aho-corasick v0.7.18
   Compiling object v0.26.2
   Compiling os_str_bytes v4.2.0
   Compiling matchers v0.0.1
   Compiling quote v1.0.10
   Compiling time v0.1.44
   Compiling atty v0.2.14
   Compiling wait-timeout v0.2.0
   Compiling tracing-log v0.1.2
   Compiling regex v1.5.4
   Compiling color-eyre v0.5.11
   Compiling darling_core v0.13.0
   Compiling synstructure v0.12.6
   Compiling tracing-attributes v0.1.18
   Compiling clap_derive v3.0.0-beta.5
   Compiling thiserror-impl v1.0.30
   Compiling darling_macro v0.13.0
   Compiling darling v0.13.0
   Compiling abscissa_derive v0.6.0-pre.2
   Compiling tracing v0.1.29
   Compiling tracing-subscriber v0.2.25
   Compiling thiserror v1.0.30
   Compiling clap v3.0.0-beta.5
   Compiling toml v0.5.8
   Compiling chrono v0.4.19
   Compiling secrecy v0.8.0
   Compiling abscissa_core v0.6.0-pre.2
error[E0432]: unresolved import `clap::Clap`
   --> /home/ctrauma/.cargo/registry/src/github.com-1ecc6299db9ec823/abscissa_core-0.6.0-pre.2/src/lib.rs:141:9
    |
141 | pub use clap::Clap;
    |         ^^^^^^^^^^ no `Clap` in the root

For more information about this error, try `rustc --explain E0432`.
error: could not compile `abscissa_core` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed

Add the ability to log in JSON

iqlusioninc/tmkms#509

JSON is way better if you use logging solutions like ELK instead of reading the logs on a machine directly. Would be nice to have the ability to produce logs in JSON and specifically have tmkms supporting it.

Open up wiki ?

Hi
I like to become a abscissa user(not developing abscissa itself).
I will document abscissa from end user perspective.
Would you consider enable wiki to take in notes/docs from users ?

Feature request: `abscissa new` generates subcommands under existing commands

It would be really great if abscissa gen allowed you to add subcommands underneath existing commands. For example, say I have a abscissa cli cli with command cmd,

// in cli project root
abscissa gen cmd --subcommands=[subcmd1, subcmd2, subcmd3]

would result in code generated

src/
    // snip
    commands/
        cmd/
             subcmd1.rs
             subcmd2.rs
             subcmd3.rs
        cmd.rs
    commands.rs
    // snip

Implicitly this shouldn't overwrite cmd.rs if it already exists.

New application without commands

Greetings,
When creating an app, is there any way to either imply a default command that the user won't have to type or directly add options to the Entrypoint?
The goal being:
$: myapp --flag --foo bar -b
rather than
$: myapp start --flag --foo bar -b

RUSTSEC-2020-0071: Potential segfault in the time crate

Potential segfault in the time crate

Details
Package time
Version 0.1.44
URL time-rs/time#293
Date 2020-11-18
Patched versions >=0.2.23
Unaffected versions =0.2.0,=0.2.1,=0.2.2,=0.2.3,=0.2.4,=0.2.5,=0.2.6

Impact

Unix-like operating systems may segfault due to dereferencing a dangling pointer in specific circumstances. This requires an environment variable to be set in a different thread than the affected functions. This may occur without the user's knowledge, notably in a third-party library.

The affected functions from time 0.2.7 through 0.2.22 are:

  • time::UtcOffset::local_offset_at
  • time::UtcOffset::try_local_offset_at
  • time::UtcOffset::current_local_offset
  • time::UtcOffset::try_current_local_offset
  • time::OffsetDateTime::now_local
  • time::OffsetDateTime::try_now_local

The affected functions in time 0.1 (all versions) are:

  • at
  • at_utc

Non-Unix targets (including Windows and wasm) are unaffected.

Patches

Pending a proper fix, the internal method that determines the local offset has been modified to always return None on the affected operating systems. This has the effect of returning an Err on the try_* methods and UTC on the non-try_* methods.

Users and library authors with time in their dependency tree should perform cargo update, which will pull in the updated, unaffected code.

Users of time 0.1 do not have a patch and should upgrade to an unaffected version: time 0.2.23 or greater or the 0.3. series.

Workarounds

No workarounds are known.

References

time-rs/time#293

See advisory page for additional details.

How to configure a Tokio component?

If I understand correctly, the order of events from a component perspective are:

  • constructor call (in register components, no config available)
  • init_tokio call (no config available, attempts to read from APP crash with Message: Abscissa application state accessed before it has been initialized!)
  • after_config call (config available, but component already running)

So if init_tokio spawns a task, how is it supposed to be configured?
Going further, why isn't the config already available in the constructor call?

crates: Replacements for failure?

std::error::Error now contains a trait as expressive as the Fail trait from failure, including downcast support and downcastable Error::source as a replacement for Error::cause (now with a 'static lifetime bound).

Additionally, there are a number of custom derive crates for std::error::Error now available:

Given that, it seems like we can eliminate failure as a dependency, potentially replacing failure_derive with one of the crates above.

Serializable Errors

A bit of a sidebar, but one of the things I'd like to eventually accomplish is serde support for the framework's Error type, making it Serialize-able (and ideally Deserialize-able as well), with the intent of serializing them as JSON for reporting to an exception reporting service.

The backtrace crate offers serde support as an optional feature, however accessing this functionality was previously difficult as Abscissa's Error type uses failure::Context to capture and store backtraces.
It seems like Abscissa could benefit from providing a similar Context type as a replacement for the one failure provided. Ideally this type could simply derive(Serialize, Deserialize), permitting straightforward serialization of errors as well as their backtraces (and ideally, the entire error chain).

Unfortunately the story around all of this is complicated by adding a Backtrace type to std, presently only available on nightly. This Backtrace type has deliberately minimal functionality.

I'd consider supporting Backtrace on stable a requirement, and ideally preserving the serde serialization support. This seems possible with snafu but needs more investigation.

Crates like err-derive and thiserror have the advantage of being pure proc macros with no additional API dependencies, so if nothing else they stay nicely out of the way and orthogonal to this problem. I imagine if we don't go with snafu, we could pick one of these to be the out-of-the-box custom derive for errors, but with the only framework-level association being inclusion in the default application template (allowing downstream users of the users to potentially remove it or swap it out if they so desire)

Parametrize tracing formatter

Summary

For our use-case in the relayer-cli crate (informalsystems/hermes#500) we would like to enable JSON-formatted tracing output. At first glance, it's not clear if abscissa permits this kind of configuration. Thanks in advance for any advice!

Description

Abscissa core is setting the global subscriber for tracing as follows:

tracing::subscriber::set_global_default(subscriber)

If I understand correctly, all applications built on abscissa are forced to use this subscriber. It would be great to allow more flexibility here. Note that documentation in tracing seems to provide guidance specifically against libraries using set_global_default.

Migrate from `log` to `tracing`

Hi, in Zebra https://github.com/ZcashFoundation/zebra we used @hawkw's tracing rather than log and wrote our own TracingComponent.

Would Abscissa be interested in upstreaming (a modified version of) that component and replacing the default log component with a tracing-based one? In contrast to log, tracing is much more async-friendly, but can remain compatible with log-based crates.

There are some design questions, if this turns out to be of interest to Abscissa:

  1. One of the really killer features of tracing is dynamic filter reloading -- how should this be exposed to Abscissa applications?

  2. In Zebra, we have an HTTP endpoint that allows feeding inputs to the filter reloading. Should Abscissa provide a default mechanism for doing filter reloading? My guess is no, that this is application-specific (e.g., we will probably fold ours into the standard RPC interface).

RUSTSEC-2020-0146: arr! macro erases lifetimes

arr! macro erases lifetimes

Details
Package generic-array
Version 0.12.3
URL fizyk20/generic-array#98
Date 2020-04-09
Patched versions >=0.14.0
Unaffected versions <0.8.0

Affected versions of this crate allowed unsoundly extending
lifetimes using arr! macro. This may result in a variety of
memory corruption scenarios, most likely use-after-free.

See advisory page for additional details.

Upgrade to gumdrop v0.8

gumdrop v0.8 fixes a number of things, including usage parsing for deeply nested commands.

We should upgrade, but it will require changes to the command usage presenter code.

Allow finer grained control over argument parsing style and error display

Currently, abscissa_core delegates to gumdrop's parsing logic with its default parsing style and error formatting:

fn from_args<A: IntoIterator<Item = String>>(into_args: A) -> Self {
let args: Vec<_> = into_args.into_iter().collect();
Self::parse_args_default(args.as_slice()).unwrap_or_else(|err| {
terminal::init();
Usage::for_command::<Self>().print_error_and_exit(err, args.as_slice());
})
}

It would be nice if the following were possible:

  • override the ParsingStyle to use StopAtFirstFree using Options::parse_args
  • customize the error output when option parsing fails โ€“ the current behavior bypasses the generated application's error formatting in src/errors.rs:
    impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    self.0.fmt(f)
    }
    }

config::Override implementation not being called

Rust: 1.67
Abscissa: 0.6.0

I have a bool config field config.simulate.enabled that I'd like to override with the start command flag --simulate. My override looks like this:

impl config::Override<StewardConfig> for StartCmd {
    fn override_config(&self, mut config: StewardConfig) -> Result<StewardConfig, FrameworkError> {
        if self.simulate {
            config.simulate.enabled = self.simulate;
        }

        Ok(config)
    }
}

The config value is not being updated even though the flag is set. I've tried logging inside of override_config() to see if it is entered at all in case the value is is overwritten somewhere else, and it seems that the method is never actually called.

2023-02-08T15:05:23.769547Z  INFO steward::commands::start: simulate flag: true, simulate enabled in config: false

If it were working, both would be true

Question: Logging target

As a followup to "Damonizing and encrypting with Abscissa"..

Since I will be running as a daemon, I need to change some logging options:

  • redirect all logging activity to file
  • Change output formatting (Time format, add threads etc)
    Is there a way to do that? I've been digging but don't see a way short of modifying "application" and "trace/component"...

Thanks
JR

Better dependency injection syntax

The current dependency injection syntax is pretty gnarly and looks like this:

#[derive(Component, Debug)]
#[component(inject = "init_foo(depname::Foo)")]
#[component(inject = "init_bar(depname::Bar)")]
pub struct MyComponent {
    pub fn init_foo(&mut self, foo: &mut depname::Foo) -> Result<(), FrameworkError> {
        [...[
    }

    pub fn init_bar(&mut self, bar: &mut depname::Bar) -> Result<(), FrameworkError> {
        [...]
    }
}

It'd be nice to be able to use an attribute macro on the "injector" functions instead. Something like this:

#[derive(Component, Debug)]
#[inject(init_foo, init_bar)]
pub struct MyComponent {
    #[inject]
    pub fn init_foo(&mut self, foo: &mut depname::Foo) -> Result<(), FrameworkError> {
        [...[
    }

    #[inject]
    pub fn init_bar(&mut self, bar: &mut depname::Bar) -> Result<(), FrameworkError> {
        [...]
    }
}

It'd be nice if the #[inject] annotations on individual functions were all that were required, but AFAICT, the #[inject(init_foo, init_bar)] is still needed to thunk between them.

`EntryPoint` and config paths

I ran into a problem trying to load a config from a file in the following way: I implemented the config_path function in impl Configurable<FooConfig> for FooCommand to supply the correct config path, and expected the application initialization to call it in order to load the config file. However, the default boilerplate generates an

impl Application for FooApplication {
    type Cmd = EntryPoint<FooCommand>;

so that the command object created here

let command = Self::Cmd::from_args(args);
has type command: EntryPoint<FooCommand>, and so when it's configured here

abscissa/src/application.rs

Lines 101 to 103 in 977b548

let config = command
.config_path()
.map(|_| self.load_config(command))
the config_path function that's called is

<abscissa::command::entrypoint::EntryPoint<Cmd> as abscissa::config::configurable::Configurable<Cfg>>::config_path

(in fact the first config_path result is discarded, but the same function is called again inside of load_config).

But since the EntryPoint is created using from_args, there's no opportunity to actually set its config path, and the config_path function for the inner command is never called.

So I'm
a) not sure how to actually set the config path "correctly";
b) a little unclear on what the role of the EntryPoint struct is -- why not have type Cmd = FooCommand?.

Questions: Damonizing and encrypting with Abscissa

Since you have probably resolved these issues in your app...
A couple of quick questions...

I'm building a cross-platform agent using Abscissa / Tokio, it will be running on Windows and other platforms...
So I need to daemonize it..

  1. Which would be the preferred daemonizing crates ?
    ceviche-rs I'm leaning towards this one...
    daemon-rs Old but cross platform

  2. Encrypting values in the config(toml)
    I'm looking at CryptoStream

  3. What is the preferred approach to embedding keys in the executable ?

All (constructive :) ) suggestions are welcome

RUST_LOG support.

Per #154 (comment), RUST_LOG support for tracing was left unresolved. It'd be nice to have it for, e.g., ZcashFoundation/zebra#98 (cc @dconnolly)

One design question I'm not sure of: what should be the priority order of RUST_LOG and a config setting? Should RUST_LOG be overridden by a config option or vice versa? If RUST_LOG is overridden by a config option, does the presence of a config default prevent RUST_LOG from ever being used?

Tokio usage: abscissa_tokio::run... take_runtime() stuck in app.write()

I have a Tokio usage question, it may be my understanding of your sequence of events ,
but I have not been able to determine it from the docs...

I have a set of sub-modules / commands that are dependent upon Tokio runtime.
They get called to perform a specific sub-task then return.
According to the doc's, Include abscissa_tokio and call run..
I added:
components.push(Box::new(TokioComponent::new()?));
then call

impl Runnable for XXXCmd {
    fn run(&self) {
        let config = app_config();
        let _ = abscissa_tokio::run(&APPLICATION, 
            async{ 
println!("Started {}", "Junk");
            }
        );

Whcih calls tokio::block_on...
Which is essentially what tokio::main does.
So, the runtime is initialized, I see all the threads in the debugger, but the
app is stuck at (partial stack)
app.write
TokioComponent::take_runtime
TokioComponent::run
Waiting for the write lock...

In my case, I have no other component's / services running.
So I just need Tokio runtime initialized and available, the terminate after the run is done.

What am I missing...

Any insight would be greatly appreciated...

If flags and params are too long, description is missing from help output

When Options is derived, the usage() output will have an extra \n after long_param if -short, --long long_param is longer than 29 characters. This causes long_param to be set to None, description to be set to what should be long_param, and the actual help description from that flag to be missing from the help output entirely.

Using lines() here doesn't work:

for line in usage.lines() {

Abscissa context poisoned in tests

I've been using the Abscissa test framework to do integration testing.

The shared context gets poisoned if one of the tests fails, bringing down all the other tests with it. (Regardless of if they should succeed or fail.)

I guess this should be considered a bug, but I don't know the working details to evaluate the issue.

This is a log from GitHub Actions: https://github.com/informalsystems/ibc-rs/runs/926134260
The query_channel_id test fails properly, but the upcoming query_client_id and query_connection_id tests, which should fail similarly, panic instead, because of the poisoned mutex.
Note: the tests all fail, even if only one fails properly and the rest should succeed.

---- query_channel_id stdout ----
thread 'query_channel_id' panicked at 'assertion failed: `(left == right)`
  left: `"\u{1b}[0m\u{1b}[0m\u{1b}[1m\u{1b}[36m     Options\u{1b}[0m QueryChannelOptions { port_id: PortId(\"firstport\"), channel_id: ChannelId(\"firstchannel\"), height: 0, proof: true }"`,
 right: `"     Options QueryChannelOptions { port_id: PortId(\"firstport\"), channel_id: ChannelId(\"firstchannel\"), height: 0, proof: true }"`', /rustc/5c1f21c3b82297671ad3ae1e8c942d2ca92e84f2/src/libstd/macros.rs:16:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- query_client_id stdout ----
thread 'query_client_id' panicked at 'poisoned cmd mutex!: "PoisonError { inner: .. }"', /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/abscissa_core-0.5.2/src/testing/runner.rs:195:26

---- query_connection_id stdout ----
thread 'query_connection_id' panicked at 'poisoned cmd mutex!: "PoisonError { inner: .. }"', /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/abscissa_core-0.5.2/src/testing/runner.rs:195:26

Better support for overriding parts of a derived Component implementation.

Currently the inject attribute allows specifying a callback for dependency injection. However, there are other functions that would be useful to override, such as after_config and before_shutdown. It would be nice to avoid having to specify some id and version impls by hand while others can be derived.

Config paths that point to non-existing config files

After implementing Configurable<FooConfig> for FooCommand to have config_path return the application's config path (and tweaking things so this is actually called, see #79 for notes on my confusion), my application exits with a hard error if a config file does not exist at the supplied path.

Ideally I would like the application to attempt to load a config from a supplied path, or use a set of defaults if that file doesn't exist.

The config_path documentation doesn't give details, but is it the responsibility of the config_path function to check whether the file exists and return None if not, or should it return the expected path for a config file, and have the config loading logic have responsibility for gracefully handling the case where the config is not supplied?

Terminal component installs the global eyre handler based on color choice

The Terminal component of the framework performs initialization of the global eyre handler with color_eyre::install, unless the application's color choice is set to Never. If the handler installation fails, a panic occurs.

This is problematic, because the application should be in control of setting such things as program-global error/panic handlers.
Or, if it's really decided that the framework is so opinionated that it makes eyre setup part of its functionality, it should provide an API to override it. The colorization choice alone is a poor way to control this, because the application may want to set up error reporting differently based on other settings (e.g. whether backtraces are enabled).

Redirecting status logging message outputs

Not sure if duplicate of #344

with tracing, one can implement a subscriber that will receive the log events -- e.g. instead of using standard output, one can use "console.log" in WASM: https://crates.io/crates/tracing-wasm

It'll be good if this is possible with status_*!(..., ...) logging macros too.
Currently, the status messages seem to use the Terminal component and it seems external applications can't modify terminal streams: https://github.com/iqlusioninc/abscissa/blob/develop/core/src/terminal.rs#L14

crates: Consider `crossterm`

Hello, nice project!

I saw this project comming by, you might be interested in using crossterm for cross-platform terminal interactions. It is quite stable and will save a huge amount of time. It supports things like styling, input reading, terminal interactions, cursor movements. And is quite lightweight since it has no external deps then WinApi and Libc which are required, of course, as well you can use feature flags to even more reduce the size.

Question: how to hook in to subcommand Help...

Hi..

I'm trying to get help implemented for an option...

target/release/my_agent.exe help scan
my_agent 0.1.1


USAGE:
    my_agent scan <OPTIONS>

DESCRIPTION:
    Perform Data Scan

POSITIONAL ARGUMENTS:
    extra

FLAGS:
    -d, --devicetype DEVICE-TYPE 
    -U, --url URL             URL or ip of target
    -m, --method METHOD       Authentication Method
    -u, --username USERNAME   Authentication User Name (root|admin|apiuser)
    -p, --password PASSWORD   Authentication Password
    --token TOKEN             Authentication token
    -c, --clientid CLIENTID   Authentication ClientId
    --clientsecret CLIENTSECRET
    --tenantid TENANTID       Authentication Tenant ID (M$)
    -e, --emailuser EMAILUSER E-Mail user name
    -r, --realm REALM         Authentication Realm
    -A, --action ACTION       SubDevice Instance or Action verb (reset|on|off...)
    -P, --actionparam ACTION-PARAM
    -C, --credentialname my-CREDS
    -v, --verbose             Show verbose message
    -t, --timeout TIMEOUT-MS  Connect timeout in milliseconds (Default 20sec/21000ms (default: 21000)
    -T, --timing              Activate timing mode (default: false)
    -l, --log_message LOG-MESSAGE
    -L, --log_path LOG-PATH   Log file base path

the option : "DEVICE-TYPE"
has a dynamic list of options...
Is there a way to hook into the help system to generate a list ?

Also... Is there a way to hook in with the "Graceful" shutdown ?
Given that my app uses Tokio:

    fn run(&self) {
        let _ = abscissa_tokio::run(&APPLICATION, 
            async{
...
                let upload_interval = 
                    Duration::from_secs(self.upload_interval.unwrap_or(60));
                info!("Starting agent Loop");
                loop {
                    APPLICATION.read().get_handler_controller().read()
                        .handle_tasks_until(&mut todo_list, upload_interval).await;
                    self.dump_data(&mut todo_list);
                    // &&##&& Termination condition ???
                }
            }
        );
    }

The application ahs the Shutdown method...
It would be handy if the "Runnable had a "shutdown(&mut self, shutdown: Shutdown)"
Or did I miss something ?

Thanks again for sharing this project...
It's been a great time saver...
JR

Using the status module across large workspaces

I've been using abscissa in several apps in a large workspace with other non-abscissa apps. I'd like to use the status.rs in those other apps, or in common libraries. This means instantiating Streams before using status_info! directly in the non-abscissa module.

However that means abscissa apps will fail with "terminal streams already initialized!". Would be nice if status didn't have a panic when the terminal is already initialized, or perhaps reusing.

/// Initialize the terminal subsystem, registering the [`Streams`] static
pub(crate) fn init(color_choice: ColorChoice) {
STREAMS
.set(Streams::new(color_choice))
.unwrap_or_else(|_| panic!("terminal streams already initialized!"));
}

Dependency documentation is out-of-date

Especially after the clap migration, the dependency table in README.md is out-of-date and needs to be updated.

It would be good to automate the process of computing the dependency and maintainer relationships.

Abscissa test: option to turn off colored output in tests

I'm doing testing using the Abscissa framework.

The output of stdout is color-coded on my local machine, but not-colored on CI. Instead of changing the dev environment (and forcing all developers to do the same) to get non-color-coded output, I would like to have an option in the Abscissa test framework that tells the application to run on a non-color terminal.

If I ran the application manually, I would be able to set an environment variable to tell the application that the terminal doesn't support colors. I guess that could be an option in the tests too.

Usage information is illegible on light backgrounds

Hi -- Not all of us use dark themes, and so I got to see this on startup of a base abscissa app:

Screen Shot 2019-07-25 at 6 23 44 PM

The white text on the light background is not wonderful :-(

I don't think there's any "magic" color which looks good everywhere, so perhaps just don't use colors at all by default? In other words, please respect the color choices I've made for my terminal.

Thanks!

Enhancement: Make self mutable in config::Override<xxxConfig>.override_config()

First, great framework...

One question.
Is it possible to make the self parameter mutable ?
I have standard libraries that I call from several executables.
In order to set missing / default parameters or override when they have specific
or standard overrides I need to update the parameters from the commandline.
I tried by setting Command::default, but it was not set.
so, if it was possible to change:
impl config::Override for XXXCmd {
fn override_config(
&self,
mut config: XXXConfig,

to
fn override_config(
&mut self,
mut config: XXXConfig,

Or add :
fn override_parameters(&mut self...)

it would solve the problem...

Question: Looking for a way to use tokio spawn_blocking

@tarcieri ,

I bumped into an issue with tokio...
I had a runaway process due to transitions from sync to async processes
using block_on...
(https://users.rust-lang.org/t/simplest-possible-block-on/48364/9)
It seems the solution is to start with spawn blocking...
So, I'm trying to find where to hook it in..

  • The best option would be to spawn blocking in abscissa/tokio/lib.rs
// 
pub fn run<A, F>(app: &'static AppCell<A>, future: F) -> Result<F::Output, FrameworkError>
where
    A: Application,
    F: Future,
{
    take_runtime(app).map(|mut runtime| runtime.block_on(future))
}

pub fn spawn_blocking<A, F>(app: &'static AppCell<A>, future: F) -> Result<F::Output, FrameworkError>
where
    A: Application,
    F: Future,
{
...
}

though this is proving to be a bit of a problem due to issues with spawn_blocking on futures.

  • Start the tokio runtime before and pass it in to the componenet

  • Or start a separate tokio runtime, just for the spawn blocking...

If you have a suggestion / solution, I'd love to hear it...
Thanks
JR

RUSTSEC-2021-0139: ansi_term is Unmaintained

ansi_term is Unmaintained

Details
Status unmaintained
Package ansi_term
Version 0.12.1
URL ogham/rust-ansi-term#72
Date 2021-08-18

The maintainer has adviced this crate is deprecated and will not
receive any maintenance.

The crate does not seem to have much dependencies and may or may not be ok to use as-is.

Last release seems to have been three years ago.

Possible Alternative(s)

The below list has not been vetted in any way and may or may not contain alternatives;

See advisory page for additional details.

Incorrect description of the crate name in the FAQ

The Readme states:

Q1: Why is it called "abscissa"?

A1: An abscissa represents the elevation of a point above the x-axis. In that regard, "Abscissa" can be thought of as a pun about getting off the ground, or elevating your project.

This is incorrect: the abscissa corresponds to the X coordinate in a Cartesian system, and represents the horizontal distance of a point to the origin, not the vertical one (or elevation as mentioned, which is represented by the ordinate).
https://en.wikipedia.org/wiki/Abscissa_and_ordinate

The name is a good one nonetheless, but for the sake of mathematical correctness and general credibility, this FAQ entry should probably be rephrased.

build error: 209 | extern crate alloc;

  • not able build
[me@centos8t01 abscissa]$ git remote -v
origin  https://github.com/iqlusioninc/abscissa/ (fetch)
origin  https://github.com/iqlusioninc/abscissa/ (push)
[me@centos8t01 abscissa]$ cargo build
   Compiling zeroize v1.1.0
   Compiling once_cell v1.2.0
   Compiling quick-error v1.2.2
   Compiling canonical-path v2.0.2
error[E0658]: use of unstable library feature 'alloc': this library is unlikely to be stabilized in its current form or name (see issue #27783)
   --> /home/me/.cargo/registry/src/github.com-1ecc6299db9ec823/zeroize-1.1.0/src/lib.rs:209:1
    |
209 | extern crate alloc;
    | ^^^^^^^^^^^^^^^^^^^

   Compiling proc-macro2 v1.0.6
   Compiling num-traits v0.2.10
error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
error: Could not compile `zeroize`.
warning: build failed, waiting for other jobs to finish...
error: build failed

[me@centos8t01 ldapcheck]$ cargo --version ;rustc --version
cargo 1.35.0
rustc 1.35.0
[me@centos8t01 ldapcheck]$ cat /etc/redhat-release
CentOS Linux release 8.0.1905 (Core)
[me@centos8t01 ldapcheck]$



Need help writing tests

I have lots of logging in my application code which is helpful when doing cargo run, but cargo test doesn't have any initialization for config or logging.

Right now, I use println! in my test code, but I'd like to see some of the debug logs from the application code, too.

I also want to test some functions that have calls to app_config(), but right now they fail with an error about config not being initialized.

How should I setup config and logging without running boot in my tests?

HCL as an alternative to TOML?

I recently switched from TOML to HCL (HashiCorp) as a main configuration language as I find it more expressive (like for arrays and hashes). Would you be interested in me working on it (as a feature or alongside with TOML) or even interested in supporting it yourself?).

Thanks.

Can you provide more example

Hi, can you provide more examples for using abscissa?

For example, provide a minimum runnable prototype for application::boot, thank you! :)

Component registry never registers components - component registry doesn't work.

pub fn register<I>(&mut self, components: I) -> Result<(), FrameworkError>

It seems that the register function goes through all the motions of registering a new set of components, but never actually mutates the registry to insert them.
Is this a known issue, not implemented yet, or am I using the registry wrong?

This breaks the ability to use registered components in applications.
In generated application.rs for example:

/// Register all components used by this application.
///
/// If you would like to add additional components to your application
/// beyond the default ones provided by the framework, this is the place
/// to do so.
fn register_components(&mut self, command: &Self::Cmd) -> Result<(), FrameworkError> {
    let mut components = self.framework_components(command)?;
    // expect the application's components register to contain:
    // abscissa_core::terminal
    // abscissa_core::logging
    self.state.components.register(components)?;

    // No components are found :(
    for component in self.state.components.iter() {
        println!("registered component: {}", component.name())
    }
    Ok(())
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.