diff --git a/README.md b/README.md index e88e3dac..ecd241ed 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,14 @@ times, then the compiler will attempt to merge the configs together. ### Optional -`--skip-validation` - If set, the compiler will skip the post-parse validation phase of compilation, +`--check-config` - If set, only runs the configuration checking step to ensure that the compiler config is correct. + +`--lint` - If set, only runs the configuration check and linting steps. + +`--validate` - If set, only runs the configuration check, linting and post-validation steps. Does not output files. + +`--skip-validation` - If set, the compiler will skip the post-parse validation phase of compilation. +If running in full compilation mode, will still produce output. `--strip-comments` - If set, any comments in the input will be removed. If an empty line is leftover, it will be discarded. diff --git a/src/Compiler/Argument/CompilerArguments.cs b/src/Compiler/Argument/CompilerArguments.cs index 4ab64085..1a8f0377 100644 --- a/src/Compiler/Argument/CompilerArguments.cs +++ b/src/Compiler/Argument/CompilerArguments.cs @@ -10,7 +10,7 @@ public class CompilerArguments public const int EmptyFolderIgnore = 0; public const int EmptyFolderWarning = 1; public const int EmptyFolderError = 2; - + public const string DefaultBuildVersion = "BUILD_VERSION"; public List ConfigFiles { get; } = new(); @@ -34,7 +34,7 @@ public override bool Equals(Object obj) // Different length, so definitely not equal if (ConfigFiles.Count != compare.ConfigFiles.Count) { - return false ; + return false; } // Check every one is equal. @@ -48,7 +48,7 @@ public override bool Equals(Object obj) return true; } - + public override int GetHashCode() { return base.GetHashCode(); @@ -65,11 +65,14 @@ public override int GetHashCode() // Replace tokens in the output public List TokenReplacers { get; } = new(); - + // The version being built public string BuildVersion { get; set; } = DefaultBuildVersion; // What to do about empty folders public int EmptyFolderAction { get; set; } = EmptyFolderIgnore; + + // What mode should we run in. + public RunMode Mode { get; set; } = RunMode.COMPILE; } } diff --git a/src/Compiler/Argument/RunMode.cs b/src/Compiler/Argument/RunMode.cs new file mode 100644 index 00000000..f2dc18fc --- /dev/null +++ b/src/Compiler/Argument/RunMode.cs @@ -0,0 +1,13 @@ +using System; + +namespace Compiler.Argument +{ + [Flags] + public enum RunMode : ushort + { + CHECK_CONFIG = 1, + LINT = 2, + VALIDATE = 4, + COMPILE = 8 + } +} diff --git a/src/Compiler/SectorFileCompiler.cs b/src/Compiler/SectorFileCompiler.cs index 7d06bee7..ba0ffb2a 100644 --- a/src/Compiler/SectorFileCompiler.cs +++ b/src/Compiler/SectorFileCompiler.cs @@ -19,6 +19,8 @@ public class SectorFileCompiler { private readonly CompilerArguments arguments; private readonly EventTracker events; + private const int SUCESS_RETURN = 0; + private const int FAILURE_RETURN = 1; public SectorFileCompiler(CompilerArguments arguments, EventTracker events) { @@ -38,7 +40,7 @@ public int Compile() if (events.HasFatalError()) { events.AddEvent(new CompilationFinishedEvent(false)); - return 1; + return FAILURE_RETURN; } // Parse all the config files @@ -49,11 +51,18 @@ public int Compile() { events.AddEvent(new CompilationMessage("Loading config files")); config = ConfigFileLoaderFactory.Make(arguments).LoadConfigFiles(arguments.ConfigFiles, arguments); - } catch (ConfigFileInvalidException e) + } + catch (ConfigFileInvalidException e) { events.AddEvent(new CompilationMessage(e.Message)); events.AddEvent(new CompilationFinishedEvent(false)); - return 1; + return FAILURE_RETURN; + } + + events.AddEvent(new CompilationMessage("Config files loaded successfully")); + if (arguments.Mode == RunMode.CHECK_CONFIG) + { + return SUCESS_RETURN; } // Parse all the input files and create elements @@ -74,18 +83,18 @@ public int Compile() { events.AddEvent(new CompilationMessage(exception.Message)); events.AddEvent(new CompilationFinishedEvent(false)); - return 1; + return FAILURE_RETURN; } - + if (events.HasFatalError()) { events.AddEvent(new CompilationFinishedEvent(false)); - return 1; + return FAILURE_RETURN; } - + events.AddEvent(new CompilationMessage("Injecting pre-parse static data")); RunwayCentrelineInjector.InjectRunwayCentrelineData(sectorElements); - + events.AddEvent(new CompilationMessage("Parsing input files")); foreach (AbstractSectorDataFile dataFile in fileList) { @@ -95,13 +104,18 @@ public int Compile() if (events.HasFatalError()) { events.AddEvent(new CompilationFinishedEvent(false)); - return 1; + return FAILURE_RETURN; } - + // There's some static data we need to inject to the collection for adjacent airports... events.AddEvent(new CompilationMessage("Injecting post-parse static data")); AdjacentAirportsInjector.InjectAdjacentAirportsData(sectorElements); - + + // We aren't going beyond linting, so stop. + if (arguments.Mode == RunMode.LINT) + { + return SUCESS_RETURN; + } // Now all the data is loaded, validate that there are no broken references etc. if (arguments.ValidateOutput) @@ -111,14 +125,20 @@ public int Compile() if (events.HasFatalError()) { events.AddEvent(new CompilationFinishedEvent(false)); - return 1; + return FAILURE_RETURN; } - } + } else { events.AddEvent(new CompilationMessage("Skipping output validation")); } + // We aren't going beyond post-validating, so don't compile. + if (arguments.Mode == RunMode.VALIDATE) + { + return SUCESS_RETURN; + } + // Generate the output - all at once OutputGenerator generator = new OutputGenerator( sectorElements, @@ -127,15 +147,16 @@ public int Compile() ); var outputTasks = new List(); - foreach(AbstractOutputFile output in arguments.OutputFiles) + foreach (AbstractOutputFile output in arguments.OutputFiles) { events.AddEvent(new CompilationMessage($"Generating {output.GetFileDescriptor()} output")); outputTasks.Add(generator.GenerateOutput(output)); } + Task.WaitAll(outputTasks.ToArray()); events.AddEvent(new CompilationFinishedEvent(true)); - return 0; + return SUCESS_RETURN; } } } diff --git a/src/CompilerCli/Argument/ArgumentParser.cs b/src/CompilerCli/Argument/ArgumentParser.cs index 861dbb16..6778560d 100644 --- a/src/CompilerCli/Argument/ArgumentParser.cs +++ b/src/CompilerCli/Argument/ArgumentParser.cs @@ -53,12 +53,12 @@ string[] args public bool HasCompilerArgument(Type type) { - return availableCompilerArguments.Select(arg => arg.GetType() == type).Count() != 0; + return availableCompilerArguments.Any(arg => arg.GetType() == type); } public bool HasCliArgument(Type type) { - return availableCompilerArguments.Select(arg => arg.GetType() == type).Count() != 0; + return availableCliArguments.Any(arg => arg.GetType() == type); } private int ProcessArguments(string[] args, int startIndex, Action> process) diff --git a/src/CompilerCli/Argument/ArgumentParserFactory.cs b/src/CompilerCli/Argument/ArgumentParserFactory.cs index 2c750ddc..7054beaf 100644 --- a/src/CompilerCli/Argument/ArgumentParserFactory.cs +++ b/src/CompilerCli/Argument/ArgumentParserFactory.cs @@ -15,7 +15,10 @@ public static ArgumentParser Make() new SkipValidationCompilerArgument(), new StripCommentsCompilerArgument(), new ConfigFileCompilerArgument(), - new BuildVersionCompilerArgument() + new BuildVersionCompilerArgument(), + new CheckConfigCompilerArgument(), + new LintCompilerArgument(), + new ValidateCompilerArgument(), }, new SortedSet { @@ -25,4 +28,4 @@ public static ArgumentParser Make() ); } } -} \ No newline at end of file +} diff --git a/src/CompilerCli/Compiler/CheckConfigCompilerArgument.cs b/src/CompilerCli/Compiler/CheckConfigCompilerArgument.cs new file mode 100644 index 00000000..27060379 --- /dev/null +++ b/src/CompilerCli/Compiler/CheckConfigCompilerArgument.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Compiler.Argument; + +namespace CompilerCli.Compiler +{ + public class CheckConfigCompilerArgument : AbstractCompilerArgument + { + public override void Parse(List values, CompilerArguments compilerSettings) + { + if (values.Count != 0) + { + throw new ArgumentException("Check config argument does not take any options"); + } + + compilerSettings.Mode = RunMode.CHECK_CONFIG; + } + + public override string GetSpecifier() + { + return "--check-config"; + } + } +} diff --git a/src/CompilerCli/Compiler/LintCompilerArgument.cs b/src/CompilerCli/Compiler/LintCompilerArgument.cs new file mode 100644 index 00000000..ac729b9b --- /dev/null +++ b/src/CompilerCli/Compiler/LintCompilerArgument.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Compiler.Argument; + +namespace CompilerCli.Compiler +{ + public class LintCompilerArgument : AbstractCompilerArgument + { + public override void Parse(List values, CompilerArguments compilerSettings) + { + if (values.Count != 0) + { + throw new ArgumentException("Lint argument does not take any options"); + } + + compilerSettings.Mode = RunMode.LINT; + } + + public override string GetSpecifier() + { + return "--lint"; + } + } +} diff --git a/src/CompilerCli/Compiler/ValidateCompilerArgument.cs b/src/CompilerCli/Compiler/ValidateCompilerArgument.cs new file mode 100644 index 00000000..a17eb580 --- /dev/null +++ b/src/CompilerCli/Compiler/ValidateCompilerArgument.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Compiler.Argument; + +namespace CompilerCli.Compiler +{ + public class ValidateCompilerArgument : AbstractCompilerArgument + { + public override void Parse(List values, CompilerArguments compilerSettings) + { + if (values.Count != 0) + { + throw new ArgumentException("Validate argument does not take any options"); + } + + compilerSettings.Mode = RunMode.VALIDATE; + } + + public override string GetSpecifier() + { + return "--validate"; + } + } +} diff --git a/tests/CompilerCliTest/Argument/ArgumentParserFactoryTest.cs b/tests/CompilerCliTest/Argument/ArgumentParserFactoryTest.cs index 1cdbf9f0..ee8e21ae 100644 --- a/tests/CompilerCliTest/Argument/ArgumentParserFactoryTest.cs +++ b/tests/CompilerCliTest/Argument/ArgumentParserFactoryTest.cs @@ -14,6 +14,9 @@ public class ArgumentParserFactoryTest [InlineData(typeof(StripCommentsCompilerArgument))] [InlineData(typeof(ConfigFileCompilerArgument))] [InlineData(typeof(BuildVersionCompilerArgument))] + [InlineData(typeof(CheckConfigCompilerArgument))] + [InlineData(typeof(LintCompilerArgument))] + [InlineData(typeof(ValidateCompilerArgument))] public void TestItAddsCompilerArguments(Type type) { Assert.True(ArgumentParserFactory.Make().HasCompilerArgument(type)); @@ -27,4 +30,4 @@ public void TestItAddsCliArguments(Type type) Assert.True(ArgumentParserFactory.Make().HasCliArgument(type)); } } -} \ No newline at end of file +} diff --git a/tests/CompilerCliTest/Compiler/CheckConfigCompilerArgumentTest.cs b/tests/CompilerCliTest/Compiler/CheckConfigCompilerArgumentTest.cs new file mode 100644 index 00000000..5d1c6323 --- /dev/null +++ b/tests/CompilerCliTest/Compiler/CheckConfigCompilerArgumentTest.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Compiler.Argument; +using CompilerCli.Compiler; +using Xunit; + +namespace CompilerCliTest.Compiler +{ + public class CheckConfigCompilerArgumentTest + { + private CompilerArguments arguments; + private CheckConfigCompilerArgument checkConfigCompilerArgument; + + public CheckConfigCompilerArgumentTest() + { + arguments = new CompilerArguments(); + checkConfigCompilerArgument = new CheckConfigCompilerArgument(); + } + + [Fact] + public void TestItSetsCompileOnlyAsMode() + { + checkConfigCompilerArgument.Parse(new List(), arguments); + Assert.Equal(RunMode.CHECK_CONFIG, arguments.Mode); + } + + [Fact] + public void TestItThrowsExceptionOnValues() + { + Assert.Throws( + () => checkConfigCompilerArgument.Parse(new List(new[] { "a"}), arguments) + ); + } + + [Fact] + public void TestItReturnsASpecifier() + { + Assert.Equal("--check-config", checkConfigCompilerArgument.GetSpecifier()); + } + } +} diff --git a/tests/CompilerCliTest/Compiler/LintCompilerArgumentTest.cs b/tests/CompilerCliTest/Compiler/LintCompilerArgumentTest.cs new file mode 100644 index 00000000..69706e67 --- /dev/null +++ b/tests/CompilerCliTest/Compiler/LintCompilerArgumentTest.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Compiler.Argument; +using CompilerCli.Compiler; +using Xunit; + +namespace CompilerCliTest.Compiler +{ + public class LintCompilerArgumentTest + { + private CompilerArguments arguments; + private LintCompilerArgument lintCompilerArgument; + + public LintCompilerArgumentTest() + { + arguments = new CompilerArguments(); + lintCompilerArgument = new LintCompilerArgument(); + } + + [Fact] + public void TestItSetsCompileOnlyAsMode() + { + lintCompilerArgument.Parse(new List(), arguments); + Assert.Equal(RunMode.LINT, arguments.Mode); + } + + [Fact] + public void TestItThrowsExceptionOnValues() + { + Assert.Throws( + () => lintCompilerArgument.Parse(new List(new[] { "a"}), arguments) + ); + } + + [Fact] + public void TestItReturnsASpecifier() + { + Assert.Equal("--lint", lintCompilerArgument.GetSpecifier()); + } + } +} diff --git a/tests/CompilerCliTest/Compiler/ValidateCompilerArgumentTest.cs b/tests/CompilerCliTest/Compiler/ValidateCompilerArgumentTest.cs new file mode 100644 index 00000000..a313e3f5 --- /dev/null +++ b/tests/CompilerCliTest/Compiler/ValidateCompilerArgumentTest.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Compiler.Argument; +using CompilerCli.Compiler; +using Xunit; + +namespace CompilerCliTest.Compiler +{ + public class ValidateCompilerArgumentTest + { + private CompilerArguments arguments; + private ValidateCompilerArgument validateCompilerArgument; + + public ValidateCompilerArgumentTest() + { + arguments = new CompilerArguments(); + validateCompilerArgument = new ValidateCompilerArgument(); + } + + [Fact] + public void TestItSetsCompileOnlyAsMode() + { + validateCompilerArgument.Parse(new List(), arguments); + Assert.Equal(RunMode.VALIDATE, arguments.Mode); + } + + [Fact] + public void TestItThrowsExceptionOnValues() + { + Assert.Throws( + () => validateCompilerArgument.Parse(new List(new[] { "a"}), arguments) + ); + } + + [Fact] + public void TestItReturnsASpecifier() + { + Assert.Equal("--validate", validateCompilerArgument.GetSpecifier()); + } + } +}