1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
usingnamespace @import("./global.zig");
const which = @import("./which.zig").which;
const std = @import("std");
pub const NPMClient = struct {
bin: string,
tag: Tag,
pub const Tag = enum {
npm,
yarn,
pnpm,
};
pub fn isYarnBerry(allocator: *std.mem.Allocator, yarn_path: string) bool {
var args = [_]string{ yarn_path, "--version" };
var child_process = std.ChildProcess.init(&args, allocator) catch return true;
defer child_process.deinit();
child_process.cwd_dir = std.fs.cwd();
child_process.expand_arg0 = .no_expand;
child_process.stdout_behavior = .Pipe;
child_process.stderr_behavior = .Pipe;
child_process.spawn() catch return true;
defer _ = child_process.kill() catch undefined;
var path_buf: [512]u8 = undefined;
var path_len = child_process.stdout.?.read(&path_buf) catch return true;
if (path_len == 0) {
return true;
}
return path_buf[0] != '1';
}
pub fn detect(allocator: *std.mem.Allocator, realpath_buf: *[std.fs.MAX_PATH_BYTES]u8, PATH: string, cwd: string, comptime allow_yarn: bool) !?NPMClient {
// We say:
// - pnpm if it exists, is the default. its most esoteric, so if you have it installed, you prob want it.
// - yarn if it exists and it is yarn 1, its the default (yarn 2 or later is not supported)
// - else npm
var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const path: [:0]const u8 = brk: {
if (comptime allow_yarn) {
break :brk which(
&path_buf,
PATH,
cwd,
"pnpm",
) orelse which(
&path_buf,
PATH,
cwd,
"yarn",
) orelse which(
&path_buf,
PATH,
cwd,
"npm",
) orelse "";
} else {
break :brk which(
&path_buf,
PATH,
cwd,
"pnpm",
) orelse which(
&path_buf,
PATH,
cwd,
"npm",
) orelse "";
}
unreachable;
};
var basename = std.fs.path.basename(path);
if (basename.len == 0) return null;
if (comptime allow_yarn) {
if (std.mem.indexOf(u8, basename, "yarn") != null) {
if (isYarnBerry(allocator, path)) {
return try detect(allocator, realpath_buf, PATH, cwd, false);
}
}
}
var file = std.fs.openFileAbsoluteZ(path, .{ .read = true }) catch return null;
defer file.close();
const out_path = std.os.getFdPath(file.handle, realpath_buf) catch return null;
if (strings.contains(basename, "pnpm")) {
return NPMClient{ .bin = out_path, .tag = .pnpm };
}
if (strings.contains(basename, "yarn")) {
return NPMClient{ .bin = out_path, .tag = .yarn };
}
if (strings.contains(basename, "npm")) {
return NPMClient{ .bin = out_path, .tag = .npm };
}
return null;
}
};
|