mirror of
https://github.com/sbrow/envr.git
synced 2026-06-27 18:48:33 -04:00
Compare commits
2 Commits
33b0063c67
...
d4653f3566
| Author | SHA1 | Date | |
|---|---|---|---|
| d4653f3566 | |||
| 8a503cedfb |
@@ -21,6 +21,11 @@ pub fn build(b: *std.Build) void {
|
||||
// target and optimize options) will be listed when running `zig build --help`
|
||||
// in this directory.
|
||||
|
||||
const comma = b.addModule("comma", .{
|
||||
.root_source_file = b.path("src/comma.zig"),
|
||||
.target = target,
|
||||
});
|
||||
|
||||
// This creates a module, which represents a collection of source files alongside
|
||||
// some compilation options, such as optimization mode and linked system libraries.
|
||||
// Zig modules are the preferred way of making Zig code available to consumers.
|
||||
@@ -39,6 +44,9 @@ pub fn build(b: *std.Build) void {
|
||||
// Later on we'll use this module as the root module of a test executable
|
||||
// which requires us to specify a target.
|
||||
.target = target,
|
||||
.imports = &.{
|
||||
.{ .name = "comma", .module = comma },
|
||||
},
|
||||
});
|
||||
|
||||
// Here we define an executable. An executable needs to have a root module
|
||||
@@ -78,6 +86,7 @@ pub fn build(b: *std.Build) void {
|
||||
// repeated because you are allowed to rename your imports, which
|
||||
// can be extremely useful in case of collisions (which can happen
|
||||
// importing modules from different packages).
|
||||
.{ .name = "comma", .module = comma },
|
||||
.{ .name = "envr", .module = mod },
|
||||
},
|
||||
}),
|
||||
|
||||
75
src/comma.zig
Normal file
75
src/comma.zig
Normal file
@@ -0,0 +1,75 @@
|
||||
//! By convention, root.zig is the root source file when making a package.
|
||||
const std = @import("std");
|
||||
// const Io = std.Io;
|
||||
|
||||
pub const Command = struct {
|
||||
name: []const u8,
|
||||
short: ?[]const u8 = null,
|
||||
long: ?[]const u8 = null,
|
||||
subcommands: []const Command = &[0]Command{},
|
||||
Type: type,
|
||||
|
||||
pub fn new(cmd: CommandOptions) Command {
|
||||
const subcommands: [cmd.subcommands.len]Command = blk: {
|
||||
var result: [cmd.subcommands.len]Command = undefined;
|
||||
inline for (cmd.subcommands, 0..) |sub, idx| {
|
||||
result[idx] = new(sub);
|
||||
}
|
||||
break :blk result;
|
||||
};
|
||||
|
||||
return .{
|
||||
.name = cmd.name,
|
||||
.short = cmd.short,
|
||||
.long = cmd.long,
|
||||
.subcommands = &subcommands,
|
||||
.Type = cmd.as_enum(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parse(comptime self: @This(), args: []const []const u8) ParseError!self.Type {
|
||||
if (args.len == 0) {
|
||||
return ParseError.InvalidType;
|
||||
}
|
||||
const target = args[0];
|
||||
|
||||
inline for (self.subcommands, 1..) |cmd, idx| {
|
||||
if (std.mem.eql(u8, target, cmd.name)) {
|
||||
return @enumFromInt(idx);
|
||||
}
|
||||
}
|
||||
|
||||
return @enumFromInt(0);
|
||||
}
|
||||
};
|
||||
|
||||
pub const ParseError = error{
|
||||
InvalidType,
|
||||
};
|
||||
|
||||
const CommandOptions = struct {
|
||||
name: []const u8,
|
||||
short: ?[]const u8 = null,
|
||||
long: ?[]const u8 = null,
|
||||
subcommands: []const CommandOptions = &[0]CommandOptions{},
|
||||
|
||||
fn as_enum(self: @This()) type {
|
||||
var field_names: [self.subcommands.len + 1][]const u8 = undefined;
|
||||
var field_values: [self.subcommands.len + 1]u32 = undefined;
|
||||
|
||||
field_names[0] = self.name;
|
||||
field_values[0] = 0;
|
||||
|
||||
inline for (self.subcommands, 1..) |cmd, idx| {
|
||||
field_names[idx] = cmd.name;
|
||||
field_values[idx] = idx;
|
||||
}
|
||||
|
||||
return @Enum(
|
||||
u32,
|
||||
.exhaustive,
|
||||
&field_names,
|
||||
&field_values,
|
||||
);
|
||||
}
|
||||
};
|
||||
99
src/main.zig
99
src/main.zig
@@ -3,6 +3,7 @@ const Io = std.Io;
|
||||
|
||||
const config = @import("config");
|
||||
|
||||
const comma = @import("comma");
|
||||
const envr = @import("envr");
|
||||
|
||||
const goBinary = "envr-go";
|
||||
@@ -13,16 +14,20 @@ pub fn main(init: std.process.Init) !void {
|
||||
|
||||
const args = try init.minimal.args.toSlice(arena);
|
||||
|
||||
run(init.io, args) catch return fallback_to_go(init.io, arena, args);
|
||||
try run(init.io, init.environ_map, args); //catch return fallback_to_go(init.io, arena, args);
|
||||
}
|
||||
|
||||
/// Attempt to run the requested command.
|
||||
fn run(io: Io, args: []const [:0]const u8) !void {
|
||||
fn run(
|
||||
io: Io,
|
||||
environ_map: *std.process.Environ.Map,
|
||||
args: []const [:0]const u8,
|
||||
) !void {
|
||||
const cmd = try envr.root.parse(args[1..]);
|
||||
switch (cmd) {
|
||||
.envr => {
|
||||
// TODO: Print help
|
||||
return envr.ParseError.InvalidType;
|
||||
return comma.ParseError.InvalidType;
|
||||
},
|
||||
.version => {
|
||||
var stdout_buffer: [1024]u8 = undefined;
|
||||
@@ -31,6 +36,17 @@ fn run(io: Io, args: []const [:0]const u8) !void {
|
||||
|
||||
return version(stdout_writer);
|
||||
},
|
||||
.deps => {
|
||||
var stdout_buffer: [1024]u8 = undefined;
|
||||
var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer);
|
||||
const stdout_writer = &stdout_file_writer.interface;
|
||||
|
||||
return deps(
|
||||
io,
|
||||
stdout_writer,
|
||||
environ_map.get("PATH").?,
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +55,83 @@ fn version(writer: *Io.Writer) !void {
|
||||
try writer.flush();
|
||||
}
|
||||
|
||||
// Display dependency statuses
|
||||
fn deps(
|
||||
io: Io,
|
||||
writer: *Io.Writer,
|
||||
path: []const u8,
|
||||
) !void {
|
||||
var feats: Features = .{};
|
||||
|
||||
// try writer.print("path: {s}\n\n", .{path});
|
||||
|
||||
var dirs = std.mem.splitScalar(u8, path, std.fs.path.delimiter);
|
||||
|
||||
// std.debug.print("feats: {b}\n", .{@as(u2, @bitCast(feats))});
|
||||
// std.debug.print("all feats: {b}\n", .{@as(u2, @bitCast(Features.all_features))});
|
||||
|
||||
loop: while (dirs.next()) |dir| {
|
||||
// try writer.print("dir: {s}\n", .{dir});
|
||||
// try writer.flush();
|
||||
|
||||
// FIXME: Need to handle this failure
|
||||
const dirt = try Io.Dir.openDir(Io.Dir.cwd(), io, dir, .{ .follow_symlinks = true, .iterate = true });
|
||||
defer dirt.close(io);
|
||||
|
||||
var dir_paths = dirt.iterate();
|
||||
|
||||
while (try dir_paths.next(io)) |file| {
|
||||
// FIXME: Check if executable
|
||||
// switch (file.kind) {
|
||||
// .file, .sym_link => {
|
||||
if (std.mem.eql(u8, std.fs.path.basename(file.name), "git")) {
|
||||
feats.git = true;
|
||||
// try writer.print("file: {s}\n", .{file.name});
|
||||
// try writer.flush();
|
||||
|
||||
if (feats == Features.all_features) {
|
||||
break :loop;
|
||||
}
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, std.fs.path.basename(file.name), "fd")) {
|
||||
feats.fd = true;
|
||||
// try writer.print("file: {s}\n", .{file.name});
|
||||
// try writer.flush();
|
||||
|
||||
if (feats == Features.all_features) {
|
||||
break :loop;
|
||||
}
|
||||
}
|
||||
|
||||
// },
|
||||
|
||||
// else => {},
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// if (path_contains(path, "git")) {
|
||||
// feats.git = true;
|
||||
// }
|
||||
|
||||
// if (path_contains(path, "fd")) {
|
||||
// feats.fd = true;
|
||||
// }
|
||||
|
||||
try writer.print("features: {}", .{feats});
|
||||
try writer.flush();
|
||||
}
|
||||
|
||||
const Features = packed struct {
|
||||
git: bool = false,
|
||||
fd: bool = false,
|
||||
const all_features: Features = .{
|
||||
.git = true,
|
||||
.fd = true,
|
||||
};
|
||||
};
|
||||
|
||||
fn fallback_to_go(
|
||||
io: Io,
|
||||
arena: std.mem.Allocator,
|
||||
|
||||
80
src/root.zig
80
src/root.zig
@@ -2,83 +2,17 @@
|
||||
const std = @import("std");
|
||||
const Io = std.Io;
|
||||
|
||||
const comma = @import("comma");
|
||||
const Command = comma.Command;
|
||||
|
||||
pub const root: Command = .new(.{
|
||||
.name = "envr",
|
||||
.subcommands = &[_]CommandOptions{.{ .name = "version" }},
|
||||
.subcommands = &.{
|
||||
.{ .name = "deps" },
|
||||
.{ .name = "version" },
|
||||
},
|
||||
});
|
||||
|
||||
const CommandOptions = struct {
|
||||
name: []const u8,
|
||||
short: ?[]const u8 = null,
|
||||
long: ?[]const u8 = null,
|
||||
subcommands: []const CommandOptions = &[0]CommandOptions{},
|
||||
|
||||
fn as_enum(self: @This()) type {
|
||||
var field_names: [self.subcommands.len + 1][]const u8 = undefined;
|
||||
var field_values: [self.subcommands.len + 1]u32 = undefined;
|
||||
|
||||
field_names[0] = self.name;
|
||||
field_values[0] = 0;
|
||||
|
||||
inline for (self.subcommands, 1..) |cmd, idx| {
|
||||
field_names[idx] = cmd.name;
|
||||
field_values[idx] = idx;
|
||||
}
|
||||
|
||||
return @Enum(
|
||||
u32,
|
||||
.exhaustive,
|
||||
&field_names,
|
||||
&field_values,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Command = struct {
|
||||
name: []const u8,
|
||||
short: ?[]const u8 = null,
|
||||
long: ?[]const u8 = null,
|
||||
subcommands: []const Command = &[0]Command{},
|
||||
Type: type,
|
||||
|
||||
pub fn new(cmd: CommandOptions) Command {
|
||||
const subcommands: [cmd.subcommands.len]Command = blk: {
|
||||
var result: [cmd.subcommands.len]Command = undefined;
|
||||
inline for (cmd.subcommands, 0..) |sub, idx| {
|
||||
result[idx] = new(sub);
|
||||
}
|
||||
break :blk result;
|
||||
};
|
||||
|
||||
return .{
|
||||
.name = cmd.name,
|
||||
.short = cmd.short,
|
||||
.long = cmd.long,
|
||||
.subcommands = &subcommands,
|
||||
.Type = cmd.as_enum(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parse(comptime self: @This(), args: []const []const u8) ParseError!self.Type {
|
||||
if (args.len == 0) {
|
||||
return ParseError.InvalidType;
|
||||
}
|
||||
const target = args[0];
|
||||
|
||||
inline for (self.subcommands, 1..) |cmd, idx| {
|
||||
if (std.mem.eql(u8, target, cmd.name)) {
|
||||
return @enumFromInt(idx);
|
||||
}
|
||||
}
|
||||
|
||||
return @enumFromInt(0);
|
||||
}
|
||||
};
|
||||
|
||||
pub const ParseError = error{
|
||||
InvalidType,
|
||||
};
|
||||
|
||||
test "enum type" {
|
||||
const got: root.Type = @enumFromInt(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user