diff --git a/package-lock.json b/package-lock.json index b71bb516..198fe596 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3900,7 +3900,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -4722,8 +4722,8 @@ }, "rimraf": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "resolved": "http://registry.npm.taobao.org/rimraf/download/rimraf-2.6.2.tgz", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", "requires": { "glob": "7.1.2" } diff --git a/package.json b/package.json index 4cfc23a5..a6ed4948 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "pretest": "npm run lint && npm run build && npm run build:tests", "test": "mocha compiled_tests/", "build": "babel src/ --out-dir dist/", - "build:tests": "babel tests/ --out-dir compiled_tests/ && ncp tests/helpers compiled_tests/helpers" + "build:tests": "babel tests/ --out-dir compiled_tests/ && rimraf compiled_tests/helpers && ncp tests/helpers compiled_tests/helpers && node scripts/createSpecialDirectory.js" }, "dependencies": { "globby": "^7.1.1", @@ -34,12 +34,14 @@ "babel-cli": "^6.8.0", "babel-preset-es2015": "^6.6.0", "chai": "^3.4.0", - "eslint": "^2.9.0", "enhanced-resolve": "^3.4.1", + "eslint": "^2.9.0", + "is-gzip": "^2.0.0", + "mkdirp": "^0.5.1", "mocha": "^2.4.5", "ncp": "^2.0.0", - "standard-version": "^4.2.0", - "is-gzip": "^2.0.0" + "rimraf": "^2.6.2", + "standard-version": "^4.2.0" }, "homepage": "https://github.com/webpack-contrib/copy-webpack-plugin", "bugs": "https://github.com/webpack-contrib/copy-webpack-plugin/issues", diff --git a/scripts/createSpecialDirectory.js b/scripts/createSpecialDirectory.js new file mode 100644 index 00000000..831f336e --- /dev/null +++ b/scripts/createSpecialDirectory.js @@ -0,0 +1,20 @@ +const mkdirp = require('mkdirp'); +const path = require('path'); +const fs = require('fs'); +const removeIllegalCharacterForWindows = require('../tests/utils/removeIllegalCharacterForWindows'); + +const baseDir = 'compiled_tests/helpers'; + +const specialFiles = { + '[special?directory]/nested/nestedfile.txt': '', + '[special?directory]/(special-*file).txt': 'special', + '[special?directory]/directoryfile.txt': 'new' +}; + +Object.keys(specialFiles).forEach(function (originFile) { + const file = removeIllegalCharacterForWindows(originFile); + const dir = path.dirname(file); + mkdirp.sync(path.join(baseDir, dir)); + fs.writeFileSync(path.join(baseDir, file), specialFiles[originFile]); +}); + diff --git a/src/utils/escape.js b/src/utils/escape.js index 447f376b..07ef750f 100644 --- a/src/utils/escape.js +++ b/src/utils/escape.js @@ -7,8 +7,7 @@ export default function escape(context, from) { // Ensure context is escaped before globbing // Handles special characters in paths const absoluteContext = path.resolve(context) - .replace(/\\/, '/') - .replace(/[\*|\?|\!|\(|\)|\[|\]|\{|\}]/g, (substring) => `\\${substring}`); + .replace(/[\*|\?|\!|\(|\)|\[|\]|\{|\}]/g, (substring) => `[${substring}]`); if (!from) { return absoluteContext; diff --git a/tests/helpers/[special?directory]/nested/nestedfile.txt b/tests/helpers/[!]/hello.txt similarity index 100% rename from tests/helpers/[special?directory]/nested/nestedfile.txt rename to tests/helpers/[!]/hello.txt diff --git a/tests/helpers/[special?directory]/(special-*file).txt b/tests/helpers/[special?directory]/(special-*file).txt deleted file mode 100644 index 065d0200..00000000 --- a/tests/helpers/[special?directory]/(special-*file).txt +++ /dev/null @@ -1 +0,0 @@ -special \ No newline at end of file diff --git a/tests/helpers/[special?directory]/directoryfile.txt b/tests/helpers/[special?directory]/directoryfile.txt deleted file mode 100644 index 3e5126c4..00000000 --- a/tests/helpers/[special?directory]/directoryfile.txt +++ /dev/null @@ -1 +0,0 @@ -new \ No newline at end of file diff --git a/tests/index.js b/tests/index.js index fefd44ec..bcb8497e 100644 --- a/tests/index.js +++ b/tests/index.js @@ -15,6 +15,8 @@ import cacache from 'cacache'; import isGzip from 'is-gzip'; import zlib from 'zlib'; +import removeIllegalCharacterForWindows from './utils/removeIllegalCharacterForWindows'; + const BUILD_DIR = path.join(__dirname, 'build'); const HELPER_DIR = path.join(__dirname, 'helpers'); const TEMP_DIR = path.join(__dirname, 'tempdir'); @@ -58,6 +60,13 @@ describe('apply function', () => { // Ideally we pass in patterns and confirm the resulting assets const run = (opts) => { return new Promise((resolve, reject) => { + if (Array.isArray(opts.patterns)) { + opts.patterns.forEach(function (pattern) { + if (pattern.context) { + pattern.context = removeIllegalCharacterForWindows(pattern.context); + } + }); + } const plugin = CopyWebpackPlugin(opts.patterns, opts.options); // Get a mock compiler to pass to plugin.apply @@ -109,7 +118,7 @@ describe('apply function', () => { return run(opts) .then((compilation) => { if (opts.expectedAssetKeys && opts.expectedAssetKeys.length > 0) { - expect(compilation.assets).to.have.all.keys(opts.expectedAssetKeys); + expect(compilation.assets).to.have.all.keys(opts.expectedAssetKeys.map(removeIllegalCharacterForWindows)); } else { expect(compilation.assets).to.deep.equal({}); } @@ -268,6 +277,7 @@ describe('apply function', () => { it('can use a glob to move multiple files to the root directory', (done) => { runEmit({ expectedAssetKeys: [ + '[!]/hello.txt', 'binextension.bin', 'file.txt', 'file.txt.gz', @@ -289,6 +299,7 @@ describe('apply function', () => { it('can use a glob to move multiple files to a non-root directory', (done) => { runEmit({ expectedAssetKeys: [ + 'nested/[!]/hello.txt', 'nested/binextension.bin', 'nested/file.txt', 'nested/file.txt.gz', @@ -405,6 +416,7 @@ describe('apply function', () => { it('can use a glob with a full path to move multiple files to the root directory', (done) => { runEmit({ expectedAssetKeys: [ + '[!]/hello.txt', 'file.txt', 'directory/directoryfile.txt', 'directory/nested/nestedfile.txt', @@ -423,6 +435,7 @@ describe('apply function', () => { it('can use a glob to move multiple files to a non-root directory with name, hash and ext', (done) => { runEmit({ expectedAssetKeys: [ + 'nested/[!]/hello-d41d8c.txt', 'nested/binextension-d41d8c.bin', 'nested/file-22af64.txt', 'nested/file.txt-5b311c.gz', @@ -445,13 +458,14 @@ describe('apply function', () => { it('can flatten or normalize glob matches', (done) => { runEmit({ expectedAssetKeys: [ + '[!]-hello.txt', '[special?directory]-(special-*file).txt', '[special?directory]-directoryfile.txt', 'directory-directoryfile.txt' ], patterns: [{ from: '*/*.*', - test: /([^\/]+)\/([^\/]+)\.\w+$/, + test: `([^\\${path.sep}]+)\\${path.sep}([^\\${path.sep}]+)\\.\\w+$`, to: '[1]-[2].[ext]' }] }) @@ -887,6 +901,7 @@ describe('apply function', () => { it('ignores files in pattern', (done) => { runEmit({ expectedAssetKeys: [ + '[!]/hello.txt', 'binextension.bin', 'directory/directoryfile.txt', 'directory/nested/nestedfile.txt', @@ -984,7 +999,7 @@ describe('apply function', () => { 'nested/nestedfile.txt' ], patterns: [{ - from: '[special?directory]' + from: (path.sep === '/' ? '[special?directory]' : '[specialdirectory]') }] }) .then(done) @@ -1324,6 +1339,7 @@ describe('apply function', () => { it('ignores files that start with a dot', (done) => { runEmit({ expectedAssetKeys: [ + '[!]/hello.txt', 'binextension.bin', 'file.txt', 'file.txt.gz', @@ -1384,13 +1400,14 @@ describe('apply function', () => { it('ignores nested directory', (done) => { runEmit({ expectedAssetKeys: [ + '[!]/hello.txt', 'binextension.bin', 'file.txt', 'file.txt.gz', 'noextension' ], options: { - ignore: ['directory/**/*', '\\[special\\?directory\\]/**/*'] + ignore: ['directory/**/*', `[[]special${process.platform === 'win32' ? '' : '[?]'}directory]/**/*`] }, patterns: [{ from: '.' @@ -1401,6 +1418,29 @@ describe('apply function', () => { .catch(done); }); + if (path.sep === '/') { + it('ignores nested directory(can use "\\" to escape if path.sep is "/")', (done) => { + runEmit({ + expectedAssetKeys: [ + '[!]/hello.txt', + 'binextension.bin', + 'file.txt', + 'file.txt.gz', + 'noextension' + ], + options: { + ignore: ['directory/**/*', '\\[special\\?directory\\]/**/*'] + }, + patterns: [{ + from: '.' + }] + + }) + .then(done) + .catch(done); + }); + } + it('ignores nested directory (glob)', (done) => { runEmit({ expectedAssetKeys: [ diff --git a/tests/utils/removeIllegalCharacterForWindows.js b/tests/utils/removeIllegalCharacterForWindows.js new file mode 100644 index 00000000..0754abbf --- /dev/null +++ b/tests/utils/removeIllegalCharacterForWindows.js @@ -0,0 +1,4 @@ +module.exports = function (string) { + return process.platform !== 'win32' ? string : string.replace(/[*?"<>|]/g, ''); +}; +