Skip to content

Commit 3a7daed

Browse files
authored
feat: enabled watching multiple files via --watch-file (#2125)
1 parent a741036 commit 3a7daed

File tree

7 files changed

+48
-21
lines changed

7 files changed

+48
-21
lines changed

src/cmd/run.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export type CmdRunParams = {|
3838
noReload: boolean,
3939
preInstall: boolean,
4040
sourceDir: string,
41-
watchFile?: string,
41+
watchFile?: Array<string>,
4242
watchIgnored?: Array<string>,
4343
startUrl?: Array<string>,
4444
target?: Array<string>,
@@ -119,6 +119,11 @@ export default async function run(
119119
noReload = true;
120120
}
121121

122+
if (watchFile != null && (!Array.isArray(watchFile) ||
123+
!watchFile.every((el) => typeof el === 'string'))) {
124+
throw new UsageError('Unexpected watchFile type');
125+
}
126+
122127
// Create an alias for --pref since it has been transformed into an
123128
// object containing one or more preferences.
124129
const customPrefs = pref;

src/extension-runners/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ export class MultiExtensionRunner {
239239
export type WatcherCreatorParams = {|
240240
reloadExtension: (string) => void,
241241
sourceDir: string,
242-
watchFile?: string,
242+
watchFile?: Array<string>,
243243
watchIgnored?: Array<string>,
244244
artifactsDir: string,
245245
onSourceChange?: OnSourceChangeFn,
@@ -276,7 +276,7 @@ export function defaultWatcherCreator(
276276
export type ReloadStrategyParams = {|
277277
extensionRunner: IExtensionRunner,
278278
sourceDir: string,
279-
watchFile?: string,
279+
watchFile?: Array<string>,
280280
watchIgnored?: Array<string>,
281281
artifactsDir: string,
282282
ignoreFiles?: Array<string>,

src/program.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ Example: $0 --help run.
621621
' file changes. This is useful if you use a custom' +
622622
' build process for your extension',
623623
demandOption: false,
624-
type: 'string',
624+
type: 'array',
625625
},
626626
'watch-ignored': {
627627
describe: 'Paths and globs patterns that should not be ' +

src/watcher.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export type OnChangeFn = () => any;
1818

1919
export type OnSourceChangeParams = {|
2020
sourceDir: string,
21-
watchFile?: string,
21+
watchFile?: Array<string>,
2222
watchIgnored?: Array<string>,
2323
artifactsDir: string,
2424
onChange: OnChangeFn,
@@ -57,18 +57,22 @@ export default function onSourceChange(
5757
proxyFileChanges({artifactsDir, onChange, filePath, shouldWatchFile});
5858
});
5959

60-
log.debug(`Watching for file changes in ${watchFile || sourceDir}`);
60+
log.debug(
61+
`Watching ${watchFile ? watchFile.join(',') : sourceDir} for changes`
62+
);
6163

6264
const watchedDirs = [];
6365
const watchedFiles = [];
6466

6567
if (watchFile) {
66-
if (fs.existsSync(watchFile) && !fs.lstatSync(watchFile).isFile()) {
67-
throw new UsageError('Invalid --watch-file value: ' +
68-
`"${watchFile}" is not a file.`);
69-
}
68+
for (const filePath of watchFile) {
69+
if (fs.existsSync(filePath) && !fs.lstatSync(filePath).isFile()) {
70+
throw new UsageError('Invalid --watch-file value: ' +
71+
`"${filePath}" is not a file.`);
72+
}
7073

71-
watchedFiles.push(watchFile);
74+
watchedFiles.push(filePath);
75+
}
7276
} else {
7377
watchedDirs.push(sourceDir);
7478
}

tests/unit/test-cmd/test.run.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,22 @@ describe('run', () => {
161161
}, {firefoxApp, firefoxClient});
162162
});
163163

164+
it('throws if watchFile is not an array', async () => {
165+
const cmd = prepareRun();
166+
await assert.isRejected(
167+
cmd.run({noReload: false, watchFile: 'invalid-value.txt' }),
168+
/Unexpected watchFile type/
169+
);
170+
});
171+
164172
it('can watch and reload the extension', async () => {
165173
const cmd = prepareRun();
166174
const {sourceDir, artifactsDir} = cmd.argv;
167175
const {reloadStrategy} = cmd.options;
168176

169-
const watchFile = fixturePath('minimal-web-ext', 'manifest.json');
177+
const watchFile = [
178+
fixturePath('minimal-web-ext', 'manifest.json'),
179+
];
170180

171181
await cmd.run({noReload: false, watchFile });
172182
assert.equal(reloadStrategy.called, true);

tests/unit/test.program.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -543,22 +543,30 @@ describe('program.main', () => {
543543
});
544544
});
545545

546-
it('calls run with a watched file', () => {
547-
const watchFile = 'path/to/fake/file.txt';
548-
546+
async function testWatchFileOption(watchFile) {
549547
const fakeCommands = fake(commands, {
550548
run: () => Promise.resolve(),
551549
});
552550

553551
return execProgram(
554-
['run', '--watch-file', watchFile],
552+
['run', '--watch-file', ...watchFile],
555553
{commands: fakeCommands})
556554
.then(() => {
557555
sinon.assert.calledWithMatch(
558556
fakeCommands.run,
559557
{watchFile}
560558
);
561559
});
560+
}
561+
562+
it('calls run with a watched file', () => {
563+
testWatchFileOption(['path/to/fake/file.txt']);
564+
});
565+
566+
it('calls run with multiple watched files', () => {
567+
testWatchFileOption(
568+
['path/to/fake/file.txt', 'path/to/fake/file2.txt']
569+
);
562570
});
563571

564572
async function testWatchIgnoredOption(watchIgnored) {

tests/unit/test.watcher.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {withTempDir} from '../../src/util/temp-dir';
1313
import { makeSureItFails } from './helpers';
1414

1515
type AssertWatchedParams = {
16-
watchFile?: string,
16+
watchFile?: Array<string>,
1717
touchedFile: string,
1818
}
1919

@@ -28,7 +28,7 @@ describe('watcher', () => {
2828
const someFile = path.join(tmpDir.path(), touchedFile);
2929

3030
if (watchFile) {
31-
watchFile = path.join(tmpDir.path(), watchFile);
31+
watchFile = watchFile.map((f) => path.join(tmpDir.path(), f));
3232
}
3333

3434
var resolveChange;
@@ -116,7 +116,7 @@ describe('watcher', () => {
116116
watchedDirPath,
117117
tmpDirPath,
118118
} = await watchChange({
119-
watchFile: 'foo.txt',
119+
watchFile: ['foo.txt'],
120120
touchedFile: 'foo.txt',
121121
});
122122

@@ -132,7 +132,7 @@ describe('watcher', () => {
132132
watchedDirPath,
133133
tmpDirPath,
134134
} = await watchChange({
135-
watchFile: 'bar.txt',
135+
watchFile: ['bar.txt'],
136136
touchedFile: 'foo.txt',
137137
});
138138

@@ -143,7 +143,7 @@ describe('watcher', () => {
143143

144144
it('throws error if a non-file is passed into --watch-file', () => {
145145
return watchChange({
146-
watchFile: '/',
146+
watchFile: ['/'],
147147
touchedFile: 'foo.txt',
148148
}).then(makeSureItFails()).catch((error) => {
149149
assert.match(

0 commit comments

Comments
 (0)