-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Chore: Sync fuzzer: Re-use the same CLI process for commands run on the same client #12913
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
Merged
laurent22
merged 25 commits into
laurent22:dev
from
personalizedrefrigerator:pr/server/fuzzer/just-one-process
Aug 10, 2025
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
01b7370
Chore: Sync fuzzer: Add action that syncs a new temporary client
personalizedrefrigerator 4da67d2
Work around sync failure during first sync of secondary client
personalizedrefrigerator a67f69a
Refactoring
personalizedrefrigerator 7abddaf
Refactoring
personalizedrefrigerator 0d38d70
Sync after accepting shares -- trying to fix E2EE key not loaded error
personalizedrefrigerator 92aeff1
Merge remote-tracking branch 'upstream/dev' into pr/server/fuzzer/syn…
personalizedrefrigerator f987fbb
WIP: Keep the CLI app open in the background, rather than re-opening for
personalizedrefrigerator 3b7db5f
Merge remote-tracking branch 'upstream/dev' into pr/server/fuzzer/syn…
personalizedrefrigerator 94f94d7
Trying to fix "master key not loaded" sync error
personalizedrefrigerator c6fb978
Add additional debug logic
personalizedrefrigerator c03770b
Remove console.log
personalizedrefrigerator 1bf4dc0
Work around certain timing-related sync issues by retrying sync with a
personalizedrefrigerator 6585bbd
Work around E2EE sync error by adjusting retry delays
personalizedrefrigerator f783ee5
Resync secondary clients on the same account if the initial checkStat…
personalizedrefrigerator f658cbd
Debugging: Add command to dump the content of a specific item
personalizedrefrigerator aca24f8
Merge remote-tracking branch 'upstream/dev' into pr/server/fuzzer/syn…
personalizedrefrigerator 1a9b539
Merge remote-tracking branch 'upstream/dev' into pr/server/fuzzer/jus…
personalizedrefrigerator 32a664f
Revert changes related to adding new clients on the same account
personalizedrefrigerator 6e03e13
Refactoring
personalizedrefrigerator 253d567
Don't start a background decryption task when syncInfoCache changes and
personalizedrefrigerator 56f48e8
Update server command help text
personalizedrefrigerator 74f7d29
Refactoring
personalizedrefrigerator d576a10
Refactoring
personalizedrefrigerator 78ef350
Batch command: Don't allow reading commands from stdin in GUI mode
personalizedrefrigerator d7a0207
Exclude more information from the client transcript
personalizedrefrigerator File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import { splitCommandBatch } from '@joplin/lib/string-utils'; | ||
| import BaseCommand from './base-command'; | ||
| import { _ } from '@joplin/lib/locale'; | ||
| import { splitCommandString } from '@joplin/utils'; | ||
| import iterateStdin from './utils/iterateStdin'; | ||
| import { readFile } from 'fs-extra'; | ||
| import app from './app'; | ||
|
|
||
| interface Options { | ||
| 'file-path': string; | ||
| options: { | ||
| 'continue-on-failure': boolean; | ||
| }; | ||
| } | ||
|
|
||
| class Command extends BaseCommand { | ||
| public usage() { | ||
| return 'batch <file-path>'; | ||
| } | ||
|
|
||
| public options() { | ||
| return [ | ||
| // These are present mostly for testing purposes | ||
| ['--continue-on-failure', 'Continue running commands when one command in the batch fails.'], | ||
| ]; | ||
| } | ||
|
|
||
| public description() { | ||
| return _('Runs the commands contained in the text file. There should be one command per line.'); | ||
| } | ||
|
|
||
| private streamCommands_ = async function*(filePath: string) { | ||
| const processLines = function*(lines: string) { | ||
| const commandLines = splitCommandBatch(lines); | ||
|
|
||
| for (const command of commandLines) { | ||
| if (!command.trim()) continue; | ||
| yield splitCommandString(command.trim()); | ||
| } | ||
| }; | ||
|
|
||
| if (filePath === '-') { // stdin | ||
| // Iterating over standard input conflicts with the CLI app's GUI. | ||
| if (app().hasGui()) { | ||
| throw new Error(_('Reading commands from standard input is only available in CLI mode.')); | ||
| } | ||
|
|
||
| for await (const lines of iterateStdin('command> ')) { | ||
| yield* processLines(lines); | ||
| } | ||
| } else { | ||
| const data = await readFile(filePath, 'utf-8'); | ||
| yield* processLines(data); | ||
| } | ||
| }; | ||
|
|
||
| public async action(options: Options) { | ||
| let lastError; | ||
| for await (const command of this.streamCommands_(options['file-path'])) { | ||
| try { | ||
| await app().refreshCurrentFolder(); | ||
| await app().execCommand(command); | ||
| } catch (error) { | ||
| if (options.options['continue-on-failure']) { | ||
| app().stdout(error.message); | ||
| lastError = error; | ||
| } else { | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (lastError) { | ||
| throw lastError; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| module.exports = Command; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import { createInterface } from 'readline/promises'; | ||
|
|
||
| const iterateStdin = async function*(prompt: string) { | ||
| let nextLineListeners: (()=> void)[] = []; | ||
| const dispatchAllListeners = () => { | ||
| const listeners = nextLineListeners; | ||
| nextLineListeners = []; | ||
| for (const listener of listeners) { | ||
| listener(); | ||
| } | ||
| }; | ||
|
|
||
| const rl = createInterface({ | ||
| input: process.stdin, | ||
| output: process.stdout, | ||
| }); | ||
| rl.setPrompt(prompt); | ||
|
|
||
| let buffer: string[] = []; | ||
| rl.on('line', (line) => { | ||
| buffer.push(line); | ||
| dispatchAllListeners(); | ||
| }); | ||
|
|
||
| let done = false; | ||
| rl.on('close', () => { | ||
| done = true; | ||
| dispatchAllListeners(); | ||
| }); | ||
|
|
||
| const readNextLines = () => { | ||
| return new Promise<string|null>(resolve => { | ||
| if (done) { | ||
| resolve(null); | ||
| } else if (buffer.length > 0) { | ||
| resolve(buffer.join('\n')); | ||
| buffer = []; | ||
| } else { | ||
| nextLineListeners.push(() => { | ||
| resolve(buffer.join('\n')); | ||
| buffer = []; | ||
| }); | ||
| } | ||
| }); | ||
| }; | ||
|
|
||
| while (!done) { | ||
| rl.prompt(); | ||
| const lines = await readNextLines(); | ||
| yield lines; | ||
| } | ||
| }; | ||
|
|
||
| export default iterateStdin; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
These commands are mostly intended for debugging. However, since they have help text, it may make sense to allow the help text to be localized.