Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V0.10.1 #63

Merged
merged 26 commits into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a3ba567
Fixed Enum Handling f/ Values
00JCIV00 May 21, 2024
b7cf094
Updated to v0.13
00JCIV00 Jun 15, 2024
241fe1d
Updated Build configurations
00JCIV00 Jul 1, 2024
cca9e64
Standardized "Type" verbiage
00JCIV00 Jul 1, 2024
ae066a0
Added reset() method for Commands
00JCIV00 Jul 1, 2024
2951636
Exposed indent_fmt for Values
00JCIV00 Jul 1, 2024
cb63b1a
Exposed indent_fmt for Values
00JCIV00 Jul 1, 2024
976c07b
Removed the preferred_release_option from build.zig
00JCIV00 Jul 2, 2024
2f43111
Added the "cova" Log Scope
00JCIV00 Jul 2, 2024
7ccfb9e
Changed default Usage Format f/ Options
00JCIV00 Jul 15, 2024
3aa4b03
Updated Basic App Example and Tests
00JCIV00 Jul 18, 2024
86dd10d
Fixed Boolean parsing issue w/ Value Aliases
00JCIV00 Jul 23, 2024
a1ffd74
Enabled Analysis f/ Multi Values & Option
00JCIV00 Jul 24, 2024
2055b94
Updated README.md
00JCIV00 Jul 29, 2024
70dcc77
Created the UsageHelpConfig for Usage/Help generation during initiali…
00JCIV00 Aug 25, 2024
e45e297
Fixed Doc Generation w/ custom Usage/Help Functions (BREAKING)
00JCIV00 Aug 25, 2024
9b0e6b0
Fixed Child Type Aliasing in Usage/Help Messages & Meta Doc Gen
00JCIV00 Aug 26, 2024
b6dc0cc
Implemented Help Categories & Fixed Usage/Help f/ Options
00JCIV00 Aug 28, 2024
c9fe007
Fixed minor inconsistencies in Command.zig
00JCIV00 Aug 29, 2024
8fa0d06
Updated build process for examples
00JCIV00 Aug 29, 2024
5a0783e
Created an errorable Meta Doc Gen Step function
00JCIV00 Aug 30, 2024
00ae25c
Updated main.yaml to use Zig v0.13
00JCIV00 Aug 30, 2024
d5ed6fe
Updated main.yaml to use Zig v0.13.0
00JCIV00 Aug 30, 2024
6f0372d
Merge pull request #61 from 00JCIV00/00JCIV00-patch-1
00JCIV00 Aug 30, 2024
a871c56
Added the 'excluded_short_opts' field to the FromConfig for Commands
00JCIV00 Sep 17, 2024
efc9070
Updated README.md f/ v0.10.1 Release
00JCIV00 Sep 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
uses: actions/configure-pages@v2
- uses: goto-bus-stop/setup-zig@v2
with:
version: master
version: 0.13.0
- run: zig build docs
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
Expand Down
77 changes: 68 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,77 @@
# Commands **⋅** Options **⋅** Values **⋅** Arguments
A simple yet robust cross-platform command line argument parsing library for Zig.

