Skip to content

Commit

Permalink
Windows platform is basically available
Browse files Browse the repository at this point in the history
  • Loading branch information
jinzhongjia committed Jun 13, 2024
1 parent 8c33d2f commit 9ac46cf
Show file tree
Hide file tree
Showing 6 changed files with 553 additions and 26 deletions.
2 changes: 1 addition & 1 deletion build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub fn build(b: *std.Build) void {
.name = "zvm",
.root_source_file = .{ .src_path = .{ .owner = b, .sub_path = "src/main.zig" } },
.target = target,
.optimize = .ReleaseFast,
.optimize = optimize,
.version = version,
});

Expand Down
92 changes: 87 additions & 5 deletions src/alias.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std");
const builtin = @import("builtin");
const tools = @import("tools.zig");

pub fn setZigVersion(version: []const u8) !void {
Expand All @@ -16,14 +17,95 @@ pub fn setZigVersion(version: []const u8) !void {
}

fn updateSymlink(zigPath: []const u8, symlinkPath: []const u8) !void {
if (doesFileExist(symlinkPath)) try std.fs.cwd().deleteFile(symlinkPath);
std.posix.symlink(zigPath, symlinkPath) catch |err| switch (err) {
if (builtin.os.tag == .windows) {
if (std.fs.path.dirname(symlinkPath)) |dirname| {
var parent_dir = try std.fs.openDirAbsolute(dirname, .{
.iterate = true,
});
defer parent_dir.close();
try parent_dir.deleteTree(std.fs.path.basename(symlinkPath));
} else {
@panic("sorry, dirname is not avaiable!");
}
if (doesDirExist(symlinkPath)) try std.fs.deleteDirAbsolute(symlinkPath);
try copyDir(zigPath, symlinkPath);
} else {
if (doesFileExist(symlinkPath)) try std.fs.cwd().deleteFile(symlinkPath);
std.posix.symlink(zigPath, symlinkPath) catch |err| switch (err) {
error.PathAlreadyExists => {
try std.fs.cwd().deleteFile(symlinkPath);
try std.posix.symlink(zigPath, symlinkPath);
},
else => return err,
};
}
}

fn copyDir(source_dir: []const u8, dest_dir: []const u8) !void {
var source = try std.fs.openDirAbsolute(
source_dir,
.{ .iterate = true },
);
defer source.close();

// try make dir
std.fs.makeDirAbsolute(dest_dir) catch |err| switch (err) {
error.PathAlreadyExists => {
try std.fs.cwd().deleteFile(symlinkPath);
try std.posix.symlink(zigPath, symlinkPath);
// The path already exists and is a directory, nothing to do here
// std.debug.print("Versions directory already exists: {s}\n", .{version_path});
},
else => return err,
else => {
tools.log.err("make dir failed, dir is {s}", .{dest_dir});
return err;
},
};

var dest = try std.fs.openDirAbsolute(
dest_dir,
.{ .iterate = true },
);
defer dest.close();

var iterate = source.iterate();
const allocator = tools.getAllocator();
while (try iterate.next()) |entry| {
const entry_name = entry.name;

const source_sub_path = try std.fs.path.join(
allocator,
&.{ source_dir, entry_name },
);
defer allocator.free(source_sub_path);

const dest_sub_path = try std.fs.path.join(
allocator,
&.{ dest_dir, entry_name },
);
defer allocator.free(dest_sub_path);

switch (entry.kind) {
.directory => {
try copyDir(source_sub_path, dest_sub_path);
},
.file => {
try std.fs.copyFileAbsolute(source_sub_path, dest_sub_path, .{});
},
else => {},
}
}
}

fn doesDirExist(path: []const u8) bool {
const result = blk: {
_ = std.fs.openDirAbsolute(path, .{}) catch |err| {
switch (err) {
error.FileNotFound => break :blk false,
else => break :blk true,
}
};
break :blk true;
};
return result;
}

fn doesFileExist(path: []const u8) bool {
Expand Down
37 changes: 21 additions & 16 deletions src/download.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ const crypto = std.crypto;

const archive_ext = if (builtin.os.tag == .windows) "zip" else "tar.xz";

fn getZvmPathSegment(segment: []const u8) ![]u8 {
const user_home = tools.getHome();
return std.fs.path.join(std.heap.page_allocator, &[_][]const u8{ user_home, ".zm", segment });
}

pub fn content(allocator: std.mem.Allocator, version: []const u8, url: []const u8) !?[32]u8 {
// Initialize the Progress structure
const root_node = Progress.start(.{
Expand All @@ -25,11 +20,11 @@ pub fn content(allocator: std.mem.Allocator, version: []const u8, url: []const u

defer root_node.end();

const data_allocator = tools.getAllocator();
// Ensure version directory exists before any operation
const version_path = try getZvmPathSegment("versions");
defer allocator.free(version_path);
const version_path = try tools.getZvmPathSegment(data_allocator, "versions");
defer data_allocator.free(version_path);

defer allocator.free(version_path);
std.fs.cwd().makePath(version_path) catch |err| switch (err) {
error.PathAlreadyExists => {
// The path already exists and is a directory, nothing to do here
Expand All @@ -45,8 +40,8 @@ pub fn content(allocator: std.mem.Allocator, version: []const u8, url: []const u
const version_folder_name = try std.fmt.allocPrint(allocator, "versions/{s}", .{version});
defer allocator.free(version_folder_name);

const version_folder_path = try getZvmPathSegment(version_folder_name);
defer allocator.free(version_folder_path);
const version_folder_path = try tools.getZvmPathSegment(data_allocator, version_folder_name);
defer data_allocator.free(version_folder_path);

if (checkExistingVersion(version_folder_path)) {
std.debug.print("→ Version {s} is already installed.\n", .{version});
Expand Down Expand Up @@ -92,7 +87,13 @@ fn confirmUserChoice() bool {
return std.ascii.toLower(buffer[0]) == 'y';
}

fn downloadAndExtract(allocator: std.mem.Allocator, uri: std.Uri, version_path: []const u8, version: []const u8, root_node: std.Progress.Node) ![32]u8 {
fn downloadAndExtract(
allocator: std.mem.Allocator,
uri: std.Uri,
version_path: []const u8,
version: []const u8,
root_node: std.Progress.Node,
) ![32]u8 {
var client = std.http.Client{ .allocator = allocator };
defer client.deinit();

Expand Down Expand Up @@ -150,9 +151,13 @@ fn downloadAndExtract(allocator: std.mem.Allocator, uri: std.Uri, version_path:
const c_allocator = std.heap.c_allocator;

// ~/.zm/versions/zig-macos-x86_64-0.10.0.tar.xz
const zvm_path = try getZvmPathSegment("");
const downloaded_file_path = try std.fs.path.join(allocator, &.{ zvm_path, file_name });
defer allocator.free(downloaded_file_path);
const data_allocator = tools.getAllocator();

const zvm_path = try tools.getZvmPathSegment(data_allocator, "");
defer data_allocator.free(zvm_path);

const downloaded_file_path = try std.fs.path.join(data_allocator, &.{ zvm_path, file_name });
defer data_allocator.free(downloaded_file_path);

std.debug.print("Downloaded file path: {s}\n", .{downloaded_file_path});

Expand Down Expand Up @@ -180,8 +185,8 @@ fn downloadAndExtract(allocator: std.mem.Allocator, uri: std.Uri, version_path:
}

fn openOrCreateZvmDir() !std.fs.Dir {
const zvm_path = try getZvmPathSegment("");
defer std.heap.page_allocator.free(zvm_path);
const zvm_path = try tools.getZvmPathSegment(tools.getAllocator(), "");
defer tools.getAllocator().free(zvm_path);

const openDirOptions = .{ .access_sub_paths = true, .no_follow = false };
const potentialDir = std.fs.cwd().openDir(zvm_path, openDirOptions);
Expand Down
48 changes: 44 additions & 4 deletions src/extract.zig
Original file line number Diff line number Diff line change
@@ -1,8 +1,48 @@
const std = @import("std");
const builtin = @import("builtin");
const tools = @import("tools.zig");

pub fn extract_tarxz_to_dir(allocator: std.mem.Allocator, outDir: std.fs.Dir, file: std.fs.File) !void {
var buffered_reader = std.io.bufferedReader(file.reader());
var decompressed = try std.compress.xz.decompress(allocator, buffered_reader.reader());
defer decompressed.deinit();
try std.tar.pipeToFileSystem(outDir, decompressed.reader(), .{ .mode_mode = .executable_bit_only, .strip_components = 1 });
if (builtin.os.tag == .windows) {
try extract_zip_dir(outDir, file);
} else {
var buffered_reader = std.io.bufferedReader(file.reader());
var decompressed = try std.compress.xz.decompress(allocator, buffered_reader.reader());
defer decompressed.deinit();
try std.tar.pipeToFileSystem(outDir, decompressed.reader(), .{ .mode_mode = .executable_bit_only, .strip_components = 1 });
}
}

pub fn extract_zip_dir(outDir: std.fs.Dir, file: std.fs.File) !void {
var arena = std.heap.ArenaAllocator.init(tools.getAllocator());
defer arena.deinit();

const allocator = arena.allocator();

const tmp_path = try tools.getZvmPathSegment(allocator, "tmpdir");
defer std.fs.deleteDirAbsolute(tmp_path) catch unreachable;

// make tmp dir
try std.fs.makeDirAbsolute(tmp_path);
var tmp_dir = try std.fs.openDirAbsolute(tmp_path, .{ .iterate = true });

try std.zip.extract(tmp_dir, file.seekableStream(), .{});

var iterate = tmp_dir.iterate();

var sub_dir = blk: {
const entry = try iterate.next() orelse return error.NotFound;
break :blk try tmp_dir.openDir(entry.name, .{
.iterate = true,
});
};
defer sub_dir.close();
const sub_path = try sub_dir.realpathAlloc(allocator, "");
defer std.fs.deleteDirAbsolute(sub_path) catch unreachable;

var sub_iterate = sub_dir.iterate();

while (try sub_iterate.next()) |entry| {
try std.fs.rename(sub_dir, entry.name, outDir, entry.name);
}
}
Loading

0 comments on commit 9ac46cf

Please sign in to comment.