diff options
| author | Mitchell Hashimoto <m@mitchellh.com> | 2025-09-19 15:22:04 -0700 |
|---|---|---|
| committer | Mitchell Hashimoto <m@mitchellh.com> | 2025-09-19 15:22:10 -0700 |
| commit | d65466362d2370bd5395f38a9678b59f4994422d (patch) | |
| tree | 44bcba29eaa36c24bb01d1c6e55c970292abeece /src/Command.zig | |
| parent | 800fa99ff27b317bff789cd0b29a5707663521b6 (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.zig | 85 |
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 { |
