Skip to content

Commit

Permalink
Add cwd option (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
jopemachine committed May 8, 2022
1 parent 5dbf6dc commit 3fe6ab4
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 8 deletions.
9 changes: 9 additions & 0 deletions index.d.ts
Expand Up @@ -15,6 +15,15 @@ declare namespace cpFile {
@default 0o777
*/
readonly directoryMode?: number;

/**
The working directory to find source files.
The source and destination path are relative to this.
@default process.cwd()
*/
readonly cwd?: string;
}

interface ProgressData {
Expand Down
34 changes: 26 additions & 8 deletions index.js
Expand Up @@ -52,11 +52,25 @@ const cpFileAsync = async (source, destination, options, progressEmitter) => {
}
};

const cpFile = (sourcePath, destinationPath, options) => {
const resolvePath = (cwd, sourcePath, destinationPath) => {
sourcePath = path.resolve(cwd, sourcePath);
destinationPath = path.resolve(cwd, destinationPath);

return {
sourcePath,
destinationPath
};
};

const cpFile = (sourcePath, destinationPath, options = {}) => {
if (!sourcePath || !destinationPath) {
return Promise.reject(new CpFileError('`source` and `destination` required'));
}

if (options.cwd) {
({sourcePath, destinationPath} = resolvePath(options.cwd, sourcePath, destinationPath));
}

options = {
overwrite: true,
...options
Expand Down Expand Up @@ -85,23 +99,27 @@ const checkSourceIsFile = (stat, source) => {
}
};

module.exports.sync = (source, destination, options) => {
if (!source || !destination) {
module.exports.sync = (sourcePath, destinationPath, options = {}) => {
if (!sourcePath || !destinationPath) {
throw new CpFileError('`source` and `destination` required');
}

if (options.cwd) {
({sourcePath, destinationPath} = resolvePath(options.cwd, sourcePath, destinationPath));
}

options = {
overwrite: true,
...options
};

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

const flags = options.overwrite ? null : fsConstants.COPYFILE_EXCL;
try {
fs.copyFileSync(source, destination, flags);
fs.copyFileSync(sourcePath, destinationPath, flags);
} catch (error) {
if (!options.overwrite && error.code === 'EEXIST') {
return;
Expand All @@ -110,5 +128,5 @@ module.exports.sync = (source, destination, options) => {
throw error;
}

fs.utimesSync(destination, stat.atime, stat.mtime);
fs.utimesSync(destinationPath, stat.atime, stat.mtime);
};
9 changes: 9 additions & 0 deletions readme.md
Expand Up @@ -59,6 +59,15 @@ Default: `true`

Overwrite existing destination file.

##### cwd

Type: `string`\
Default: `process.cwd()`

The working directory to find source files.

The source and destination path are relative to this.

##### directoryMode

Type: `number`\
Expand Down
9 changes: 9 additions & 0 deletions test/async.js
Expand Up @@ -269,3 +269,12 @@ test.serial('rethrow read after open errors', async t => {

Object.assign(fs, {createWriteStream, createReadStream});
});

test('cwd option', async t => {
const error = await t.throwsAsync(cpFile('sync.js', t.context.destination));

t.is(error.name, 'CpFileError');
t.is(error.code, 'ENOENT');

await t.notThrowsAsync(cpFile('sync.js', t.context.destination, {cwd: 'test'}));
});
13 changes: 13 additions & 0 deletions test/sync.js
Expand Up @@ -218,3 +218,16 @@ test('rethrow utimes errors', t => {

fs.utimesSync.restore();
});

test('cwd option', t => {
const error = t.throws(() => {
cpFile.sync('sync.js', t.context.destination);
});

t.is(error.name, 'CpFileError');
t.is(error.code, 'ENOENT');

t.notThrows(() => {
cpFile.sync('sync.js', t.context.destination, {cwd: 'test'});
});
});

0 comments on commit 3fe6ab4

Please sign in to comment.