@lgtm-hq/lintro 0.160.2 → 0.160.3-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/lintro +4 -1
- package/lib/resolve.js +66 -0
- package/package.json +4 -4
package/bin/lintro
CHANGED
|
@@ -10,12 +10,15 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const { execFileSync } = require("child_process");
|
|
13
|
-
const { resolveBinary } = require("../lib/resolve.js");
|
|
13
|
+
const { ensureExecutable, resolveBinary } = require("../lib/resolve.js");
|
|
14
14
|
|
|
15
15
|
function main() {
|
|
16
16
|
let binaryPath;
|
|
17
17
|
try {
|
|
18
18
|
binaryPath = resolveBinary();
|
|
19
|
+
// The published tarball may carry the binary without its exec bit (the
|
|
20
|
+
// publish pipeline's artifact handoff drops file modes); repair it.
|
|
21
|
+
ensureExecutable(binaryPath);
|
|
19
22
|
} catch (err) {
|
|
20
23
|
process.stderr.write(`${err.message}\n`);
|
|
21
24
|
process.exit(1);
|
package/lib/resolve.js
CHANGED
|
@@ -131,6 +131,71 @@ function resolveBinary(requireFn, platform, arch) {
|
|
|
131
131
|
return mod.path;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Make sure the platform binary carries its executable bit.
|
|
136
|
+
*
|
|
137
|
+
* The publish pipeline hands the staged package set between jobs as a
|
|
138
|
+
* workflow artifact, and that zip drops file modes: every file lands as
|
|
139
|
+
* 0644, so the tarball npm publishes can ship the binary without `+x`.
|
|
140
|
+
* npm only restores modes for a package's own `bin` entries, and the
|
|
141
|
+
* platform packages declare none, so the launcher repairs it here. A
|
|
142
|
+
* binary that is already executable is left untouched.
|
|
143
|
+
*
|
|
144
|
+
* @param {string} binaryPath - Absolute path to the platform binary.
|
|
145
|
+
* @param {typeof import('fs')} [fsModule] - Injectable `fs` (testing).
|
|
146
|
+
* @returns {boolean} `true` when the mode had to be repaired.
|
|
147
|
+
* @throws {Error} When the binary is not executable and cannot be made so.
|
|
148
|
+
*/
|
|
149
|
+
function ensureExecutable(binaryPath, fsModule) {
|
|
150
|
+
const fs = fsModule || require('fs');
|
|
151
|
+
try {
|
|
152
|
+
fs.accessSync(binaryPath, fs.constants.X_OK);
|
|
153
|
+
return false;
|
|
154
|
+
} catch {
|
|
155
|
+
// Not executable (or not accessible): fall through to the repair.
|
|
156
|
+
}
|
|
157
|
+
// Repair through a descriptor opened without following symlinks, so the
|
|
158
|
+
// mode change lands on the file that was inspected: a tampered platform
|
|
159
|
+
// package or a race cannot redirect it to another path.
|
|
160
|
+
const flags = fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0);
|
|
161
|
+
let fd;
|
|
162
|
+
try {
|
|
163
|
+
fd = fs.openSync(binaryPath, flags);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
if (err.code === 'ENOENT') {
|
|
166
|
+
throw new Error(`lintro: the platform binary at "${binaryPath}" is missing`);
|
|
167
|
+
}
|
|
168
|
+
if (err.code === 'ELOOP') {
|
|
169
|
+
throw new Error(
|
|
170
|
+
`lintro: the platform binary at "${binaryPath}" is a symlink; ` +
|
|
171
|
+
'refusing to change its mode'
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
throw new Error(
|
|
175
|
+
`lintro: the platform binary at "${binaryPath}" could not be opened: ${err.message}`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
if (!fs.fstatSync(fd).isFile()) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
`lintro: the platform binary at "${binaryPath}" is not a regular file; ` +
|
|
182
|
+
'refusing to change its mode'
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
fs.fchmodSync(fd, 0o755);
|
|
187
|
+
} catch (err) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
`lintro: the platform binary at "${binaryPath}" is not executable ` +
|
|
190
|
+
`and could not be made executable: ${err.message}`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
} finally {
|
|
194
|
+
fs.closeSync(fd);
|
|
195
|
+
}
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
134
199
|
module.exports = {
|
|
135
200
|
PLATFORM_PACKAGES,
|
|
136
201
|
UNSUPPORTED_PLATFORM_HINTS,
|
|
@@ -138,4 +203,5 @@ module.exports = {
|
|
|
138
203
|
unsupportedPlatformHint,
|
|
139
204
|
supportedPlatforms,
|
|
140
205
|
resolveBinary,
|
|
206
|
+
ensureExecutable,
|
|
141
207
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lgtm-hq/lintro",
|
|
3
|
-
"version": "0.160.2",
|
|
3
|
+
"version": "0.160.3-rc.2",
|
|
4
4
|
"description": "A unified CLI for code formatting, linting, and quality assurance. Ships self-contained platform binaries — no Python required.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lint",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"lib/resolve.js"
|
|
31
31
|
],
|
|
32
32
|
"optionalDependencies": {
|
|
33
|
-
"@lgtm-hq/lintro-darwin-arm64": "0.160.2",
|
|
34
|
-
"@lgtm-hq/lintro-linux-arm64": "0.160.2",
|
|
35
|
-
"@lgtm-hq/lintro-linux-x64": "0.160.2"
|
|
33
|
+
"@lgtm-hq/lintro-darwin-arm64": "0.160.3-rc.2",
|
|
34
|
+
"@lgtm-hq/lintro-linux-arm64": "0.160.3-rc.2",
|
|
35
|
+
"@lgtm-hq/lintro-linux-x64": "0.160.3-rc.2"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
38
|
"node": ">=18"
|