Skip to content

Commit

Permalink
Rewrote and added debug mode
Browse files Browse the repository at this point in the history
  • Loading branch information
kevlened committed Oct 12, 2016
1 parent 1890d37 commit 42c1ca2
Show file tree
Hide file tree
Showing 11 changed files with 372 additions and 331 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ A pattern looks like:
- is optional
- defaults to `false` (only copies modified files)
- `true` copies all files while using watch or webpack-dev-server
* `debug`
- is optional
- defaults to `'warning'` (only logs on warning)
- `true` is the same as `'info'`
- options are `'warning'`, `'info'`, and `'debug'`

### Examples

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
"glob": "^6.0.4",
"lodash": "^4.3.0",
"minimatch": "^3.0.0",
"node-dir": "^0.1.10"
"node-dir": "^0.1.10",
"loader-utils": "^0.2.15"
},
"scripts": {
"lint": "eslint src/ tests/",
"pretest": "npm run lint && npm run build && npm run build:tests",
"test": "mocha compiled_tests/",
"test:nolint": "npm run build && npm run build:tests && mocha compiled_tests/",
"build": "babel src/ --out-dir dist/",
"build:tests": "babel tests/ --out-dir compiled_tests/ && ncp tests/helpers compiled_tests/helpers"
},
Expand Down
226 changes: 84 additions & 142 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,175 +1,117 @@
import _ from 'lodash';
import path from 'path';
import Promise from 'bluebird';
import toLooksLikeDirectory from './toLooksLikeDirectory';
import writeFileToAssets from './writeFileToAssets';
import writeDirectoryToAssets from './writeDirectoryToAssets';
import shouldIgnore from './shouldIgnore';

/* eslint-disable import/no-commonjs */
const globAsync = Promise.promisify(require('glob'));
const fs = Promise.promisifyAll(require('fs-extra'));
/* eslint-enable */
import _ from 'lodash';
import preProcessPattern from './preProcessPattern';
import processPattern from './processPattern';

