diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..cd81d86 --- /dev/null +++ b/Package.swift @@ -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"), + ] +) diff --git a/Sources/main.swift b/Sources/main.swift new file mode 100644 index 0000000..375c697 --- /dev/null +++ b/Sources/main.swift @@ -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? +} + diff --git a/build.zig b/build.zig deleted file mode 100644 index d78f743..0000000 --- a/build.zig +++ /dev/null @@ -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); -} diff --git a/src/main.zig b/src/main.zig deleted file mode 100644 index 08f7140..0000000 --- a/src/main.zig +++ /dev/null @@ -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])); -}