mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-19 01:06:39 +00:00
fix: copy when punctuation marks in sketch path
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>
This commit is contained in:
parent
e6828f86d7
commit
964ea3bc0c
@ -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.
|
* 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`
|
* `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) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
temp.mkdir({ prefix: TempSketchPrefix }, (createError, dirPath) => {
|
temp.mkdir({ prefix: TempSketchPrefix }, (createError, dirPath) => {
|
||||||
if (createError) {
|
if (createError) {
|
||||||
@ -523,13 +523,14 @@ export class SketchesServiceImpl
|
|||||||
} else {
|
} else {
|
||||||
filter = () => true;
|
filter = () => true;
|
||||||
}
|
}
|
||||||
await cpy(source, destination, {
|
await cpy(sourceFolderBasename, destination, {
|
||||||
rename: (basename) =>
|
rename: (basename) =>
|
||||||
sourceFolderBasename !== destinationFolderBasename &&
|
sourceFolderBasename !== destinationFolderBasename &&
|
||||||
basename === `${sourceFolderBasename}.ino`
|
basename === `${sourceFolderBasename}.ino`
|
||||||
? `${destinationFolderBasename}.ino`
|
? `${destinationFolderBasename}.ino`
|
||||||
: basename,
|
: basename,
|
||||||
filter,
|
filter,
|
||||||
|
cwd: path.dirname(source),
|
||||||
});
|
});
|
||||||
const copiedSketch = await this.doLoadSketch(destinationUri, false);
|
const copiedSketch = await this.doLoadSketch(destinationUri, false);
|
||||||
return copiedSketch;
|
return copiedSketch;
|
||||||
|
@ -2,6 +2,7 @@ import {
|
|||||||
Disposable,
|
Disposable,
|
||||||
DisposableCollection,
|
DisposableCollection,
|
||||||
} from '@theia/core/lib/common/disposable';
|
} from '@theia/core/lib/common/disposable';
|
||||||
|
import { isWindows } from '@theia/core/lib/common/os';
|
||||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||||
import { Container } from '@theia/core/shared/inversify';
|
import { Container } from '@theia/core/shared/inversify';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
@ -226,16 +227,94 @@ describe('sketches-service-impl', () => {
|
|||||||
expect(mainFileContentOneAfterCopy).to.be.equal(contentOne);
|
expect(mainFileContentOneAfterCopy).to.be.equal(contentOne);
|
||||||
expect(mainFileContentTwoAfterCopy).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 {
|
function disposeSketch(...sketch: Sketch[]): Disposable {
|
||||||
|
return disposeFolder(...sketch.map(({ uri }) => FileUri.fsPath(uri)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function disposeFolder(...paths: string[]): Disposable {
|
||||||
return new DisposableCollection(
|
return new DisposableCollection(
|
||||||
...sketch
|
...paths.map((path) =>
|
||||||
.map(({ uri }) => FileUri.fsPath(uri))
|
Disposable.create(() => rimrafSync(path, { maxBusyTries: 5 }))
|
||||||
.map((path) =>
|
)
|
||||||
Disposable.create(() => rimrafSync(path, { maxBusyTries: 5 }))
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user