-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: do not alter file ownership (#216)
BREAKING CHANGE: this package no longer attempts to change file ownership automatically
- Loading branch information
Showing
4 changed files
with
78 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,4 @@ | ||
const fakeSudo = process.argv[2] === 'fake-sudo' | ||
const fs = require('fs') | ||
process.chownLog = [] | ||
if (fakeSudo) { | ||
process.realUid = process.getuid() | ||
process.getuid = () => 0 | ||
const fakeChown = type => (path, uid, gid, cb) => { | ||
process.chownLog.push({ type, path, uid, gid }) | ||
process.nextTick(cb) | ||
} | ||
fs.chown = fakeChown('chown') | ||
fs.lchown = fakeChown('lchown') | ||
} | ||
|
||
fs.utimes = () => { | ||
throw new Error('do not call utimes') | ||
|
@@ -106,10 +94,6 @@ t.test('tarball data', async t => { | |
|
||
t.test('tarballFile', t => { | ||
const target = resolve(me, 'tarball-file') | ||
if (fakeSudo) { | ||
process.chownLog.length = 0 | ||
} | ||
|
||
t.test('basic copy', t => | ||
new FileFetcher(abbrevspec, { cache }) | ||
.tarballFile(target + '/basic/1.tgz')) | ||
|
@@ -198,10 +182,6 @@ t.test('extract', t => { | |
}) | ||
} | ||
|
||
if (fakeSudo) { | ||
process.chownLog.length = 0 | ||
} | ||
|
||
return new FileFetcher(abbrevspec, { cache }).extract(target + '/uncached') | ||
.then(check('uncached')) | ||
.then(() => new FileFetcher(abbrevspec, { | ||
|
@@ -210,12 +190,6 @@ t.test('extract', t => { | |
resolved: abbrev, | ||
}).extract(target + '/cached')) | ||
.then(check('cached')) | ||
.then(!fakeSudo ? () => {} : () => { | ||
t.not(process.chownLog.length, 0, 'did some chowns') | ||
const log = { uid: process.realUid, gid: process.getgid() } | ||
process.chownLog.forEach(entry => t.match(entry, log, 'chowned to me')) | ||
process.chownLog.length = 0 | ||
}) | ||
.then(() => { | ||
// test a bad cache entry | ||
cacache.get.stream.byDigest = () => { | ||
|
@@ -413,7 +387,6 @@ t.test('a non-retriable cache error', t => { | |
const poop = new Error('poop') | ||
poop.code = 'LE_POOP' | ||
t.teardown(mutateFS.fail('read', poop)) | ||
t.teardown(() => process.chownLog.length = 0) | ||
return cacache.put(cache, 'any-old-key', data, { | ||
integrity: abbrevMani._integrity, | ||
}).then(() => t.rejects(new FileFetcher(abbrev, { | ||
|
@@ -422,70 +395,65 @@ t.test('a non-retriable cache error', t => { | |
}).manifest(), poop)) | ||
}) | ||
|
||
// no need to do some of these basic tests in sudo mode | ||
if (!fakeSudo) { | ||
t.spawn(process.execPath, [__filename, 'fake-sudo'], 'fake sudo mode') | ||
t.test('before implies full metadata', t => { | ||
const f = new Fetcher('foo', { before: new Date('1979-07-01') }) | ||
t.equal(f.fullMetadata, true) | ||
t.end() | ||
}) | ||
|
||
t.test('before implies full metadata', t => { | ||
const f = new Fetcher('foo', { before: new Date('1979-07-01') }) | ||
t.equal(f.fullMetadata, true) | ||
t.end() | ||
t.test('various projectiles', t => { | ||
t.throws(() => new Fetcher(), { message: 'options object is required' }) | ||
const f = new Fetcher('foo', {}) | ||
// base class doesn't implement functionality | ||
const expect = { | ||
message: 'not implemented in this fetcher type: FetcherBase', | ||
} | ||
t.rejects(f.resolve(), expect) | ||
f.resolved = 'fooblz' | ||
t.resolveMatch(f.resolve(), 'fooblz', 'has resolved') | ||
t.rejects(f.extract('target'), expect) | ||
t.rejects(f.manifest(), expect) | ||
t.rejects(f.packument(), expect) | ||
t.rejects(f.tarball(), expect) | ||
const foo = npa('foo@bar') | ||
foo.type = 'blerg' | ||
t.throws(() => Fetcher.get(foo, {}), { | ||
message: 'Unknown spec type: blerg', | ||
}) | ||
|
||
t.test('various projectiles', t => { | ||
t.throws(() => new Fetcher(), { message: 'options object is required' }) | ||
const f = new Fetcher('foo', {}) | ||
// base class doesn't implement functionality | ||
const expect = { | ||
message: 'not implemented in this fetcher type: FetcherBase', | ||
} | ||
t.rejects(f.resolve(), expect) | ||
f.resolved = 'fooblz' | ||
t.resolveMatch(f.resolve(), 'fooblz', 'has resolved') | ||
t.rejects(f.extract('target'), expect) | ||
t.rejects(f.manifest(), expect) | ||
t.rejects(f.packument(), expect) | ||
t.rejects(f.tarball(), expect) | ||
const foo = npa('foo@bar') | ||
foo.type = 'blerg' | ||
t.throws(() => Fetcher.get(foo, {}), { | ||
message: 'Unknown spec type: blerg', | ||
}) | ||
|
||
class KidFetcher extends Fetcher { | ||
get types () { | ||
return ['kid'] | ||
} | ||
class KidFetcher extends Fetcher { | ||
get types () { | ||
return ['kid'] | ||
} | ||
t.throws(() => new KidFetcher('foo', {}), { | ||
message: `Wrong spec type (tag) for KidFetcher. Supported types: kid`, | ||
}) | ||
t.end() | ||
} | ||
t.throws(() => new KidFetcher('foo', {}), { | ||
message: `Wrong spec type (tag) for KidFetcher. Supported types: kid`, | ||
}) | ||
t.end() | ||
}) | ||
|
||
t.test('fetcher.get', t => { | ||
const specToType = { | ||
foo: 'RegistryFetcher', | ||
'foo@bar': 'RegistryFetcher', | ||
'[email protected]': 'RegistryFetcher', | ||
'[email protected]': 'RegistryFetcher', | ||
'npm:foo@2': 'RegistryFetcher', | ||
'@foo/bar': 'RegistryFetcher', | ||
'@foo/[email protected]': 'RegistryFetcher', | ||
'@foo/[email protected]': 'RegistryFetcher', | ||
'foo.tgz': 'FileFetcher', | ||
'/path/to/foo': 'DirFetcher', | ||
'isaacs/foo': 'GitFetcher', | ||
'git+https://github.com/isaacs/foo': 'GitFetcher', | ||
'https://server.com/foo.tgz': 'RemoteFetcher', | ||
} | ||
for (const [spec, type] of Object.entries(specToType)) { | ||
t.equal(Fetcher.get(spec).type, type) | ||
} | ||
t.test('fetcher.get', t => { | ||
const specToType = { | ||
foo: 'RegistryFetcher', | ||
'foo@bar': 'RegistryFetcher', | ||
'[email protected]': 'RegistryFetcher', | ||
'[email protected]': 'RegistryFetcher', | ||
'npm:foo@2': 'RegistryFetcher', | ||
'@foo/bar': 'RegistryFetcher', | ||
'@foo/[email protected]': 'RegistryFetcher', | ||
'@foo/[email protected]': 'RegistryFetcher', | ||
'foo.tgz': 'FileFetcher', | ||
'/path/to/foo': 'DirFetcher', | ||
'isaacs/foo': 'GitFetcher', | ||
'git+https://github.com/isaacs/foo': 'GitFetcher', | ||
'https://server.com/foo.tgz': 'RemoteFetcher', | ||
} | ||
for (const [spec, type] of Object.entries(specToType)) { | ||
t.equal(Fetcher.get(spec).type, type) | ||
} | ||
|
||
t.end() | ||
}) | ||
} | ||
t.end() | ||
}) | ||
|
||
t.test('make bins executable', async t => { | ||
const file = resolve(__dirname, 'fixtures/bin-object.tgz') | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,7 +61,6 @@ const fs = require('fs') | |
const http = require('http') | ||
|
||
const { dirname, basename, resolve } = require('path') | ||
const rimraf = require('rimraf') | ||
const fixtures = resolve(__dirname, 'fixtures') | ||
const abbrev = resolve(fixtures, 'abbrev-1.1.1.tgz') | ||
const prepIgnore = resolve(fixtures, 'prepare-requires-gitignore-1.2.3.tgz') | ||
|
@@ -84,7 +83,8 @@ const spawnGit = require('@npmcli/git').spawn | |
const { spawn } = require('child_process') | ||
const spawnNpm = require('../lib/util/npm.js') | ||
|
||
const mkdirp = require('mkdirp') | ||
const { mkdir } = require('fs/promises') | ||
const { rmSync } = require('fs') | ||
|
||
const tar = require('tar') | ||
|
||
|
@@ -99,8 +99,8 @@ t.test('setup', { bail: true }, t => { | |
'--no-sign-git-tag', | ||
], repo) | ||
|
||
mkdirp.sync(repo) | ||
return git('init') | ||
return mkdir(repo, { recursive: true }) | ||
.then(() => git('init')) | ||
.then(() => git('config', 'user.name', 'pacotedev')) | ||
.then(() => git('config', 'user.email', '[email protected]')) | ||
.then(() => git('config', 'tag.gpgSign', 'false')) | ||
|
@@ -180,7 +180,7 @@ t.test('setup', { bail: true }, t => { | |
const name = basename(repoDir) | ||
const otherName = basename(other) | ||
|
||
mkdirp.sync(repoDir) | ||
await mkdir(repoDir, { recursive: true }) | ||
await git('init') | ||
await git('config', 'user.name', 'pacotedev') | ||
await git('config', 'user.email', '[email protected]') | ||
|
@@ -227,15 +227,15 @@ t.test('setup', { bail: true }, t => { | |
} | ||
daemon.stderr.on('data', onDaemonData) | ||
// only clean up the dir once the daemon is banished | ||
daemon.on('close', () => rimraf.sync(me)) | ||
daemon.on('close', () => rmSync(me, { recursive: true, force: true })) | ||
}) | ||
|
||
t.test('create a repo with a submodule', t => { | ||
const submoduleRepo = resolve(me, 'submodule-repo') | ||
const git = (...cmd) => spawnGit(cmd, { cwd: submoduleRepo }) | ||
const write = (f, c) => fs.writeFileSync(`${submoduleRepo}/${f}`, c) | ||
mkdirp.sync(submoduleRepo) | ||
return git('init') | ||
return mkdir(submoduleRepo, { recursive: true }) | ||
.then(() => git('init')) | ||
.then(() => git('config', 'user.name', 'pacotedev')) | ||
.then(() => git('config', 'user.email', '[email protected]')) | ||
.then(() => git('config', 'tag.gpgSign', 'false')) | ||
|
@@ -293,8 +293,8 @@ t.test('setup', { bail: true }, t => { | |
const wsfolder = resolve(me, 'workspaces-repo/a') | ||
const git = (...cmd) => spawnGit(cmd, { cwd: workspacesRepo }) | ||
const write = (f, c) => fs.writeFileSync(`${workspacesRepo}/${f}`, c) | ||
mkdirp.sync(wsfolder) | ||
return git('init') | ||
return mkdir(wsfolder, { recursive: true }) | ||
.then(() => git('init')) | ||
.then(() => git('config', 'user.name', 'pacotedev')) | ||
.then(() => git('config', 'user.email', '[email protected]')) | ||
.then(() => git('config', 'tag.gpgSign', 'false')) | ||
|
@@ -322,8 +322,8 @@ t.test('setup', { bail: true }, t => { | |
const prepackRepo = resolve(me, 'prepack-repo') | ||
const git = (...cmd) => spawnGit(cmd, { cwd: prepackRepo }) | ||
const write = (f, c) => fs.writeFileSync(`${prepackRepo}/${f}`, c) | ||
mkdirp.sync(prepackRepo) | ||
return git('init') | ||
return mkdir(prepackRepo, { recursive: true }) | ||
.then(() => git('init')) | ||
.then(() => git('config', 'user.name', 'pacotedev')) | ||
.then(() => git('config', 'user.email', '[email protected]')) | ||
.then(() => git('config', 'tag.gpgSign', 'false')) | ||
|