srctree

Gregory Mullen parent 7ab645f1 d6238241
Add internal logging module

README.md added: 238, removed: 94, total 144
@@ -60,6 +60,7 @@ clone [hsh]<br>
- [ ] fg
- [ ] jobs
- [ ] kill?
- [ ] pipeline
- [ ] pwd
- [ ] read
- [ ] set
 
build.zig added: 238, removed: 94, total 144
@@ -13,6 +13,10 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
});
 
exe.addModule("log", b.createModule(.{
.source_file = .{ .path = "src/log.zig" },
}));
 
b.installArtifact(exe);
 
const run_cmd = b.addRunArtifact(exe);
 
src/builtins.zig added: 238, removed: 94, total 144
@@ -7,8 +7,10 @@ const ParsedIterator = @import("parse.zig").ParsedIterator;
pub const State = @import("state.zig");
pub const aliases = @import("builtins/alias.zig");
pub const Set = @import("builtins/set.zig");
pub const Pipeline = @import("builtins/pipeline.zig");
 
const alias = aliases.alias;
const pipeline = Pipeline.pipeline;
const set = Set.set;
 
var Self = @This();
@@ -21,7 +23,7 @@ pub const Err = error{
FileSysErr,
};
 
const BuiltinFn = *const fn (a: *HSH, b: *ParsedIterator) Err!void;
pub const BuiltinFn = *const fn (a: *HSH, b: *ParsedIterator) Err!void;
 
