diff --git a/src/CodeQLToolkit.Features.Pack/CodeQLToolkit.Features.Pack.csproj b/src/CodeQLToolkit.Features.Pack/CodeQLToolkit.Features.Pack.csproj
index 0fdbb7f..8afb4a9 100644
--- a/src/CodeQLToolkit.Features.Pack/CodeQLToolkit.Features.Pack.csproj
+++ b/src/CodeQLToolkit.Features.Pack/CodeQLToolkit.Features.Pack.csproj
@@ -15,4 +15,9 @@
+
+
+
+
+
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/PackCommandFeature.cs b/src/CodeQLToolkit.Features.Pack/Commands/PackCommandFeature.cs
deleted file mode 100644
index d01968b..0000000
--- a/src/CodeQLToolkit.Features.Pack/Commands/PackCommandFeature.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using CodeQLToolkit.Features.Pack.Commands.Targets;
-using System;
-using System.Collections.Generic;
-using System.CommandLine;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace CodeQLToolkit.Features.Pack.Commands
-{
- public class PackCommandFeature : FeatureBase, IToolkitCommandFeature
- {
- public void Register(Command parentCommand)
- {
- Log.G().LogInformation("Registering command submodule.");
-
- var runCommand = new Command("run", "Functions pertaining to running pack-related commands.");
- parentCommand.Add(runCommand);
-
- // a command that installs query packs
- var sayHello = new Command("hello-jeongsoo", "Says hello!");
- var howManyTimesHello = new Option("--times", "how many times to say it") { IsRequired = true };
- sayHello.Add(howManyTimesHello);
-
- var sayGoodbye = new Command("goodbye-jeongsoo", "Says goodbye!");
-
- var howManyTimes = new Option("--times", "how many times to say it") { IsRequired = true };
- sayGoodbye.Add(howManyTimes);
-
-
- runCommand.Add(sayHello);
- runCommand.Add(sayGoodbye);
-
- sayHello.SetHandler((basePath, times) => {
-
- new HelloJeongsooCommandTarget() {
- Base = basePath,
- Times = times
-
- }.Run();
-
- }, Globals.BasePathOption, howManyTimesHello);
-
- sayGoodbye.SetHandler((basePath, times) => {
-
- Console.WriteLine($"Saying goodbye {times} number of times");
-
- for (int i = 0; i < times; i++)
- {
- Console.WriteLine("Goodbye!");
- }
-
-
- }, Globals.BasePathOption, howManyTimes);
-
- }
-
- public int Run()
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/Targets/HelloJeongsooCommandTarget.cs b/src/CodeQLToolkit.Features.Pack/Commands/Targets/HelloJeongsooCommandTarget.cs
deleted file mode 100644
index 33b4420..0000000
--- a/src/CodeQLToolkit.Features.Pack/Commands/Targets/HelloJeongsooCommandTarget.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using CodeQLToolkit.Shared.Utils;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace CodeQLToolkit.Features.Pack.Commands.Targets
-{
- public class HelloJeongsooCommandTarget : CommandTarget
- {
-
- public int Times { get; set; }
-
-
- public override void Run()
- {
- for(int i = 0; i < Times; i++) {
- Console.WriteLine($"Hello! My Base Target is: {Base}");
- }
-
-
- var c = new QLTConfig()
- {
- Base = Base
- };
-
- if (!File.Exists(c.CodeQLConfigFilePath))
- {
- ProcessUtils.DieWithError($"Cannot read values from missing file {c.CodeQLConfigFilePath}");
- }
-
- var config = c.FromFile();
-
-
- Console.WriteLine($"---------current settings---------");
- Console.WriteLine($"CodeQL CLI Version: {config.CodeQLCLI}");
- Console.WriteLine($"CodeQL Standard Library Version: {config.CodeQLStandardLibrary}");
- Console.WriteLine($"CodeQL CLI Bundle Version: {config.CodeQLCLIBundle}");
- Console.WriteLine($"----------------------------------");
- Console.WriteLine("(hint: use `qlt codeql set` to modify these values.)");
-
- }
- }
-}
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/ExtQlpackYmlSchema.cs b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/ExtQlpackYmlSchema.cs
new file mode 100644
index 0000000..6cdb3ad
--- /dev/null
+++ b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/ExtQlpackYmlSchema.cs
@@ -0,0 +1,31 @@
+namespace CodeQLToolkit.Features.Pack.Commands.Validate.Schemas
+{
+ public class ExtQlpackYmlFileSchema : IYmlSchema
+ {
+ public bool Library { get; set; }
+ public string Name { get; set; }
+ public string Version { get; set; }
+ public Dictionary ExtensionTargets { get; set; }
+ public List DataExtensions { get; set; }
+
+ override public string ToString()
+ {
+ string ExtensionTargetsString = "\n";
+ if (ExtensionTargets is not null)
+ foreach (KeyValuePair pair in ExtensionTargets)
+ ExtensionTargetsString += $"{pair.Key}: {pair.Value}\n";
+
+ string DataExtensionString = "\n";
+ if (DataExtensions is not null)
+ foreach (string DataExtension in DataExtensions)
+ DataExtensionString += $"{DataExtension}, ";
+
+ return $@"Ext qlpack.yml file:
+ Library: {Library},
+ Name: {Name},
+ Version: {Version},
+ ExtensionTargets: {ExtensionTargetsString}
+ DataExtensions: {DataExtensionString}";
+ }
+ }
+}
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/IYmlSchema.cs b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/IYmlSchema.cs
new file mode 100644
index 0000000..88ba606
--- /dev/null
+++ b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/IYmlSchema.cs
@@ -0,0 +1,6 @@
+namespace CodeQLToolkit.Features.Pack.Commands.Validate.Schemas {
+ public interface IYmlSchema {
+ public string Name { get; set; }
+ public string Version { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/LibQlpackYmlSchema.cs b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/LibQlpackYmlSchema.cs
new file mode 100644
index 0000000..cf765fa
--- /dev/null
+++ b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/LibQlpackYmlSchema.cs
@@ -0,0 +1,28 @@
+namespace CodeQLToolkit.Features.Pack.Commands.Validate.Schemas
+{
+ public class LibQlpackYmlFileSchema : IYmlSchema
+ {
+ public bool Library { get; set; }
+ public string Name { get; set; }
+ public string Version { get; set; }
+ public string Suites { get; set; }
+ public string Extractor { get; set; }
+ public Dictionary Dependencies { get; set; }
+
+ override public string ToString()
+ {
+ string DependenciesString = "\n";
+ if (Dependencies is not null)
+ foreach (KeyValuePair pair in Dependencies)
+ DependenciesString += $"{pair.Key}: {pair.Value}\n";
+
+ return $@"Lib qlpack.yml file:
+ Library: {Library},
+ Name: {Name},
+ Version: {Version},
+ Suites: {Suites},
+ Extractor: {Extractor},
+ Dependencies: {DependenciesString}";
+ }
+ }
+}
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/SrcQlpackYmlSchema.cs b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/SrcQlpackYmlSchema.cs
new file mode 100644
index 0000000..aa1c4cc
--- /dev/null
+++ b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/SrcQlpackYmlSchema.cs
@@ -0,0 +1,35 @@
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+
+namespace CodeQLToolkit.Features.Pack.Commands.Validate.Schemas
+{
+ public class SrcQlpackYmlSchema : IYmlSchema
+ {
+ public bool Library { get; set; }
+ public string Name { get; set; }
+ public string Version { get; set; }
+ public string Suites { get; set; }
+ public string Extractor { get; set; }
+ public Dictionary Dependencies { get; set; }
+
+ [YamlMember(Alias = "default-suite-file", ApplyNamingConventions = false)]
+ public string DefaultSuiteFile { get; set; }
+
+ public override string ToString()
+ {
+ string DependenciesString = "\n";
+ if (Dependencies is not null)
+ foreach (KeyValuePair pair in Dependencies)
+ DependenciesString += $"{pair.Key}: {pair.Value}\n";
+
+ return $@"Src qlpack.yml file:
+ Library: {Library},
+ Name: {Name},
+ Version: {Version},
+ Suites: {Suites},
+ Extractor: {Extractor},
+ Dependencies: {DependenciesString},
+ DefaultSuiteFile: {DefaultSuiteFile}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/TestQlpackYmlSchema.cs b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/TestQlpackYmlSchema.cs
new file mode 100644
index 0000000..35df92b
--- /dev/null
+++ b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/Schemas/TestQlpackYmlSchema.cs
@@ -0,0 +1,24 @@
+namespace CodeQLToolkit.Features.Pack.Commands.Validate.Schemas
+{
+ public class TestQlpackYmlFileSchema : IYmlSchema
+ {
+ public string Name { get; set; }
+ public string Version { get; set; }
+ public string Extractor { get; set; }
+ public Dictionary Dependencies { get; set; }
+
+ override public string ToString()
+ {
+ string DependenciesString = "\n";
+ if (Dependencies is not null)
+ foreach (KeyValuePair pair in Dependencies)
+ DependenciesString += $"{pair.Key}: {pair.Value}\n";
+
+ return $@"Test qlpack.yml file:
+ Name: {Name},
+ Version: {Version},
+ Extractor: {Extractor},
+ Dependencies: {DependenciesString}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/ValidateSyntaxTarget.cs b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/ValidateSyntaxTarget.cs
new file mode 100644
index 0000000..64b9c6f
--- /dev/null
+++ b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/ValidateSyntaxTarget.cs
@@ -0,0 +1,16 @@
+using CodeQLToolkit.Shared.Logging;
+using CodeQLToolkit.Shared.Utils;
+using YamlDotNet.Serialization;
+
+namespace CodeQLToolkit.Features.Pack.Commands.Validate.Targets
+{
+ public class ValidateSyntaxTarget : CommandTarget
+ {
+ public string ExtFilePath { get; set; }
+
+ public override void Run()
+ {
+ Console.WriteLine("Hello world!");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/ValidateVersionTarget.cs b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/ValidateVersionTarget.cs
new file mode 100644
index 0000000..54a826b
--- /dev/null
+++ b/src/CodeQLToolkit.Features.Pack/Commands/Validate/Targets/ValidateVersionTarget.cs
@@ -0,0 +1,96 @@
+using CodeQLToolkit.Shared.Logging;
+using CodeQLToolkit.Shared.Utils;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+using Semver;
+using CodeQLToolkit.Features.Pack.Commands.Validate.Schemas;
+using System.Diagnostics;
+
+namespace CodeQLToolkit.Features.Pack.Commands.Validate.Targets
+{
+ public class YamlParseException : Exception
+ {
+ public string message { get; set; }
+ public YamlParseException(string failMessage)
+ {
+ message = failMessage;
+ }
+ }
+ public class ValidateVersionTarget : CommandTarget
+ {
+ public string[] QlpackYmlFiles { get; set; }
+ private static Deserializer YamlDeserializer = (Deserializer)new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build();
+
+ public override void Run()
+ {
+ Console.WriteLine("Hello world! I got: ");
+ foreach (string qlpackYmlFile in QlpackYmlFiles)
+ private static UnbrokenSemVersionRange FindUnbrokenSemverRangeOverlap(
+ UnbrokenSemVersionRange range1,
+ UnbrokenSemVersionRange range2
+ )
+ {
+ if (range1.End.ComparePrecedenceTo(range2.Start) == -1 || range2.End.ComparePrecedenceTo(range1.Start) == -1) {
+ return UnbrokenSemVersionRange.Empty;
+ } else {
+ var start = range1.Start.ComparePrecedenceTo(range2.Start) == -1 ? range2.Start : range1.Start;
+ var end = range1.End.ComparePrecedenceTo(range2.End) == -1 ? range1.End : range2.End;
+ return UnbrokenSemVersionRange.Inclusive(start, end);
+ }
+ }
+
+ private static SemVersionRange FindSemverRangeOverlap(
+ SemVersionRange range1,
+ SemVersionRange range2
+ )
+ {
+ var acc = new List();
+ foreach (UnbrokenSemVersionRange unbrokenRange1 in range1)
+ foreach (UnbrokenSemVersionRange unbrokenRange2 in range2)
+ acc.Add(FindUnbrokenSemverRangeOverlap(unbrokenRange1, unbrokenRange2));
+
+ return SemVersionRange.Create(acc);
+ }
+
+ private static bool thereIsSemVersionRangeOverlap(
+ SemVersionRange range1,
+ SemVersionRange range2
+ )
+ {
+ var intersection = FindSemverRangeOverlap(range1, range2);
+ bool foundNonemptyUnbrokenSemVersionRange = false;
+
+ foreach (UnbrokenSemVersionRange unbrokenRange in intersection)
+ {
+ Console.WriteLine($"Inspecting [{unbrokenRange.Start}, {unbrokenRange.End})...");
+ if (!unbrokenRange.Equals(UnbrokenSemVersionRange.Empty))
+ foundNonemptyUnbrokenSemVersionRange = true;
+ break;
+ }
+
+ return foundNonemptyUnbrokenSemVersionRange;
+ }
+
+ private static void testRangeOverlap()
+ {
+ var semver21 = SemVersionRange.Parse("1.2.1");
+ var semver22 = SemVersionRange.Parse("^1.2.0");
+
+ Debug.Assert(thereIsSemVersionRangeOverlap(semver21, semver22));
+
+ var semver31 = SemVersionRange.Parse("^1.2.0");
+ var semver32 = SemVersionRange.Parse("1.2.1");
+
+ Debug.Assert(thereIsSemVersionRangeOverlap(semver31, semver32));
+
+ var semver41 = UnbrokenSemVersionRange.AtLeast(SemVersion.Parse("1.2.0"));
+ var semver42 = UnbrokenSemVersionRange.Equals(SemVersion.Parse("1.2.1"));
+
+ Console.WriteLine($"semver41: {semver41.Start}, {semver41.End}");
+ Console.WriteLine($"semver42: {semver42.Start}, {semver42.End}");
+
+ var intersection = FindUnbrokenSemverRangeOverlap(semver41, semver42);
+ Console.WriteLine($"intersection: {intersection.Start}, {intersection.End}");
+ }
+ }
+}
diff --git a/src/CodeQLToolkit.Features.Pack/Commands/Validate/ValidateFeature.cs b/src/CodeQLToolkit.Features.Pack/Commands/Validate/ValidateFeature.cs
new file mode 100644
index 0000000..2760765
--- /dev/null
+++ b/src/CodeQLToolkit.Features.Pack/Commands/Validate/ValidateFeature.cs
@@ -0,0 +1,70 @@
+using CodeQLToolkit.Shared.Logging;
+using CodeQLToolkit.Shared.Utils;
+using CodeQLToolkit.Shared.Feature;
+using CodeQLToolkit.Features.Pack.Commands.Validate.Targets;
+using System.CommandLine;
+using System.IO;
+
+namespace CodeQLToolkit.Features.Pack.Commands.Validate
+{
+ public class ValidateFeature : FeatureBase, IToolkitCommandFeature
+ {
+ public void Register(Command parentCommand)
+ {
+ Log.G().LogInformation("Registering Validate submodule.");
+ var validateCommand = new Command("validate", "Checking correctness of various files");
+ parentCommand.Add(validateCommand);
+
+ var validateSyntaxCommand = new Command("syntax", "Check if the extensions designators are in correct syntax");
+ var extFilePath = new Option("--ext", "path to the extensions' definition file in yml format") { IsRequired = true, Arity = ArgumentArity.ExactlyOne };
+ validateSyntaxCommand.Add(extFilePath);
+
+ var validateVersionCommand = new Command("version", "Check if the versions match up across the qlpack.yml files");
+ var qlpackYmlFiles = new Option("--yml", "qlpack.yml files to check against") { IsRequired = true, Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = true };
+ validateVersionCommand.Add(qlpackYmlFiles);
+
+ validateCommand.Add(validateSyntaxCommand);
+ validateCommand.Add(validateVersionCommand);
+
+ validateSyntaxCommand.SetHandler((basePath, extFilePath) =>
+ {
+ var fileExists = File.Exists(extFilePath);
+ var isYamlFile = Path.GetExtension(extFilePath) == ".yml" || Path.GetExtension(extFilePath) == ".yaml";
+ if (!fileExists)
+ DieWithError($"{extFilePath} does not exist.");
+ if (!isYamlFile)
+ DieWithError($"{extFilePath} is not a yaml file.");
+ new ValidateSyntaxTarget()
+ {
+ Base = basePath,
+ ExtFilePath = extFilePath
+ }.Run();
+ }, Globals.BasePathOption, extFilePath);
+ validateVersionCommand.SetHandler(() => { throw new NotImplementedException(); });
+
+ validateVersionCommand.SetHandler((basePath, qlpackYmlFiles) =>
+ {
+ foreach (var qlpackYmlFile in qlpackYmlFiles)
+ {
+ var fileExists = File.Exists(qlpackYmlFile);
+ var isYamlFile = Path.GetExtension(qlpackYmlFile) == ".yml" || Path.GetExtension(qlpackYmlFile) == ".yaml";
+ if (!fileExists)
+ DieWithError($"{qlpackYmlFile} does not exist.");
+ if (!isYamlFile)
+ DieWithError($"{qlpackYmlFile} is not a yaml file.");
+ }
+ new ValidateVersionTarget()
+ {
+ Base = basePath,
+ QlpackYmlFiles = qlpackYmlFiles
+ }.Run();
+ }, Globals.BasePathOption, qlpackYmlFiles
+ );
+ }
+ public int Run()
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+}
diff --git a/src/CodeQLToolkit.Features.Pack/PackFeatureMain.cs b/src/CodeQLToolkit.Features.Pack/PackFeatureMain.cs
index 9fa81ea..f0d1ad6 100644
--- a/src/CodeQLToolkit.Features.Pack/PackFeatureMain.cs
+++ b/src/CodeQLToolkit.Features.Pack/PackFeatureMain.cs
@@ -1,4 +1,5 @@
using CodeQLToolkit.Features.Pack.Commands;
+using CodeQLToolkit.Features.Pack.Commands.Validate;
using System;
using System.Collections.Generic;
using System.CommandLine;
@@ -12,7 +13,7 @@ public class PackFeatureMain : IToolkitFeature
{
readonly static PackFeatureMain instance;
- readonly PackCommandFeature commandFeature;
+ readonly ValidateFeature validateFeature;
static PackFeatureMain()
{
@@ -21,7 +22,7 @@ static PackFeatureMain()
private PackFeatureMain()
{
- commandFeature = new PackCommandFeature();
+ validateFeature = new ValidateFeature();
}
public static PackFeatureMain Instance { get { return instance; } }
@@ -31,7 +32,7 @@ public void Register(Command parentCommand)
parentCommand.Add(packCommand);
Log.G().LogInformation("Registering scaffolding submodule.");
- commandFeature.Register(packCommand);
+ validateFeature.Register(packCommand);
}
public int Run()