Skip to content

Commit 39ab836

Browse files
Akos Kittakittaakos
Akos Kitta
authored andcommitted
fix: let the resource finish all write operation
before checking if it's in sync or not. Closes #437 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent dafb245 commit 39ab836

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

+6
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ import { Account } from './contributions/account';
356356
import { SidebarBottomMenuWidget } from './theia/core/sidebar-bottom-menu-widget';
357357
import { SidebarBottomMenuWidget as TheiaSidebarBottomMenuWidget } from '@theia/core/lib/browser/shell/sidebar-bottom-menu-widget';
358358
import { CreateCloudCopy } from './contributions/create-cloud-copy';
359+
import { FileResourceResolver } from './theia/filesystem/file-resource';
360+
import { FileResourceResolver as TheiaFileResourceResolver } from '@theia/filesystem/lib/browser/file-resource';
359361

360362
export default new ContainerModule((bind, unbind, isBound, rebind) => {
361363
// Commands and toolbar items
@@ -1034,4 +1036,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
10341036
bind(FrontendApplicationContribution).toService(DaemonPort);
10351037
bind(IsOnline).toSelf().inSingletonScope();
10361038
bind(FrontendApplicationContribution).toService(IsOnline);
1039+
1040+
// https://github.com/arduino/arduino-ide/issues/437
1041+
bind(FileResourceResolver).toSelf().inSingletonScope();
1042+
rebind(TheiaFileResourceResolver).toService(FileResourceResolver);
10371043
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { ResourceSaveOptions } from '@theia/core/lib/common/resource';
2+
import { Readable } from '@theia/core/lib/common/stream';
3+
import URI from '@theia/core/lib/common/uri';
4+
import { injectable } from '@theia/core/shared/inversify';
5+
import {
6+
FileResource,
7+
FileResourceOptions,
8+
FileResourceResolver as TheiaFileResourceResolver,
9+
} from '@theia/filesystem/lib/browser/file-resource';
10+
import { FileService } from '@theia/filesystem/lib/browser/file-service';
11+
import {
12+
FileOperationError,
13+
FileOperationResult,
14+
FileStat,
15+
} from '@theia/filesystem/lib/common/files';
16+
import * as PQueue from 'p-queue';
17+
18+
@injectable()
19+
export class FileResourceResolver extends TheiaFileResourceResolver {
20+
override async resolve(uri: URI): Promise<WriteQueuedFileResource> {
21+
let stat: FileStat | undefined;
22+
try {
23+
stat = await this.fileService.resolve(uri);
24+
} catch (e) {
25+
if (
26+
!(
27+
e instanceof FileOperationError &&
28+
e.fileOperationResult === FileOperationResult.FILE_NOT_FOUND
29+
)
30+
) {
31+
throw e;
32+
}
33+
}
34+
if (stat && stat.isDirectory) {
35+
throw new Error(
36+
'The given uri is a directory: ' + this.labelProvider.getLongName(uri)
37+
);
38+
}
39+
return new WriteQueuedFileResource(uri, this.fileService, {
40+
shouldOverwrite: () => this.shouldOverwrite(uri),
41+
shouldOpenAsText: (error) => this.shouldOpenAsText(uri, error),
42+
});
43+
}
44+
}
45+
46+
class WriteQueuedFileResource extends FileResource {
47+
private readonly writeQueue = new PQueue({ autoStart: true, concurrency: 1 });
48+
49+
constructor(
50+
uri: URI,
51+
fileService: FileService,
52+
options: FileResourceOptions
53+
) {
54+
super(uri, fileService, options);
55+
const originalSaveContentChanges = this['saveContentChanges'];
56+
if (originalSaveContentChanges) {
57+
this['saveContentChanges'] = (changes, options) => {
58+
return this.writeQueue.add(() =>
59+
originalSaveContentChanges.bind(this)(changes, options)
60+
);
61+
};
62+
}
63+
}
64+
65+
protected override async doWrite(
66+
content: string | Readable<string>,
67+
options?: ResourceSaveOptions
68+
): Promise<void> {
69+
return this.writeQueue.add(() => super.doWrite(content, options));
70+
}
71+
72+
protected override async isInSync(): Promise<boolean> {
73+
// Let all the write operations finish to update the version (mtime) before checking whether the resource is in sync.
74+
// https://github.com/eclipse-theia/theia/issues/12327
75+
await this.writeQueue.onIdle();
76+
return super.isInSync();
77+
}
78+
}

0 commit comments

Comments
 (0)