Skip to content

Commit

Permalink
fix: copy when punctuation marks in sketch path
Browse files Browse the repository at this point in the history
Changed the `source` and `cwd` args to avoid accidentally creating an
invalid `glob` patterns when doing the brace expansion by `cpy`.

Closes #2043

Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
  • Loading branch information
Akos Kitta authored and kittaakos committed May 6, 2023
1 parent e6828f8 commit 964ea3b
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 7 deletions.
5 changes: 3 additions & 2 deletions arduino-ide-extension/src/node/sketches-service-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ export class SketchesServiceImpl
* For example, on Windows, instead of getting an [8.3 filename](https://en.wikipedia.org/wiki/8.3_filename), callers will get a fully resolved path.
* `C:\\Users\\KITTAA~1\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2022615-21100-iahybb.yyvh\\sketch_jul15a` will be `C:\\Users\\kittaakos\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2022615-21100-iahybb.yyvh\\sketch_jul15a`
*/
createTempFolder(): Promise<string> {
private createTempFolder(): Promise<string> {
return new Promise<string>((resolve, reject) => {
temp.mkdir({ prefix: TempSketchPrefix }, (createError, dirPath) => {
if (createError) {
Expand Down Expand Up @@ -523,13 +523,14 @@ export class SketchesServiceImpl
} else {
filter = () => true;
}
await cpy(source, destination, {
await cpy(sourceFolderBasename, destination, {
rename: (basename) =>
sourceFolderBasename !== destinationFolderBasename &&
basename === `${sourceFolderBasename}.ino`
? `${destinationFolderBasename}.ino`
: basename,
filter,
cwd: path.dirname(source),
});
const copiedSketch = await this.doLoadSketch(destinationUri, false);
return copiedSketch;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Disposable,
DisposableCollection,
} from '@theia/core/lib/common/disposable';
import { isWindows } from '@theia/core/lib/common/os';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { Container } from '@theia/core/shared/inversify';
import { expect } from 'chai';
Expand Down Expand Up @@ -226,16 +227,94 @@ describe('sketches-service-impl', () => {
expect(mainFileContentOneAfterCopy).to.be.equal(contentOne);
expect(mainFileContentTwoAfterCopy).to.be.equal(contentOne);
});

(
[
['(', ')', 'parentheses'],
['[', ']', 'brackets'],
['{', '}', 'braces'],
[
'<',
'>',
'chevrons',
{
predicate: () => isWindows,
why: '< (less than) and > (greater than) are reserved characters on Windows (https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions)',
},
],
] as [
open: string,
close: string,
name: string,
skip?: { predicate: () => boolean; why: string }
][]
).map(([open, close, name, skip]) =>
it(`should copy a sketch when the path contains ${name} in the sketch folder path: '${open},${close}'`, async function () {
if (skip) {
const { predicate, why } = skip;
if (predicate()) {
console.info(why);
return this.skip();
}
}
this.timeout(testTimeout);
const sketchesService =
container.get<SketchesServiceImpl>(SketchesService);
const content = `// special content when ${name} are in the path`;
const tempRoot = await sketchesService['createTempFolder']();
toDispose.push(disposeFolder(tempRoot));
const sketch = await sketchesService.createNewSketch(
'punctuation_marks',
content
);
toDispose.push(disposeSketch(sketch));

// the destination path contains punctuation marks
const tempRootUri = FileUri.create(tempRoot);
const testSegment = `path segment with ${open}${name}${close}`;
const firstDestinationUri = tempRootUri
.resolve(testSegment)
.resolve('first')
.resolve(sketch.name);

const firstSketchCopy = await sketchesService.copy(sketch, {
destinationUri: firstDestinationUri.toString(),
});
expect(firstSketchCopy).to.be.not.undefined;
expect(firstSketchCopy.mainFileUri).to.be.equal(
firstDestinationUri.resolve(`${sketch.name}.ino`).toString()
);
const firstCopyContent = await mainFileContentOf(firstSketchCopy);
expect(firstCopyContent).to.be.equal(content);

// the source path contains punctuation marks. yes, the target too, but it does not matter
const secondDestinationUri = tempRootUri
.resolve(testSegment)
.resolve('second')
.resolve(sketch.name);
const secondSketchCopy = await sketchesService.copy(firstSketchCopy, {
destinationUri: secondDestinationUri.toString(),
});
expect(secondSketchCopy).to.be.not.undefined;
expect(secondSketchCopy.mainFileUri).to.be.equal(
secondDestinationUri.resolve(`${sketch.name}.ino`).toString()
);
const secondCopyContent = await mainFileContentOf(secondSketchCopy);
expect(secondCopyContent).to.be.equal(content);
})
);
});
});

function disposeSketch(...sketch: Sketch[]): Disposable {
return disposeFolder(...sketch.map(({ uri }) => FileUri.fsPath(uri)));
}

function disposeFolder(...paths: string[]): Disposable {
return new DisposableCollection(
...sketch
.map(({ uri }) => FileUri.fsPath(uri))
.map((path) =>
Disposable.create(() => rimrafSync(path, { maxBusyTries: 5 }))
)
...paths.map((path) =>
Disposable.create(() => rimrafSync(path, { maxBusyTries: 5 }))
)
);
}

Expand Down

0 comments on commit 964ea3b

Please sign in to comment.