[![Static Badge](https://img.shields.io/badge/v0.12(nightly)-orange?logo=Zig&logoColor=Orange&label=Zig&labelColor=Orange)](https://ziglang.org/download/)
[![Static Badge](https://img.shields.io/badge/v0.10.0b-blue?logo=GitHub&label=Release)](https://github.com/00JCIV00/cova/releases/tag/v0.10.0-beta)
[![GitHub commit activity](https://img.shields.io/github/commits-since/00JCIV00/cova/latest/v0.10.0?include_prereleases&logo=Github&label=Commits%20(v0.10.0b))](https://github.com/00JCIV00/cova/commits/v0.10.0/)
[![Static Badge](https://img.shields.io/badge/v0.13(stable)-orange?logo=Zig&logoColor=Orange&label=Zig&labelColor=Orange)](https://ziglang.org/download/)
[![Static Badge](https://img.shields.io/badge/v0.10.1b-blue?logo=GitHub&label=Release)](https://github.com/00JCIV00/cova/releases/tag/v0.10.1-beta)
[![GitHub commit activity](https://img.shields.io/github/commits-since/00JCIV00/cova/latest/v0.10.1?include_prereleases&logo=Github&label=Commits%20(v0.10.1b))](https://github.com/00JCIV00/cova/commits/v0.10.1/)
[![Static Badge](https://img.shields.io/badge/MIT-silver?label=License)](https://github.com/00JCIV00/cova/blob/main/LICENSE)

___

## Overview
`command --option value`

Cova is based on the idea that Arguments will fall into one of three types: Commands, Options, or Values. These Types are assembled into a single Command struct which is then used to parse argument tokens. Whether you're looking for simple argument parsing or want to create something as complex as the [`ip`](https://www.man7.org/linux/man-pages/man8/ip.8.html) or [`git`](https://www.man7.org/linux/man-pages/man1/git.1.html) commands, Cova makes it easy.

## Get Started Quickly!
- [Quick Start Guide](https://github.com/00JCIV00/cova/wiki/Getting-Started)
- [Full Wiki Guide](https://github.com/00JCIV00/cova/wiki/)
- [API Docs](https://00jciv00.github.io/cova/)

### Quick Example
[Log Enum Example](https://github.com/00JCIV00/cova/blob/main/examples/log-enum.zig)
```shell
logger --log-level info
```
#### Set up a Command
```zig
// ...
pub const CommandT = cova.Command.Custom(.{...});
pub const setup_cmd = CommandT{
.name = "log_enum",
.description = "A small demo of using the Log Level Enum as an Option.",
.opts = &.{
.{
.name = "log_level",
.description = "An Option using the `log.Level` Enum.",
.long_name = "log-level",
.mandatory = true,
.val = CommandT.ValueT.ofType(log.Level, .{
.name = "log_level_val",
.description = " This Value will handle the Enum."
})
}
},
};
```
#### Parse the Command
```zig
pub fn main() !void {
// ...
var main_cmd = try setup_cmd.init(alloc, .{});
defer main_cmd.deinit();
var args_iter = try cova.ArgIteratorGeneric.init(alloc);
defer args_iter.deinit();

cova.parseArgs(&args_iter, CommandT, main_cmd, stdout, .{}) catch |err| switch (err) {
error.UsageHelpCalled => {},
else => return err,
};
// ...
```
#### Use the Data
```zig
// ...
const main_opts = try main_cmd.getOpts(.{});
const log_lvl_opt = main_opts.get("log_level").?;
const log_lvl = log_lvl_opt.val.getAs(log.Level) catch {
log.err("The provided Log Level was invalid.", .{});
return;
};
log.info("Provided Log Level: {s}", .{ @tagName(log_lvl) });
}
```

## Features
- **[Comptime Setup](#comptime-setup). [Runtime Use](#runtime-use).**
- Cova is designed to have Argument Types set up at ***compile time*** so they can be validated during each compilation, thus providing you with immediate feedback.
Expand All @@ -27,11 +83,13 @@ Cova is based on the idea that Arguments will fall into one of three types: Comm
- All argument tokens are parsed to Argument Types: Commands, Options, or Values.
- Options = _Flags_ and Values = _Positional Arguments_
- These Argument Types can be *created from* or *converted to* your Structs, Unions, and Functions along with their corresponding Fields and Parameters.
- Default Arguments such as `usage` and `help` can be automatically added to all Commands easily.
- This design allows for **infinitely nestable** Commands, Options, and Values in a way that's simple to parse, analyze, and use in your projects.
- **Multiplatform.** Tested across common architectures of Linux, Mac, and Windows.
- **Granular, Robust Customization:**
- [POSIX Compliant](https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html) by default, with plenty of ways to configure to whatever standard you'd like.
- Ex: `command --option option_string "standalone value" subcmd -i 42 --bool`
- [POSIX Compliant](https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html) by default, with plenty of ways to configure to **whatever standard you'd like**.
- Posix: `command --option option_string "standalone value" subcmd -i 42 --bool`
- Windows: `Your-Command -StringOption "value" -FileOption .\user\file\path`
- Cova offers deep customization through the Argument Types and several Config Structs. These customizations all provide simple and predictable defaults, allowing you to only configure what you need.
- [***And much more!***](https://github.com/00JCIV00/cova/wiki/Feature-List)

Expand Down Expand Up @@ -109,7 +167,7 @@ pub const setup_cmd: CommandT = .{
</details>

### Runtime Use
Once Cova has parsed input from your end users it puts that data into the Command you set up.
Once Cova has parsed input from your end users, it puts that data into the Command you set up.
You can call various methods on the Command to use that data however you need.

<details>
Expand Down Expand Up @@ -172,6 +230,7 @@ pub fn main() !void {
</details>

### More Examples
- [log-enum](./examples/log-enum.zig): The simple example from the top of the README.
- [basic-app](./examples/basic_app.zig): Where the above examples come from.
- [covademo](./examples/covademo.zig): This is the testbed for Cova, but its a good demo of virtually every feature in the library.

Expand Down Expand Up @@ -203,8 +262,8 @@ pub fn build(b: *std.Build) void {

const cova_gen = @import("cova").addCovaDocGenStep(b, cova_dep, exe, .{
.kinds = &.{ .all },
.version = "0.10.0",
.ver_date = "06 APR 2024",
.version = "0.10.1",
.ver_date = "12 SEP 2024",
.author = "00JCIV00",
.copyright = "MIT License",
});
Expand All @@ -218,8 +277,8 @@ pub fn build(b: *std.Build) void {
![cova_demo](./docs/cova_demo.gif)

## Alternatives
- [flags](https://github.com/n0s4/flags)
- [yazap](https://github.com/PrajwalCH/yazap)
- [zig-args](https://github.com/masterQ32/zig-args)
- [zig-clap](https://github.com/Hejsil/zig-clap)
- [zig-cli](https://github.com/sam701/zig-cli)
- [zig-parse-args](https://github.com/winksaville/zig-parse-args)
151 changes: 77 additions & 74 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -52,85 +52,61 @@ pub fn build(b: *std.Build) void {
//==========================================
// Examples
//==========================================
// - Cova Demo Exe
const cova_demo = b.addExecutable(.{
.name = bin_name orelse "covademo",
.root_source_file = b.path("examples/covademo.zig"),
.target = target,
.optimize = optimize,
});
cova_demo.root_module.addImport("cova", cova_mod);
const build_cova_demo = b.addInstallArtifact(cova_demo, .{});
const build_cova_demo_step = b.step("cova-demo", "Build the 'covademo' example (default: Debug)");
build_cova_demo_step.dependOn(&build_cova_demo.step);
// - Cova Demo Meta Docs
const cova_demo_gen = createDocGenStep(
b,
cova_mod,
b.path("src/generator.zig"),
cova_demo,
.{
.kinds = &.{ .all },
.version = "0.10.0",
.ver_date = "16 MAY 2024",
.author = "00JCIV00",
.copyright = "MIT License",
.help_docs_config = .{
.local_filepath = "examples/cova_demo_meta/help_docs/",
},
.tab_complete_config = .{
.local_filepath = "examples/cova_demo_meta/tab_completions/",
.include_opts = true,
},
.arg_template_config = .{
.local_filepath = "examples/cova_demo_meta/arg_templates",
},
},
);
const cova_demo_gen_step = b.step("cova-demo-gen", "Generate Meta Docs for the 'covademo'");
cova_demo_gen_step.dependOn(&cova_demo_gen.step);

// - Basic App Exe
const basic_app = b.addExecutable(.{
.name = bin_name orelse "basic-app",
.root_source_file = b.path("examples/basic_app.zig"),
.target = target,
.optimize = optimize,
});
basic_app.root_module.addImport("cova", cova_mod);
const build_basic_app = b.addInstallArtifact(basic_app, .{});
const build_basic_app_step = b.step("basic-app", "Build the 'basic-app' example (default: Debug)");
build_basic_app_step.dependOn(&build_basic_app.step);
// - Basic App Meta Docs
const basic_app_gen = createDocGenStep(
b,
cova_mod,
b.path("src/generator.zig"),
basic_app,
.{
.kinds = &.{ .all },
.version = "0.10.0",
.ver_date = "06 APR 2024",
.author = "00JCIV00",
.copyright = "MIT License",
.help_docs_config = .{
.local_filepath = "examples/basic_app_meta/help_docs/",
},
.tab_complete_config = .{
.local_filepath = "examples/basic_app_meta/tab_completions/",
.include_opts = true,
const examples = &.{ "cova-demo", "basic-app", "log-enum" };
var ex_arena = std.heap.ArenaAllocator.init(b.allocator);
defer ex_arena.deinit();
const ex_alloc = ex_arena.allocator();
inline for (examples) |example| {
var ex_scored_buf = ex_alloc.dupe(u8, example) catch @panic("OOM");
const ex_scored = std.mem.replaceOwned(u8, ex_alloc, ex_scored_buf[0..], "-", "_") catch @panic("OOM");
const ex_name = exName: {
if (std.mem.eql(u8, example, "cova-demo")) break :exName "covademo";
break :exName example;
};
// - Exe
const ex_exe = b.addExecutable(.{
.name = bin_name orelse ex_name,
.root_source_file = b.path(std.fmt.allocPrint(ex_alloc, "examples/{s}.zig", .{ ex_name }) catch @panic("OOM")),
.target = target,
.optimize = optimize,
});
ex_exe.root_module.addImport("cova", cova_mod);
const build_ex_demo = b.addInstallArtifact(ex_exe, .{});
const build_ex_demo_step = b.step(example, "Build the '" ++ example ++ "' example (default: Debug)");
build_ex_demo_step.dependOn(&build_ex_demo.step);
// - Demo Meta Docs
const ex_demo_gen = createDocGenStep(
b,
cova_mod,
b.path("src/generator.zig"),
ex_exe,
.{
.kinds = &.{ .all },
.version = "0.10.1",
.ver_date = "27 AUG 2024",
.author = "00JCIV00",
.copyright = "MIT License",
.help_docs_config = .{
.local_filepath = std.fmt.allocPrint(ex_alloc, "examples/{s}_meta/help_docs/", .{ ex_scored }) catch @panic("OOM"),
},
.tab_complete_config = .{
.local_filepath = std.fmt.allocPrint(ex_alloc,"examples/{s}_meta/tab_completions/", .{ ex_scored }) catch @panic("OOM"),
.include_opts = true,
},
.arg_template_config = .{
.local_filepath = std.fmt.allocPrint(ex_alloc, "examples/{s}_meta/arg_templates/", .{ ex_scored }) catch @panic("OOM"),
},
},
.arg_template_config = .{
.local_filepath = "examples/basic_app_meta/arg_templates",
},
},
);
const basic_app_gen_step = b.step("basic-app-gen", "Generate Meta Docs for the 'basic-app'");
basic_app_gen_step.dependOn(&basic_app_gen.step);
);
const ex_demo_gen_step = b.step(example ++ "-gen", "Generate Meta Docs for the '" ++ example ++ "'");
ex_demo_gen_step.dependOn(&ex_demo_gen.step);
}
}


/// Add Cova's Meta Doc Generation Step to a project's `build.zig`.
/// Note, the `program_step` must have the same Target as the host machine.
/// Prefer to use `addCovaDocGenStepOrError` if the step will be used in cross-compilation CI pipeline.
pub fn addCovaDocGenStep(
b: *std.Build,
/// The Cova Dependency of the project's `build.zig`.
Expand All @@ -151,6 +127,33 @@ pub fn addCovaDocGenStep(
);
}

/// Add Cova's Meta Doc Generation Step to a project's `build.zig` or return an error if there's a Target mismatch.
/// A Target mismatch happens if the provided `program_step` doesn't have the same Target as the host machine.
/// This function is useful for cross-compilation in CI pipelines to ensure Target mismatches are handled properly.
pub fn addCovaDocGenStepOrError(
b: *std.Build,
/// The Cova Dependency of the project's `build.zig`.
cova_dep: *std.Build.Dependency,
/// The Program Compile Step where the Command Type and Setup Command can be found.
/// This is typically created with `const exe = b.addExecutable(.{...});` or similar
program_step: *std.Build.Step.Compile,
/// The Config for Meta Doc Generation.
doc_gen_config: generate.MetaDocConfig,
) !*std.Build.Step.Run {
const host_triplets = b.graph.host.result.zigTriple(b.allocator) catch @panic("OOM");
defer b.allocator.free(host_triplets);
const program_triplets = program_step.rootModuleTarget().zigTriple(b.allocator) catch @panic("OOM");
defer b.allocator.free(program_triplets);
if (!std.mem.eql(u8, host_triplets, program_triplets)) return error.TargetMismatch;
return createDocGenStep(
b,
cova_dep.module("cova"),
cova_dep.path("src/generator.zig"),
program_step,
doc_gen_config,
);
}

/// Create the Meta Doc Generation Step.
fn createDocGenStep(
b: *std.Build,
Expand Down
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"build.zig.zon",
"src",
},
.version = "0.10.0",
.version = "0.10.1",
.dependencies = .{},
}
6 changes: 3 additions & 3 deletions examples/basic_app.zig
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ pub fn open(filename: []const u8) !std.fs.File {
break :filenameChecked (try std.fmt.bufPrint(fnc_buf[0..], "{s}.csv", .{ filename }))[0..(filename.len + 4)];
};
const open_file = try std.fs.cwd().createFile(filename_checked, .{ .read = true, .truncate = false });
try std.fs.cwd().writeFile(".ba_persist", filename_checked);
try std.fs.cwd().writeFile(.{ .sub_path = ".ba_persist", .data = filename_checked });
return open_file;
}

Expand Down Expand Up @@ -294,12 +294,12 @@ pub fn main() !void {
// The `cova.utils.displayCmdInfo()` function is useful for seeing the results of a parsed
// Command. This is done recursively for any sub Argument Types within the Command and can be
// used to debug said Command.
if (builtin.mode == .Debug) try cova.utils.displayCmdInfo(CommandT, main_cmd, alloc, &stdout);
if (builtin.mode == .Debug) try cova.utils.displayCmdInfo(CommandT, main_cmd, alloc, &stdout, true);

// - App Vars
var user_filename_buf: [100]u8 = .{ 0 } ** 100;
_ = std.fs.cwd().readFile(".ba_persist", user_filename_buf[0..]) catch {
try std.fs.cwd().writeFile(".ba_persist", "users.csv");
try std.fs.cwd().writeFile(.{ .sub_path = ".ba_persist", .data = "users.csv" });
for (user_filename_buf[0..9], "users.csv") |*u, c| u.* = c;
};
const ufb_end = std.mem.indexOfScalar(u8, user_filename_buf[0..], 0) orelse 9;
Expand Down
Loading
Loading