Skip to content

Commit

Permalink
feat: support download zls
Browse files Browse the repository at this point in the history
  • Loading branch information
jinzhongjia committed Aug 6, 2024
1 parent 305c5e9 commit 25053c7
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 29 deletions.
19 changes: 16 additions & 3 deletions src/alias.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,22 @@ pub fn set_zig_version(version: []const u8) !void {
defer arena.deinit();
const arena_allocator = arena.allocator();

const user_home = tools.get_home();
const version_path = try std.fs.path.join(arena_allocator, &[_][]const u8{ user_home, ".zm", "version", version });
const symlink_path = try tools.get_zvm_path_segment(arena_allocator, "current");
try tools.try_create_path(try tools.get_zvm_path_segment(arena_allocator, "current"));

const version_path = try std.fs.path.join(
arena_allocator,
&.{ try tools.get_zvm_zig_version(arena_allocator), version },
);

std.fs.accessAbsolute(version_path, .{}) catch |err| {
if (err != error.FileNotFound)
return err;

std.debug.print("zig {s} is not installed, please install it!\n", .{version});
std.process.exit(1);
};

const symlink_path = try tools.get_zvm_current_zig(arena_allocator);

try update_current(version_path, symlink_path);
try verify_zig_version(version);
Expand Down
24 changes: 14 additions & 10 deletions src/command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ const command_opts = [_]CommandOption{

/// Parse and handle commands
pub fn handle_command(params: []const []const u8) !void {
if (builtin.os.tag != .windows) {
if (std.mem.eql(u8, std.fs.path.basename(params[0]), "zig"))
try handle_alias(params);
}

const command: CommandData = blk: {
if (params.len < 2) break :blk CommandData{};

Expand Down Expand Up @@ -100,16 +95,22 @@ pub fn handle_command(params: []const []const u8) !void {
}
}

fn handle_alias(params: []const []const u8) !void {
/// handle alias, now only support zig
pub fn handle_alias(params: []const []const u8) !void {
if (builtin.os.tag != .windows) {
if (!std.mem.eql(u8, std.fs.path.basename(params[0]), "zig"))
return;
}

var arena = std.heap.ArenaAllocator.init(tools.get_allocator());
defer arena.deinit();

const allocator = arena.allocator();

const new_params = try allocator.dupe([]const u8, params);

const home = tools.get_home();
const current_zig_path = try std.fs.path.join(allocator, &.{ home, ".zm", "current", "zig" });
const current_zig = try tools.get_zvm_current_zig(allocator) ;
const current_zig_path = try std.fs.path.join(allocator, &.{ current_zig, "zig" });

std.fs.accessAbsolute(current_zig_path, .{}) catch |err| {
if (err == std.fs.Dir.AccessError.FileNotFound) {
Expand Down Expand Up @@ -173,8 +174,11 @@ fn install_version(subcmd: ?[]const u8, param: ?[]const u8) !void {
std.debug.print("Please specify a version to install using 'install zig <version>'.\n", .{});
}
} else if (std.mem.eql(u8, scmd, "zls")) {
// Handle ZLS installation if supported
std.debug.print("[Unsupported] install zls\n", .{});
if (param) |version| {
try install.install_zls(version);
} else {
std.debug.print("Please specify a version to install using 'install zls <version>'.\n", .{});
}
} else {
std.debug.print("Unknown subcommand '{s}'. Use 'install zig <version>' or 'install zls <version>'.\n", .{scmd});
}
Expand Down
5 changes: 4 additions & 1 deletion src/config.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,7 @@ pub const zig_name = switch (builtin.os.tag) {
};

/// zig archive_ext
pub const zig_archive_ext = if (builtin.os.tag == .windows) "zip" else "tar.xz";
pub const archive_ext = if (builtin.os.tag == .windows)
"zip"
else
"tar.xz";
9 changes: 5 additions & 4 deletions src/extract.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@ const xz = std.compress.xz;
const tar = std.tar;

/// extract file to out_dir
pub fn extrace(
pub fn extract(
out_dir: std.fs.Dir,
file: std.fs.File,
file_type: enum { tarxz, zip },
is_zls: bool,
) !void {
switch (file_type) {
.zip => try extract_zip_dir(out_dir, file),
.tarxz => try extract_tarxz_to_dir(out_dir, file),
.tarxz => try extract_tarxz_to_dir(out_dir, file, is_zls),
}
}

/// extract tar.xz to dir
fn extract_tarxz_to_dir(out_dir: std.fs.Dir, file: std.fs.File) !void {
fn extract_tarxz_to_dir(out_dir: std.fs.Dir, file: std.fs.File, is_zls: bool) !void {
var buffered_reader = std.io.bufferedReader(file.reader());

var decompressed = try xz.decompress(tools.get_allocator(), buffered_reader.reader());
Expand All @@ -27,7 +28,7 @@ fn extract_tarxz_to_dir(out_dir: std.fs.Dir, file: std.fs.File) !void {
try tar.pipeToFileSystem(
out_dir,
decompressed.reader(),
.{ .mode_mode = .executable_bit_only, .strip_components = 1 },
.{ .mode_mode = .executable_bit_only, .strip_components = if (is_zls) 0 else 1 },
);
}

Expand Down
66 changes: 63 additions & 3 deletions src/install.zig
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn install_zig(version: []const u8) !void {
const arena_allocator = arena.allocator();

// get version path
const version_path = try tools.get_zvm_path_segment(arena_allocator, "version");
const version_path = try tools.get_zvm_zig_version(arena_allocator);
// get extract path
const extract_path = try std.fs.path.join(arena_allocator, &.{ version_path, version });

Expand All @@ -56,7 +56,7 @@ pub fn install_zig(version: []const u8) !void {
const file_name = try std.mem.concat(
arena_allocator,
u8,
&.{ "zig-", reverse_platform_str, "-", version, ".", config.zig_archive_ext },
&.{ "zig-", reverse_platform_str, "-", version, ".", config.archive_ext },
);

const parsed_uri = std.Uri.parse(version_data.tarball) catch unreachable;
Expand All @@ -66,7 +66,67 @@ pub fn install_zig(version: []const u8) !void {
try tools.try_create_path(extract_path);
const extract_dir = try std.fs.openDirAbsolute(extract_path, .{});

try extract.extrace(extract_dir, new_file, if (builtin.os.tag == .windows) .zip else .tarxz);
try extract.extract(extract_dir, new_file, if (builtin.os.tag == .windows) .zip else .tarxz, false);

try alias.set_zig_version(version);
}

/// Try to install the specified version of zls
pub fn install_zls(version: []const u8) !void {
const allocator = tools.get_allocator();

const reverse_platform_str = try architecture.platform_str(architecture.DetectParams{
.os = builtin.os.tag,
.arch = builtin.cpu.arch,
.reverse = true,
}) orelse unreachable;

var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();

const arena_allocator = arena.allocator();

// get version data
const version_data: meta.Zls.VersionData = blk: {
const res = try tools.http_get(arena_allocator, config.zls_url);
var zls_meta = try meta.Zls.init(res, arena_allocator);
const tmp_val = try zls_meta.get_version_data(version, reverse_platform_str, arena_allocator);
break :blk tmp_val orelse return error.UnsupportedVersion;
};

const file_name = try std.mem.concat(
arena_allocator,
u8,
&.{ "zls-", reverse_platform_str, "-", version, ".", config.archive_ext },
);

const parsed_uri = std.Uri.parse(version_data.tarball) catch unreachable;
const new_file = try tools.download(parsed_uri, file_name, null, version_data.size);
defer new_file.close();

// get version path
const version_path = try tools.get_zvm_zls_version(arena_allocator);
// get extract path
const extract_path = try std.fs.path.join(arena_allocator, &.{ version_path, version });

try tools.try_create_path(extract_path);

const extract_dir = try std.fs.openDirAbsolute(extract_path, .{});
try extract.extract(extract_dir, new_file, if (builtin.os.tag == .windows) .zip else .tarxz, true);

std.debug.print(
\\zls version data:
\\version: {s}
\\id: {}
\\size: {}
\\tarball: {s}
\\
, .{
version_data.version,
version_data.id,
version_data.size,
version_data.tarball,
});
}

pub fn build_zls() !void {}
3 changes: 3 additions & 0 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub fn main() !void {
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);

// try handle alias
try command.handle_alias(args);

// parse the args and handle command
try command.handle_command(args);
}
53 changes: 53 additions & 0 deletions src/meta.zig
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,19 @@ pub const Zig = struct {
pub const Zls = struct {
data: jsonValue,

/// version data for zig
pub const VersionData = struct {
version: []const u8,
id: usize,
tarball: []const u8,
size: usize,

pub fn deinit(self: VersionData, allocator: Allocator) void {
allocator.free(self.version);
allocator.free(self.tarball);
}
};

// init the zig data
pub fn init(raw: []const u8, allocator: Allocator) !Zls {
const data =
Expand All @@ -149,6 +162,46 @@ pub const Zls = struct {
self.data.deinit();
}

pub fn get_version_data(
self: *Zls,
version: []const u8,
platform_str: []const u8,
allocator: Allocator,
) !?VersionData {
const file_name = try std.fmt.allocPrint(
allocator,
"zls-{s}.{s}",
.{ platform_str, config.archive_ext },
);
for (self.data.value.array.items) |item| {
const item_obj = item.object;

const tag = item_obj.get("tag_name") orelse continue;
if (!tools.eql_str(version, tag.string)) continue;

const assets = item_obj.get("assets") orelse continue;
for (assets.array.items) |asset| {
const asset_obj = asset.object;

const name = asset_obj.get("name") orelse continue;
if (!tools.eql_str(file_name, name.string)) continue;

const tarball = asset_obj.get("browser_download_url") orelse return null;
const id = asset_obj.get("id") orelse return null;
const size = asset_obj.get("size") orelse return null;

return VersionData{
.version = try allocator.dupe(u8, version),
.id = @intCast(id.integer),
.tarball = try allocator.dupe(u8, tarball.string),
.size = @intCast(size.integer),
};
}
break;
}
return null;
}

/// return the version list
pub fn get_version_list(self: *Zls, allocator: Allocator) ![][]const u8 {
var list = std.ArrayList([]const u8).init(allocator);
Expand Down
41 changes: 33 additions & 8 deletions src/tools.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,36 @@ pub fn get_allocator() std.mem.Allocator {
}

/// Get zvm path segment
pub fn get_zvm_path_segment(tmp_allocator: std.mem.Allocator, segment: []const u8) ![]u8 {
return std.fs.path.join(
tmp_allocator,
&[_][]const u8{ get_home(), ".zm", segment },
);
pub fn get_zvm_path_segment(allocator: std.mem.Allocator, segment: []const u8) ![]u8 {
return try std.fs.path.join(allocator, &[_][]const u8{ get_home(), ".zm", segment });
}

pub fn get_zvm_current_zig(allocator: std.mem.Allocator) ![]u8 {
const current = try get_zvm_path_segment(allocator, "current");
defer allocator.free(current);
return try std.fs.path.join(allocator, &[_][]const u8{ current, "zig" });
}

pub fn get_zvm_current_zls(allocator: std.mem.Allocator) ![]u8 {
const current = try get_zvm_path_segment(allocator, "current");
defer allocator.free(current);
return try std.fs.path.join(allocator, &[_][]const u8{ current, "zls" });
}

pub fn get_zvm_store(allocator: std.mem.Allocator) ![]u8 {
return get_zvm_path_segment(allocator, "store");
}

pub fn get_zvm_zig_version(allocator: std.mem.Allocator) ![]u8 {
const current = try get_zvm_path_segment(allocator, "version");
defer allocator.free(current);
return try std.fs.path.join(allocator, &[_][]const u8{ current, "zig" });
}

pub fn get_zvm_zls_version(allocator: std.mem.Allocator) ![]u8 {
const current = try get_zvm_path_segment(allocator, "version");
defer allocator.free(current);
return try std.fs.path.join(allocator, &[_][]const u8{ current, "zls" });
}

/// Free str array
Expand Down Expand Up @@ -133,7 +158,7 @@ pub fn try_create_path(path: []const u8) !void {
/// try to get zig version
pub fn get_zig_version(allocator: std.mem.Allocator) ![]u8 {
const home_dir = get_home();
const current_zig_path = try std.fs.path.join(allocator, &.{ home_dir, ".zm", "current", config.zig_name });
const current_zig_path = try std.fs.path.join(allocator, &.{ home_dir, ".zm", "current", "zig", config.zig_name });
defer allocator.free(current_zig_path);

// here we must use the absolute path, we can not just use "zig"
Expand Down Expand Up @@ -249,14 +274,14 @@ pub fn download(
return file;
}
}
try std.fs.deleteFileAbsolute(file_name);
try store.deleteFile(file_name);
}

// http client
var client = std.http.Client{ .allocator = allocator };
defer client.deinit();

var header_buffer: [1024]u8 = undefined; // 1024b
var header_buffer: [10240]u8 = undefined; // 1024b

var req = try client.open(.GET, uri, .{ .server_header_buffer = &header_buffer });
defer req.deinit();
Expand Down

0 comments on commit 25053c7

Please sign in to comment.