-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Add --only-changed flag to CLI #5910
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
aa67512
7aa5f3b
9d04d64
d488c24
66e21f6
1952ba9
91951df
8679b70
47ffe28
f51c31b
11bb087
12c1b77
392c451
94f3c2b
7420a3b
8f2fa71
126eedf
171603a
ddeaadc
c9add14
db47a2a
5e1e508
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| "use strict"; | ||
|
|
||
| const crypto = require("crypto"); | ||
|
|
||
| // Generates a hash of the input string. | ||
| function hash(data) { | ||
| return crypto | ||
| .createHash("sha1") | ||
| .update(data) | ||
| .digest("base64"); | ||
| } | ||
|
|
||
| // Generates the cache key using the file path, options and the support info hash. | ||
| function calcKey(path, options, supportInfoHash) { | ||
| return hash(path + JSON.stringify(options) + supportInfoHash); | ||
| } | ||
|
|
||
| class ChangedCache { | ||
| // Initializes the in-memory cache data from the configured location. | ||
| // Also calculates the static support info hash used to compute file keys. | ||
| // A missing cache file is not treated as an error because it is expected on first run. | ||
| constructor(options) { | ||
| this.location = options.location; | ||
| this.readFile = options.readFile; | ||
| this.writeFile = options.writeFile; | ||
| this.context = options.context; | ||
| this.supportInfoHash = hash(JSON.stringify(options.supportInfo)); | ||
|
|
||
| this.cache = {}; | ||
|
|
||
| let contents; | ||
| try { | ||
| contents = this.readFile(this.location, "utf8"); | ||
| } catch (err) { | ||
| if (err.code !== "ENOENT") { | ||
| this.context.logger.error(`Could not read cache file: ${err}`); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| this.cache = JSON.parse(contents); | ||
| } catch (err) { | ||
| this.context.logger.error(`Could not parse cache contents: ${err}`); | ||
| } | ||
| } | ||
|
|
||
| // Writes the in-memory cache data to the configured file. | ||
| // Previous file contents are overwritten. | ||
| close() { | ||
| let contents; | ||
| try { | ||
| contents = JSON.stringify(this.cache); | ||
| } catch (err) { | ||
| this.context.logger.error(`Could not serialize cache: ${err}`); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| this.writeFile(this.location, contents, "utf8"); | ||
| } catch (err) { | ||
| this.context.logger.error(`Could not write cache to file: ${err}`); | ||
| } | ||
| } | ||
|
|
||
| // Checks if the expected contents of the file path match the in-memory data. | ||
| notChanged(path, options, content) { | ||
| return ( | ||
| this.cache[calcKey(path, options, this.supportInfoHash)] === hash(content) | ||
| ); | ||
| } | ||
|
|
||
| // Updates the expected contents of the file path in the in-memory data. | ||
| update(path, options, content) { | ||
| this.cache[calcKey(path, options, this.supportInfoHash)] = hash(content); | ||
| } | ||
| } | ||
|
|
||
| module.exports = ChangedCache; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,11 @@ function run(args) { | |
| process.exit(1); | ||
| } | ||
|
|
||
| if (context.argv["only-changed"] && !context.argv["write"]) { | ||
| context.logger.error("Cannot use --only-changed without --write."); | ||
| process.exit(1); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should enable
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought it might be best to avoid changing existing behavior silently, especially since this flag writes a file that needs to gitignored. I'll defer to the maintainers, y'all know best.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. /cc @prettier/core
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we can do this for
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, probably better to do it for v2
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But what is problem implement |
||
|
|
||
| if (context.argv["find-config-path"] && context.filePatterns.length) { | ||
| context.logger.error("Cannot use --find-config-path with multiple files"); | ||
| process.exit(1); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ const globby = require("globby"); | |
| const chalk = require("chalk"); | ||
| const readline = require("readline"); | ||
| const stringify = require("json-stable-stringify"); | ||
| const findCacheDir = require("find-cache-dir"); | ||
|
|
||
| const minimist = require("./minimist"); | ||
| const prettier = require("../../index"); | ||
|
|
@@ -20,6 +21,7 @@ const optionsNormalizer = require("../main/options-normalizer"); | |
| const thirdParty = require("../common/third-party"); | ||
| const arrayify = require("../utils/arrayify"); | ||
| const isTTY = require("../utils/is-tty"); | ||
| const ChangedCache = require("./changed-cache"); | ||
|
|
||
| const OPTION_USAGE_THRESHOLD = 25; | ||
| const CHOICE_USAGE_MARGIN = 3; | ||
|
|
@@ -441,6 +443,18 @@ function formatFiles(context) { | |
| context.logger.log("Checking formatting..."); | ||
| } | ||
|
|
||
| let changedCache = null; | ||
| if (context.argv["only-changed"]) { | ||
| const cacheDir = findCacheDir({ name: "prettier", create: true }); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. /cc @g-harel need use
In theory you can install
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice catch! I've openned a PR with a fix (#6327). |
||
| changedCache = new ChangedCache({ | ||
| location: path.join(cacheDir, "changed"), | ||
| readFile: fs.readFileSync, | ||
| writeFile: thirdParty.writeFileAtomic, | ||
| context: context, | ||
| supportInfo: prettier.getSupportInfo() | ||
| }); | ||
| } | ||
|
|
||
| eachFilename(context, context.filePatterns, filename => { | ||
| const fileIgnored = ignorer.filter([filename]).length === 0; | ||
| if ( | ||
|
|
@@ -457,9 +471,15 @@ function formatFiles(context) { | |
| filepath: filename | ||
| }); | ||
|
|
||
| let removeFilename = () => {}; | ||
| if (isTTY()) { | ||
| // Don't use `console.log` here since we need to replace this line. | ||
| context.logger.log(filename, { newline: false }); | ||
| removeFilename = () => { | ||
| readline.clearLine(process.stdout, 0); | ||
| readline.cursorTo(process.stdout, 0, null); | ||
| removeFilename = () => {}; | ||
| }; | ||
| } | ||
|
|
||
| let input; | ||
|
|
@@ -477,6 +497,19 @@ function formatFiles(context) { | |
| return; | ||
| } | ||
|
|
||
| if (changedCache) { | ||
| if (changedCache.notChanged(filename, options, input)) { | ||
| // Remove previously printed filename to log it with "unchanged". | ||
| removeFilename(); | ||
|
|
||
| if (!context.argv["check"] && !context.argv["list-different"]) { | ||
| context.logger.log(chalk.grey(`${filename} unchanged`)); | ||
| } | ||
|
|
||
| return; | ||
| } | ||
| } | ||
|
|
||
| if (fileIgnored) { | ||
| writeOutput(context, { formatted: input }, options); | ||
| return; | ||
|
|
@@ -501,11 +534,8 @@ function formatFiles(context) { | |
|
|
||
| const isDifferent = output !== input; | ||
|
|
||
| if (isTTY()) { | ||
| // Remove previously printed filename to log it with duration. | ||
| readline.clearLine(process.stdout, 0); | ||
| readline.cursorTo(process.stdout, 0, null); | ||
| } | ||
| // Remove previously printed filename to log it with duration. | ||
| removeFilename(); | ||
|
|
||
| if (context.argv["write"]) { | ||
| // Don't write the file if it won't change in order not to invalidate | ||
|
|
@@ -524,8 +554,15 @@ function formatFiles(context) { | |
| // Don't exit the process if one file failed | ||
| process.exitCode = 2; | ||
| } | ||
| } else if (!context.argv["check"] && !context.argv["list-different"]) { | ||
| context.logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`); | ||
| } else { | ||
| if (!context.argv["check"] && !context.argv["list-different"]) { | ||
| context.logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`); | ||
| } | ||
| } | ||
|
|
||
| // Cache is updated to record pretty content. | ||
| if (changedCache) { | ||
| changedCache.update(filename, options, output); | ||
| } | ||
| } else if (context.argv["debug-check"]) { | ||
| if (result.filepath) { | ||
|
|
@@ -546,6 +583,10 @@ function formatFiles(context) { | |
| } | ||
| }); | ||
|
|
||
| if (changedCache) { | ||
| changedCache.close(); | ||
| } | ||
|
|
||
| // Print check summary based on expected exit code | ||
| if (context.argv["check"]) { | ||
| context.logger.log( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| // Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
|
||
| exports[`create cache with --write --only-changed + formatted file (stderr) 1`] = `""`; | ||
|
|
||
| exports[`create cache with --write --only-changed + formatted file (stdout) 1`] = ` | ||
| "formatted.js 0ms | ||
| " | ||
| `; | ||
|
|
||
| exports[`create cache with --write --only-changed + unformatted file (stderr) 1`] = `""`; | ||
|
|
||
| exports[`create cache with --write --only-changed + unformatted file (stdout) 1`] = ` | ||
| "unformatted.js 0ms | ||
| " | ||
| `; | ||
|
|
||
| exports[`detect config change with --write --only-changed + unformatted file (stderr) 1`] = `""`; | ||
|
|
||
| exports[`detect config change with --write --only-changed + unformatted file (stderr) 2`] = `""`; | ||
|
|
||
| exports[`detect config change with --write --only-changed + unformatted file (stdout) 1`] = ` | ||
| "unformatted.js 0ms | ||
| " | ||
| `; | ||
|
|
||
| exports[`detect config change with --write --only-changed + unformatted file (stdout) 2`] = ` | ||
| "unformatted.js 0ms | ||
| " | ||
| `; | ||
|
|
||
| exports[`detect unchanged with --write --only-changed + formatted file (stderr) 1`] = `""`; | ||
|
|
||
| exports[`detect unchanged with --write --only-changed + formatted file (stderr) 2`] = `""`; | ||
|
|
||
| exports[`detect unchanged with --write --only-changed + formatted file (stdout) 1`] = ` | ||
| "formatted.js 0ms | ||
| " | ||
| `; | ||
|
|
||
| exports[`detect unchanged with --write --only-changed + formatted file (stdout) 2`] = ` | ||
| "formatted.js unchanged | ||
| " | ||
| `; |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe
md4(better usexxHash, butxxHashdoesn't built-in in node 😞 ),sha1is very slow, also we don't need strong hereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We had a bit of a discussion about this on the issue and ended up finding that hashing is not a bottleneck in this case. I'm open to changing it, but I'm not sure it's worth adding a dependency.
#5853 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okey, let's wait other feedback, for me
md4is best solution here, when you have really big codebase, it is increase perf around 5%