Initial Commit

This commit is contained in:
2026-08-23 21:43:19 +03:00
commit 2a5df4609e
12 changed files with 348 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
./index
.zig-cache
zig-out
+24
View File
@@ -0,0 +1,24 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "xpk",
.root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize }),
});
b.installArtifact(exe);
const run_step = b.step("run", "Run the app");
const run_cmd = b.addRunArtifact(exe);
run_step.dependOn(&run_cmd.step);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
}
+10
View File
@@ -0,0 +1,10 @@
.{
.name = .xpk,
.version = "0.0.0",
.fingerprint = 0x50fc21dcc3f3cc25,
.minimum_zig_version = "0.16.0",
.dependencies = .{},
.paths = .{ "build.zig", "build.zig.zon", "src", ".gitignore" },
}
+2
View File
@@ -0,0 +1,2 @@
description A small example package
license MIT
+8
View File
@@ -0,0 +1,8 @@
pub const installed_directory = "./installed";
pub const index_directory = "./index";
pub const arch = "x86_64";
pub const repos = .{
.main = "http://localhost:3000",
};
+30
View File
@@ -0,0 +1,30 @@
const std = @import("std");
const config = @import("config.zig");
pub fn load(
init: std.process.Init,
repo_name: []const u8,
package_name: []const u8,
) ![]u8 {
const allocator = init.gpa;
const cwd = std.Io.Dir.cwd();
const path = try std.fmt.allocPrint(
allocator,
"{s}/{s}/{s}.mt",
.{
config.index_directory,
repo_name,
package_name,
},
);
defer allocator.free(path);
return try cwd.readFileAlloc(
init.io,
path,
allocator,
.limited(1024 * 1024),
);
}
+37
View File
@@ -0,0 +1,37 @@
const std = @import("std");
const index = @import("index.zig");
pub fn run(init: std.process.Init, args: []const [:0]const u8) !void {
if (args.len < 3) {
std.debug.print("usage: xpk install <package>\n", .{});
return;
}
const package_name = args[2];
const metadata = index.load(
init,
"main",
package_name,
) catch |err| {
if (err == error.FileNotFound) {
std.debug.print(
"package '{s}' is not in the local index\n",
.{package_name},
);
return;
}
return err;
};
defer init.gpa.free(metadata);
std.debug.print(
"metadata for {s}:\n{s}\n",
.{
package_name,
metadata,
},
);
}
+56
View File
@@ -0,0 +1,56 @@
const std = @import("std");
const Io = std.Io;
const config = @import("config.zig");
const network = @import("network.zig");
const install = @import("install.zig");
const repo = @import("repo.zig");
const Command = enum {
install,
remove,
sync,
search,
info,
};
fn parse_command(name: []const u8) !Command {
if (std.mem.eql(u8, name, "install")) return .install;
if (std.mem.eql(u8, name, "remove")) return .remove;
if (std.mem.eql(u8, name, "sync")) return .sync;
if (std.mem.eql(u8, name, "search")) return .search;
if (std.mem.eql(u8, name, "info")) return .info;
return error.UnknownCommand;
}
pub fn main(init: std.process.Init) !void {
const arena = init.arena.allocator();
const args = try init.minimal.args.toSlice(arena);
if (args.len < 2) {
std.debug.print("usage: xpk <command>\n", .{});
return;
}
const command = try parse_command(args[1]);
switch (command) {
.install => try install.run(init, args),
.remove => {
// later
},
.sync => try repo.sync(init),
.search => {
// later
},
.info => {
// later
},
}
}
+57
View File
@@ -0,0 +1,57 @@
const std = @import("std");
pub fn download(
io: std.Io,
allocator: std.mem.Allocator,
url: []const u8,
path: []const u8,
) !void {
var client = std.http.Client{
.allocator = allocator,
.io = io,
};
defer client.deinit();
const cwd = std.Io.Dir.cwd();
var file = try cwd.createFile(io, path, .{});
defer file.close(io);
var writer_buffer: [64 * 1024]u8 = undefined;
var writer = file.writer(io, &writer_buffer);
const response = try client.fetch(.{
.location = .{ .url = url },
.response_writer = &writer.interface,
});
if (response.status != .ok) {
return error.HttpError;
}
}
pub fn get(
io: std.Io,
allocator: std.mem.Allocator,
url: []const u8,
) ![]u8 {
var client = std.http.Client{
.allocator = allocator,
.io = io,
};
defer client.deinit();
var body = std.Io.Writer.Allocating.init(allocator);
defer body.deinit();
const response = try client.fetch(.{
.location = .{ .url = url },
.response_writer = &body.writer,
});
if (response.status != .ok) {
return error.HttpError;
}
return body.toOwnedSlice();
}
+8
View File
@@ -0,0 +1,8 @@
const std = @import("std");
pub const Package = struct {
name: []const u8,
version: []const u8,
description: ?[]const u8,
license: ?[]const u8,
};
View File
+113
View File
@@ -0,0 +1,113 @@
const std = @import("std");
const config = @import("config.zig");
const network = @import("network.zig");
pub fn sync(init: std.process.Init) !void {
const allocator = init.gpa;
const repo = "main";
const list_url = try std.fmt.allocPrint(
allocator,
"{s}/{s}/{s}/.mt",
.{
config.repos.main,
repo,
config.arch,
},
);
defer allocator.free(list_url);
std.debug.print("syncing {s}\n", .{list_url});
const list = try network.get(
init.io,
allocator,
list_url,
);
defer allocator.free(list);
const cwd = std.Io.Dir.cwd();
cwd.createDir(
init.io,
config.index_directory,
.default_dir,
) catch |err| switch (err) {
error.PathAlreadyExists => {},
else => return err,
};
const index_path = try std.fmt.allocPrint(
allocator,
"{s}/{s}",
.{
config.index_directory,
repo,
},
);
defer allocator.free(index_path);
cwd.createDir(
init.io,
index_path,
.default_dir,
) catch |err| switch (err) {
error.PathAlreadyExists => {},
else => return err,
};
var lines = std.mem.splitScalar(u8, list, '\n');
while (lines.next()) |line| {
const package = std.mem.trim(u8, line, " \r\t");
if (package.len == 0)
continue;
const url = try std.fmt.allocPrint(
allocator,
"{s}/{s}/{s}/{s}/.mt",
.{
config.repos.main,
repo,
config.arch,
package,
},
);
defer allocator.free(url);
std.debug.print(" {s}\n", .{package});
const metadata = try network.get(
init.io,
init.gpa,
url,
);
defer init.gpa.free(metadata);
const path = try std.fmt.allocPrint(
allocator,
"{s}/{s}.mt",
.{
index_path,
package,
},
);
defer allocator.free(path);
var file = try cwd.createFile(
init.io,
path,
.{},
);
defer file.close(init.io);
try file.writeStreamingAll(
init.io,
metadata,
);
}
std.debug.print("sync complete\n", .{});
}