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
|
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,
};
// This check adds around 150ms
// so...if we do do this, we should do it in a separate thread
pub fn isYarnBerry(allocator: *std.mem.Allocator, cwd_dir: string, yarn_path: string) bool {
var args = [_]string{ yarn_path, "--version" };
var term = std.ChildProcess.exec(.{
.argv = &args,
.allocator = allocator,
.cwd = if (cwd_dir.len > 1) std.mem.trimRight(u8, cwd_dir, "/") else cwd_dir,
}) catch return true;
defer allocator.free(term.stderr);
defer allocator.free(term.stdout);
if (term.stdout.len == 0) return true;
return term.stdout[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
const out_path = brk: {
var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const path: [:0]const u8 = if (comptime allow_yarn)
which(
&path_buf,
PATH,
cwd,
"pnpm",
) orelse which(
&path_buf,
PATH,
cwd,
"yarn",
) orelse which(
&path_buf,
PATH,
cwd,
"npm",
) orelse ""
else
which(
&path_buf,
PATH,
cwd,
"pnpm",
) orelse which(
&path_buf,
PATH,
cwd,
"npm",
) orelse "";
std.mem.copy(u8, realpath_buf, std.mem.span(path));
// It's important we don't resolve the symlink
// That breaks volta.
break :brk realpath_buf[0..path.len];
};
const basename = std.fs.path.basename(std.mem.span(out_path));
if (basename.len == 0) return null;
// if (comptime allow_yarn) {
// if (std.mem.indexOf(u8, basename, "yarn") != null) {
// if (isYarnBerry(allocator, cwd, out_path)) {
// return try detect(allocator, realpath_buf, PATH, cwd, false);
// }
// }
// }
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;
}
};
|