Merge pull request #12982 from keymanapp/chore/developer/12981-check-for-filename-collisions-kmc-copy

chore(developer): report on filename collisions in kmc-copy
This commit is contained in:
Marc Durdin 2025-01-23 14:43:18 +07:00 committed by GitHub
commit 85404a3291
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 36 additions and 34 deletions

View file

@ -310,7 +310,6 @@ export class KeymanProjectCopier implements KeymanCompiler {
};
private async copyFolder(inputPath: string, outputPath: string, ignorePatterns: (string | RegExp)[], result: CopierResult) {
// TODO-COPY: watch out for file collisions when copying project files -- after renames
const files = await this.asyncCallbacks.fsAsync.readdir(inputPath);
for(const {filename,type} of files) {
const fullPath = this.normalizePath(this.callbacks.path.join(inputPath, filename));
@ -320,9 +319,17 @@ export class KeymanProjectCopier implements KeymanCompiler {
if(type == 'dir') {
await this.copyFolder(fullPath, this.callbacks.path.join(outputPath, filename), ignorePatterns, result);
} else if(!result.artifacts[fullPath]) {
const filename = this.generateNewFilename(fullPath, outputPath);
for(const artifact of Object.keys(result.artifacts)) {
if(result.artifacts[artifact].filename == filename) {
this.callbacks.reportMessage(CopierMessages.Warn_FilenameCollides({filename}));
}
}
result.artifacts[fullPath] = {
data: await this.asyncCallbacks.fsAsync.readFile(fullPath),
filename: this.generateNewFilename(fullPath, outputPath)
filename
}
}
}

View file

@ -225,4 +225,10 @@ export class CopierMessages {
`The specified lexical model id '${def(o.id)}' contains characters that are not permitted or does not match the required pattern of 'author.bcp47.uniq'.`,
);
static WARN_FilenameCollides = SevWarn | 0x0020;
static Warn_FilenameCollides = (o:{filename:string}) => m(
this.WARN_FilenameCollides,
`The output file '${def(o.filename)}' has two different possible source files.`,
);
};

View file

@ -44,36 +44,11 @@ describe('CopierMessages', function () {
assert.isTrue(callbacks.hasMessage(CopierMessages.ERROR_InvalidLexicalModelId));
});
// it('should generate ERROR_OutputPathAlreadyExists if output path already exists', async function () {
// const ag = new AbstractGenerator();
// const callbacks = new TestCompilerCallbacks();
// const options: GeneratorOptions = {
// id: 'ERROR_OutputPathAlreadyExists',
// outPath: path.dirname(fileURLToPath(import.meta.url)),
// };
// assert(await ag.init(callbacks, options));
// const dir = path.join(path.dirname(fileURLToPath(import.meta.url)), 'ERROR_OutputPathAlreadyExists');
// if(!fs.existsSync(dir))
// fs.mkdirSync(dir);
// assert.isFalse(await ag.write({}));
// assert.isTrue(callbacks.hasMessage(CopierMessages.ERROR_OutputPathAlreadyExists),
// `messageId ERROR_OutputPathAlreadyExists not generated, instead got: `+JSON.stringify(callbacks.messages,null,2));
// fs.rmdirSync(dir);
// });
// it('should generate ERROR_CannotWriteOutputFile if it cannot create a folder, e.g. invalid filename', async function () {
// const ag = new AbstractGenerator();
// const callbacks = new TestCompilerCallbacks();
// const options: GeneratorOptions = {
// id: 'ERROR_CannotWriteOutputFile',
// outPath: path.dirname(fileURLToPath(import.meta.url)),
// };
// assert(await ag.init(callbacks, options));
// assert.isFalse(await ag.write({
// '.': {filename: '.', data: new Uint8Array([1,2,3])}
// }));
// assert.isTrue(callbacks.hasMessage(GeneratorMessages.ERROR_CannotWriteOutputFile),
// `messageId ERROR_CannotWriteOutputFile not generated, instead got: `+JSON.stringify(callbacks.messages,null,2));
// });
it('should generate WARN_FilenameCollision if a copied file will collide', async function() {
const copier = new KeymanProjectCopier();
assert.isTrue(await copier.init(callbacks, {dryRun: true, outPath: 'collided'}))
const result = await copier.run(makePathToFixture('projects/collision/collision.kpj'));
assert.isNotNull(result);
assert.isTrue(callbacks.hasMessage(CopierMessages.WARN_FilenameCollides));
});
});

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<KeymanDeveloperProject>
<Options>
<ProjectType>keyboard</ProjectType>
<Version>2.0</Version>
</Options>
</KeymanDeveloperProject>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,7 @@
store(&TARGETS) 'any'
store(&NAME) 'Collision'
store(&BITMAP) 'collision.ico'
begin Unicode > use(main)
group(main) using keys