Skip to content

Commit

Permalink
Add directoryMode option (#44)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
dittyroma and sindresorhus committed Jun 13, 2021
1 parent 694ddb2 commit 4eb8f47
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 6 deletions.
6 changes: 3 additions & 3 deletions fs.js
Expand Up @@ -57,13 +57,13 @@ exports.utimesSync = (path, atime, mtime) => {
}
};

exports.makeDir = path => makeDir(path, {fs}).catch(error => {
exports.makeDir = (path, options) => makeDir(path, {...options, fs}).catch(error => {
throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error);
});

exports.makeDirSync = path => {
exports.makeDirSync = (path, options) => {
try {
makeDir.sync(path, {fs});
makeDir.sync(path, {...options, fs});
} catch (error) {
throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error);
}
Expand Down
7 changes: 7 additions & 0 deletions index.d.ts
Expand Up @@ -6,6 +6,13 @@ declare namespace cpFile {
@default true
*/
readonly overwrite?: boolean;

/**
[Permissions](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) for created directories.
@default 0o777
*/
readonly directoryMode?: number;
}

interface ProgressData {
Expand Down
4 changes: 2 additions & 2 deletions index.js
Expand Up @@ -12,7 +12,7 @@ const cpFileAsync = async (source, destination, options, progressEmitter) => {
progressEmitter.size = stat.size;

const readStream = await fs.createReadStream(source);
await fs.makeDir(path.dirname(destination));
await fs.makeDir(path.dirname(destination), {mode: options.directoryMode});
const writeStream = fs.createWriteStream(destination, {flags: options.overwrite ? 'w' : 'wx'});

readStream.on('data', () => {
Expand Down Expand Up @@ -94,7 +94,7 @@ module.exports.sync = (source, destination, options) => {

const stat = fs.statSync(source);
checkSourceIsFile(stat, source);
fs.makeDirSync(path.dirname(destination));
fs.makeDirSync(path.dirname(destination), {mode: options.directoryMode});

const flags = options.overwrite ? null : fsConstants.COPYFILE_EXCL;
try {
Expand Down
22 changes: 21 additions & 1 deletion index.test-d.ts
@@ -1,4 +1,4 @@
import {expectType} from 'tsd';
import {expectError, expectType} from 'tsd';
import cpFile = require('.');
import {ProgressEmitter, ProgressData} from '.';

Expand All @@ -8,6 +8,16 @@ expectType<Promise<void> & ProgressEmitter>(
expectType<Promise<void> & ProgressEmitter>(
cpFile('source/unicorn.png', 'destination/unicorn.png', {overwrite: false})
);
expectType<Promise<void> & ProgressEmitter>(
cpFile('source/unicorn.png', 'destination/unicorn.png', {
directoryMode: 0o700
})
);
expectError(
await cpFile('source/unicorn.png', 'destination/unicorn.png', {
directoryMode: '700'
})
);
expectType<Promise<void>>(
cpFile('source/unicorn.png', 'destination/unicorn.png').on(
'progress',
Expand All @@ -29,3 +39,13 @@ expectType<void>(
overwrite: false
})
);
expectType<void>(
cpFile.sync('source/unicorn.png', 'destination/unicorn.png', {
directoryMode: 0o700
})
);
expectError(
cpFile.sync('source/unicorn.png', 'destination/unicorn.png', {
directoryMode: '700'
})
);
7 changes: 7 additions & 0 deletions readme.md
Expand Up @@ -59,6 +59,13 @@ Default: `true`

Overwrite existing destination file.

##### directoryMode

Type: `number`\
Default: `0o777`

[Permissions](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) for created directories. Not supported on Windows.

### cpFile.on('progress', handler)

Progress reporting. Only available when using the async method.
Expand Down
9 changes: 9 additions & 0 deletions test/async.js
Expand Up @@ -80,6 +80,15 @@ test('do not overwrite when disabled', async t => {
t.is(error.code, 'EEXIST', error.message);
});

test('create directories with specified mode', async t => {
const directory = t.context.destination;
const destination = `${directory}/${uuidv4()}`;
const directoryMode = 0o700;
await cpFile('license', destination, {directoryMode});
const stat = fs.statSync(directory);
t.is(stat.mode & directoryMode, directoryMode);
});

test('do not create `destination` on unreadable `source`', async t => {
const error = await t.throwsAsync(cpFile('node_modules', t.context.destination));
t.is(error.name, 'CpFileError', error.message);
Expand Down
9 changes: 9 additions & 0 deletions test/sync.js
Expand Up @@ -81,6 +81,15 @@ test('do not overwrite when disabled', t => {
t.is(fs.readFileSync(t.context.destination, 'utf8'), '');
});

test('create directories with specified mode', t => {
const directory = t.context.destination;
const destination = `${directory}/${uuidv4()}`;
const directoryMode = 0o700;
cpFile.sync('license', destination, {directoryMode});
const stat = fs.statSync(directory);
t.is(stat.mode & directoryMode, directoryMode);
});

test('do not create `destination` on unreadable `source`', t => {
t.throws(
() => {
Expand Down

0 comments on commit 4eb8f47

Please sign in to comment.