summaryrefslogtreecommitdiff
path: root/src/Command.zig
diff options
context:
space:
mode:
authorMitchell Hashimoto <m@mitchellh.com>2025-09-19 15:22:04 -0700
committerMitchell Hashimoto <m@mitchellh.com>2025-09-19 15:22:10 -0700
commitd65466362d2370bd5395f38a9678b59f4994422d (patch)
tree44bcba29eaa36c24bb01d1c6e55c970292abeece /src/Command.zig
parent800fa99ff27b317bff789cd0b29a5707663521b6 (diff)
build: Command.expandPath can go in its own dedicated os/path.zig file
Diffstat (limited to 'src/Command.zig')
-rw-r--r--src/Command.zig85
1 files changed, 0 insertions, 85 deletions
diff --git a/src/Command.zig b/src/Command.zig
index 1bddf8b82..b0d804327 100644
--- a/src/Command.zig
+++ b/src/Command.zig
@@ -404,91 +404,6 @@ pub fn getData(self: Command, comptime DT: type) ?*DT {
return if (self.data) |ptr| @ptrCast(@alignCast(ptr)) else null;
}
-/// Search for "cmd" in the PATH and return the absolute path. This will
-/// always allocate if there is a non-null result. The caller must free the
-/// resulting value.
-pub fn expandPath(alloc: Allocator, cmd: []const u8) !?[]u8 {
- // If the command already contains a slash, then we return it as-is
- // because it is assumed to be absolute or relative.
- if (std.mem.indexOfScalar(u8, cmd, '/') != null) {
- return try alloc.dupe(u8, cmd);
- }
-
- const PATH = switch (builtin.os.tag) {
- .windows => blk: {
- const win_path = std.process.getenvW(std.unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse return null;
- const path = try std.unicode.utf16LeToUtf8Alloc(alloc, win_path);
- break :blk path;
- },
- else => std.posix.getenvZ("PATH") orelse return null,
- };
- defer if (builtin.os.tag == .windows) alloc.free(PATH);
-
- var path_buf: [std.fs.max_path_bytes]u8 = undefined;
- var it = std.mem.tokenizeScalar(u8, PATH, std.fs.path.delimiter);
- var seen_eacces = false;
- while (it.next()) |search_path| {
- // We need enough space in our path buffer to store this
- const path_len = search_path.len + cmd.len + 1;
- if (path_buf.len < path_len) return error.PathTooLong;
-
- // Copy in the full path
- @memcpy(path_buf[0..search_path.len], search_path);
- path_buf[search_path.len] = std.fs.path.sep;
- @memcpy(path_buf[search_path.len + 1 ..][0..cmd.len], cmd);
- path_buf[path_len] = 0;
- const full_path = path_buf[0..path_len :0];
-
- // Stat it
- const f = std.fs.cwd().openFile(
- full_path,
- .{},
- ) catch |err| switch (err) {
- error.FileNotFound => continue,
- error.AccessDenied => {
- // Accumulate this and return it later so we can try other
- // paths that we have access to.
- seen_eacces = true;
- continue;
- },
- else => return err,
- };
- defer f.close();
- const stat = try f.stat();
- if (stat.kind != .directory and isExecutable(stat.mode)) {
- return try alloc.dupe(u8, full_path);
- }
- }
-
- if (seen_eacces) return error.AccessDenied;
-
- return null;
-}
-
-fn isExecutable(mode: std.fs.File.Mode) bool {
- if (builtin.os.tag == .windows) return true;
- return mode & 0o0111 != 0;
-}
-
-// `uname -n` is the *nix equivalent of `hostname.exe` on Windows
-test "expandPath: hostname" {
- const executable = if (builtin.os.tag == .windows) "hostname.exe" else "uname";
- const path = (try expandPath(testing.allocator, executable)).?;
- defer testing.allocator.free(path);
- try testing.expect(path.len > executable.len);
-}
-
-test "expandPath: does not exist" {
- const path = try expandPath(testing.allocator, "thisreallyprobablydoesntexist123");
- try testing.expect(path == null);
-}
-
-test "expandPath: slash" {
- const path = (try expandPath(testing.allocator, "foo/env")).?;
- defer testing.allocator.free(path);
- try testing.expect(path.len == 7);
-}
-
// Copied from Zig. This is a publicly exported function but there is no
// way to get it from the std package.
fn createNullDelimitedEnvMap(arena: mem.Allocator, env_map: *const EnvMap) ![:null]?[*:0]u8 {