diff options
author | Andrew Walbran <qwandor@google.com> | 2022-01-21 12:58:28 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-01-21 12:58:28 +0000 |
commit | d68b68e34fd1c3275fa57850a7888aaaf8fe3e16 (patch) | |
tree | fc8f622bc356dba116f5665acf523c2b5e20f303 | |
parent | 5dcbbb6c33ede2f6ca1d29ac6e75644c28d075d2 (diff) | |
parent | 6c7113ea11aa28aeedefb7fb064abc2dc03cc9f3 (diff) | |
download | argh_shared-d68b68e34fd1c3275fa57850a7888aaaf8fe3e16.tar.gz |
Initial import. am: 6c7113ea11
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/argh_shared/+/1955042
Change-Id: I2fd2348ace88e46a4c95369c5d214d43cad6279f
-rw-r--r-- | .cargo_vcs_info.json | 6 | ||||
-rw-r--r-- | Android.bp | 18 | ||||
-rw-r--r-- | Cargo.toml | 20 | ||||
-rw-r--r-- | Cargo.toml.orig | 9 | ||||
-rw-r--r-- | LICENSE | 27 | ||||
-rw-r--r-- | METADATA | 19 | ||||
-rw-r--r-- | MODULE_LICENSE_BSD_LIKE | 0 | ||||
-rw-r--r-- | OWNERS | 1 | ||||
-rw-r--r-- | README.md | 177 | ||||
-rw-r--r-- | cargo2android.json | 9 | ||||
-rw-r--r-- | src/lib.rs | 80 |
11 files changed, 366 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json new file mode 100644 index 0000000..116e262 --- /dev/null +++ b/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "f1f85d2d89cbe09314dc1b59e581b8a43531cf3e" + }, + "path_in_vcs": "argh_shared" +}
\ No newline at end of file diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..3d05aa8 --- /dev/null +++ b/Android.bp @@ -0,0 +1,18 @@ +// This file is generated by cargo2android.py --config cargo2android.json. +// Do not modify this file as changes will be overridden on upgrade. + + + +rust_library { + name: "libargh_shared", + host_supported: true, + crate_name: "argh_shared", + cargo_env_compat: true, + cargo_pkg_version: "0.1.7", + srcs: ["src/lib.rs"], + edition: "2018", + apex_available: [ + "//apex_available:platform", + "com.android.virt", + ], +} diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d54a07f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "argh_shared" +version = "0.1.7" +authors = ["Taylor Cramer <cramertj@google.com>", "Benjamin Brittain <bwb@google.com>", "Erick Tryzelaar <etryzelaar@google.com>"] +description = "Derive-based argument parsing optimized for code size" +readme = "README.md" +license = "BSD-3-Clause" +repository = "https://github.com/google/argh" diff --git a/Cargo.toml.orig b/Cargo.toml.orig new file mode 100644 index 0000000..1f7e694 --- /dev/null +++ b/Cargo.toml.orig @@ -0,0 +1,9 @@ +[package] +name = "argh_shared" +version = "0.1.7" +authors = ["Taylor Cramer <cramertj@google.com>", "Benjamin Brittain <bwb@google.com>", "Erick Tryzelaar <etryzelaar@google.com>"] +edition = "2018" +license = "BSD-3-Clause" +description = "Derive-based argument parsing optimized for code size" +repository = "https://github.com/google/argh" +readme = "README.md" @@ -0,0 +1,27 @@ +Copyright 2019 The Fuchsia Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/METADATA b/METADATA new file mode 100644 index 0000000..e3c64c5 --- /dev/null +++ b/METADATA @@ -0,0 +1,19 @@ +name: "argh_shared" +description: "Derive-based argument parsing optimized for code size" +third_party { + url { + type: HOMEPAGE + value: "https://crates.io/crates/argh_shared" + } + url { + type: ARCHIVE + value: "https://static.crates.io/crates/argh_shared/argh_shared-0.1.7.crate" + } + version: "0.1.7" + license_type: NOTICE + last_upgrade_date { + year: 2022 + month: 1 + day: 13 + } +} diff --git a/MODULE_LICENSE_BSD_LIKE b/MODULE_LICENSE_BSD_LIKE new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_BSD_LIKE @@ -0,0 +1 @@ +include platform/prebuilts/rust:master:/OWNERS diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e949e4 --- /dev/null +++ b/README.md @@ -0,0 +1,177 @@ +# Argh +**Argh is an opinionated Derive-based argument parser optimized for code size** + +[![crates.io](https://img.shields.io/crates/v/argh.svg)](https://crates.io/crates/argh) +[![license](https://img.shields.io/badge/license-BSD3.0-blue.svg)](https://github.com/google/argh/LICENSE) +[![docs.rs](https://docs.rs/argh/badge.svg)](https://docs.rs/crate/argh/) +![Argh](https://github.com/google/argh/workflows/Argh/badge.svg) + +Derive-based argument parsing optimized for code size and conformance +to the Fuchsia commandline tools specification + +The public API of this library consists primarily of the `FromArgs` +derive and the `from_env` function, which can be used to produce +a top-level `FromArgs` type from the current program's commandline +arguments. + +## Basic Example + +```rust,no_run +use argh::FromArgs; + +#[derive(FromArgs)] +/// Reach new heights. +struct GoUp { + /// whether or not to jump + #[argh(switch, short = 'j')] + jump: bool, + + /// how high to go + #[argh(option)] + height: usize, + + /// an optional nickname for the pilot + #[argh(option)] + pilot_nickname: Option<String>, +} + +fn main() { + let up: GoUp = argh::from_env(); +} +``` + +`./some_bin --help` will then output the following: + +``` +Usage: cmdname [-j] --height <height> [--pilot-nickname <pilot-nickname>] + +Reach new heights. + +Options: + -j, --jump whether or not to jump + --height how high to go + --pilot-nickname an optional nickname for the pilot + --help display usage information +``` + +The resulting program can then be used in any of these ways: +- `./some_bin --height 5` +- `./some_bin -j --height 5` +- `./some_bin --jump --height 5 --pilot-nickname Wes` + +Switches, like `jump`, are optional and will be set to true if provided. + +Options, like `height` and `pilot_nickname`, can be either required, +optional, or repeating, depending on whether they are contained in an +`Option` or a `Vec`. Default values can be provided using the +`#[argh(default = "<your_code_here>")]` attribute, and in this case an +option is treated as optional. + +```rust +use argh::FromArgs; + +fn default_height() -> usize { + 5 +} + +#[derive(FromArgs)] +/// Reach new heights. +struct GoUp { + /// an optional nickname for the pilot + #[argh(option)] + pilot_nickname: Option<String>, + + /// an optional height + #[argh(option, default = "default_height()")] + height: usize, + + /// an optional direction which is "up" by default + #[argh(option, default = "String::from(\"only up\")")] + direction: String, +} + +fn main() { + let up: GoUp = argh::from_env(); +} +``` + +Custom option types can be deserialized so long as they implement the +`FromArgValue` trait (automatically implemented for all `FromStr` types). +If more customized parsing is required, you can supply a custom +`fn(&str) -> Result<T, String>` using the `from_str_fn` attribute: + +```rust +use argh::FromArgs; + +#[derive(FromArgs)] +/// Goofy thing. +struct FiveStruct { + /// always five + #[argh(option, from_str_fn(always_five))] + five: usize, +} + +fn always_five(_value: &str) -> Result<usize, String> { + Ok(5) +} +``` + +Positional arguments can be declared using `#[argh(positional)]`. +These arguments will be parsed in order of their declaration in +the structure: + +```rust +use argh::FromArgs; + +#[derive(FromArgs, PartialEq, Debug)] +/// A command with positional arguments. +struct WithPositional { + #[argh(positional)] + first: String, +} +``` + +The last positional argument may include a default, or be wrapped in +`Option` or `Vec` to indicate an optional or repeating positional argument. + +Subcommands are also supported. To use a subcommand, declare a separate +`FromArgs` type for each subcommand as well as an enum that cases +over each command: + +```rust +use argh::FromArgs; + +#[derive(FromArgs, PartialEq, Debug)] +/// Top-level command. +struct TopLevel { + #[argh(subcommand)] + nested: MySubCommandEnum, +} + +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand)] +enum MySubCommandEnum { + One(SubCommandOne), + Two(SubCommandTwo), +} + +#[derive(FromArgs, PartialEq, Debug)] +/// First subcommand. +#[argh(subcommand, name = "one")] +struct SubCommandOne { + #[argh(option)] + /// how many x + x: usize, +} + +#[derive(FromArgs, PartialEq, Debug)] +/// Second subcommand. +#[argh(subcommand, name = "two")] +struct SubCommandTwo { + #[argh(switch)] + /// whether to fooey + fooey: bool, +} +``` + +NOTE: This is not an officially supported Google product. diff --git a/cargo2android.json b/cargo2android.json new file mode 100644 index 0000000..6e516e0 --- /dev/null +++ b/cargo2android.json @@ -0,0 +1,9 @@ +{ + "apex-available": [ + "//apex_available:platform", + "com.android.virt" + ], + "device": true, + "run": true, + "tests": true +}
\ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..c6e7a5c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,80 @@ +// Copyright (c) 2020 Google LLC All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//! Shared functionality between argh_derive and the argh runtime. +//! +//! This library is intended only for internal use by these two crates. + +/// Information about a particular command used for output. +pub struct CommandInfo<'a> { + /// The name of the command. + pub name: &'a str, + /// A short description of the command's functionality. + pub description: &'a str, +} + +pub const INDENT: &str = " "; +const DESCRIPTION_INDENT: usize = 20; +const WRAP_WIDTH: usize = 80; + +/// Write command names and descriptions to an output string. +pub fn write_description(out: &mut String, cmd: &CommandInfo<'_>) { + let mut current_line = INDENT.to_string(); + current_line.push_str(cmd.name); + + if cmd.description.is_empty() { + new_line(&mut current_line, out); + return; + } + + if !indent_description(&mut current_line) { + // Start the description on a new line if the flag names already + // add up to more than DESCRIPTION_INDENT. + new_line(&mut current_line, out); + } + + let mut words = cmd.description.split(' ').peekable(); + while let Some(first_word) = words.next() { + indent_description(&mut current_line); + current_line.push_str(first_word); + + 'inner: while let Some(&word) = words.peek() { + if (char_len(¤t_line) + char_len(word) + 1) > WRAP_WIDTH { + new_line(&mut current_line, out); + break 'inner; + } else { + // advance the iterator + let _ = words.next(); + current_line.push(' '); + current_line.push_str(word); + } + } + } + new_line(&mut current_line, out); +} + +// Indent the current line in to DESCRIPTION_INDENT chars. +// Returns a boolean indicating whether or not spacing was added. +fn indent_description(line: &mut String) -> bool { + let cur_len = char_len(line); + if cur_len < DESCRIPTION_INDENT { + let num_spaces = DESCRIPTION_INDENT - cur_len; + line.extend(std::iter::repeat(' ').take(num_spaces)); + true + } else { + false + } +} + +fn char_len(s: &str) -> usize { + s.chars().count() +} + +// Append a newline and the current line to the output, +// clearing the current line. +fn new_line(current_line: &mut String, out: &mut String) { + out.push('\n'); + out.push_str(current_line); + current_line.truncate(0); +} |