refactor: change zig to swift
This commit is contained in:
parent
d9ea5cf7d6
commit
c0f664d287
4 changed files with 93 additions and 210 deletions
14
Package.swift
Normal file
14
Package.swift
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// swift-tools-version: 6.0
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "wacli",
|
||||||
|
targets: [
|
||||||
|
// Targets are the basic building blocks of a package, defining a module or a test suite.
|
||||||
|
// Targets can depend on other targets in this package and products from dependencies.
|
||||||
|
.executableTarget(
|
||||||
|
name: "wacli"),
|
||||||
|
]
|
||||||
|
)
|
79
Sources/main.swift
Normal file
79
Sources/main.swift
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// The Swift Programming Language
|
||||||
|
// https://docs.swift.org/swift-book
|
||||||
|
|
||||||
|
enum Types {
|
||||||
|
case path
|
||||||
|
case method
|
||||||
|
case bin
|
||||||
|
case uri
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Aliases {
|
||||||
|
enum Alias {
|
||||||
|
case single(String)
|
||||||
|
case multiple([String])
|
||||||
|
}
|
||||||
|
var alias: Alias,
|
||||||
|
var type: Types,
|
||||||
|
var description: String?,
|
||||||
|
var content: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Tool {
|
||||||
|
var integrity: String,
|
||||||
|
var source: String,
|
||||||
|
var installPath: String,
|
||||||
|
var alias: String?,
|
||||||
|
var version: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias Tools = [String : Tool]
|
||||||
|
|
||||||
|
struct LockFile {
|
||||||
|
var fileVersion: Int = 1,
|
||||||
|
var bins: Tools,
|
||||||
|
var ains: Tools
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OauthFlows {
|
||||||
|
var implict: struct {
|
||||||
|
var authrizationUrl: String
|
||||||
|
var scopes: [String: String]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SettingsAuth {
|
||||||
|
enum Scheme {
|
||||||
|
case basic
|
||||||
|
case bearer
|
||||||
|
case oauth2
|
||||||
|
}
|
||||||
|
var scheme: Scheme?,
|
||||||
|
var tokenName: String?
|
||||||
|
var flows: OauthFlows?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WellKnownSettings {
|
||||||
|
var contentType: String = "application/json"
|
||||||
|
var headers: [String]?
|
||||||
|
var aliases: [Aliases]?
|
||||||
|
var auth: SettingsAuth?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UserSettings {
|
||||||
|
dbPath: String = "$HOME/.cache/wacrd.db",
|
||||||
|
installDir: String = "$HOME/.local/bin",
|
||||||
|
uriSchems: [String : String]?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WellKnownSchema = struct {
|
||||||
|
enum Path {
|
||||||
|
var path
|
||||||
|
}
|
||||||
|
var api: String?
|
||||||
|
var registry: Boolean?
|
||||||
|
var manifests: [String: Path]?
|
||||||
|
var bin: [String : [String : String]]?
|
||||||
|
var settings: WellKnownSettings?
|
||||||
|
}
|
||||||
|
|
70
build.zig
70
build.zig
|
@ -1,70 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
// Although this function looks imperative, note that its job is to
|
|
||||||
// declaratively construct a build graph that will be executed by an external
|
|
||||||
// runner.
|
|
||||||
pub fn build(b: *std.Build) void {
|
|
||||||
// Standard target options allows the person running `zig build` to choose
|
|
||||||
// what target to build for. Here we do not override the defaults, which
|
|
||||||
// means any target is allowed, and the default is native. Other options
|
|
||||||
// for restricting supported target set are available.
|
|
||||||
const target = b.standardTargetOptions(.{});
|
|
||||||
|
|
||||||
// Standard optimization options allow the person running `zig build` to select
|
|
||||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
|
||||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
|
||||||
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = "wacli",
|
|
||||||
// In this case the main source file is merely a path, however, in more
|
|
||||||
// complicated build scripts, this could be a generated file.
|
|
||||||
.root_source_file = b.path("src/main.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
// This declares intent for the executable to be installed into the
|
|
||||||
// standard location when the user invokes the "install" step (the default
|
|
||||||
// step when running `zig build`).
|
|
||||||
b.installArtifact(exe);
|
|
||||||
|
|
||||||
// This *creates* a Run step in the build graph, to be executed when another
|
|
||||||
// step is evaluated that depends on it. The next line below will establish
|
|
||||||
// such a dependency.
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
|
||||||
|
|
||||||
// By making the run step depend on the install step, it will be run from the
|
|
||||||
// installation directory rather than directly from within the cache directory.
|
|
||||||
// This is not necessary, however, if the application depends on other installed
|
|
||||||
// files, this ensures they will be present and in the expected location.
|
|
||||||
run_cmd.step.dependOn(b.getInstallStep());
|
|
||||||
|
|
||||||
// This allows the user to pass arguments to the application in the build
|
|
||||||
// command itself, like this: `zig build run -- arg1 arg2 etc`
|
|
||||||
if (b.args) |args| {
|
|
||||||
run_cmd.addArgs(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This creates a build step. It will be visible in the `zig build --help` menu,
|
|
||||||
// and can be selected like this: `zig build run`
|
|
||||||
// This will evaluate the `run` step rather than the default, which is "install".
|
|
||||||
const run_step = b.step("run", "Run the app");
|
|
||||||
run_step.dependOn(&run_cmd.step);
|
|
||||||
|
|
||||||
// Creates a step for unit testing. This only builds the test executable
|
|
||||||
// but does not run it.
|
|
||||||
const unit_tests = b.addTest(.{
|
|
||||||
.root_source_file = b.path("src/main.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
const run_unit_tests = b.addRunArtifact(unit_tests);
|
|
||||||
|
|
||||||
// Similar to creating the run step earlier, this exposes a `test` step to
|
|
||||||
// the `zig build --help` menu, providing a way for the user to request
|
|
||||||
// running the unit tests.
|
|
||||||
const test_step = b.step("test", "Run unit tests");
|
|
||||||
test_step.dependOn(&run_unit_tests.step);
|
|
||||||
}
|
|
140
src/main.zig
140
src/main.zig
|
@ -1,140 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
/// The cow is not mine, but a BratishkaErik
|
|
||||||
const Samsa = union(enum) {
|
|
||||||
array: []const []const u8,
|
|
||||||
string: []const u8,
|
|
||||||
|
|
||||||
pub fn jsonParse(allocator: std.mem.Allocator, source: anytype, options: std.json.ParseOptions) !Samsa {
|
|
||||||
return switch (try source.peekNextTokenType()) {
|
|
||||||
.array_begin => .{ .array = try std.json.innerParse([]const []const u8, allocator, source, options) },
|
|
||||||
.string => .{ .string = try std.json.innerParse([]const u8, allocator, source, options) },
|
|
||||||
else => error.UnexpectedToken,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Aliases = struct {
|
|
||||||
alias: Samsa,
|
|
||||||
type: enum { path, method, bin, uri },
|
|
||||||
description: ?[]const u8 = null,
|
|
||||||
content: []const u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Tools = std.json.ArrayHashMap(struct {
|
|
||||||
integrity: [std.crypto.hash.sha256.Sha256.digest_length]u8,
|
|
||||||
source: []const u8,
|
|
||||||
installPath: []const u8,
|
|
||||||
alias: ?[]const u8 = null,
|
|
||||||
version: []const u8,
|
|
||||||
});
|
|
||||||
|
|
||||||
const LockFile = struct {
|
|
||||||
fileVersion: i8 = 1,
|
|
||||||
bins: Tools,
|
|
||||||
ains: Tools
|
|
||||||
};
|
|
||||||
|
|
||||||
const OauthFlows = struct { implict: struct { authrizationUrl: []const u8, scopes: std.json.ArrayHashMap([]const u8) } };
|
|
||||||
|
|
||||||
const WellKnownSettings = struct {
|
|
||||||
contentType: []const u8 = "application/json",
|
|
||||||
headers: ?[]const []const u8 = null,
|
|
||||||
aliases: ?[]const Aliases = null,
|
|
||||||
auth: ?struct { scheme: enum { basic, bearer, oauth2 }, tokenName: ?[]const u8 = null, flows: ?OauthFlows = null } = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const WellKnownSchema = struct { api: ?[]const u8 = null, registry: ?bool = false, manifests: ?std.json.ArrayHashMap(struct { path: []const u8 }) = null, bin: ?std.json.ArrayHashMap([]const std.json.ArrayHashMap([]const u8)) = null, settings: ?WellKnownSettings = null };
|
|
||||||
|
|
||||||
const UserSettings = struct { db_path: []const u8 = "$HOME/.cache/wacrd.db", install_dir: []const u8 = "$HOME/.local/bin", uri_schemes: ?std.json.ArrayHashMap([]const u8) = null };
|
|
||||||
|
|
||||||
pub fn getHomeDir() !?std.fs.Dir {
|
|
||||||
return try std.fs.openDirAbsolute(std.posix.getenv("HOME") orelse {
|
|
||||||
return null;
|
|
||||||
}, .{ .iterate = true });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getXDGConfigHomeDir() !?std.fs.Dir {
|
|
||||||
return try std.fs.openDirAbsolute(std.posix.getenv("XDG_CONFIG_HOME") orelse {
|
|
||||||
return null;
|
|
||||||
}, .{ .iterate = true });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn readTypedConfig(allocator: std.mem.Allocator, comptime T: type, filePath: []const u8, buffer_size: usize) !std.json.Parsed(T) {
|
|
||||||
const contents = try std.fs.cwd().readFileAlloc(allocator, filePath, buffer_size);
|
|
||||||
defer allocator.free(contents);
|
|
||||||
return std.json.parseFromSlice(T, allocator, contents, .{
|
|
||||||
.allocate = .alloc_always,
|
|
||||||
.ignore_unknown_fields = true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fetchResource(allocator: std.mem.Allocator, api: ?[]const u8,) !struct{ std.http.Status, std.ArrayList(u8)} {
|
|
||||||
const http = std.http;
|
|
||||||
var client = http.Client{ .allocator = allocator };
|
|
||||||
defer client.deinit();
|
|
||||||
var list = std.ArrayList(u8).init(allocator);
|
|
||||||
const fetch = try client.fetch(.{.location = .{.url = api.?}, .method = .GET, .response_storage = .{.dynamic = &list}});
|
|
||||||
return .{ fetch.status, list};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() !void {}
|
|
||||||
|
|
||||||
test "fetch openapi schema" {
|
|
||||||
const parsedWaCLISchema = try readTypedConfig(std.testing.allocator, WellKnownSchema, "examples/git.0ut0f.space/.well-known/wacli.json", 2048);
|
|
||||||
defer parsedWaCLISchema.deinit();
|
|
||||||
const waCLISchema = parsedWaCLISchema.value;
|
|
||||||
const status, const data = try fetchResource(std.testing.allocator,waCLISchema.api);
|
|
||||||
defer data.deinit();
|
|
||||||
|
|
||||||
std.debug.print("{u}\n",.{status});
|
|
||||||
std.debug.print("{s}\n",.{data.items});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "parse registry schema:" {
|
|
||||||
const parsedExampleSettings = try readTypedConfig(std.testing.allocator, UserSettings, "examples/settings.json", 512);
|
|
||||||
const parsedWaCLISchema = try readTypedConfig(std.testing.allocator, WellKnownSchema, "examples/wacli.ofs.lol/.well-known/wacli.json", 512);
|
|
||||||
defer {
|
|
||||||
parsedExampleSettings.deinit();
|
|
||||||
parsedWaCLISchema.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
const waCLISettings = parsedExampleSettings.value;
|
|
||||||
const waCLISchema = parsedWaCLISchema.value;
|
|
||||||
|
|
||||||
// const uri_schemes = waCLISettings.uri_schemes.?.map;
|
|
||||||
|
|
||||||
// std.debug.print("{any}\n", .{waCLISchema});
|
|
||||||
try std.testing.expect(waCLISchema.registry == true);
|
|
||||||
try std.testing.expect(waCLISchema.api == null);
|
|
||||||
try std.testing.expect(std.mem.eql(u8, waCLISettings.db_path, "$HOME/.cache/wacrd.db"));
|
|
||||||
}
|
|
||||||
|
|
||||||
test "parse schema:" {
|
|
||||||
const parsedWaCLISchema = try readTypedConfig(std.testing.allocator, WellKnownSchema, "examples/git.0ut0f.space/.well-known/wacli.json", 2048);
|
|
||||||
var AliasesArray = std.MultiArrayList(Aliases){};
|
|
||||||
|
|
||||||
defer {
|
|
||||||
parsedWaCLISchema.deinit();
|
|
||||||
AliasesArray.deinit(std.testing.allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
const waCLISchema = parsedWaCLISchema.value;
|
|
||||||
|
|
||||||
//const binaryPathLinux = waCLISchema.bin.?.map.get("linux").?[0].map.get("x86").?;
|
|
||||||
//std.debug.print("{s}\n", .{binaryPathLinux});
|
|
||||||
try std.testing.expect(std.mem.eql(u8, waCLISchema.api.?, "https://git.0ut0f.space/swagger.v1.json"));
|
|
||||||
try AliasesArray.insert(std.testing.allocator, 0, .{
|
|
||||||
.alias = .{ .string = "issues" },
|
|
||||||
.type = .path,
|
|
||||||
.content = "/repos/{owner}/{repo}/issues",
|
|
||||||
});
|
|
||||||
try AliasesArray.append(std.testing.allocator, .{
|
|
||||||
.alias = .{ .array = &[_][]const u8{ "c", "create" } },
|
|
||||||
.type = .method,
|
|
||||||
.content = "POST",
|
|
||||||
});
|
|
||||||
try AliasesArray.append(std.testing.allocator, .{ .alias = .{ .array = &[_][]const u8{ "d", "delete" } }, .type = .method, .content = "DELETE" });
|
|
||||||
try AliasesArray.append(std.testing.allocator, .{ .alias = .{ .string = "tea" }, .type = .bin, .content = "tea" });
|
|
||||||
try std.testing.expect(@TypeOf(AliasesArray.get(0)) == @TypeOf(waCLISchema.settings.?.aliases.?[0]));
|
|
||||||
}
|
|
Loading…
Reference in a new issue