Skip to content
This repository was archived by the owner on Aug 11, 2022. It is now read-only.

Commit be04bbd

Browse files
committed
badly-named man files won't install (fixes #7000)
Before, if you tried to put a filename in the `man` stanza of package.json that didn't follow the rules as listed in `npm help 5 package.json`, installing would work, but upgrading or uninstalling would fail with a cryptic failure. Now, fail on build with a descriptive message, and log the same descriptive message as an error (but don't fail) on unbuild.
1 parent 7f6557f commit be04bbd

3 files changed

Lines changed: 115 additions & 16 deletions

File tree

lib/build.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ function linkMans (pkg, folder, parent, gtop, cb) {
212212
if (!pkg.man || !gtop || process.platform === "win32") return cb()
213213

214214
var manRoot = path.resolve(npm.config.get("prefix"), "share", "man")
215+
log.verbose("linkMans", "man files are", pkg.man, "in", manRoot)
215216

216217
// make sure that the mans are unique.
217218
// otherwise, if there are dupes, it'll fail with EEXIST
@@ -225,11 +226,20 @@ function linkMans (pkg, folder, parent, gtop, cb) {
225226

226227
asyncMap(pkg.man, function (man, cb) {
227228
if (typeof man !== "string") return cb()
229+
log.silly("linkMans", "preparing to link", man)
228230
var parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/)
229-
, stem = parseMan[1]
230-
, sxn = parseMan[2]
231-
, bn = path.basename(stem)
232-
, manDest = path.join(manRoot, "man" + sxn, bn)
231+
if (!parseMan) {
232+
return cb(new Error(
233+
man+" is not a valid name for a man file. " +
234+
"Man files must end with a number, " +
235+
"and optionally a .gz suffix if they are compressed."
236+
))
237+
}
238+
239+
var stem = parseMan[1]
240+
var sxn = parseMan[2]
241+
var bn = path.basename(stem)
242+
var manDest = path.join(manRoot, "man" + sxn, bn)
233243

234244
linkIfExists(man, manDest, gtop && folder, cb)
235245
}, cb)

lib/unbuild.js

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -81,25 +81,35 @@ function rmMans (pkg, folder, parent, top, cb) {
8181
return cb()
8282
}
8383
var manRoot = path.resolve(npm.config.get("prefix"), "share", "man")
84+
log.verbose("rmMans", "man files are", pkg.man, "in", manRoot)
8485
asyncMap(pkg.man, function (man, cb) {
8586
if (Array.isArray(man)) {
8687
man.forEach(rmMan)
8788
} else {
8889
rmMan(man)
8990
}
9091

91-
function rmMan(man) {
92-
var parseMan = man.match(/(.*)\.([0-9]+)(\.gz)?$/)
93-
, stem = parseMan[1]
94-
, sxn = parseMan[2]
95-
, gz = parseMan[3] || ""
96-
, bn = path.basename(stem)
97-
, manDest = path.join( manRoot
98-
, "man"+sxn
99-
, (bn.indexOf(pkg.name) === 0 ? bn
100-
: pkg.name + "-" + bn)
101-
+ "." + sxn + gz
102-
)
92+
function rmMan (man) {
93+
log.silly("rmMan", "preparing to remove", man)
94+
var parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/)
95+
if (!parseMan) {
96+
log.error(
97+
"rmMan", man, "is not a valid name for a man file.",
98+
"Man files must end with a number, " +
99+
"and optionally a .gz suffix if they are compressed."
100+
)
101+
return cb()
102+
}
103+
104+
var stem = parseMan[1]
105+
var sxn = parseMan[2]
106+
var gz = parseMan[3] || ""
107+
var bn = path.basename(stem)
108+
var manDest = path.join(
109+
manRoot,
110+
"man"+sxn,
111+
(bn.indexOf(pkg.name) === 0 ? bn : pkg.name+"-"+bn)+"."+sxn+gz
112+
)
103113
gentlyRm(manDest, true, cb)
104114
}
105115
}, cb)

test/tap/install-bad-man.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
var fs = require("fs")
2+
var resolve = require("path").resolve
3+
4+
var osenv = require("osenv")
5+
var mkdirp = require("mkdirp")
6+
var rimraf = require("rimraf")
7+
var test = require("tap").test
8+
9+
var common = require("../common-tap.js")
10+
11+
var pkg = resolve(__dirname, "install-bad-man")
12+
var target = resolve(__dirname, "install-bad-man-target")
13+
14+
var EXEC_OPTS = {
15+
cwd: target
16+
}
17+
18+
test("setup", function (t) {
19+
setup()
20+
t.pass("setup ran")
21+
t.end()
22+
})
23+
24+
test("install from repo on 'OS X'", function (t) {
25+
common.npm(
26+
[
27+
"install",
28+
"--prefix", target,
29+
"--global",
30+
pkg
31+
],
32+
EXEC_OPTS,
33+
function (err, code, stdout, stderr) {
34+
t.ifError(err, "npm command ran from test")
35+
t.equals(code, 1, "install exited with failure (1)")
36+
t.notOk(stdout, "no output indicating success")
37+
t.notOk(
38+
stderr.match(/Cannot read property '1' of null/),
39+
"no longer has cryptic error output"
40+
)
41+
t.ok(
42+
stderr.match(/install-bad-man\.1\.lol is not a valid name/),
43+
"got expected error output"
44+
)
45+
46+
t.end()
47+
}
48+
)
49+
})
50+
51+
test("clean", function (t) {
52+
cleanup()
53+
t.pass("cleaned up")
54+
t.end()
55+
})
56+
57+
var json = {
58+
name : "install-bad-man",
59+
version : "1.2.3",
60+
man : [ "./install-bad-man.1.lol" ]
61+
}
62+
63+
function setup () {
64+
cleanup()
65+
mkdirp.sync(pkg)
66+
// make sure it installs locally
67+
mkdirp.sync(resolve(target, "node_modules"))
68+
fs.writeFileSync(
69+
resolve(pkg, "package.json"),
70+
JSON.stringify(json, null, 2)+"\n"
71+
)
72+
fs.writeFileSync(resolve(pkg, "install-bad-man.1.lol"), "lol\n")
73+
}
74+
75+
function cleanup () {
76+
process.chdir(osenv.tmpdir())
77+
rimraf.sync(pkg)
78+
rimraf.sync(target)
79+
}

0 commit comments

Comments
 (0)