Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sindresorhus/cpy-cli
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: dbf801fd63508d90cd12bdcdf001f1826ccabb45
Choose a base ref
...
head repository: sindresorhus/cpy-cli
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8329dc996fe5fb38a15df734e39718946d69891e
Choose a head ref
  • 13 commits
  • 7 files changed
  • 6 contributors

Commits on May 28, 2019

  1. Create funding.yml

    sindresorhus authored May 28, 2019

    Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    31303d9 View commit details
  2. Require Node.js 8

    sindresorhus committed May 28, 2019
    Copy the full SHA
    a31ef18 View commit details

Commits on Dec 6, 2019

  1. Update dependencies

    sindresorhus committed Dec 6, 2019
    Copy the full SHA
    4f843b3 View commit details
  2. 3.0.0

    sindresorhus committed Dec 6, 2019
    Copy the full SHA
    af00c3b View commit details

Commits on Feb 13, 2020

  1. Copy the full SHA
    122f4de View commit details
  2. 3.1.0

    sindresorhus committed Feb 13, 2020
    Copy the full SHA
    c6e1f26 View commit details

Commits on May 4, 2020

  1. Update dependencies (#25)

    xtqqczze authored May 4, 2020
    Copy the full SHA
    65637f7 View commit details
  2. 3.1.1

    sindresorhus committed May 4, 2020
    Copy the full SHA
    1c9bd16 View commit details

Commits on Jan 1, 2021

  1. Copy the full SHA
    d6bdd28 View commit details

Commits on Feb 27, 2022

  1. Copy the full SHA
    7ee777f View commit details
  2. Meta tweaks

    sindresorhus committed Feb 27, 2022
    Copy the full SHA
    b271612 View commit details

Commits on Mar 1, 2022

  1. Update cpy to v9 (#34)

    Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
    andy2mrqz and sindresorhus authored Mar 1, 2022
    4
    Copy the full SHA
    693722f View commit details
  2. 4.0.0

    sindresorhus committed Mar 1, 2022
    Copy the full SHA
    8329dc9 View commit details
Showing with 123 additions and 75 deletions.
  1. +22 −0 .github/workflows/main.yml
  2. +0 −5 .travis.yml
  3. +39 −28 cli.js
  4. +1 −1 license
  5. +12 −10 package.json
  6. +8 −16 readme.md
  7. +41 −15 test.js
22 changes: 22 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: CI
on:
- push
- pull_request
jobs:
test:
name: Node.js ${{ matrix.node-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version:
- 16
- 14
- 12
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
5 changes: 0 additions & 5 deletions .travis.yml

This file was deleted.

67 changes: 39 additions & 28 deletions cli.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,67 @@
#!/usr/bin/env node
'use strict';
const meow = require('meow');
const cpy = require('cpy');
import process from 'node:process';
import meow from 'meow';
import cpy from 'cpy';

const cli = meow(`
Usage
$ cpy <source>... <destination>
$ cpy <source …> <destination>
Options
--no-overwrite Don't overwrite the destination
--parents Preserve path structure
--cwd=<dir> Working directory for files
--rename=<filename> Rename all <source> filenames to <filename>
--dot Allow patterns to match entries that begin with a period (.)
--flat Flatten directory structure. All copied files will be put in the same directory.
<source> can contain globs if quoted
Examples
Copy all .png files in src folder into dist except src/goat.png
$ cpy 'src/*.png' '!src/goat.png' dist
Copy all .html files inside src folder into dist and preserve path structure
$ cpy '**/*.html' '../dist/' --cwd=src --parents
Copy all files inside src folder into dist and preserve path structure
$ cpy . '../dist/' --cwd=src
`, {
importMeta: import.meta,
flags: {
overwrite: {
type: 'boolean',
default: true
},
parents: {
type: 'boolean',
default: false
default: true,
},
cwd: {
type: 'string',
default: process.cwd()
default: process.cwd(),
},
rename: {
type: 'string'
}
}
type: 'string',
},
dot: {
type: 'boolean',
default: false,
},
flat: {
type: 'boolean',
default: false,
},
},
});

cpy(cli.input, cli.input.pop(), {
cwd: cli.flags.cwd,
rename: cli.flags.rename,
parents: cli.flags.parents,
overwrite: cli.flags.overwrite
}).catch(err => {
if (err.name === 'CpyError') {
console.error(err.message);
process.exit(1);
} else {
throw err;
(async () => {
try {
await cpy(cli.input, cli.input.pop(), {
cwd: cli.flags.cwd,
rename: cli.flags.rename,
overwrite: cli.flags.overwrite,
dot: cli.flags.dot,
flat: cli.flags.flat,
});
} catch (error) {
if (error.name === 'CpyError') {
console.error(error.message);
process.exit(1);
} else {
throw error;
}
}
});
})();
2 changes: 1 addition & 1 deletion license
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

22 changes: 12 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "cpy-cli",
"version": "2.0.0",
"version": "4.0.0",
"description": "Copy files",
"license": "MIT",
"repository": "sindresorhus/cpy-cli",
"funding": "https://github.com/sponsors/sindresorhus",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
"url": "https://sindresorhus.com"
},
"maintainers": [
{
@@ -20,8 +21,9 @@
"cpy": "cli.js"
},
"engines": {
"node": ">=6"
"node": ">=12.20"
},
"type": "module",
"scripts": {
"test": "xo && ava"
},
@@ -49,14 +51,14 @@
"contents"
],
"dependencies": {
"cpy": "^7.0.0",
"meow": "^5.0.0"
"cpy": "^9.0.0",
"meow": "^10.1.2"
},
"devDependencies": {
"ava": "*",
"execa": "^0.10.0",
"path-exists": "^3.0.0",
"tempfile": "^2.0.0",
"xo": "*"
"ava": "^4.0.1",
"execa": "^6.1.0",
"path-exists": "^5.0.0",
"tempfile": "^4.0.0",
"xo": "^0.48.0"
}
}
24 changes: 8 additions & 16 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,45 @@
# cpy-cli [![Build Status](https://travis-ci.org/sindresorhus/cpy-cli.svg?branch=master)](https://travis-ci.org/sindresorhus/cpy-cli)
# cpy-cli

> Copy files

## Why

- Fast by using streams.
- Resilient by using [graceful-fs](https://github.com/isaacs/node-graceful-fs).
- User-friendly by accepting [globs](https://github.com/sindresorhus/globby#globbing-patterns) and creating non-existant destination directories.
- User-friendly error messages.


## Install

```sh
npm install --global cpy-cli
```
$ npm install --global cpy-cli
```


## Usage

```
$ cpy --help
Usage
$ cpy <source>... <destination>
$ cpy <source …> <destination>
Options
--no-overwrite Don't overwrite the destination
--parents Preserve path structure
--cwd=<dir> Working directory for files
--rename=<filename> Rename all <source> filenames to <filename>
--dot Allow patterns to match entries that begin with a period (.)
--flat Flatten directory structure. All copied files will be put in the same directory.
<source> can contain globs if quoted
Examples
Copy all .png files in src folder into dist except src/goat.png
$ cpy 'src/*.png' '!src/goat.png' dist
Copy all .html files inside src folder into dist and preserve path structure
$ cpy '**/*.html' '../dist/' --cwd=src --parents
Copy all files inside src folder into dist and preserve path structure
$ cpy . '../dist/' --cwd=src
```


## Related

- [cpy](https://github.com/sindresorhus/cpy) - API for this module


## License

MIT © [Sindre Sorhus](https://sindresorhus.com)
56 changes: 41 additions & 15 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import path from 'path';
import fs from 'fs';
import path from 'node:path';
import fs from 'node:fs';
import test from 'ava';
import tempfile from 'tempfile';
import execa from 'execa';
import pathExists from 'path-exists';
import {execa} from 'execa';
import {pathExistsSync} from 'path-exists';

const read = (...args) => fs.readFileSync(path.join(...args), 'utf8');
const read = (...arguments_) => fs.readFileSync(path.join(...arguments_), 'utf8');

test.beforeEach(t => {
t.context.tmp = tempfile();
});

test('missing file operands', async t => {
await t.throws(execa('./cli.js'), /`files` and `destination` required/);
await t.throwsAsync(execa('./cli.js'), {message: /`source` and `destination` required/});
});

// TODO: Blocked by https://github.com/mrmlnc/fast-glob/issues/110
test.failing('source file does not exist', async t => {
await t.throws(execa('./cli.js', [path.join(t.context.tmp, 'nonexistentfile'), t.context.tmp]), /nonexistentfile/);
test('source file does not exist', async t => {
await t.throwsAsync(execa('./cli.js', [path.join(t.context.tmp, 'nonexistentfile'), t.context.tmp]), {message: /nonexistentfile/});
});

test('cwd', async t => {
@@ -30,14 +29,18 @@ test('cwd', async t => {
t.is(read(t.context.tmp, 'cwd/hello.js'), read(t.context.tmp, 'cwd/dest/hello.js'));
});

test('keep path structure with flag `--parents`', async t => {
test('path structure', async t => {
fs.mkdirSync(t.context.tmp);
fs.mkdirSync(path.join(t.context.tmp, 'cwd'));
fs.mkdirSync(path.join(t.context.tmp, 'out'));
fs.writeFileSync(path.join(t.context.tmp, 'cwd/hello.js'), 'console.log("hello");');

await execa('./cli.js', [path.join(t.context.tmp, 'cwd/hello.js'), t.context.tmp, '--parents']);
await execa('./cli.js', [path.join(t.context.tmp, '**'), path.join(t.context.tmp, 'out')]);

t.is(read(t.context.tmp, 'cwd/hello.js'), read(t.context.tmp, t.context.tmp, 'cwd/hello.js'));
t.is(
read(t.context.tmp, 'cwd/hello.js'),
read(t.context.tmp, 'out/cwd/hello.js'),
);
});

test('rename filenames but not filepaths', async t => {
@@ -69,9 +72,32 @@ test('do not copy files in the negated glob patterns', async t => {
fs.writeFileSync(path.join(t.context.tmp, 'src/hello.jsx'), 'console.log("world");');
fs.writeFileSync(path.join(t.context.tmp, 'src/hello.es2015'), 'console.log("world");');

await execa('./cli.js', ['src/*.*', '!src/*.jsx', '!src/*.es2015', 'dest', '--cwd', t.context.tmp]);
await execa('./cli.js', ['src/*.*', '!src/*.jsx', '!src/*.es2015', path.join(t.context.tmp, 'dest'), '--cwd', t.context.tmp]);

t.is(read(t.context.tmp, 'dest/hello.js'), 'console.log("hello");');
t.false(pathExists.sync(path.join(t.context.tmp, 'dest/hello.jsx')));
t.false(pathExists.sync(path.join(t.context.tmp, 'dest/hello.es2015')));
t.false(pathExistsSync(path.join(t.context.tmp, 'dest/hello.jsx')));
t.false(pathExistsSync(path.join(t.context.tmp, 'dest/hello.es2015')));
});

test('flatten directory tree', async t => {
fs.mkdirSync(t.context.tmp);
fs.mkdirSync(path.join(t.context.tmp, 'source'));
fs.mkdirSync(path.join(t.context.tmp, 'source', 'nested'));
fs.writeFileSync(path.join(t.context.tmp, 'foo.js'), 'console.log("foo");');
fs.writeFileSync(path.join(t.context.tmp, 'source/bar.js'), 'console.log("bar");');
fs.writeFileSync(path.join(t.context.tmp, 'source/nested/baz.ts'), 'console.log("baz");');

await execa('./cli.js', ['**/*.js', 'destination/subdir', '--cwd', t.context.tmp, '--flat']);

t.is(
read(t.context.tmp, 'foo.js'),
read(t.context.tmp, 'destination/subdir/foo.js'),
);
t.is(
read(t.context.tmp, 'source/bar.js'),
read(t.context.tmp, 'destination/subdir/bar.js'),
);
t.falsy(
fs.existsSync(path.join(t.context.tmp, 'destination/subdir/baz.ts')),
);
});