pub const Builtins = enum {
alias,
@@ -32,6 +34,7 @@ pub const Builtins = enum {
exit,
fg,
jobs,
pipeline,
set,
which,
// DEBUGGING BUILTINS
@@ -52,6 +55,7 @@ pub fn exec(self: Builtins) BuiltinFn {
.exit => exit, // TODO exit should be kinder than die
.fg => fg,
.jobs => jobs,
.pipeline => pipeline,
.set => set,
.which => which,
// DEBUGGING BUILTIN
 
src/exec.zig added: 238, removed: 94, total 144
@@ -2,14 +2,19 @@ const std = @import("std");
const hsh = @import("hsh.zig");
const HSH = hsh.HSH;
const jobs = @import("jobs.zig");
const Tokens = @import("tokenizer.zig");
const tokenizer = @import("tokenizer.zig");
const Allocator = mem.Allocator;
const Tokenizer = Tokens.Tokenizer;
const Tokenizer = tokenizer.Tokenizer;
const ArrayList = std.ArrayList;
const TokenKind = @import("tokenizer.zig").TokenKind;
const ParsedIterator = @import("parse.zig").ParsedIterator;
const TokenKind = tokenizer.TokenKind;
const TokenIterator = tokenizer.TokenIterator;
const parse = @import("parse.zig");
const Parser = parse.Parser;
const ParsedIterator = parse.ParsedIterator;
 
const mem = std.mem;
const fd_t = std.os.fd_t;
const bi = @import("builtins.zig");
 
pub const Error = error{
InvalidSrc,
@@ -30,15 +35,30 @@ const StdIo = struct {
stderr: fd_t,
};
 
const ExecStack = struct {
const Exec = struct {
arg: ARG,
argv: ARGV,
};
 
const Builtin = struct {
builtin: []const u8,
argv: *ParsedIterator,
};
 
const Callable = union(enum) {
builtin: Builtin,
exec: Exec,
};
 
const CallableStack = struct {
callable: Callable,
stdio: ?StdIo,
};
 
fn setup() void {}
 
pub fn executable(h: *HSH, str: []const u8) bool {
if (bi.exists(str)) return true;
var plsfree = makeAbsExecutable(h.alloc, h.fs.paths.items, str) catch return false;
plsfree.clearAndFree();
return true;
@@ -86,58 +106,76 @@ fn makeExeZ(a: Allocator, paths: [][]const u8, str: []const u8) Error!ARG {
return exe.toOwnedSliceSentinel(0) catch return Error.Memory;
}
 
fn mkBuiltin(_: *const HSH, titr: *ParsedIterator) Error!Builtin {
return Builtin{
.builtin = titr.first().cannon(),
.argv = titr,
};
}
 
/// Caller owns memory of argv, and the open fds
fn makeExecStack(h: *const HSH, titr: *ParsedIterator) Error![]ExecStack {
var stack = ArrayList(ExecStack).init(h.alloc);
fn mkExec(h: *const HSH, titr: *ParsedIterator) Error!Exec {
var exeZ: ?ARG = null;
var argv = ArrayList(?ARG).init(h.alloc);
 
while (titr.next()) |t| {
switch (t.type) {
if (exeZ) |_| {} else {
exeZ = makeExeZ(h.alloc, h.fs.paths.items, t.cannon()) catch |e| {
std.debug.print("path missing {s}\n", .{t.cannon()});
return e;
};
argv.append(exeZ.?) catch return Error.Memory;
continue;
}
argv.append(
h.alloc.dupeZ(u8, t.cannon()) catch return Error.Memory,
) catch return Error.Memory;
}
return Exec{
.arg = exeZ.?,
.argv = argv.toOwnedSliceSentinel(null) catch return Error.Memory,
};
}
 
fn mkCallableStack(h: *HSH, itr: *TokenIterator) Error![]CallableStack {
var stack = ArrayList(CallableStack).init(h.alloc);
 
itr.restart();
 
while (itr.peek()) |peek| {
var io: ?StdIo = null;
switch (peek.type) {
.IoRedir => {
if (!std.mem.eql(u8, "|", t.cannon())) unreachable;
if (!std.mem.eql(u8, "|", peek.cannon())) unreachable;
const pipe = std.os.pipe2(0) catch return Error.OSErr;
const io = StdIo{
io = StdIo{
.left = pipe[1],
.right = pipe[0],
.stderr = std.os.STDERR_FILENO,
};
stack.append(ExecStack{
.arg = exeZ.?,
.argv = argv.toOwnedSliceSentinel(null) catch return Error.Memory,
.stdio = io,
}) catch return Error.Memory;
exeZ = null;
argv = ArrayList(?ARG).init(h.alloc);
continue;
},
else => {
if (exeZ) |_| {} else {
exeZ = makeExeZ(h.alloc, h.fs.paths.items, t.cannon()) catch |e| {
std.debug.print("path missing {s}\n", .{t.cannon()});
return e;
};
argv.append(exeZ.?) catch return Error.Memory;
continue;
}
argv.append(
h.alloc.dupeZ(u8, t.cannon()) catch return Error.Memory,
) catch return Error.Memory;
},
else => {},
}
var eslice = itr.toSliceExec(h.alloc) catch unreachable;
std.debug.print("{any}\n", .{peek});
std.debug.print("{any}\n", .{eslice});
defer h.alloc.free(eslice);
var parsed = Parser.parse(&h.alloc, eslice, false) catch unreachable;
var callable = switch (peek.type) {
.Builtin => Callable{ .builtin = try mkBuiltin(h, &parsed) },
else => Callable{ .exec = try mkExec(h, &parsed) },
};
stack.append(CallableStack{
.callable = callable,
.stdio = io,
}) catch return Error.Memory;
}
 
stack.append(ExecStack{
.arg = exeZ.?,
.argv = argv.toOwnedSliceSentinel(null) catch return Error.Memory,
.stdio = null,
}) catch return Error.Memory;
return stack.toOwnedSlice() catch return Error.Memory;
}
 
pub fn exec(h: *const HSH, titr: *ParsedIterator) Error!ArrayList(jobs.Job) {
pub fn exec(h: *HSH, titr: *TokenIterator) Error!ArrayList(jobs.Job) {
titr.restart();
const stack = makeExecStack(h, titr) catch |e| {
const stack = mkCallableStack(h, titr) catch |e| {
std.debug.print("unable to make stack {}\n", .{e});
return e;
};
@@ -147,7 +185,7 @@ pub fn exec(h: *const HSH, titr: *ParsedIterator) Error!ArrayList(jobs.Job) {
 
var cjobs = ArrayList(jobs.Job).init(h.alloc);
 
for (stack) |s| {
for (stack) |*s| {
const fpid: std.os.pid_t = std.os.fork() catch return Error.OSErr;
if (fpid == 0) {
if (previo) |pio| {
@@ -163,18 +201,28 @@ pub fn exec(h: *const HSH, titr: *ParsedIterator) Error!ArrayList(jobs.Job) {
std.os.dup2(rootout, std.os.STDOUT_FILENO) catch return Error.OSErr;
}
 
// TODO manage env
const res = std.os.execveZ(
s.arg,
s.argv,
@ptrCast([*:null]?[*:0]u8, std.os.environ),
);
switch (res) {
error.FileNotFound => {
// we validate exes internall now this should be impossible
unreachable;
switch (s.callable) {
.builtin => |*b| {
const bi_func = bi.strExec(b.builtin);
bi_func(h, b.argv) catch |err| {
std.debug.print("builtin error {}\n", .{err});
};
},
.exec => |e| {
// TODO manage env
const res = std.os.execveZ(
e.arg,
e.argv,
@ptrCast([*:null]?[*:0]u8, std.os.environ),
);
switch (res) {
error.FileNotFound => {
// we validate exes internall now this should be impossible
unreachable;
},
else => std.debug.print("exec error {}\n", .{res}),
}
},
else => std.debug.print("exec error {}\n", .{res}),
}
unreachable;
}
@@ -182,10 +230,14 @@ pub fn exec(h: *const HSH, titr: *ParsedIterator) Error!ArrayList(jobs.Job) {
// Child must noreturn
// Parent
//std.debug.print("chld pid {}\n", .{fpid});
const name = switch (s.callable) {
.builtin => |b| b.builtin,
.exec => |e| std.mem.sliceTo(e.arg, 0),
};
cjobs.append(jobs.Job{
.status = if (s.stdio) |_| .Piped else .Running,
.pid = fpid,
.name = h.alloc.dupe(u8, std.mem.sliceTo(s.arg, 0)) catch return Error.Memory,
.name = h.alloc.dupe(u8, name) catch return Error.Memory,
}) catch return Error.Memory;
if (previo) |pio| {
std.os.close(pio.left);
 
filename was Deleted added: 238, removed: 94, total 144
@@ -0,0 +1,43 @@
const std = @import("std");
 
pub const Log = @This();
 
pub const Level = enum(u4) {
panic = 0,
critical,
err,
warning,
notice,
info,
debug,
trace,
};
 
/// TODO NO_COLOR support
pub fn hshLogFn(
comptime level: Level,
comptime _: @TypeOf(.EnumLiteral),
comptime format: []const u8,
args: anytype,
) void {
const prefix = comptime switch (level) {
.err => "[\x1B[31merr\x1B[39m] ",
.warning => "[\x1B[33mwrn\x1B[39m] ",
.info => "[\x1B[32minf\x1B[39m] ",
.debug => "[\x1B[24mdbg\x1B[39m] ",
else => "[ NOS ] ",
};
 
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
const stderr = std.io.getStdErr().writer();
stderr.print(prefix ++ format, args) catch return;
}
 
pub fn err(comptime format: []const u8, args: anytype) void {
hshLogFn(.err, .default, format, args);
}
 
pub fn info(comptime format: []const u8, args: anytype) void {
hshLogFn(.info, .default, format, args);
}
 
src/main.zig added: 238, removed: 94, total 144
@@ -20,7 +20,6 @@ const ctxContext = @import("prompt.zig").ctxContext;
const Context = @import("context.zig");
const HSH = @import("hsh.zig").HSH;
const complete = @import("completion.zig");
const Builtins = @import("builtins.zig");
const Keys = @import("keys.zig");
const Exec = @import("exec.zig");
const exec = Exec.exec;
@@ -28,6 +27,7 @@ const Signals = @import("signals.zig");
const History = @import("history.zig");
const layoutTable = @import("draw/layout.zig").layoutTable;
const jobs = @import("jobs.zig");
const log = @import("log");
 
test "main" {
std.testing.refAllDecls(@This());
@@ -291,7 +291,7 @@ pub fn main() !void {
 
var args = std.process.args();
while (args.next()) |arg| {
std.debug.print("arg: {s}\n", .{arg});
log.info("arg: {s}\n", .{arg});
}
 
hsh.tkn = Tokenizer.init(a);
@@ -328,39 +328,27 @@ pub fn main() !void {
titr.restart();
if (hsh.hist) |*hist| try hist.push(hsh.tkn.raw.items);
if (titr.peek()) |peek| {
switch (peek.type) {
.String => {
if (!Exec.executable(&hsh, peek.cannon())) {
std.debug.print("Unable to find {s}\n", .{peek.cannon()});
continue;
}
 
try hsh.tty.pushOrig();
var exec_jobs = exec(&hsh, &titr) catch |err| {
if (err == Exec.Error.ExeNotFound) {
std.debug.print("exe pipe error {}\n", .{err});
}
std.debug.print("Exec error {}\n", .{err});
unreachable;
};
defer exec_jobs.clearAndFree();
hsh.tkn.reset();
_ = try jobs.add(exec_jobs.pop());
while (exec_jobs.popOrNull()) |j| {
_ = try jobs.add(j);
}
},
.Builtin => {
hsh.draw.reset();
const bi_func = Builtins.strExec(peek.cannon());
bi_func(&hsh, &titr) catch |err| {
std.debug.print("builtin error {}\n", .{err});
};
hsh.tkn.reset();
continue;
},
else => continue,
if (!Exec.executable(&hsh, peek.cannon())) {
std.debug.print("Unable to find {s}\n", .{peek.cannon()});
continue;
}
 
try hsh.tty.pushOrig();
var itr = hsh.tkn.iterator();
var exec_jobs = exec(&hsh, &itr) catch |err| {
if (err == Exec.Error.ExeNotFound) {
std.debug.print("exe pipe error {}\n", .{err});
}
std.debug.print("Exec error {}\n", .{err});
unreachable;
};
defer exec_jobs.clearAndFree();
hsh.tkn.reset();
_ = try jobs.add(exec_jobs.pop());
while (exec_jobs.popOrNull()) |j| {
_ = try jobs.add(j);
}
continue;
}
} else {
break;
 
src/tokenizer.zig added: 238, removed: 94, total 144
@@ -134,6 +134,8 @@ pub const TokenIterator = struct {
}
 
pub fn peek(self: *Self) ?*const Token {
const old = self.index;
defer self.index = old;
return self.next();
}
 
@@ -247,6 +249,10 @@ pub const Tokenizer = struct {
return self.raw.items.len - self.c_idx;
}
 
pub fn iterator(self: *Tokenizer) TokenIterator {
return TokenIterator{ .raw = self.raw.items };
}
 
/// Return a slice of the current tokens;
/// Tokenizer owns memory, and makes no guarantee it'll be valid by the time
/// it's used.
@@ -868,3 +874,49 @@ test "token pipeline slice" {
try std.testing.expectEqualStrings("works", slice[2].cannon());
std.testing.allocator.free(slice);
}
 
test "token pipeline slice safe with next()" {
var ti = TokenIterator{
.raw = "ls -la | cat | sort ; echo this works",
};
 
var len: usize = 0;
while (ti.next()) |_| {
len += 1;
}
try std.testing.expectEqual(len, 10);
 
ti.restart();
len = 0;
while (ti.nextExec()) |_| {
len += 1;
}
try std.testing.expectEqual(len, 2);
 
ti.restart();
 
var slice = try ti.toSliceExec(std.testing.allocator);
try std.testing.expectEqual(slice.len, 2);
std.testing.allocator.free(slice);
 
_ = ti.next();
 
slice = try ti.toSliceExec(std.testing.allocator);
try std.testing.expectEqual(slice.len, 1);
std.testing.allocator.free(slice);
 
_ = ti.next();
 
slice = try ti.toSliceExec(std.testing.allocator);
try std.testing.expectEqual(slice.len, 1);
std.testing.allocator.free(slice);
 
_ = ti.next();
 
slice = try ti.toSliceExec(std.testing.allocator);
try std.testing.expectEqual(slice.len, 3);
try std.testing.expectEqualStrings("echo", slice[0].cannon());
try std.testing.expectEqualStrings("this", slice[1].cannon());
try std.testing.expectEqualStrings("works", slice[2].cannon());
std.testing.allocator.free(slice);
}