package wwfixture; import fmt; import os; import strings; type options = struct { root: str, patterns: []str, jobs: i32, list: bool, keep: bool, timeoutms: i64, input: str, }; fn usage() void = { fmt.errorln("usage: wwfixture [-root path] [-run glob]... [-list] [-j N] [-keep] [-timeout-ms N]"); fmt.errorln(" wwfixture validate [-root path] [-run glob]... STREAM"); }; fn positive(s: str, limit: i64, out: *i64) bool = { if (s.len == 0) { return false; }; let n: i64 = 0i64; let i: i32 = 0; for (i < s.len) { let c: u8 = s[i]; if (c < '0': u8 || c > '9': u8) { return false; }; let digit: i64 = (c - '0': u8): i64; if (n > (limit - digit) / 10i64) { return false; }; n = n * 10i64 + digit; i += 1; }; if (n == 0i64) { return false; }; *out = n; return true; }; fn initoptions(out: *options) void = { out.root = ""; let patterns: []str = alloc([], 16u64)!; out.patterns = patterns; out.jobs = 4; out.list = false; out.keep = false; out.timeoutms = 30000i64; out.input = ""; }; fn parseoptions(args: []str, start: i32, validate: bool, out: *options) bool = { initoptions(out); let i: i32 = start; for (i < args.len) { let a: str = args[i]; if (a == "-root" || a == "-run") { if (i + 1 >= args.len) { return false; }; if (a == "-root") { if (out.root.len != 0) { return false; }; out.root = args[i + 1]; } else { append(out.patterns, args[i + 1]); }; i += 2; continue; }; if (!validate && a == "-list") { if (out.list) { return false; }; out.list = true; i += 1; continue; }; if (!validate && a == "-keep") { if (out.keep) { return false; }; out.keep = true; i += 1; continue; }; if (!validate && (a == "-j" || a == "-timeout-ms")) { if (i + 1 >= args.len) { return false; }; let n: i64 = 0i64; let limit: i64 = 64i64; if (a == "-timeout-ms") { limit = 3600000i64; }; if (!positive(args[i + 1], limit, &n)) { return false; }; if (a == "-j") { out.jobs = n: i32; } else { out.timeoutms = n; }; i += 2; continue; }; if (validate && a.len > 0 && a[0] != '-': u8 && out.input.len == 0) { out.input = a; i += 1; continue; }; return false; }; if (validate && out.input.len == 0) { return false; }; return true; }; fn listfixtures(c: *corpus, ids: []identity) bool = { let i: i32 = 0; for (i < ids.len) { let f: *fixture = &c.fixtures[ids[i].fixtureindex]; let line: str = strings.concat(f.id, "\t", stageword(ids[i].stage), "\n"); if (!writeall(os.STDOUT_FILENO, line)) { return false; }; i += 1; }; return true; }; fn validatecommand(opts: *options) int = { let c: corpus; if (!loadcorpus(opts.root, &c)) { fmt.errorln("wwfixture validate: ", error()); return 1; }; let ids: []identity; selectidentities(&c, opts.patterns, &ids); let data: str; if (!readfile(opts.input, &data)) { fmt.errorln("wwfixture validate: ", error()); return 1; }; if (!validatestream(data, &c, ids)) { fmt.errorln("wwfixture validate: ", protocolerror()); return 1; }; return 0; }; export fn command(args: []str) int = { if (args.len < 1) { usage(); return 2; }; let validate: bool = args.len > 1 && args[1] == "validate"; let start: i32 = 1; if (validate) { start = 2; }; let opts: options; if (!parseoptions(args, start, validate, &opts)) { usage(); return 2; }; if (validate) { return validatecommand(&opts); }; let c: corpus; if (!loadcorpus(opts.root, &c)) { fmt.errorln("wwfixture: ", error()); return 1; }; let ids: []identity; selectidentities(&c, opts.patterns, &ids); if (opts.list) { if (!listfixtures(&c, ids)) { fmt.errorln("wwfixture: result output failed"); return 1; }; return 0; }; return runfixtures(&opts, &c, ids); };