Skip to content

Commit

Permalink
Add --no-overwrite flag to preserve target file
Browse files Browse the repository at this point in the history
  • Loading branch information
dpilafian committed Mar 17, 2024
1 parent 2100aef commit f320ff2
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 13 deletions.
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@ You can also install **copy-file-util** globally (`--global`) and then run it an

### 3. CLI flags
Command-line flags:
| Flag | Description | Values |
| ---------- | ---------------------------------------------- | ---------- |
| `--cd` | Change working directory before starting copy. | **string** |
| `--folder` | Indicates the target is a folder. | N/A |
| `--move` | Delete the source file after copying it. | N/A |
| `--note` | Place to add a comment only for humans. | **string** |
| `--quiet` | Suppress informational messages. | N/A |
| Flag | Description | Values |
| ---------------- | ---------------------------------------------- | ---------- |
| `--cd` | Change working directory before starting copy. | **string** |
| `--folder` | Indicates the target is a folder. | N/A |
| `--move` | Delete the source file after copying it. | N/A |
| `--note` | Place to add a comment only for humans. | **string** |
| `--quiet` | Suppress informational messages. | N/A |
| `--no-overwrite` | Abort if target file already exists. | N/A |

Examples:
- `copy-file app.js app.mjs --quiet`<br>
Expand All @@ -66,6 +67,9 @@ Examples:
- `copy-file app.js --move --folder dist`<br>
Like the `mv` Unix command.

- `copy-file default-config.json settings/config.json --no-overwrite`<br>
Performs a safe copy that aborts if the **settings/config.json** file already exists.

_**Note:** Single quotes in commands are normalized so they work cross-platform and avoid the errors often encountered on Microsoft Windows._

### 4. Template variables
Expand Down
3 changes: 2 additions & 1 deletion bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { dna } from 'dna-engine';
import fs from 'fs';

// Parameters and flags
const validFlags = ['cd', 'folder', 'move', 'note', 'quiet'];
const validFlags = ['cd', 'folder', 'move', 'no-overwrite', 'note', 'quiet'];
const cli = cliArgvUtil.parse(validFlags);
const source = cli.params[0];
const target = cli.params[1];
Expand All @@ -51,6 +51,7 @@ const targetKey = cli.flagOn.folder ? 'targetFolder' : 'targetFile';
const options = {
cd: cli.flagMap.cd ?? null,
move: cli.flagOn.move,
overwrite: !cli.flagOn.noOverwrite,
[targetKey]: target.replace(/{{[^{}]*}}/g, getPackageField),
};
const result = copyFile.cp(source, options);
Expand Down
19 changes: 14 additions & 5 deletions copy-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ export type Settings = {
targetFolder: string, //destination folder for file copy operation
fileExtension: string, //new file extension for the target file
move: boolean, //delete the source file after copying it
overwrite: boolean, //clobber target file if it exists
};
export type Result = {
origin: string, //path of origination file
dest: string, //path of destination file
duration: number, //execution time in milliseconds
moved: boolean, //original file was deleted
skipped: boolean, //target file exists and was not overwritten
};

const copyFile = {
Expand All @@ -31,9 +33,10 @@ const copyFile = {
targetFolder: null,
fileExtension: null,
move: false,
overwrite: true,
};
const settings = { ...defaults, ...options };
const startTime = Date.now();
const settings = { ...defaults, ...options };
const startTime = Date.now();
const missingTarget = !settings.targetFile && !settings.targetFolder;
const ambiguousTarget = !!settings.targetFile && !!settings.targetFolder;
const normalize = (folder: string | null) =>
Expand All @@ -47,6 +50,8 @@ const copyFile = {
const targetFolder = targetPath ? normalize(startFolder + targetPath) : null;
const targetFile = settings.targetFile ?? settings.targetFolder + '/' + sourceFilename;
const target = normalize(startFolder + targetFile);
const targetExists = !missingTarget && fs.existsSync(target);
const skip = targetExists && !settings.overwrite;
if (targetFolder)
fs.mkdirSync(targetFolder, { recursive: true });
const badTargetFolder = !targetFolder || !fs.existsSync(targetFolder);
Expand All @@ -61,24 +66,28 @@ const copyFile = {
null;
if (errorMessage)
throw Error('[copy-file-util] ' + errorMessage);
if (settings.move)
if (!skip && settings.move)
fs.renameSync(source, target);
else
else if (!skip)
fs.copyFileSync(source, target);
return {
origin: source,
dest: target,
moved: settings.move,
skipped: skip,
duration: Date.now() - startTime,
};
},

reporter(result: Result): Result {
// Example output:
// [10:52:42] copy-file build/app.js → dist/app.js (1ms, moved)
const name = chalk.gray('copy-file');
const origin = chalk.blue.bold(result.origin);
const dest = chalk.magenta(result.dest);
const arrow = chalk.gray.bold('→');
const info = chalk.white(`(${result.duration}ms${result.moved ? ', move' : ''})`);
const status = result.skipped ? ', skip -- target exists' : result.moved ? ', move' : '';
const info = chalk.white(`(${result.duration}ms${status})`);
log(name, origin, arrow, dest, info);
return result;
},
Expand Down
11 changes: 11 additions & 0 deletions spec/fixtures/target/skip/mock1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>📂📂📂 copy-file-util 📂📂📂</title>
</head>
<body>
<h1>📂📂📂 copy-file-util 📂📂📂</h1>
<h2>Copy or rename a file with optional package version number (CLI tool designed for use in npm package.json scripts)</h2>
</body>
</html>
11 changes: 11 additions & 0 deletions spec/fixtures/target/skip/mock2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>📂📂📂 copy-file-util 📂📂📂</title>
</head>
<body>
<h1>📂📂📂 copy-file-util 📂📂📂</h1>
<h2>Copy or rename a file with optional package version number (CLI tool designed for use in npm package.json scripts)</h2>
</body>
</html>
12 changes: 12 additions & 0 deletions spec/mocha.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,16 @@ describe('Executing the CLI', () => {
assertDeepStrictEqual(actual, expected);
});

it('with the --no-overwrite flag prevents the target file from being clobbered', () => {
run('copy-file spec/fixtures/source/mock.html spec/fixtures/target/skip/mock1.html --no-overwrite --quiet');
run('copy-file spec/fixtures/source/mock.html spec/fixtures/target/skip/mock2.html --no-overwrite --quiet');
run('copy-file spec/fixtures/target/skip/mock1.html spec/fixtures/target/skip/mock2.html --move --no-overwrite');
const actual = cliArgvUtil.readFolder('spec/fixtures/target/skip');
const expected = [
'mock1.html',
'mock2.html',
];
assertDeepStrictEqual(actual, expected);
});

});

0 comments on commit f320ff2

Please sign in to comment.