Skip to content

Commit

Permalink
Merge branch 'addPassthroughCopy-follow-symlinks' of github.com:milah…
Browse files Browse the repository at this point in the history
…u/eleventy into milahu-addPassthroughCopy-follow-symlinks

# Conflicts:
#	src/TemplatePassthrough.js
#	src/TemplatePassthroughManager.js
  • Loading branch information
zachleat committed Jun 24, 2022
2 parents b8076f3 + 4398626 commit 81f765e
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 63 deletions.
17 changes: 13 additions & 4 deletions src/TemplatePassthrough.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class TemplatePassthrough {
this.outputPath = path.outputPath;
this.outputDir = outputDir;

this.copyOptions = path.copyOptions; // custom options for recursive-copy

this.isDryRun = false;
this.isIncremental = false;
}
Expand Down Expand Up @@ -189,16 +191,23 @@ class TemplatePassthrough {
debug("Copying %o", this.inputPath);
let fileMap = await this.getFileMap();

let copyOptions = {
overwrite: true,
dot: true,
junk: false,
// default options for recursive-copy
// see https://www.npmjs.com/package/recursive-copy#arguments
const copyOptionsDefault = {
overwrite: true, // overwrite output. fails when input is directory (mkdir) and output is file
dot: true, // copy dotfiles
junk: false, // copy cache files like Thumbs.db
results: false,
expand: false, // follow symlinks (matches recursive-copy default)
debug: false, // (matches recursive-copy default)

// Note: `filter` callback function only passes in a relative path, which is unreliable
// See https://github.com/timkendrick/recursive-copy/blob/4c9a8b8a4bf573285e9c4a649a30a2b59ccf441c/lib/copy.js#L59
// e.g. `{ filePaths: [ './img/coolkid.jpg' ], relativePaths: [ '' ] }`
};

const copyOptions = Object.assign(copyOptionsDefault, this.copyOptions);

let promises = fileMap.map((entry) => {
// For-free passthrough copy
if (checkPassthroughCopyBehavior(this.config, this.runMode)) {
Expand Down
53 changes: 29 additions & 24 deletions src/TemplatePassthroughManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,24 @@ class TemplatePassthroughManager {
}
}

_normalizePaths(path, outputPath) {
_normalizePaths(path, outputPath, copyOptions = {}) {
return {
inputPath: TemplatePath.addLeadingDotSlash(path),
outputPath: outputPath
? TemplatePath.stripLeadingDotSlash(outputPath)
: true,
copyOptions,
};
}

getConfigPaths() {
let paths = [];
let target = this.config.passthroughCopies || {};
debug("`addPassthroughCopy` config API paths: %o", target);
for (let path in target) {
paths.push(this._normalizePaths(path, target[path]));
const paths = [];
const pathsRaw = this.config.passthroughCopies || {};
debug("`addPassthroughCopy` config API paths: %o", pathsRaw);
for (const [inputPath, { outputPath, copyOptions }] of Object.entries(
pathsRaw
)) {
paths.push(this._normalizePaths(inputPath, outputPath, copyOptions));
}
debug("`addPassthroughCopy` config API normalized paths: %o", paths);
return paths;
Expand Down Expand Up @@ -244,23 +247,27 @@ class TemplatePassthroughManager {
return [];
}

let normalizedPaths = [];

let pathsFromConfigurationFile = this.getConfigPaths();
for (let path of pathsFromConfigurationFile) {
debug("TemplatePassthrough copying from config: %o", path);
normalizedPaths.push(path);
const normalizedPaths = this.getConfigPaths();
if (debug.enabled) {
for (const path of normalizedPaths) {
debug("TemplatePassthrough copying from config: %o", path);
}
}

if (paths && paths.length) {
let passthroughPaths = this.getNonTemplatePaths(paths);
for (let path of passthroughPaths) {
let normalizedPath = this._normalizePaths(path);
debug(
`TemplatePassthrough copying from non-matching file extension: ${normalizedPath.inputPath}`
);
const passthroughPaths = this.getNonTemplatePaths(paths);
for (const path of passthroughPaths) {
const normalizedPath = this._normalizePaths(path);
normalizedPaths.push(normalizedPath);
}
if (debug.enabled) {
for (const path of passthroughPaths) {
const normalizedPath = this._normalizePaths(path);
debug(
`TemplatePassthrough copying from non-matching file extension: ${normalizedPath.inputPath}`
);
}
}
}

return normalizedPaths;
Expand Down Expand Up @@ -289,14 +296,12 @@ class TemplatePassthroughManager {
debug("TemplatePassthrough copy started.");
let normalizedPaths = this.getAllNormalizedPaths(paths);

let passthroughs = [];
for (let path of normalizedPaths) {
let passthroughs = normalizedPaths.map((path) => {
// if incrementalFile is set but it isn’t a passthrough copy, normalizedPaths will be an empty array
let isIncremental = !!this.incrementalFile;
passthroughs.push(
this.getTemplatePassthroughForPath(path, isIncremental)
);
}

return this.getTemplatePassthroughForPath(path, isIncremental);
});

return Promise.all(
passthroughs.map((pass) => this.copyPassthrough(pass))
Expand Down
12 changes: 9 additions & 3 deletions src/UserConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,14 +410,20 @@ class UserConfig {
*
* @param {string|object} fileOrDir The path to the file or directory that should
* be copied. OR an object where the key is the input glob and the property is the output directory
* @param {object} copyOptions options for recursive-copy.
* see https://www.npmjs.com/package/recursive-copy#arguments
* default options are defined in TemplatePassthrough copyOptionsDefault
* @returns {any} a reference to the `EleventyConfig` object.
* @memberof EleventyConfig
*/
addPassthroughCopy(fileOrDir) {
addPassthroughCopy(fileOrDir, copyOptions = {}) {
if (typeof fileOrDir === "string") {
this.passthroughCopies[fileOrDir] = true;
const inputPath = fileOrDir;
this.passthroughCopies[inputPath] = { outputPath: true, copyOptions };
} else {
Object.assign(this.passthroughCopies, fileOrDir);
for (const [inputPath, outputPath] of Object.entries(fileOrDir)) {
this.passthroughCopies[inputPath] = { outputPath, copyOptions };
}
}

return this;
Expand Down
47 changes: 26 additions & 21 deletions test/TemplatePassthroughManagerTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@ const EleventyExtensionMap = require("../src/EleventyExtensionMap");
test("Get paths from Config", async (t) => {
let eleventyConfig = new TemplateConfig();
eleventyConfig.userConfig.passthroughCopies = {
img: true,
img: { outputPath: true },
};
let mgr = new TemplatePassthroughManager(eleventyConfig);

t.deepEqual(mgr.getConfigPaths(), [{ inputPath: "./img", outputPath: true }]);
t.deepEqual(mgr.getConfigPaths(), [
{ inputPath: "./img", outputPath: true, copyOptions: {} },
]);
});

test("isPassthroughCopyFile", async (t) => {
let eleventyConfig = new TemplateConfig();
eleventyConfig.userConfig.passthroughCopies = {
img: true,
fonts: true,
img: { outputPath: true },
fonts: { outputPath: true },
};
let mgr = new TemplatePassthroughManager(eleventyConfig);

Expand Down Expand Up @@ -48,9 +50,9 @@ test("isPassthroughCopyFile", async (t) => {
test("Get glob paths from config", async (t) => {
let eleventyConfig = new TemplateConfig();
eleventyConfig.userConfig.passthroughCopies = {
"test/stubs/img": true,
"test/stubs/img/**": "./",
"test/stubs/img/*.js": "./",
"test/stubs/img": { outputPath: true },
"test/stubs/img/**": { outputPath: "./" },
"test/stubs/img/*.js": { outputPath: "./" },
};
let mgr = new TemplatePassthroughManager(eleventyConfig);

Expand Down Expand Up @@ -100,11 +102,11 @@ test("Get file paths (one image path)", async (t) => {
test("Naughty paths outside of project dir", async (t) => {
let eleventyConfig = new TemplateConfig();
eleventyConfig.userConfig.passthroughCopies = {
"../static": true,
"../*": "./",
"./test/stubs/template-passthrough2/static/*.css": "./",
"./test/stubs/template-passthrough2/static/*.js": "../../",
"./test/stubs/template-passthrough2/img.jpg": "../../",
"../static": { outputPath: true },
"../*": { outputPath: "./" },
"./test/stubs/template-passthrough2/static/*.css": { outputPath: "./" },
"./test/stubs/template-passthrough2/static/*.js": { outputPath: "../../" },
"./test/stubs/template-passthrough2/img.jpg": { outputPath: "../../" },
};

let mgr = new TemplatePassthroughManager(eleventyConfig);
Expand Down Expand Up @@ -132,36 +134,39 @@ test("Naughty paths outside of project dir", async (t) => {
test("getAllNormalizedPaths", async (t) => {
let eleventyConfig = new TemplateConfig();
eleventyConfig.userConfig.passthroughCopies = {
img: true,
img: { outputPath: true },
};

let mgr = new TemplatePassthroughManager(eleventyConfig);
t.deepEqual(mgr.getAllNormalizedPaths(), [
{ inputPath: "./img", outputPath: true },
{ inputPath: "./img", outputPath: true, copyOptions: {} },
]);
});

test("getAllNormalizedPaths with globs", async (t) => {
let eleventyConfig = new TemplateConfig();
eleventyConfig.userConfig.passthroughCopies = {
img: true,
"img/**": "./",
"img/*.js": "./",
img: { outputPath: true },
"img/**": { outputPath: "./" },
"img/*.js": { outputPath: "./" },
};

let mgr = new TemplatePassthroughManager(eleventyConfig);
t.deepEqual(mgr.getAllNormalizedPaths(), [
{ inputPath: "./img", outputPath: true },
{ inputPath: "./img/**", outputPath: "" },
{ inputPath: "./img/*.js", outputPath: "" },
{ inputPath: "./img", outputPath: true, copyOptions: {} },
{ inputPath: "./img/**", outputPath: "", copyOptions: {} },
{ inputPath: "./img/*.js", outputPath: "", copyOptions: {} },
]);
});

test("Look for uniqueness on template passthrough paths #1677", async (t) => {
let formats = [];
let eleventyConfig = new TemplateConfig();
eleventyConfig.userConfig.passthroughCopies = {
"./test/stubs/template-passthrough-duplicates/**/*.png": "./",
"./test/stubs/template-passthrough-duplicates/**/*.png": {
outputPath: "./",
copyOptions: {},
},
};

let files = new EleventyFiles(
Expand Down
20 changes: 16 additions & 4 deletions test/TemplateWriterTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -690,10 +690,22 @@ test("Passthrough file output", async (t) => {

let eleventyConfig = new TemplateConfig();
eleventyConfig.userConfig.passthroughCopies = {
"./test/stubs/template-passthrough/static": true,
"./test/stubs/template-passthrough/static/": "./",
"./test/stubs/template-passthrough/static/**/*": "./all/",
"./test/stubs/template-passthrough/static/**/*.js": "./js/",
"./test/stubs/template-passthrough/static": {
outputPath: true,
copyOptions: {},
},
"./test/stubs/template-passthrough/static/": {
outputPath: "./",
copyOptions: {},
},
"./test/stubs/template-passthrough/static/**/*": {
outputPath: "./all/",
copyOptions: {},
},
"./test/stubs/template-passthrough/static/**/*.js": {
outputPath: "./js/",
copyOptions: {},
},
};

let tw = new TemplateWriter(
Expand Down
35 changes: 28 additions & 7 deletions test/UserConfigTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ test("Set manual Pass-through File Copy (single call)", (t) => {
let userCfg = new UserConfig();
userCfg.addPassthroughCopy("img");

t.is(userCfg.passthroughCopies["img"], true);
t.deepEqual(userCfg.passthroughCopies["img"], {
outputPath: true,
copyOptions: {},
});
});

test("Set manual Pass-through File Copy (chained calls)", (t) => {
Expand All @@ -110,10 +113,22 @@ test("Set manual Pass-through File Copy (chained calls)", (t) => {
.addPassthroughCopy({ "./src/static": "static" })
.addPassthroughCopy({ "./src/empty": "./" });

t.is(userCfg.passthroughCopies["css"], true);
t.is(userCfg.passthroughCopies["js"], true);
t.is(userCfg.passthroughCopies["./src/static"], "static");
t.is(userCfg.passthroughCopies["./src/empty"], "./");
t.deepEqual(userCfg.passthroughCopies["css"], {
outputPath: true,
copyOptions: {},
});
t.deepEqual(userCfg.passthroughCopies["js"], {
outputPath: true,
copyOptions: {},
});
t.deepEqual(userCfg.passthroughCopies["./src/static"], {
outputPath: "static",
copyOptions: {},
});
t.deepEqual(userCfg.passthroughCopies["./src/empty"], {
outputPath: "./",
copyOptions: {},
});
});

test("Set manual Pass-through File Copy (glob patterns)", (t) => {
Expand All @@ -128,8 +143,14 @@ test("Set manual Pass-through File Copy (glob patterns)", (t) => {
t.is(userCfg.passthroughCopies["js/**"], undefined);

// exists
t.is(userCfg.passthroughCopies["./src/static/**/*"], "renamed");
t.is(userCfg.passthroughCopies["./src/markdown/*.md"], "");
t.deepEqual(userCfg.passthroughCopies["./src/static/**/*"], {
outputPath: "renamed",
copyOptions: {},
});
t.deepEqual(userCfg.passthroughCopies["./src/markdown/*.md"], {
outputPath: "",
copyOptions: {},
});
});

test("Set Template Formats (string)", (t) => {
Expand Down

0 comments on commit 81f765e

Please sign in to comment.