authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-01-31 12:04:23 -08:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-01-31 12:04:23 -08:00
logfadbc7086ce770835e747cd88b62859c34195b70
tree6c01bf1d065a0b873849a8222b6f9fe82e534fc6
parent3df411d44f33f2bc6cb1ca28c3e517b249fc92fb

add 'zpm add' subcommand


2 files changed, 97 insertions(+), 0 deletions(-)

src/cmd_zpm.zig+2
......@@ -7,6 +7,7 @@ const u = @import("./util/index.zig");
77//
88
99const commands = struct {
10 const add = @import("./cmd_zpm_add.zig");
1011};
1112
1213pub fn execute(args: [][]u8) !void {
......@@ -17,6 +18,7 @@ pub fn execute(args: [][]u8) !void {
1718 \\The default remote is https://zpm.random-projects.net/.
1819 \\
1920 \\The subcommands available are:
21 \\ - add Append this package to your dependencies
2022 });
2123 return;
2224 }
src/cmd_zpm_add.zig created+95
......@@ -0,0 +1,95 @@
1const std = @import("std");
2const gpa = std.heap.c_allocator;
3
4const zuri = @import("zuri");
5const iguanatls = @import("iguanatls");
6const u = @import("./util/index.zig");
7
8//
9//
10
11const Zpm = struct {
12 pub const Package = struct {
13 author: []const u8,
14 name: []const u8,
15 tags: [][]const u8,
16 git: []const u8,
17 root_file: ?[]const u8,
18 description: []const u8,
19 };
20};
21
22pub fn execute(args: [][]u8) !void {
23 const url = try zuri.Uri.parse("https://zpm.random-projects.net:443/api/packages", true);
24
25 const sock = try std.net.tcpConnectToHost(gpa, url.host.name, url.port.?);
26 defer sock.close();
27
28 var client = try iguanatls.client_connect(.{
29 .reader = sock.reader(),
30 .writer = sock.writer(),
31 .cert_verifier = .none,
32 .temp_allocator = gpa,
33 .ciphersuites = iguanatls.ciphersuites.all,
34 }, url.host.name);
35 defer client.close_notify() catch {};
36
37 const w = client.writer();
38 try w.print("GET {s} HTTP/1.1\r\n", .{url.path});
39 try w.print("Host: {s}:{}\r\n", .{url.host.name, url.port.?});
40 try w.writeAll("Accept: application/json; charset=UTF-8\r\n");
41 try w.writeAll("Connection: Close\r\n");
42 try w.writeAll("\r\n");
43
44 const r = client.reader();
45 const stdout = std.io.getStdOut();
46 var buf: [1]u8 = undefined;
47 const data = &std.ArrayList(u8).init(gpa);
48 while (true) {
49 // const len = try r.read(&buf);
50 // if (len == 0) {
51 // break;
52 // }
53 // TODO: workaround for https://github.com/alexnask/iguanaTLS/issues/7
54 const len = r.read(&buf) catch |err| switch (err) {
55 error.ServerMalformedResponse => break,
56 else => 0,
57 };
58 try data.appendSlice(buf[0..len]);
59 }
60
61 const index = std.mem.indexOf(u8, data.items, "\r\n\r\n").?;
62 const html_contents = data.items[index..];
63
64 var stream = std.json.TokenStream.init(html_contents[4..]);
65 const res = try std.json.parse([]Zpm.Package, &stream, .{ .allocator = gpa, });
66
67 const found = blk: {
68 for (res) |pkg| {
69 if (std.mem.eql(u8, pkg.name, args[0])) {
70 break :blk pkg;
71 }
72 }
73 u.assert(false, "no package with name '{s}' found", .{args[0]});
74 unreachable;
75 };
76
77 u.assert(found.root_file != null, "package must have an entry point to be able to be added to your dependencies", .{});
78
79 const self_module = try u.ModFile.init(gpa, "zig.mod");
80 for (self_module.deps) |dep| {
81 if (std.mem.eql(u8, dep.name, found.name)) {
82 u.assert(false, "dependency with name '{s}' already exists in your dependencies", .{found.name});
83 }
84 }
85
86 const file = try std.fs.cwd().openFile("zig.mod", .{ .read=true, .write=true });
87 try file.seekTo(try file.getEndPos());
88
89 const file_w = file.writer();
90 try file_w.print(" - src: git {s}\n", .{found.git});
91 try file_w.print(" name: {s}\n", .{found.name});
92 try file_w.print(" main: {s}\n", .{found.root_file.?[1..]});
93
94 std.log.info("Successfully added package {s} by {s}", .{found.name, found.author});
95}