function CopyWebpackPlugin(patterns = [], options = {}) {
if (!_.isArray(patterns)) {
throw new Error('CopyWebpackPlugin: patterns must be an array');
if (!Array.isArray(patterns)) {
throw new Error('[copy-webpack-plugin] patterns must be an array');
}

const apply = (compiler) => {
const webpackContext = compiler.options.context;
const outputPath = compiler.options.output.path;
const fileDependencies = [];
const contextDependencies = [];
const webpackIgnore = options.ignore || [];
const copyUnmodified = options.copyUnmodified;
const writtenAssetHashes = {};
// Defaults debug level to 'warning'
options.debug = options.debug || 'warning';

compiler.plugin('emit', (compilation, cb) => {
// Defaults debugging to info if only true is specified
if (options.debug === true) {
options.debug = 'info';
}

Promise.each(patterns, (pattern) => {
let relDest;
let globOpts;
const debugLevels = ['warning', 'info', 'debug'];
const debugLevelIndex = debugLevels.indexOf(options.debug);
function log(msg, level) {
if (level === 0) {
msg = `WARNING - ${msg}`;
} else {
level = level || 1;
}
if (level <= debugLevelIndex) {
console.log('[copy-webpack-plugin] ' + msg); // eslint-disable-line no-console
}
}

if (pattern.context && !path.isAbsolute(pattern.context)) {
pattern.context = path.resolve(webpackContext, pattern.context);
}
function warning(msg) {
log(msg, 0);
}

const context = pattern.context || webpackContext;
const ignoreList = webpackIgnore.concat(pattern.ignore || []);
function info(msg) {
log(msg, 1);
}

globOpts = {
cwd: context
};
function debug(msg) {
log(msg, 2);
}

// From can be an object
if (pattern.from.glob) {
globOpts = _.assignIn(globOpts, _.omit(pattern.from, 'glob'));
pattern.from = pattern.from.glob;
}
const apply = (compiler) => {
const fileDependencies = [];
const contextDependencies = [];
const written = {};

const relSrc = pattern.from;
const absSrc = path.resolve(context, relSrc);

relDest = pattern.to || '';

const forceWrite = Boolean(pattern.force);

return fs
.statAsync(absSrc)
.catch(() => {
return null;
})
.then((stat) => {
if (stat && stat.isDirectory()) {
contextDependencies.push(absSrc);

// Make the relative destination actually relative
if (path.isAbsolute(relDest)) {
relDest = path.relative(outputPath, relDest);
}

return writeDirectoryToAssets({
absDirSrc: absSrc,
compilation,
copyUnmodified,
flatten: pattern.flatten,
forceWrite,
ignoreList,
relDirDest: relDest,
writtenAssetHashes
});
}

return globAsync(relSrc, globOpts)
.each((relFileSrcParam) => {
let relFileDest;
let relFileSrc;

relFileSrc = relFileSrcParam;

// Skip if it matches any of our ignore list
if (shouldIgnore(relFileSrc, ignoreList)) {
return false;
}

const absFileSrc = path.resolve(context, relFileSrc);

relFileDest = pattern.to || '';

// Remove any directory references if flattening
if (pattern.flatten) {
relFileSrc = path.basename(relFileSrc);
}

const relFileDirname = path.dirname(relFileSrc);

fileDependencies.push(absFileSrc);

// If the pattern is a blob
if (!stat) {
// If the source is absolute
if (path.isAbsolute(relFileSrc)) {
// Make the destination relative
relFileDest = path.join(path.relative(context, relFileDirname), path.basename(relFileSrc));

// If the source is relative
} else {
relFileDest = path.join(relFileDest, relFileSrc);
}

// If it looks like a directory
} else if (toLooksLikeDirectory(pattern)) {
// Make the path relative to the source
relFileDest = path.join(relFileDest, path.basename(relFileSrc));
}

// If there's still no relFileDest
relFileDest = relFileDest || path.basename(relFileSrc);

// Make sure the relative destination is actually relative
if (path.isAbsolute(relFileDest)) {
relFileDest = path.relative(outputPath, relFileDest);
}

return writeFileToAssets({
absFileSrc,
compilation,
copyUnmodified,
forceWrite,
relFileDest,
writtenAssetHashes
});
});
});
compiler.plugin('emit', (compilation, cb) => {
debug('starting emit');
const callback = () => {
debug('finishing emit');
cb();
};

const globalRef = {
info,
debug,
warning,
compilation,
written,
fileDependencies,
contextDependencies,
context: compiler.options.context,
output: compiler.options.output.path,
ignore: options.ignore || [],
copyUnmodified: options.copyUnmodified
};

Promise.each(patterns, (pattern) => {
// Identify absolute source of each pattern and destination type
return preProcessPattern(globalRef, pattern)
.then((pattern) => {
// Every source (from) is assumed to exist here
return processPattern(globalRef, pattern);
});
})
.catch((err) => {
compilation.errors.push(err);
})
.finally(cb);
.finally(callback);
});

compiler.plugin('after-emit', (compilation, callback) => {
const trackedFiles = compilation.fileDependencies;
compiler.plugin('after-emit', (compilation, cb) => {
debug('starting after-emit');
const callback = () => {
debug('finishing after-emit');
cb();
};

// Add file dependencies if they're not already tracked
_.forEach(fileDependencies, (file) => {
if (!_.includes(trackedFiles, file)) {
trackedFiles.push(file);
if (_.includes(compilation.fileDependencies, file)) {
debug(`not adding ${file} to change tracking, because it's already tracked`);
} else {
debug(`adding ${file} to change tracking`);
compilation.fileDependencies.push(file);
}
});

const trackedDirs = compilation.contextDependencies;

// Add context dependencies if they're not already tracked
_.forEach(contextDependencies, (context) => {
if (!_.includes(trackedDirs, context)) {
trackedDirs.push(context);
if (_.includes(compilation.contextDependencies, context)) {
debug(`not adding ${context} to change tracking, because it's already tracked`);
} else {
debug(`adding ${context} to change tracking`);
compilation.contextDependencies.push(context);
}
});

callback();
});
};

return {
apply
};
Expand Down
85 changes: 85 additions & 0 deletions src/preProcessPattern.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import Promise from 'bluebird';
import path from 'path';
import _ from 'lodash';

const fs = Promise.promisifyAll(require('fs')); // eslint-disable-line import/no-commonjs

var isGlobLike = /\*/;
var isTemplateLike = new RegExp('templateRegExp');

export default function preProcessPattern(globalRef, pattern) {
const {info, debug, warning, context,
fileDependencies, contextDependencies, compilation} = globalRef;

pattern = _.cloneDeep(pattern);
pattern.to = pattern.to || '';
pattern.context = pattern.context || context;
if (!path.isAbsolute(pattern.context)) {
pattern.context = path.join(context, pattern.context);
}
pattern.ignore = globalRef.ignore.concat(pattern.ignore || []);

info(`processing from: '${pattern.from}' to: '${pattern.to}'`);

switch(true) {
case !!pattern.toType: // if toType already exists
break;
case isTemplateLike.test(pattern.to):
pattern.toType = 'template';
break;
case path.extname(pattern.to) === '' || pattern.to.slice(-1) === '/':
pattern.toType = 'dir';
break;
default:
pattern.toType = 'file';
}

debug(`determined '${pattern.to}' is a '${pattern.toType}'`);

if (path.isAbsolute(pattern.from)) {
pattern.absoluteFrom = pattern.from;
} else {
pattern.absoluteFrom = path.resolve(pattern.context, pattern.from);
}

debug(`determined '${pattern.from}' to be read from '${pattern.absoluteFrom}'`);

return fs
.statAsync(pattern.absoluteFrom)
.catch(() => {
// If from doesn't appear to be a glob, then log a warning
if (isGlobLike.test(pattern.from)) {
pattern.fromType = 'glob';
} else {
const msg = `unable to locate '${pattern.from}' at '${pattern.absoluteFrom}'`;
warning(msg);
compilation.errors.push(`[copy-webpack-plugin] ${msg}`);
pattern.fromType = 'nonexistent';
}
})
.then((stat) => {
if (!stat) {
return pattern;
}

if (stat.isDirectory()) {
pattern.fromType = 'dir';
pattern.context = pattern.absoluteFrom;
contextDependencies.push(pattern.absoluteFrom);
pattern.absoluteFrom = path.join(pattern.absoluteFrom, '**/*');
pattern.fromArgs = {
dot: true
};
} else if(stat.isFile()) {
pattern.fromType = 'file';
pattern.context = path.dirname(pattern.absoluteFrom);
pattern.fromArgs = {
dot: true
};
fileDependencies.push(pattern.absoluteFrom);
} else if(!pattern.fromType) {
info(`Unrecognized file type for ${pattern.from}`);
}
return pattern;
});
}
Loading

0 comments on commit 42c1ca2

Please sign in to comment.