mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 00:15:32 +00:00
Merge pull request #16076 from keymanapp/feat/developer/16068-run-project-validation-from-tike
feat(developer): run project validation from IDE
This commit is contained in:
commit
f52f383d93
11 changed files with 119 additions and 16 deletions
|
|
@ -198,6 +198,13 @@ The following parameters are available:
|
|||
project (which can also be controlled at a project level with the
|
||||
`skipMetadataFiles` option). This option is only valid for compiling projects.
|
||||
|
||||
`--publish-only`
|
||||
|
||||
: Skip building component files within a project, and only run the validation
|
||||
step. Must be combined with `--for-publishing` in order to have an effect.
|
||||
This option is only valid for compiling projects, and is mostly intended for
|
||||
use by the IDE. Will fail if build artifacts for components are not present.
|
||||
|
||||
### Examples
|
||||
|
||||
```shell
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export function declareBuild(program: Command) {
|
|||
buildCommand.command('file [infile...]', {isDefault: true})
|
||||
.description(`Compile one or more source files or projects ('file' subcommand is default).`)
|
||||
.option('--for-publishing', 'Verify that project meets @keymanapp repository requirements')
|
||||
.option('--publish-only', 'Only run the for-publishing validation, skip all other build steps')
|
||||
.addHelpText('after', `
|
||||
Supported file types:
|
||||
* folder: Keyman project in folder
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export class BuildKeyboardInfo extends BuildActivity {
|
|||
sourcePath: calculateSourcePath(infile),
|
||||
lastCommitDate,
|
||||
forPublishing: !!options.forPublishing,
|
||||
publishOnly: !!options.publishOnly,
|
||||
};
|
||||
// Note: should we always ignore the passed-in output filename for .keyboard_info?
|
||||
const outputFilename = project.getOutputFilePath(KeymanFileTypes.Binary.KeyboardInfo);
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ export class BuildModelInfo extends BuildActivity {
|
|||
kpsFilename: project.resolveInputFilePath(kps),
|
||||
lastCommitDate,
|
||||
forPublishing: !!options.forPublishing,
|
||||
publishOnly: !!options.publishOnly,
|
||||
};
|
||||
|
||||
// Note: should we always ignore the passed-in output filename for .model_info?
|
||||
|
|
|
|||
|
|
@ -51,15 +51,17 @@ class ProjectBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
// Go through the various file types and build them
|
||||
for(const builder of buildActivities) {
|
||||
if(builder.sourceExtension == KeymanFileTypes.Source.Project) {
|
||||
// We don't support nested projects
|
||||
continue;
|
||||
}
|
||||
if(!this.options.publishOnly) {
|
||||
// Go through the various file types and build them
|
||||
for(const builder of buildActivities) {
|
||||
if(builder.sourceExtension == KeymanFileTypes.Source.Project) {
|
||||
// We don't support nested projects
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!await this.buildProjectTargets(builder)) {
|
||||
return false;
|
||||
if(!await this.buildProjectTargets(builder)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +115,11 @@ class ProjectBuilder {
|
|||
|
||||
const buildFilename = path.relative(process.cwd(), infile).replace(/\\/g, '/');
|
||||
const callbacks = new CompilerFileCallbacks(buildFilename, options, this.callbacks);
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_BuildingFile({filename: infile, relativeFilename:buildFilename}));
|
||||
if(activity.sourceExtension == KeymanFileTypes.Source.Project) {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_ValidatingProject({filename: infile, relativeFilename:buildFilename}));
|
||||
} else {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_BuildingFile({filename: infile, relativeFilename:buildFilename}));
|
||||
}
|
||||
|
||||
fs.mkdirSync(path.dirname(outfile), {recursive:true});
|
||||
|
||||
|
|
@ -123,12 +129,19 @@ class ProjectBuilder {
|
|||
// note: command line option here, if set, overrides project setting
|
||||
result = result && !callbacks.hasFailureMessage(this.options.compilerWarningsAsErrors ?? this.project.options.compilerWarningsAsErrors);
|
||||
|
||||
if(result) {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_FileBuiltSuccessfully({filename: infile, relativeFilename:buildFilename}));
|
||||
if(activity.sourceExtension == KeymanFileTypes.Source.Project) {
|
||||
if(result) {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_ProjectValidatedSuccessfully({filename: infile, relativeFilename:buildFilename}));
|
||||
} else {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_ProjectNotValidatedSuccessfully({filename: infile, relativeFilename:buildFilename}));
|
||||
}
|
||||
} else {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename: infile, relativeFilename: buildFilename}));
|
||||
if(result) {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_FileBuiltSuccessfully({filename: infile, relativeFilename:buildFilename}));
|
||||
} else {
|
||||
callbacks.reportMessage(InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename: infile, relativeFilename: buildFilename}));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -197,5 +197,26 @@ export class InfrastructureMessages {
|
|||
`Failed to generate new project '${def(o.id)}'.`,
|
||||
)});
|
||||
|
||||
// For this message, we override the filename with the passed-in file. A bit of a hack but does the job
|
||||
static INFO_ValidatingProject = SevInfo | 0x0029;
|
||||
static Info_ValidatingProject = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m(
|
||||
this.INFO_ValidatingProject,
|
||||
`Validating ${def(o.relativeFilename)}`,
|
||||
)});
|
||||
|
||||
// For this message, we override the filename with the passed-in file. A bit of a hack but does the job
|
||||
static INFO_ProjectValidatedSuccessfully = SevInfo | 0x002A;
|
||||
static Info_ProjectValidatedSuccessfully = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m(
|
||||
this.INFO_ProjectValidatedSuccessfully,
|
||||
`${def(o.relativeFilename)} validated successfully.`,
|
||||
)});
|
||||
|
||||
// For this message, we override the filename with the passed-in file. A bit of a hack but does the job
|
||||
static INFO_ProjectNotValidatedSuccessfully = SevInfo | 0x002B;
|
||||
static Info_ProjectNotValidatedSuccessfully = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m(
|
||||
this.INFO_ProjectNotValidatedSuccessfully,
|
||||
`${def(o.relativeFilename)} failed to validate.`
|
||||
)});
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -242,22 +242,26 @@ export class NodeCompilerCallbacks implements CompilerCallbacks {
|
|||
* We treat a few certain infrastructure messages with special colours
|
||||
* @param event
|
||||
* @returns
|
||||
* Keep in sync with: UfrmMessages.pas, TfrmMessages.Add
|
||||
*/
|
||||
messageSpecialColor(event: CompilerEvent) {
|
||||
switch(event.code) {
|
||||
case InfrastructureMessages.INFO_BuildingFile:
|
||||
case InfrastructureMessages.INFO_CopyingProject:
|
||||
case InfrastructureMessages.INFO_GeneratingProject:
|
||||
case InfrastructureMessages.INFO_ValidatingProject:
|
||||
return color.whiteBright;
|
||||
case InfrastructureMessages.INFO_FileNotBuiltSuccessfully:
|
||||
case InfrastructureMessages.INFO_ProjectNotBuiltSuccessfully:
|
||||
case InfrastructureMessages.INFO_ProjectNotCopiedSuccessfully:
|
||||
case InfrastructureMessages.INFO_ProjectNotGeneratedSuccessfully:
|
||||
case InfrastructureMessages.INFO_ProjectNotValidatedSuccessfully:
|
||||
return color.red;
|
||||
case InfrastructureMessages.INFO_FileBuiltSuccessfully:
|
||||
case InfrastructureMessages.INFO_ProjectBuiltSuccessfully:
|
||||
case InfrastructureMessages.INFO_ProjectCopiedSuccessfully:
|
||||
case InfrastructureMessages.INFO_ProjectGeneratedSuccessfully:
|
||||
case InfrastructureMessages.INFO_ProjectValidatedSuccessfully:
|
||||
return color.green;
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,12 @@ export interface ExtendedCompilerOptions extends CompilerOptions {
|
|||
* MIT
|
||||
*/
|
||||
forPublishing?: boolean;
|
||||
/**
|
||||
* Do not build components, just do the publish phase for the project. This is
|
||||
* used mostly by Keyman Developer IDE, which will run the .keyboard_info /
|
||||
* .package_info validation and compilation step if skipMetadataFiles is true.
|
||||
*/
|
||||
publishOnly?: boolean;
|
||||
/**
|
||||
* Overrides for message reporting
|
||||
*/
|
||||
|
|
@ -198,6 +204,7 @@ export function commanderOptionsToCompilerOptions(options: any, callbacks: Compi
|
|||
warnDeprecatedCode: options.warnDeprecatedCode,
|
||||
// ExtendedOptions
|
||||
forPublishing: options.forPublishing,
|
||||
publishOnly: options.publishOnly,
|
||||
messageOverrides: overrides,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ type
|
|||
function Run(const parameters: TArray<string>; const path, logFilename: string; Callback: TUtilExecuteCallbackEvent): Boolean;
|
||||
public
|
||||
function Compile(ProjectFile: TProjectFile; const infile, outfile: string; debug: Boolean; Callback: TUtilExecuteCallbackEvent = nil): Boolean;
|
||||
function CompileForPublishing(ProjectFile: TProjectFile; const projectFilename: string; debug: Boolean; Callback: TUtilExecuteCallbackEvent = nil): Boolean;
|
||||
function Copy(const source, dest, cwd: string; relocateExternal: Boolean; Callback: TUtilExecuteCallbackEvent = nil): Boolean;
|
||||
end;
|
||||
|
||||
|
|
@ -39,6 +40,39 @@ uses
|
|||
|
||||
{ TKmcWrapper }
|
||||
|
||||
function TKmcWrapper.CompileForPublishing(
|
||||
ProjectFile: TProjectFile;
|
||||
const projectFilename: string;
|
||||
debug: Boolean;
|
||||
Callback: TUtilExecuteCallbackEvent
|
||||
): Boolean;
|
||||
var
|
||||
cmdline: TArray<string>;
|
||||
begin
|
||||
cmdline := [
|
||||
'build',
|
||||
'--log-format', 'tsv',
|
||||
'--log-level', 'info',
|
||||
'--for-publishing',
|
||||
'--publish-only',
|
||||
projectFilename
|
||||
];
|
||||
|
||||
if Assigned(FGlobalProject) and (FGlobalProject.Options.CompilerWarningsAsErrors) then
|
||||
cmdline := cmdline + ['--compiler-warnings-as-errors']
|
||||
else
|
||||
cmdline := cmdline + ['--no-compiler-warnings-as-errors'];
|
||||
|
||||
if Assigned(FGlobalProject) and (not FGlobalProject.Options.WarnDeprecatedCode) then
|
||||
cmdline := cmdline + ['--no-warn-deprecated-code'];
|
||||
|
||||
if debug then
|
||||
cmdline := cmdline + ['--debug'];
|
||||
|
||||
Result := Run(cmdline, ExtractFileDir(projectFilename), projectFilename, Callback);
|
||||
end;
|
||||
|
||||
|
||||
function TKmcWrapper.Compile(
|
||||
ProjectFile: TProjectFile;
|
||||
const infile: string;
|
||||
|
|
|
|||
|
|
@ -170,6 +170,12 @@ const // ABGR - text on white bg, Colors similar to Light+ VSCode color theme
|
|||
INFO_FileNotBuiltSuccessfully = NAMESPACE_Infrastructure or $0007;
|
||||
INFO_ProjectBuiltSuccessfully = NAMESPACE_Infrastructure or $000B;
|
||||
INFO_ProjectNotBuiltSuccessfully = NAMESPACE_Infrastructure or $000C;
|
||||
INFO_ProjectCopiedSuccessfully = NAMESPACE_Infrastructure or $0024;
|
||||
INFO_ProjectNotCopiedSuccessfully = NAMESPACE_Infrastructure or $0025;
|
||||
INFO_ProjectGeneratedSuccessfully = NAMESPACE_Infrastructure or $0027;
|
||||
INFO_ProjectNotGeneratedSuccessfully = NAMESPACE_Infrastructure or $0028;
|
||||
INFO_ProjectValidatedSuccessfully = NAMESPACE_Infrastructure or $002A;
|
||||
INFO_ProjectNotValidatedSuccessfully = NAMESPACE_Infrastructure or $002B;
|
||||
|
||||
Segment_Filename = 0;
|
||||
Segment_Filename_Separator = 1;
|
||||
|
|
@ -254,12 +260,18 @@ begin
|
|||
FColor := clBlack;
|
||||
FTextColor := Color_Text;
|
||||
|
||||
// Override formatting for 4 known messages
|
||||
// Override formatting for known messages -- keep in sync with messageSpecialColor() in NodeCompilerCallbacks.ts
|
||||
if (MsgCode = INFO_FileBuiltSuccessfully) or
|
||||
(MsgCode = INFO_ProjectBuiltSuccessfully) then
|
||||
(MsgCode = INFO_ProjectBuiltSuccessfully) or
|
||||
(MsgCode = INFO_ProjectCopiedSuccessfully) or
|
||||
(MsgCode = INFO_ProjectGeneratedSuccessfully) or
|
||||
(MsgCode = INFO_ProjectValidatedSuccessfully) then
|
||||
state := plsSuccess
|
||||
else if (MsgCode = INFO_FileNotBuiltSuccessfully) or
|
||||
(MsgCode = INFO_ProjectNotBuiltSuccessfully) then
|
||||
(MsgCode = INFO_ProjectNotBuiltSuccessfully) or
|
||||
(MsgCode = INFO_ProjectNotCopiedSuccessfully) or
|
||||
(MsgCode = INFO_ProjectNotGeneratedSuccessfully) or
|
||||
(MsgCode = INFO_ProjectNotValidatedSuccessfully) then
|
||||
state := plsFailure;
|
||||
|
||||
case state of
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ begin
|
|||
w := TKmcWrapper.Create;
|
||||
try
|
||||
Result := w.Compile(Self, FileName, TargetFilename, False);
|
||||
if not OwnerProject.Options.SkipMetadataFiles then
|
||||
Result := Result and w.CompileForPublishing(Self, OwnerProject.FileName, False);
|
||||
// TODO(lowpri): FDebug flag
|
||||
finally
|
||||
w.Free;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue