88 lines
4.0 KiB
Markdown
88 lines
4.0 KiB
Markdown
Contents
|
|
========
|
|
* [The **Cmd** trait](#the-cmd-trait)
|
|
* [A simple example applet](#a-simple-example-applet)
|
|
* [Incorporating a new applet](#incorporating-a-new-applet)
|
|
* [Dependencies](#dependencies)
|
|
* [Coding Guidelines](#coding_guidelines)
|
|
|
|
## The Cmd trait
|
|
The `Cmd` trait is defined in `src/cmd/mod.rs`. All applets should live in their
|
|
own submodule under `crate::cmd` and include a struct with the name of the command,
|
|
in snake case. This struct must implement `Cmd`. It is recommended that this struct
|
|
have at least the fields `name: &'static str` and `path: crate::Path`. The
|
|
trait methods `name` and `path` can then just return the corresponding fields.
|
|
For simplicity's sake, `run` will always return `Box<dyn Error>` on failure and
|
|
bubble the error up to the caller, where the error will be presented to the user.
|
|
|
|
The applet module should further implement `Default` for the struct which implements
|
|
the `Cmd` trait.
|
|
|
|
## A Simple Example Applet
|
|
```Rust
|
|
// src/cmd/myapplet/mod.rs
|
|
use clap::Command;
|
|
use super::Cmd;
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct MyApplet;
|
|
|
|
impl Cmd for MyApplet {
|
|
fn cli(&self) -> clap::Command {
|
|
Command::new(self.name)
|
|
.version(env!("CARGO_PKG_VERSION"))
|
|
.author("Zaphod Beeblebrox")
|
|
.about("Does sketchy things")
|
|
}
|
|
|
|
fn run(&self, _matches: Option<&clap::ArgMatches>) -> Result<(), Box<dyn std::error::Error>> {
|
|
println!("If there's anything more important than my ego around, I want it caught and shot now.");
|
|
Ok(())
|
|
}
|
|
|
|
fn path(&self) -> Option<crate::Path> {
|
|
Some(crate::Path::UsrBin)
|
|
}
|
|
}
|
|
```
|
|
## Incorporating a new applet
|
|
Each command module should be public in `src/cmd/mod.rs` and both the struct which
|
|
implements `Cmd` should be exported as public in that file. The function `cmd::get`
|
|
has a match statement, to which should be added a line which matches the name of
|
|
the new command and returns an `Option<Box<dyn Cmd>>` for your type. The static
|
|
`cmd::COMMANDS` should have your new command's name added and the array's number
|
|
incremented by 1.
|
|
## Dependencies
|
|
In order to accept a new dependency, the crate should provide utility that can be
|
|
used in multiple applets. It should introduce as few transitive dependencies as
|
|
possible, and the functionality provided should be something that cannot be easily
|
|
replicated cleanly. Preference is given to crates that are standalone and do not
|
|
significantly increase binary size. The prospective crate must be well maintained
|
|
and as free of security issues as can be realistically achieved. All that said,
|
|
it is sometimes better to take on a dependency than to implement the desired
|
|
functionality from scratch. This is absolutely a judgement call.
|
|
## Coding Guidelines
|
|
Before accepting changes, the code should be formatted using `cargo fmt` and all
|
|
lints discovered via `cargo clippy` should be addressed. The default lint level
|
|
is pedantic. If there is good reason, an individual lint may be allowed for a
|
|
specific block of code with `#[allow(clippy::<lint>)]`.
|
|
|
|
New applets must be Posix compliant. They can and should implement GNU or BSD extensions
|
|
to Posix if the extended behavior is in widespread enough to cause widespread shell
|
|
script failures if left unimplemented. Further extension is allowed under the
|
|
following conditions.
|
|
- the extended behavior does not conflict with Posix
|
|
- the extended behavior increases utility
|
|
- the extended behavior is in keeping with behavior of other applets and increases
|
|
consistency of behavior for the overall userland
|
|
|
|
### Unsafe
|
|
As a functional Unix userland exposes much low level functionality to the user, it
|
|
is unavoidable that there will be cases of `unsafe` in this codebase. Please limit
|
|
use of `unsafe` to those places where the desired functionality is not exposed via
|
|
Rust's std library. Blocks of `unsafe` should only encapsulate the desired calls,
|
|
and not contain logic etc.
|
|
|
|
Keep memory usage small be preferring pass by reference, use of techniques such as
|
|
bitflags and avoiding unneeded allocations.
|