summaryrefslogtreecommitdiff
path: root/src/install.zig
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2022-04-25 05:09:55 +0300
committerGravatar Uko Kokņevičs2022-04-25 23:34:05 +0300
commitd303b53f2ced75703bf022a5d337ee3ba530b288 (patch)
treef2e64057120d01ee8a821596ea01b8fc37c53c2c /src/install.zig
downloadzup-d303b53f2ced75703bf022a5d337ee3ba530b288.tar.gz
zup-d303b53f2ced75703bf022a5d337ee3ba530b288.tar.xz
zup-d303b53f2ced75703bf022a5d337ee3ba530b288.zip
Initial commit0.1.0
Diffstat (limited to 'src/install.zig')
-rw-r--r--src/install.zig101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/install.zig b/src/install.zig
new file mode 100644
index 0000000..7a52d44
--- /dev/null
+++ b/src/install.zig
@@ -0,0 +1,101 @@
1const libarchive = @import("libarchive");
2const curl = @import("curl");
3const std = @import("std");
4const xdg = @import("xdg");
5const zup = @import("zup");
6
7const Allocator = std.mem.Allocator;
8const ArchiveRead = libarchive.Read;
9const Installation = zup.Installation;
10const Installations = zup.Installations;
11
12pub const params =
13 \\-f, --force Install over existing installations
14 \\<NAME>
15;
16pub const description = "Installs a Zig version. Run `zup list -i` to see installed <NAME>s.";
17pub const min_args = 1;
18pub const max_args = 1;
19
20pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void {
21 var available = try Installation.getAvailableList(allocator);
22 defer Installation.deinitMap(allocator, &available);
23
24 return perform(allocator, res.positionals[0], res.args.force, available);
25}
26
27pub fn perform(allocator: Allocator, name: []const u8, force: bool, available: Installations) !void {
28 if (!force and try Installation.isInstalled(allocator, name)) {
29 std.log.err("{s} already installed, not overwriting without --force!", .{name});
30 return error.AlreadyInstalled;
31 }
32
33 const installation = available.get(name) orelse {
34 std.log.err("Installation by name {s} not available!", .{name});
35 return error.InstallationNotFound;
36 };
37
38 if (installation.url == null) {
39 std.log.err("No tarball URL for {s} found!", .{name});
40 }
41
42 const installation_dir = blk: {
43 const data_home = try xdg.getDataHome(allocator, "zup");
44 defer allocator.free(data_home);
45
46 break :blk try std.fs.path.join(allocator, &.{ data_home, name });
47 };
48 defer allocator.free(installation_dir);
49
50 std.log.info("Installing {s}, version {}", .{ name, installation.version });
51 const filename = std.fs.path.basename(installation.url.?);
52
53 // TODO: Platform-agnostic tempfile creation
54 var tmpname = try std.fmt.allocPrintZ(allocator, "/tmp/{s}", .{filename});
55 defer allocator.free(tmpname);
56
57 var tmpdir = try std.fs.openDirAbsolute(std.fs.path.dirname(tmpname).?, .{});
58 defer tmpdir.close();
59
60 var tmpfile = try tmpdir.createFile(filename, .{});
61 defer {
62 tmpfile.close();
63 std.log.info("Deleting /tmp/{s}...", .{filename});
64 tmpdir.deleteFile(filename) catch |err| {
65 std.log.warn("Failed to delete /tmp/{s}: {}", .{ filename, err });
66 };
67 }
68
69 std.log.info("Downloading to /tmp/{s}...", .{filename});
70 try curl.easyDownloadToFile(&tmpfile, installation.url.?);
71
72 std.log.info("Extracting...", .{});
73 var archive = try ArchiveRead.init();
74 defer archive.deinit();
75
76 try archive.supportFilter(.all);
77 try archive.supportFormat(.all);
78 try archive.openFilename(tmpname, 10240);
79
80 while (try archive.nextHeader()) |*entry| {
81 const source = entry.pathname();
82 const dest = try preparePathname(allocator, installation_dir, source);
83 defer allocator.free(dest);
84
85 entry.setPathname(dest);
86 try archive.extract(entry.*, 0);
87 }
88
89 std.log.info("Installed to {s}", .{installation_dir});
90 // TODO: Check if it is already active
91 std.log.info("If you want to use this installation, run `zup switch {s}`", .{name});
92}
93
94fn preparePathname(allocator: Allocator, installation_dir: []const u8, source: []const u8) ![:0]u8 {
95 const stripped = if (std.mem.indexOfScalar(u8, source, '/')) |idx|
96 source[idx + 1 ..]
97 else
98 "";
99
100 return std.fs.path.joinZ(allocator, &.{ installation_dir, stripped });
101}