aboutsummaryrefslogtreecommitdiff
path: root/src/Package.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2023-02-17 01:44:08 +0000
committermlugg <mlugg@mlugg.co.uk>2023-02-21 01:59:37 +0000
commit705d2a3c2cd94faf8e16c660b3b342d6fe900e55 (patch)
tree4db97f8c31a2bbd4299418caf609aff219d543a6 /src/Package.zig
parentdc1f50e505105cabe1ed53951ca612778d6019ee (diff)
downloadzig-705d2a3c2cd94faf8e16c660b3b342d6fe900e55.tar.gz
zig-705d2a3c2cd94faf8e16c660b3b342d6fe900e55.zip
Implement new module CLI
Diffstat (limited to 'src/Package.zig')
-rw-r--r--src/Package.zig123
1 files changed, 94 insertions, 29 deletions
diff --git a/src/Package.zig b/src/Package.zig
index 5878e7bad6..68d67a6d62 100644
--- a/src/Package.zig
+++ b/src/Package.zig
@@ -22,17 +22,16 @@ pub const Table = std.StringHashMapUnmanaged(*Package);
root_src_directory: Compilation.Directory,
/// Relative to `root_src_directory`. May contain path separators.
root_src_path: []const u8,
+/// The dependency table of this module. Shared dependencies such as 'std', 'builtin', and 'root'
+/// are not specified in every dependency table, but instead only in the table of `main_pkg`.
+/// `Module.importFile` is responsible for detecting these names and using the correct package.
table: Table = .{},
-parent: ?*Package = null,
/// Whether to free `root_src_directory` on `destroy`.
root_src_directory_owned: bool = false,
-/// This information can be recovered from 'table', but it's more convenient to store on the package.
-name: []const u8,
/// Allocate a Package. No references to the slices passed are kept.
pub fn create(
gpa: Allocator,
- name: []const u8,
/// Null indicates the current working directory
root_src_dir_path: ?[]const u8,
/// Relative to root_src_dir_path
@@ -47,9 +46,6 @@ pub fn create(
const owned_src_path = try gpa.dupe(u8, root_src_path);
errdefer gpa.free(owned_src_path);
- const owned_name = try gpa.dupe(u8, name);
- errdefer gpa.free(owned_name);
-
ptr.* = .{
.root_src_directory = .{
.path = owned_dir_path,
@@ -57,7 +53,6 @@ pub fn create(
},
.root_src_path = owned_src_path,
.root_src_directory_owned = true,
- .name = owned_name,
};
return ptr;
@@ -65,7 +60,6 @@ pub fn create(
pub fn createWithDir(
gpa: Allocator,
- name: []const u8,
directory: Compilation.Directory,
/// Relative to `directory`. If null, means `directory` is the root src dir
/// and is owned externally.
@@ -79,9 +73,6 @@ pub fn createWithDir(
const owned_src_path = try gpa.dupe(u8, root_src_path);
errdefer gpa.free(owned_src_path);
- const owned_name = try gpa.dupe(u8, name);
- errdefer gpa.free(owned_name);
-
if (root_src_dir_path) |p| {
const owned_dir_path = try directory.join(gpa, &[1][]const u8{p});
errdefer gpa.free(owned_dir_path);
@@ -93,14 +84,12 @@ pub fn createWithDir(
},
.root_src_directory_owned = true,
.root_src_path = owned_src_path,
- .name = owned_name,
};
} else {
ptr.* = .{
.root_src_directory = directory,
.root_src_directory_owned = false,
.root_src_path = owned_src_path,
- .name = owned_name,
};
}
return ptr;
@@ -110,7 +99,6 @@ pub fn createWithDir(
/// inside its table; the caller is responsible for calling destroy() on them.
pub fn destroy(pkg: *Package, gpa: Allocator) void {
gpa.free(pkg.root_src_path);
- gpa.free(pkg.name);
if (pkg.root_src_directory_owned) {
// If root_src_directory.path is null then the handle is the cwd()
@@ -130,15 +118,97 @@ pub fn deinitTable(pkg: *Package, gpa: Allocator) void {
pkg.table.deinit(gpa);
}
-pub fn add(pkg: *Package, gpa: Allocator, package: *Package) !void {
+pub fn add(pkg: *Package, gpa: Allocator, name: []const u8, package: *Package) !void {
try pkg.table.ensureUnusedCapacity(gpa, 1);
- pkg.table.putAssumeCapacityNoClobber(package.name, package);
+ const name_dupe = try gpa.dupe(u8, name);
+ pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
}
-pub fn addAndAdopt(parent: *Package, gpa: Allocator, child: *Package) !void {
- assert(child.parent == null); // make up your mind, who is the parent??
- child.parent = parent;
- return parent.add(gpa, child);
+/// Compute a readable name for the package. The returned name should be freed from gpa. This
+/// function is very slow, as it traverses the whole package hierarchy to find a path to this
+/// package. It should only be used for error output.
+pub fn getName(target: *const Package, gpa: Allocator, mod: Module) ![]const u8 {
+ // we'll do a breadth-first search from the root module to try and find a short name for this
+ // module, using a TailQueue of module/parent pairs. note that the "parent" there is just the
+ // first-found shortest path - a module may be children of arbitrarily many other modules.
+ // also, this path may vary between executions due to hashmap iteration order, but that doesn't
+ // matter too much.
+ var node_arena = std.heap.ArenaAllocator.init(gpa);
+ defer node_arena.deinit();
+ const Parented = struct {
+ parent: ?*const @This(),
+ mod: *const Package,
+ };
+ const Queue = std.TailQueue(Parented);
+ var to_check: Queue = .{};
+
+ {
+ const new = try node_arena.allocator().create(Queue.Node);
+ new.* = .{ .data = .{ .parent = null, .mod = mod.root_pkg } };
+ to_check.prepend(new);
+ }
+
+ if (mod.main_pkg != mod.root_pkg) {
+ const new = try node_arena.allocator().create(Queue.Node);
+ // TODO: once #12201 is resolved, we may want a way of indicating a different name for this
+ new.* = .{ .data = .{ .parent = null, .mod = mod.main_pkg } };
+ to_check.prepend(new);
+ }
+
+ // set of modules we've already checked to prevent loops
+ var checked = std.AutoHashMap(*const Package, void).init(gpa);
+ defer checked.deinit();
+
+ const linked = while (to_check.pop()) |node| {
+ const check = &node.data;
+
+ if (checked.contains(check.mod)) continue;
+ try checked.put(check.mod, {});
+
+ if (check.mod == target) break check;
+
+ var it = check.mod.table.iterator();
+ while (it.next()) |kv| {
+ var new = try node_arena.allocator().create(Queue.Node);
+ new.* = .{ .data = .{
+ .parent = check,
+ .mod = kv.value_ptr.*,
+ } };
+ to_check.prepend(new);
+ }
+ } else {
+ // this can happen for e.g. @cImport packages
+ return gpa.dupe(u8, "<unnamed>");
+ };
+
+ // we found a path to the module! unfortunately, we can only traverse *up* it, so we have to put
+ // all the names into a buffer so we can then print them in order.
+ var names = std.ArrayList([]const u8).init(gpa);
+ defer names.deinit();
+
+ var cur: *const Parented = linked;
+ while (cur.parent) |parent| : (cur = parent) {
+ // find cur's name in parent
+ var it = parent.mod.table.iterator();
+ const name = while (it.next()) |kv| {
+ if (kv.value_ptr.* == cur.mod) {
+ break kv.key_ptr.*;
+ }
+ } else unreachable;
+ try names.append(name);
+ }
+
+ // finally, print the names into a buffer!
+ var buf = std.ArrayList(u8).init(gpa);
+ defer buf.deinit();
+ try buf.writer().writeAll("root");
+ var i: usize = names.items.len;
+ while (i > 0) {
+ i -= 1;
+ try buf.writer().print(".{s}", .{names.items[i]});
+ }
+
+ return buf.toOwnedSlice();
}
pub const build_zig_basename = "build.zig";
@@ -236,7 +306,7 @@ pub fn fetchAndAddDependencies(
color,
);
- try addAndAdopt(pkg, gpa, sub_pkg);
+ try add(pkg, gpa, fqn, sub_pkg);
try dependencies_source.writer().print(" pub const {s} = @import(\"{}\");\n", .{
std.zig.fmtId(fqn), std.zig.fmtEscapes(fqn),
@@ -248,7 +318,6 @@ pub fn fetchAndAddDependencies(
pub fn createFilePkg(
gpa: Allocator,
- name: []const u8,
cache_directory: Compilation.Directory,
basename: []const u8,
contents: []const u8,
@@ -269,7 +338,7 @@ pub fn createFilePkg(
const o_dir_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;
try renameTmpIntoCache(cache_directory.handle, tmp_dir_sub_path, o_dir_sub_path);
- return createWithDir(gpa, name, cache_directory, o_dir_sub_path, basename);
+ return createWithDir(gpa, cache_directory, o_dir_sub_path, basename);
}
const Report = struct {
@@ -363,9 +432,6 @@ fn fetchAndUnpack(
const owned_src_path = try gpa.dupe(u8, build_zig_basename);
errdefer gpa.free(owned_src_path);
- const owned_name = try gpa.dupe(u8, fqn);
- errdefer gpa.free(owned_name);
-
const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});
errdefer gpa.free(build_root);
@@ -380,7 +446,6 @@ fn fetchAndUnpack(
},
.root_src_directory_owned = true,
.root_src_path = owned_src_path,
- .name = owned_name,
};
return ptr;
@@ -455,7 +520,7 @@ fn fetchAndUnpack(
std.zig.fmtId(fqn), std.zig.fmtEscapes(build_root),
});
- return createWithDir(gpa, fqn, global_cache_directory, pkg_dir_sub_path, build_zig_basename);
+ return createWithDir(gpa, global_cache_directory, pkg_dir_sub_path, build_zig_basename);
}
fn unpackTarball(