mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-14 11:37:43 +00:00
Merge pull request #8627 from keymanapp/feat/developer/8150-kmc-package-messages
feat(developer): add CompilerMessages support to kmc-package
This commit is contained in:
commit
c129dfe9a2
7 changed files with 131 additions and 16 deletions
|
|
@ -6,6 +6,8 @@ import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
|||
|
||||
import type { KpsFile, KpsFileContentFile, KpsFileInfo, KpsFileKeyboard, KpsFileLanguage, KpsFileLexicalModel, KpsFileOptions, KpsPackage } from './kps-file.js';
|
||||
import type { KmpJsonFile, KmpJsonFileInfo, KmpJsonFileLanguage, KmpJsonFileOptions } from './kmp-json-file.js';
|
||||
import { CompilerCallbacks } from 'common/web/types/build/src/main.js';
|
||||
import { CompilerMessages } from './messages.js';
|
||||
|
||||
export { type KmpJsonFile } from './kmp-json-file.js';
|
||||
|
||||
|
|
@ -13,6 +15,9 @@ const FILEVERSION_KMP_JSON = '12.0';
|
|||
|
||||
export default class KmpCompiler {
|
||||
|
||||
constructor(private callbacks: CompilerCallbacks) {
|
||||
}
|
||||
|
||||
public transformKpsToKmpObject(kpsString: string, kpsPath: string): KmpJsonFile {
|
||||
|
||||
// Load the KPS data from XML as JS structured data.
|
||||
|
|
@ -234,7 +239,8 @@ export default class KmpCompiler {
|
|||
data.files = [];
|
||||
}
|
||||
|
||||
data.files.forEach(function(value) {
|
||||
let failed = false;
|
||||
data.files.forEach((value) => {
|
||||
// Get the path of the file
|
||||
let filename = value.name;
|
||||
|
||||
|
|
@ -246,7 +252,7 @@ export default class KmpCompiler {
|
|||
if(path.isAbsolute(value.name)) {
|
||||
// absolute paths are not very cross-platform compatible -- we are going to have trouble
|
||||
// with path separators and roots
|
||||
// TODO: emit a warning
|
||||
this.callbacks.reportMessage(CompilerMessages.Warn_AbsolutePath({filename: value.name}));
|
||||
} else {
|
||||
// Transform separators to platform separators -- kps files may use
|
||||
// either / or \, although older kps files were always \.
|
||||
|
|
@ -258,13 +264,31 @@ export default class KmpCompiler {
|
|||
filename = path.resolve(basePath, filename);
|
||||
}
|
||||
const basename = path.basename(filename);
|
||||
let data = fs.readFileSync(filename);
|
||||
|
||||
if(!fs.existsSync(filename)) {
|
||||
this.callbacks.reportMessage(CompilerMessages.Error_FileDoesNotExist({filename: filename}));
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
let data;
|
||||
try {
|
||||
data = fs.readFileSync(filename);
|
||||
} catch(e) {
|
||||
this.callbacks.reportMessage(CompilerMessages.Error_FileCouldNotBeRead({filename: filename, e: e}));
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
zip.file(basename, data);
|
||||
|
||||
// Remove path data from files before JSON save
|
||||
value.name = basename;
|
||||
});
|
||||
|
||||
if(failed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
zip.file(kmpJsonFileName, JSON.stringify(data, null, 2));
|
||||
|
||||
// Generate kmp file
|
||||
|
|
|
|||
23
developer/src/kmc-package/src/messages.ts
Normal file
23
developer/src/kmc-package/src/messages.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m } from "@keymanapp/common-types";
|
||||
|
||||
const Namespace = CompilerErrorNamespace.PackageCompiler;
|
||||
// const SevInfo = CompilerErrorSeverity.Info | Namespace;
|
||||
// const SevHint = CompilerErrorSeverity.Hint | Namespace;
|
||||
const SevWarn = CompilerErrorSeverity.Warn | Namespace;
|
||||
const SevError = CompilerErrorSeverity.Error | Namespace;
|
||||
const SevFatal = CompilerErrorSeverity.Fatal | Namespace;
|
||||
|
||||
export class CompilerMessages {
|
||||
static Fatal_UnexpectedException = (o:{e: any}) => m(this.FATAL_UnexpectedException, `Unexpected exception: ${(o.e ?? 'unknown error').toString()}\n\nCall stack:\n${(o.e instanceof Error ? o.e.stack : (new Error()).stack)}`);
|
||||
static FATAL_UnexpectedException = SevFatal | 0x0001;
|
||||
|
||||
static Warn_AbsolutePath = (o:{filename: string}) => m(this.WARN_AbsolutePath, `File ${o.filename} has an absolute path, which is not portable`);
|
||||
static WARN_AbsolutePath = SevWarn | 0x0002;
|
||||
|
||||
static Error_FileDoesNotExist = (o:{filename: string}) => m(this.ERROR_FileDoesNotExist, `File ${o.filename} does not exist.`);
|
||||
static ERROR_FileDoesNotExist = SevError | 0x0003;
|
||||
|
||||
static Error_FileCouldNotBeRead = (o:{filename: string; e: any}) => m(this.ERROR_FileCouldNotBeRead, `File ${o.filename} could not be read: ${(o.e ?? 'unknown error').toString()}.`);
|
||||
static ERROR_FileCouldNotBeRead = SevError | 0x0004;
|
||||
}
|
||||
|
||||
30
developer/src/kmc-package/test/fixtures/absolute_path/source/absolute_path.kps
vendored
Normal file
30
developer/src/kmc-package/test/fixtures/absolute_path/source/absolute_path.kps
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package>
|
||||
<System>
|
||||
<KeymanDeveloperVersion>15.0.266.0</KeymanDeveloperVersion>
|
||||
<FileVersion>7.0</FileVersion>
|
||||
</System>
|
||||
<Options>
|
||||
<ExecuteProgram></ExecuteProgram>
|
||||
<ReadMeFile></ReadMeFile>
|
||||
<GraphicFile></GraphicFile>
|
||||
<MSIFileName></MSIFileName>
|
||||
<MSIOptions></MSIOptions>
|
||||
<FollowKeyboardVersion/>
|
||||
</Options>
|
||||
<StartMenu>
|
||||
<Folder></Folder>
|
||||
<Items/>
|
||||
</StartMenu>
|
||||
<Info>
|
||||
<Name URL="">Absolute Path</Name>
|
||||
</Info>
|
||||
<Files>
|
||||
<File>
|
||||
<Name>\build\absolute_path.kmx</Name>
|
||||
<Description>File absolute_path.kmx</Description>
|
||||
<CopyLocation>0</CopyLocation>
|
||||
<FileType>.kmx</FileType>
|
||||
</File>
|
||||
</Files>
|
||||
</Package>
|
||||
|
|
@ -7,6 +7,9 @@ import {makePathToFixture} from './helpers/index.js';
|
|||
import JSZip from 'jszip';
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { type KmpJsonFile } from '../src/kmp-json-file.js';
|
||||
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
|
||||
import { CompilerMessages } from '../src/messages.js';
|
||||
|
||||
|
||||
describe('KmpCompiler', function () {
|
||||
const MODELS : string[] = [
|
||||
|
|
@ -14,7 +17,8 @@ describe('KmpCompiler', function () {
|
|||
'withfolders.qaa.sencoten',
|
||||
];
|
||||
|
||||
let kmpCompiler = new KmpCompiler();
|
||||
const callbacks = new TestCompilerCallbacks();
|
||||
let kmpCompiler = new KmpCompiler(callbacks);
|
||||
|
||||
for (let modelID of MODELS) {
|
||||
const kpsPath = modelID.includes('withfolders') ?
|
||||
|
|
@ -78,11 +82,13 @@ describe('KmpCompiler', function () {
|
|||
}
|
||||
|
||||
it('should generates a valid .kmp (zip) file', async function() {
|
||||
this.timeout(10000); // building a zip file can sometimes be slow
|
||||
|
||||
// const kmpPath = makePathToFixture('khmer_angkor', 'build', 'khmer_angkor.kmp');
|
||||
const kpsPath = makePathToFixture('khmer_angkor', 'source', 'khmer_angkor.kps');
|
||||
const kmpJsonRefPath = makePathToFixture('khmer_angkor', 'ref', 'kmp.json');
|
||||
|
||||
const kmpCompiler = new KmpCompiler();
|
||||
const kmpCompiler = new KmpCompiler(callbacks);
|
||||
const source = fs.readFileSync(kpsPath, 'utf-8');
|
||||
const kmpJsonFixture: KmpJsonFile = JSON.parse(fs.readFileSync(kmpJsonRefPath, 'utf-8'));
|
||||
|
||||
|
|
@ -117,4 +123,27 @@ describe('KmpCompiler', function () {
|
|||
assert.deepEqual(kmpJsonData, kmpJsonFixture);
|
||||
});
|
||||
|
||||
it('should warn on absolute paths', async function() {
|
||||
this.timeout(10000); // building a zip file can sometimes be slow
|
||||
|
||||
callbacks.clear();
|
||||
|
||||
// const kmpPath = makePathToFixture('khmer_angkor', 'build', 'khmer_angkor.kmp');
|
||||
const kpsPath = makePathToFixture('absolute_path', 'source', 'absolute_path.kps');
|
||||
const kmpCompiler = new KmpCompiler(callbacks);
|
||||
const source = fs.readFileSync(kpsPath, 'utf-8');
|
||||
|
||||
let kmpJson: KmpJsonFile = null;
|
||||
|
||||
assert.doesNotThrow(() => {
|
||||
kmpJson = kmpCompiler.transformKpsToKmpObject(source, kpsPath);
|
||||
});
|
||||
|
||||
await assert.isNull(kmpCompiler.buildKmpFile(kpsPath, kmpJson));
|
||||
|
||||
assert.lengthOf(callbacks.messages, 2);
|
||||
assert.deepEqual(callbacks.messages[0].code, CompilerMessages.WARN_AbsolutePath);
|
||||
assert.deepEqual(callbacks.messages[1].code, CompilerMessages.ERROR_FileDoesNotExist); //TODO: this should be a file-missing-error
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import * as fs from 'fs';
|
||||
import { BuildActivity, BuildActivityOptions } from './BuildActivity.js';
|
||||
import KmpCompiler from '@keymanapp/kmc-package';
|
||||
import { CompilerCallbacks } from '@keymanapp/common-types';
|
||||
import { NodeCompilerCallbacks } from 'src/util/NodeCompilerCallbacks.js';
|
||||
|
||||
export class BuildPackage extends BuildActivity {
|
||||
public get name(): string { return 'Package'; }
|
||||
|
|
@ -8,28 +10,31 @@ export class BuildPackage extends BuildActivity {
|
|||
public get compiledExtension(): string { return '.kmp'; }
|
||||
public get description(): string { return 'Build a Keyman package'; }
|
||||
public async build(infile: string, options: BuildActivityOptions): Promise<boolean> {
|
||||
let outfile = this.getOutputFilename(infile, options);
|
||||
const c: CompilerCallbacks = new NodeCompilerCallbacks();
|
||||
|
||||
const outfile = this.getOutputFilename(infile, options);
|
||||
|
||||
//
|
||||
// Load .kps source data
|
||||
//
|
||||
|
||||
let kpsString: string = fs.readFileSync(infile, 'utf8');
|
||||
let kmpCompiler = new KmpCompiler();
|
||||
let kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsString, infile);
|
||||
const kpsString: string = fs.readFileSync(infile, 'utf8');
|
||||
const kmpCompiler = new KmpCompiler(c);
|
||||
const kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsString, infile);
|
||||
if(!kmpJsonData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Build the .kmp package file
|
||||
//
|
||||
|
||||
let data = await kmpCompiler.buildKmpFile(infile, kmpJsonData);
|
||||
if(data) {
|
||||
fs.writeFileSync(outfile, data, 'binary');
|
||||
} else {
|
||||
// TODO error logging
|
||||
const data = await kmpCompiler.buildKmpFile(infile, kmpJsonData);
|
||||
if(!data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fs.writeFileSync(outfile, data, 'binary');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import KmpCompiler from '@keymanapp/kmc-package';
|
|||
import { ModelInfoOptions as ModelInfoOptions, writeMergedModelMetadataFile } from '@keymanapp/kmc-model-info';
|
||||
import { SysExits } from './util/sysexits.js';
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { NodeCompilerCallbacks } from './util/NodeCompilerCallbacks.js';
|
||||
|
||||
let inputFilename: string;
|
||||
const program = new Command();
|
||||
|
|
@ -45,8 +46,9 @@ let jsFilename = program.opts().jsFilename ? program.opts().jsFilename : path.jo
|
|||
// Load .kps source data
|
||||
//
|
||||
|
||||
const callbacks = new NodeCompilerCallbacks();
|
||||
let kpsString: string = fs.readFileSync(kpsFilename, 'utf8');
|
||||
let kmpCompiler = new KmpCompiler();
|
||||
let kmpCompiler = new KmpCompiler(callbacks);
|
||||
let kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsString, kpsFilename);
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { Command } from 'commander';
|
|||
import KmpCompiler from '@keymanapp/kmc-package';
|
||||
import { SysExits } from './util/sysexits.js';
|
||||
import KEYMAN_VERSION from "@keymanapp/keyman-version";
|
||||
import { NodeCompilerCallbacks } from './util/NodeCompilerCallbacks.js';
|
||||
|
||||
let inputFilename: string;
|
||||
const program = new Command();
|
||||
|
|
@ -34,8 +35,9 @@ let outputFilename: string = program.opts().outFile ? program.opts().outFile : i
|
|||
// Load .kps source data
|
||||
//
|
||||
|
||||
const callbacks = new NodeCompilerCallbacks();
|
||||
let kpsString: string = fs.readFileSync(inputFilename, 'utf8');
|
||||
let kmpCompiler = new KmpCompiler();
|
||||
let kmpCompiler = new KmpCompiler(callbacks);
|
||||
let kmpJsonData = kmpCompiler.transformKpsToKmpObject(kpsString, inputFilename);
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue