wip error context
This commit is contained in:
parent
6aa4b01692
commit
a4d5be6fab
@ -35,10 +35,30 @@ pub fn writer(self: *ErrCtx) Writer {
|
|||||||
return Writer{ .context = self };
|
return Writer{ .context = self };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn err(self: *ErrCtx, comptime format: []const u8, args: anytype) void {
|
pub fn print(self: *ErrCtx, comptime format: []const u8, args: anytype) void {
|
||||||
self.writer().print(format, args) catch unreachable;
|
self.writer().print(format, args) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn returnf(
|
||||||
|
self: *ErrCtx,
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
comptime ret: anytype,
|
||||||
|
) @TypeOf(ret) {
|
||||||
|
self.writer().print(format, args) catch unreachable;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap(self: *ErrCtx, comptime msg: []const u8) *ErrCtx {
|
||||||
|
self.writer().writeAll(msg) catch unreachable;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrapf(self: *ErrCtx, comptime format: []const u8, args: anytype) *ErrCtx {
|
||||||
|
self.writer().print(format, args) catch unreachable;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iterator(self: *const ErrCtx) mem.SplitIterator(u8) {
|
pub fn iterator(self: *const ErrCtx) mem.SplitIterator(u8) {
|
||||||
const slice = self.buf.constSlice();
|
const slice = self.buf.constSlice();
|
||||||
const last_byte = if (slice[slice.len - 1] == '0') slice.len - 1 else slice.len;
|
const last_byte = if (slice[slice.len - 1] == '0') slice.len - 1 else slice.len;
|
||||||
|
32
src/User.zig
32
src/User.zig
@ -58,7 +58,7 @@ fn fromLine(allocator: Allocator, err_ctx: *ErrCtx, line: []const u8) error{ Inv
|
|||||||
|
|
||||||
// all fields are set
|
// all fields are set
|
||||||
if (shell == null) {
|
if (shell == null) {
|
||||||
err_ctx.err("too few user fields in line: {s}", .{line});
|
err_ctx.print("too few user fields in line: {s}", .{line});
|
||||||
return error.InvalidRecord;
|
return error.InvalidRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,19 +67,33 @@ fn fromLine(allocator: Allocator, err_ctx: *ErrCtx, line: []const u8) error{ Inv
|
|||||||
return error.InvalidRecord;
|
return error.InvalidRecord;
|
||||||
|
|
||||||
const uid = fmt.parseInt(u32, uids.?, 10) catch {
|
const uid = fmt.parseInt(u32, uids.?, 10) catch {
|
||||||
err_ctx.err("bad uid: {s}", .{uids.?});
|
return err_ctx.returnf("bad uid: {s}", .{uids.?}, error.InvalidRecord);
|
||||||
return error.InvalidRecord;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const gid = fmt.parseInt(u32, gids.?, 10) catch {
|
const gid = fmt.parseInt(u32, gids.?, 10) catch {
|
||||||
err_ctx.err("bad uid: {s}", .{gids.?});
|
return err_ctx.returnf("bad uid: {s}", .{gids.?}, error.InvalidRecord);
|
||||||
return error.InvalidRecord;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
validate.utf8(name.?) catch err_ctx.err("name is invalid utf8: {s}", .{name.?});
|
validate.utf8(name.?) catch return err_ctx.returnf(
|
||||||
validate.utf8(gecos.?) catch err_ctx.err("gecos is invalid utf8: {s}", .{gecos.?});
|
"name is invalid utf8: {s}",
|
||||||
validate.utf8(home.?) catch err_ctx.err("home is invalid utf8: {s}", .{home.?});
|
.{name.?},
|
||||||
validate.utf8(shell.?) catch err_ctx.err("shell is invalid utf8: {s}", .{shell.?});
|
error.InvalidRecord,
|
||||||
|
);
|
||||||
|
validate.utf8(gecos.?) catch return err_ctx.returnf(
|
||||||
|
"gecos is invalid utf8: {s}",
|
||||||
|
.{gecos.?},
|
||||||
|
error.InvalidRecord,
|
||||||
|
);
|
||||||
|
validate.utf8(home.?) catch return err_ctx.returnf(
|
||||||
|
"home is invalid utf8: {s}",
|
||||||
|
.{home.?},
|
||||||
|
error.InvalidRecord,
|
||||||
|
);
|
||||||
|
validate.utf8(shell.?) catch return err_ctx.returnf(
|
||||||
|
"shell is invalid utf8: {s}",
|
||||||
|
.{shell.?},
|
||||||
|
error.InvalidRecord,
|
||||||
|
);
|
||||||
|
|
||||||
if (err_ctx.dirty)
|
if (err_ctx.dirty)
|
||||||
return error.InvalidRecord;
|
return error.InvalidRecord;
|
||||||
|
@ -28,16 +28,16 @@ pub fn main() !void {
|
|||||||
const argv: []const [*:0]const u8 = os.argv;
|
const argv: []const [*:0]const u8 = os.argv;
|
||||||
const gpa = GeneralPurposeAllocator(.{});
|
const gpa = GeneralPurposeAllocator(.{});
|
||||||
|
|
||||||
const return_code = execute(gpa, argv[1..]) catch |err| {
|
const stderr = try io.getStdErr();
|
||||||
try io.getStdErr().writeAll("uncaught error: {s}\n", @intToError(err));
|
const stdout = try io.getStdOut();
|
||||||
os.exit(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const return_code = execute(gpa, stdout, stderr, argv[1..]);
|
||||||
os.exit(return_code);
|
os.exit(return_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute(
|
fn execute(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
|
stdout: anytype,
|
||||||
stderr: anytype,
|
stderr: anytype,
|
||||||
argv: []const [*:0]const u8,
|
argv: []const [*:0]const u8,
|
||||||
) u8 {
|
) u8 {
|
||||||
@ -52,7 +52,7 @@ fn execute(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (result.boolFlag("-h")) {
|
if (result.boolFlag("-h")) {
|
||||||
io.getStdOut().writeAll(usage) catch return 1;
|
stdout.writeAll(usage) catch return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,62 +66,72 @@ fn execute(
|
|||||||
const groupFname = result.argFlag("--group") orelse "./group";
|
const groupFname = result.argFlag("--group") orelse "./group";
|
||||||
const outFile = result.argFlag("--output") orelse "./db.turbo";
|
const outFile = result.argFlag("--output") orelse "./db.turbo";
|
||||||
|
|
||||||
// to catch a specific file.OpenError, wait for
|
// to catch a specific file.OpenError, hold thumbs for
|
||||||
// https://github.com/ziglang/zig/issues/2473
|
// https://github.com/ziglang/zig/issues/2473
|
||||||
|
var errc = ErrCtx{};
|
||||||
var passwdFile = fs.cwd().openFile(
|
var passwdFile = fs.cwd().openFile(
|
||||||
passwdFname,
|
passwdFname,
|
||||||
.{ .mode = .read_only },
|
.{ .mode = .read_only },
|
||||||
) catch |err| {
|
) catch |err| return fail(errc.wrapf("open {s}", .{passwdFname}), stderr, err);
|
||||||
stderr.print("Error opening {s}: {s}\n", .{ passwdFname, @errorName(err) }) catch {};
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
defer passwdFile.close();
|
defer passwdFile.close();
|
||||||
var groupFile = fs.cwd().openFile(groupFname, .{ .mode = .read_only }) catch |err| {
|
var groupFile = fs.cwd().openFile(groupFname, .{ .mode = .read_only }) catch |err|
|
||||||
stderr.print("Error opening {s}: {s}\n", .{ groupFname, @errorName(err) }) catch {};
|
return fail(errc.wrapf("open {s}", .{groupFname}), stderr, err);
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
defer groupFile.close();
|
defer groupFile.close();
|
||||||
|
|
||||||
var err_ctx = ErrCtx{};
|
var users = User.fromReader(
|
||||||
var users = try User.fromReader(
|
|
||||||
allocator,
|
allocator,
|
||||||
&err_ctx,
|
&errc,
|
||||||
passwdFile.reader(),
|
passwdFile.reader(),
|
||||||
);
|
) catch |err| return fail(errc.wrap("read users"), stderr, err);
|
||||||
errdefer {
|
|
||||||
stderr.print("ERROR", .{}) catch {};
|
|
||||||
var it = err_ctx.rev();
|
|
||||||
while (it.next()) |err|
|
|
||||||
stderr.print(": {s}", .{err}) catch {};
|
|
||||||
stderr.print("\n", .{}) catch {};
|
|
||||||
}
|
|
||||||
defer for (users) |*user| user.deinit(allocator);
|
defer for (users) |*user| user.deinit(allocator);
|
||||||
defer allocator.free(users);
|
defer allocator.free(users);
|
||||||
|
|
||||||
var groups = try Group.fromReader(allocator, groupFile.reader());
|
var groups = Group.fromReader(
|
||||||
|
allocator,
|
||||||
|
groupFile.reader(),
|
||||||
|
) catch |err| return fail(errc.wrap("read groups"), stderr, err);
|
||||||
defer for (groups) |*group| group.deinit(allocator);
|
defer for (groups) |*group| group.deinit(allocator);
|
||||||
defer allocator.free(groups);
|
defer allocator.free(groups);
|
||||||
|
|
||||||
var corpus = try Corpus.init(allocator, users, groups);
|
var corpus = Corpus.init(allocator, users, groups) catch |err|
|
||||||
|
return fail(errc.wrap("init corpus"), stderr, err);
|
||||||
|
|
||||||
defer corpus.deinit();
|
defer corpus.deinit();
|
||||||
var db = try DB.fromCorpus(allocator, &corpus);
|
var db = DB.fromCorpus(allocator, &corpus) catch |err|
|
||||||
|
return fail(errc.wrap("construct db from corpus"), stderr, err);
|
||||||
defer db.deinit(allocator);
|
defer db.deinit(allocator);
|
||||||
|
|
||||||
const fd = try os.open(outFile, os.O.WRONLY | os.O.TRUNC | os.O.CREAT, 0644);
|
const fd = os.open(outFile, os.O.WRONLY | os.O.TRUNC | os.O.CREAT, 0644) catch |err|
|
||||||
|
return fail(errc.wrapf("open for writing {s}", .{outFile}), stderr, err);
|
||||||
errdefer os.close(fd);
|
errdefer os.close(fd);
|
||||||
|
|
||||||
const len = try os.writev(fd, db.iov().constSlice());
|
const len = os.writev(fd, db.iov().constSlice()) catch |err|
|
||||||
try os.fsync(fd);
|
return fail(errc.wrapf("writev to {s}", .{outFile}), stderr, err);
|
||||||
|
os.fsync(fd) catch |err|
|
||||||
|
return fail(errc.wrapf("fsync {s}", .{outFile}), stderr, err);
|
||||||
os.close(fd);
|
os.close(fd);
|
||||||
|
|
||||||
try stderr.print("total {d} bytes. groups={d} users={d}\n", .{
|
stderr.print("total {d} bytes. groups={d} users={d}\n", .{
|
||||||
len,
|
len,
|
||||||
users.len,
|
users.len,
|
||||||
groups.len,
|
groups.len,
|
||||||
});
|
}) catch return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fail(errc: *ErrCtx, stderr: anytype, err: anytype) u8 {
|
||||||
|
stderr.print("ERROR {s}", .{@errorName(err)}) catch {};
|
||||||
|
var it = errc.rev();
|
||||||
|
while (it.next()) |msg|
|
||||||
|
stderr.print(": {s}", .{msg}) catch {};
|
||||||
|
|
||||||
|
stderr.print("\n", .{}) catch {};
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
test "invalid argument" {
|
test "invalid argument" {
|
||||||
@ -129,8 +139,12 @@ test "invalid argument" {
|
|||||||
const args = &[_][*:0]const u8{"--invalid-argument"};
|
const args = &[_][*:0]const u8{"--invalid-argument"};
|
||||||
var stderr = ArrayList(u8).init(allocator);
|
var stderr = ArrayList(u8).init(allocator);
|
||||||
defer stderr.deinit();
|
defer stderr.deinit();
|
||||||
|
var stderrw = stderr.writer();
|
||||||
|
var stdout = ArrayList(u8).init(allocator);
|
||||||
|
defer stdout.deinit();
|
||||||
|
var stdoutw = stdout.writer();
|
||||||
|
|
||||||
const exit_code = execute(allocator, stderr.writer(), args[0..]);
|
const exit_code = execute(allocator, stdoutw, stderrw, args[0..]);
|
||||||
try testing.expectEqual(@as(u8, 1), exit_code);
|
try testing.expectEqual(@as(u8, 1), exit_code);
|
||||||
try testing.expect(mem.startsWith(
|
try testing.expect(mem.startsWith(
|
||||||
u8,
|
u8,
|
||||||
|
Loading…
Reference in New Issue
Block a user