iqlusioninc / abscissa Goto Github PK
View Code? Open in Web Editor NEWApplication microframework with command-line option parsing, configuration, error handling, logging, and shell interactions
License: Apache License 2.0
Application microframework with command-line option parsing, configuration, error handling, logging, and shell interactions
License: Apache License 2.0
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.
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)
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..
Which would be the preferred daemonizing crates ?
ceviche-rs I'm leaning towards this one...
daemon-rs Old but cross platform
Encrypting values in the config(toml)
I'm looking at CryptoStream
What is the preferred approach to embedding keys in the executable ?
All (constructive :) ) suggestions are welcome
As a followup to "Damonizing and encrypting with Abscissa"..
Since I will be running as a daemon, I need to change some logging options:
Thanks
JR
Presently Abscissa uses the failure
as its error handling abstraction, and uses the following features:
failure_derive
proc macro "DSL" for describing errorscause
support for capturing error causes (and potentially downcasting them)backtrace
supportIn 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
.
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.
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..
//
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
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
Hi, can you provide more examples for using abscissa?
For example, provide a minimum runnable prototype for application::boot, thank you! :)
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
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?
abscissa/core/src/component/registry.rs
Line 35 in 710e106
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(())
}
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...
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.
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:
One of the really killer features of tracing
is dynamic filter reloading -- how should this be exposed to Abscissa applications?
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).
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.
[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]$
Cargo.lock has zeroize 0.4.0, we need 0.4.2 to include support for musl-libc.
It looks like arc-swap
could address many of the global state-related problems with the current RwLock
used to lock application state:
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!
Abscissa core is setting the global subscriber for tracing as follows:
abscissa/core/src/trace/component.rs
Line 40 in cbecf5f
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
.
There were two primary reasons why Abscissa used gumdrop
over clap
v2 originally:
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).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
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):
Hi -- Not all of us use dark themes, and so I got to see this on startup of a base abscissa app:
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!
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...
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 ?
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.
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 |
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.
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.
No workarounds are known.
See advisory page for additional details.
Absissca makes synchronization primitives for asynchronous multithreaded application contexts available. https://github.com/iqlusioninc/abscissa/blob/develop/core/src/application/lock.rs#L10-L46
Should there abscissa tokio make the async flavor of those primitives available?
Add in the equivalent of application lock with https://docs.rs/tokio/0.2.21/tokio/sync/struct.RwLock.html
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
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.
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).
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
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.
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.
Lines 17 to 22 in 6630727
Currently, abscissa_core
delegates to gumdrop
's parsing logic with its default parsing style and error formatting:
Lines 32 to 39 in 67097d5
It would be nice if the following were possible:
ParsingStyle
to use StopAtFirstFree
using Options::parse_args
src/errors.rs
:abscissa/cli/template/src/error.rs.hbs
Lines 23 to 27 in 67097d5
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?
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:
abscissa/core/src/command/usage.rs
Line 350 in bee6525
abscissa/core/src/component/registry.rs
Line 76 in 6930a00
Is the &mut self
a bug (should be just &self
to allow non-mutable usage)?
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.
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.
If I understand correctly, the order of events from a component perspective are:
APP
crash with Message: Abscissa application state accessed before it has been initialized!
)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?
Previously the EntryPoint
command would handle the -c /path/to/config.toml
argument generated by CmdRunner::config
.
However, after the clap
v3 upgrade there is no longer a universal -c
option available, especially one that works with subcommands.
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.
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
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
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
Line 54 in 977b548
command: EntryPoint<FooCommand>
, and so when it's configured here Lines 101 to 103 in 977b548
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
?.
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.
I was following these instructions:
Line 47 in 28e400b
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.
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.
The below list has not been vetted in any way and may or may not contain alternatives;
See advisory page for additional details.
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.
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
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?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.