Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add zls support #58

Merged
merged 26 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4ad28d0
fix typo
jinzhongjia Jul 28, 2024
c9863ff
support parse zls version list
jinzhongjia Jul 28, 2024
2d86d1b
fix command parse
jinzhongjia Jul 31, 2024
ae3f8fa
some change
jinzhongjia Jul 31, 2024
7cd8355
remove `hash.zig`
jinzhongjia Jul 31, 2024
b8a6cbd
feat: add `zvm ls zig` and `zvm ls zls`
jinzhongjia Aug 2, 2024
eaf79c5
remove useless comment
jinzhongjia Aug 2, 2024
c980dd2
function integration, remove `fetch_version_data` and use `meta.Zig.g…
jinzhongjia Aug 2, 2024
b0d1698
simplify code
jinzhongjia Aug 4, 2024
7e3cd05
Refactoring the zig download section
jinzhongjia Aug 4, 2024
f553563
Before downloading, check whether the file already exists. If there i…
jinzhongjia Aug 4, 2024
37cf22c
When there is content in the version directory, use it directly
jinzhongjia Aug 4, 2024
1d42ad8
Modify zls resource acquisition logic
jinzhongjia Aug 5, 2024
305c5e9
remove download file
jinzhongjia Aug 5, 2024
25053c7
feat: support download zls
jinzhongjia Aug 6, 2024
0f2c85f
feat: support install zls
jinzhongjia Aug 6, 2024
148de26
feat: support alias zig and zls
jinzhongjia Aug 7, 2024
ffc245d
add command `remove <version>` and `remove zig/zls <version>`
jinzhongjia Aug 7, 2024
cba75d5
rename `tools.get_version` to `tools.get_current_version`
jinzhongjia Aug 7, 2024
c82c31c
add file module comment
jinzhongjia Aug 7, 2024
c4da338
Text modification
jinzhongjia Aug 8, 2024
ada0c04
Split `tools.zig` into `util/*.zig`, and put arch and extract related…
jinzhongjia Aug 8, 2024
1940599
remove useless code
jinzhongjia Aug 8, 2024
4487078
format code
jinzhongjia Aug 8, 2024
2f5061a
fix
jinzhongjia Aug 9, 2024
6045071
fix for windows platform
jinzhongjia Aug 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 38 additions & 24 deletions src/command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -53,33 +53,46 @@ pub fn handle_command(params: []const []const u8) !void {

const args = params[1..];

for (args, 0..) |arg, index| {
for (command_opts) |opt| {
const is_eql_short_handle = if (opt.short_handle) |short_handle|
std.mem.eql(u8, arg, short_handle)
else
false;

const is_eql_handle = std.mem.eql(u8, arg, opt.handle);

if (!is_eql_short_handle and !is_eql_handle)
continue;

const next_param = if (index + 1 < args.len) args[index + 1] else null;
const is_version = if (next_param) |np| std.ascii.isDigit(np[0]) else false;

break :blk CommandData{
.cmd = opt.cmd,
.param = if (is_version) next_param else null,
.subcmd = if (!is_version) next_param else null,
};
}
// for (args, 0..) |arg, index| {
jinzhongjia marked this conversation as resolved.
Show resolved Hide resolved
const arg = args[0];
for (command_opts) |opt| {
const is_eql_short_handle = if (opt.short_handle) |short_handle|
std.mem.eql(u8, arg, short_handle)
else
false;

const is_eql_handle = std.mem.eql(u8, arg, opt.handle);

if (!is_eql_short_handle and !is_eql_handle)
continue;

const subcmd = if (args.len > 2) args[1] else null;
const param = kk: {
if (subcmd != null) {
break :kk args[2];
}

if (args.len > 1)
break :kk args[1];

break :kk null;
};

// const next_param = if (index + 1 < args.len) args[index + 1] else null;
// const is_version = if (next_param) |np| std.ascii.isDigit(np[0]) else false;

break :blk CommandData{
.cmd = opt.cmd,
.subcmd = subcmd,
.param = param,
};
}
// }
break :blk CommandData{};
};

switch (command.cmd) {
.List => try handle_list(),
.List => try handle_list(command.param),
.Install => try install_version(command.subcmd, command.param),
.Use => try use_version(command.param),
.Default => try set_default(),
Expand Down Expand Up @@ -112,9 +125,10 @@ fn handle_alias(params: []const []const u8) !void {
return std.process.execv(allocator, new_params);
}

fn handle_list() !void {
fn handle_list(_: ?[]const u8) !void {
// TODO:
const allocator = tools.get_allocator();
var version_list = try versions.VersionList.init(allocator);
var version_list = try versions.VersionList.init(allocator, .zig);
defer version_list.deinit();

for (version_list.slice()) |version| {
Expand Down
21 changes: 20 additions & 1 deletion src/config.zig
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
pub const download_manifest_url: []const u8 = "https://ziglang.org/download/index.json";
const std = @import("std");
const builtin = @import("builtin");

var allocator: std.mem.Allocator = undefined;
var home_dir: []const u8 = undefined;

pub const zig_meta_url: []const u8 = "https://ziglang.org/download/index.json";
pub const zls_meta_url: []const u8 = "https://zigtools-releases.nyc3.digitaloceanspaces.com/zls/index.json";

pub const zig_url = std.Uri.parse(zig_meta_url) catch unreachable;
pub const zls_url = std.Uri.parse(zls_meta_url) catch unreachable;

pub const zig_name = switch (builtin.os.tag) {
.windows => "zig.exe",
.linux => "zig",
.macos => "zig",
else => @compileError("not support current platform"),
};
jinzhongjia marked this conversation as resolved.
Show resolved Hide resolved

pub const archive_ext = if (builtin.os.tag == .windows) "zip" else "tar.xz";
4 changes: 1 addition & 3 deletions src/download.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ const alias = @import("alias.zig");
const hash = @import("hash.zig");
const lib = @import("extract.zig");

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

pub fn content(allocator: std.mem.Allocator, version: []const u8, url: []const u8) !?[32]u8 {
assert(version.len > 0);
assert(url.len > 0);
Expand Down Expand Up @@ -113,7 +111,7 @@ fn download_and_extract(
.reverse = false,
}) orelse unreachable;

const file_name = try std.mem.concat(allocator, u8, &[_][]const u8{ "zig-", platform_str, "-", version, ".", archive_ext });
const file_name = try std.mem.concat(allocator, u8, &[_][]const u8{ "zig-", platform_str, "-", version, ".", tools.archive_ext });
defer allocator.free(file_name);

const total_size: usize = @intCast(req.response.content_length orelse 0);
Expand Down
40 changes: 0 additions & 40 deletions src/hash.zig

This file was deleted.

6 changes: 3 additions & 3 deletions src/install.zig
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const std = @import("std");
const builtin = @import("builtin");
const config = @import("config.zig");
const hash = @import("hash.zig");
const download = @import("download.zig");
const architecture = @import("architecture.zig");
const tools = @import("tools.zig");
Expand Down Expand Up @@ -30,7 +29,7 @@ const Error = error{
};

fn fetch_version_data(allocator: Allocator, requested_version: []const u8, sub_key: []const u8) !?Version {
const uri = std.Uri.parse(config.download_manifest_url) catch unreachable;
const uri = config.zig_url;

var client = std.http.Client{ .allocator = allocator };
defer client.deinit();
Expand Down Expand Up @@ -96,6 +95,7 @@ fn fetch_version_data(allocator: Allocator, requested_version: []const u8, sub_k
return null;
}

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

Expand All @@ -115,7 +115,7 @@ pub fn from_version(version: []const u8) !void {
if (data.shasum) |actual_shasum| {
const computed_hash = try download.content(allocator, data.name, data.tarball.?);
if (computed_hash) |shasum| {
if (!hash.verify_hash(shasum, actual_shasum)) {
if (!tools.verify_hash(shasum, actual_shasum)) {
return error.HashMismatch;
}
}
Expand Down
80 changes: 80 additions & 0 deletions src/meta.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const std = @import("std");
const config = @import("config.zig");

const json = std.json;
const Allocator = std.mem.Allocator;
const jsonValue = std.json.Parsed(std.json.Value);

pub const Zig = struct {
data: jsonValue,

// init the zig data
pub fn init(raw: []const u8, allocator: Allocator) !Zig {
const data =
try json.parseFromSlice(std.json.Value, allocator, raw, .{});

return Zig{ .data = data };
}

// deinit the zig data
pub fn deinit(self: *Zig) void {
self.data.deinit();
}

/// return the version list
pub fn get_version_list(self: *Zig, allocator: Allocator) ![][]const u8 {
const root = self.data.value;

var list = std.ArrayList([]const u8).init(allocator);
var iterate = root.object.iterator();

while (iterate.next()) |entry| {
const key_ptr = entry.key_ptr;
const key = key_ptr.*;

const key_copy = try allocator.dupe(u8, key);
try list.append(key_copy);
}

return try list.toOwnedSlice();
}
};

pub const Zls = struct {
data: jsonValue,

// init the zig data
pub fn init(raw: []const u8, allocator: Allocator) !Zls {
const data =
try json.parseFromSlice(std.json.Value, allocator, raw, .{});

return Zls{ .data = data };
}

// deinit the zig data
pub fn deinit(self: *Zls) void {
self.data.deinit();
}

/// return the version list
pub fn get_version_list(self: *Zls, allocator: Allocator) ![][]const u8 {
var zls_versions =
self.data.value.object.get("versions") orelse
return error.NotFoundZlsVersion;

var list = std.ArrayList([]const u8).init(allocator);

var iterate = zls_versions.object.iterator();
while (iterate.next()) |entry| {
const key_ptr = entry.key_ptr;
const key = key_ptr.*;

const key_copy = try allocator.dupe(u8, key);
try list.append(key_copy);
}

const slice = try list.toOwnedSlice();

std.mem.reverse([]const u8, slice);
}
};
41 changes: 41 additions & 0 deletions src/tools.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const std = @import("std");
const builtin = @import("builtin");

const testing = std.testing;

var allocator: std.mem.Allocator = undefined;
var home_dir: []const u8 = undefined;

Expand All @@ -13,6 +15,8 @@ pub const zig_name = switch (builtin.os.tag) {
else => @compileError("not support current platform"),
};

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

/// Initialize the data.
pub fn data_init(tmp_allocator: std.mem.Allocator) !void {
allocator = tmp_allocator;
Expand Down Expand Up @@ -45,3 +49,40 @@ pub fn get_zvm_path_segment(tmp_allocator: std.mem.Allocator, segment: []const u
&[_][]const u8{ get_home(), ".zm", segment },
);
}

/// for verify hash
pub fn verify_hash(computed_hash: [32]u8, actual_hash_string: []const u8) bool {
jinzhongjia marked this conversation as resolved.
Show resolved Hide resolved
if (actual_hash_string.len != 64) return false; // SHA256 hash should be 64 hex characters

var actual_hash_bytes: [32]u8 = undefined;
var i: usize = 0;

for (actual_hash_string) |char| {
const byte = switch (char) {
'0'...'9' => char - '0',
'a'...'f' => char - 'a' + 10,
'A'...'F' => char - 'A' + 10,
else => return false, // Invalid character in hash string
};

if (i % 2 == 0) {
actual_hash_bytes[i / 2] = byte << 4;
} else {
actual_hash_bytes[i / 2] |= byte;
}

i += 1;
}

return std.mem.eql(u8, computed_hash[0..], actual_hash_bytes[0..]);
}

test "verify_hash basic test" {
const sample_hash: [32]u8 = [_]u8{ 0x33, 0x9a, 0x89, 0xdc, 0x08, 0x73, 0x6b, 0x84, 0xc4, 0x75, 0x2b, 0x3d, 0xed, 0xdc, 0x0f, 0x2c, 0x71, 0xb5, 0x0b, 0x66, 0xa2, 0x68, 0x5f, 0x26, 0x77, 0x9c, 0xbb, 0xac, 0x46, 0x11, 0x1b, 0x68 };

var sample_hash_hex: [64]u8 = undefined;
_ = std.fmt.bufPrint(&sample_hash_hex, "{}", .{std.fmt.fmtSliceHexLower(sample_hash[0..])}) catch unreachable;

try testing.expect(verify_hash(sample_hash, &sample_hash_hex));
try testing.expect(!verify_hash(sample_hash, "incorrect_hash"));
}
Loading
Loading