diff --git a/src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/ICompilerOptions.cs b/src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/ICompilerOptions.cs index c70bcb4a..c9504e48 100644 --- a/src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/ICompilerOptions.cs +++ b/src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/ICompilerOptions.cs @@ -10,5 +10,8 @@ namespace AXSharp.Compiler; public interface ICompilerOptions { string? OutputProjectFolder { get; set; } + string? ProjectFile { get; set; } bool UseBase { get; set; } + + bool NoDependencyUpdate { get; set; } } \ No newline at end of file diff --git a/src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/TargetProject/ITargetProject.cs b/src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/TargetProject/ITargetProject.cs index d59a26a5..a27824f8 100644 --- a/src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/TargetProject/ITargetProject.cs +++ b/src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/TargetProject/ITargetProject.cs @@ -25,5 +25,9 @@ public interface ITargetProject void GenerateResources(); + void GenerateCompanionData(); + + void InstallAXSharpDependencies(IEnumerable dependencies); + IEnumerable LoadReferences(); } \ No newline at end of file diff --git a/src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpConfig.cs b/src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpConfig.cs index 00bd4dd5..7a34ca80 100644 --- a/src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpConfig.cs +++ b/src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpConfig.cs @@ -20,7 +20,7 @@ public class AXSharpConfig : ICompilerOptions /// /// Creates new instance of IxConfig object. /// - [Obsolete("Use 'Create IxConfig' instead.")] + [Obsolete($"Use 'Create {nameof(RetrieveAXSharpConfig)} instead.")] public AXSharpConfig() { @@ -31,7 +31,9 @@ public AXSharpConfig() /// public const string CONFIG_FILE_NAME = "AXSharp.config.json"; - + + + private string _outputProjectFolder = "ix"; /// @@ -43,8 +45,18 @@ public string OutputProjectFolder set => _outputProjectFolder = value; } + /// + /// Gets or sets whether compiler should use $base for base types of a class. + /// public bool UseBase { get; set; } + public bool NoDependencyUpdate { get; set; } + + + /// + /// Gets or sets name of the output project file. + /// + public string? ProjectFile { get; set; } private string _axProjectFolder; @@ -62,9 +74,9 @@ public string AxProjectFolder /// Gets updated or creates default config for given AX project. /// /// AX project directory - /// Compiler options. + /// Compiler options. /// Ix configuration for given AX project. - public static AXSharpConfig UpdateAndGetIxConfig(string directory, ICompilerOptions? cliCompilerOptions = null) + public static AXSharpConfig UpdateAndGetAXSharpConfig(string directory, ICompilerOptions? newCompilerOptions = null) { var ixConfigFilePath = Path.Combine(directory, CONFIG_FILE_NAME); @@ -81,7 +93,7 @@ public static AXSharpConfig UpdateAndGetIxConfig(string directory, ICompilerOpti if (AXSharpConfig != null) { AXSharpConfig.AxProjectFolder = directory; - OverridesFromCli(AXSharpConfig, cliCompilerOptions); + OverridesFromCli(AXSharpConfig, newCompilerOptions); } using (StreamWriter file = File.CreateText(ixConfigFilePath)) @@ -107,7 +119,7 @@ public static AXSharpConfig UpdateAndGetIxConfig(string directory, ICompilerOpti } - public static AXSharpConfig RetrieveIxConfig(string ixConfigFilePath) + public static AXSharpConfig RetrieveAXSharpConfig(string ixConfigFilePath) { try { @@ -128,13 +140,15 @@ public static AXSharpConfig RetrieveIxConfig(string ixConfigFilePath) } - private static void OverridesFromCli(ICompilerOptions fromConfig, ICompilerOptions? fromCli) + private static void OverridesFromCli(ICompilerOptions fromConfig, ICompilerOptions? newCompilerOptions) { // No CLI params - if (fromCli == null) + if (newCompilerOptions == null) return; // Items to override from the CLI - fromConfig.OutputProjectFolder = fromCli.OutputProjectFolder ?? fromConfig.OutputProjectFolder; + fromConfig.OutputProjectFolder = newCompilerOptions.OutputProjectFolder ?? fromConfig.OutputProjectFolder; + fromConfig.ProjectFile = string.IsNullOrEmpty(newCompilerOptions.ProjectFile) ? fromConfig.ProjectFile : newCompilerOptions.ProjectFile; + fromConfig.NoDependencyUpdate = newCompilerOptions.NoDependencyUpdate; } } \ No newline at end of file diff --git a/src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpProject.cs b/src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpProject.cs index b621442f..5d998839 100644 --- a/src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpProject.cs +++ b/src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpProject.cs @@ -6,6 +6,7 @@ // Third party licenses: https://github.com/ix-ax/axsharp/blob/master/notices.md using System.Text; +using System.Xml.Linq; using AX.ST.Semantic; using AX.ST.Semantic.Model.Declarations; using AX.ST.Semantic.Model.Declarations.Types; @@ -14,6 +15,7 @@ using AX.Text; using AXSharp.Compiler.Core; using AXSharp.Compiler.Exceptions; +using Microsoft.CodeAnalysis.Diagnostics; using Newtonsoft.Json; using Polly; @@ -42,7 +44,7 @@ public class AXSharpProject : IAXSharpProject public AXSharpProject(AxProject axProject, IEnumerable builderTypes, Type targetProjectType, ICompilerOptions? cliCompilerOptions = null) { AxProject = axProject; - CompilerOptions = AXSharpConfig.UpdateAndGetIxConfig(axProject.ProjectFolder, cliCompilerOptions); + CompilerOptions = AXSharpConfig.UpdateAndGetAXSharpConfig(axProject.ProjectFolder, cliCompilerOptions); OutputFolder = Path.GetFullPath(Path.Combine(AxProject.ProjectFolder, CompilerOptions.OutputProjectFolder)); if (cliCompilerOptions != null) UseBaseSymbol = cliCompilerOptions.UseBase; BuilderTypes = builderTypes; @@ -50,8 +52,7 @@ public AXSharpProject(AxProject axProject, IEnumerable builderTypes, Type InvalidOperationException("Target project type must implement ITargetProject interface."); } - - + /// /// Get AX project. /// @@ -134,9 +135,12 @@ public void Generate() TargetProject.ProvisionProjectStructure(); GenerateMetadata(compilation); TargetProject.GenerateResources(); + TargetProject.GenerateCompanionData(); Log.Logger.Information($"Compilation of project '{AxProject.SrcFolder}' done."); } + + /// /// Cleans all output files from the output directory /// @@ -207,7 +211,8 @@ private IEnumerable GetReferences() private void CompileProjectReferences(IEnumerable referencedDependencies) { - foreach (var ixProjectReference in AxProject.AXSharpReferences) + TargetProject.InstallAXSharpDependencies(AxProject.AXSharpReferences); + foreach (var ixProjectReference in AxProject.AXSharpReferences.OfType()) { if (compiled.Contains(ixProjectReference.AxProjectFolder)) diff --git a/src/AXSharp.compiler/src/AXSharp.Compiler/Apax.cs b/src/AXSharp.compiler/src/AXSharp.Compiler/Apax.cs index 57c22150..11e615e2 100644 --- a/src/AXSharp.compiler/src/AXSharp.Compiler/Apax.cs +++ b/src/AXSharp.compiler/src/AXSharp.Compiler/Apax.cs @@ -67,7 +67,7 @@ public Apax() /// Project file from which the ApaxFile object will be created. /// /// - public static Apax CreateApax(string projectFile) + public static Apax CreateApaxDto(string projectFile) { try { @@ -85,6 +85,27 @@ public static Apax CreateApax(string projectFile) } } + public static Apax TryCreateApaxDto(string projectFile) + { + try + { + if (!File.Exists(projectFile)) + return null; + + var deserializer = new DeserializerBuilder() + .WithNamingConvention(CamelCaseNamingConvention.Instance) + .IgnoreUnmatchedProperties() + .Build(); + + return deserializer.Deserialize(File.ReadAllText(projectFile)); + } + catch (FileNotFoundException) + { + throw new FileNotFoundException( + "'apax.yml' file was not found in the working directory. Make sure your current directory is simatic-ax project directory or provide source directory argument (for details see ixc --help)"); + } + } + /// /// Update version in an apax.yml file /// @@ -95,7 +116,7 @@ public static void UpdateVersion(string apaxFile, string version) { try { - var apax = CreateApax(apaxFile); + var apax = CreateApaxDto(apaxFile); apax.Version = version; diff --git a/src/AXSharp.compiler/src/AXSharp.Compiler/AxProject.cs b/src/AXSharp.compiler/src/AXSharp.Compiler/AxProject.cs index 33f279f2..a96298a8 100644 --- a/src/AXSharp.compiler/src/AXSharp.Compiler/AxProject.cs +++ b/src/AXSharp.compiler/src/AXSharp.Compiler/AxProject.cs @@ -9,6 +9,7 @@ using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; using System.IO; +using System; namespace AXSharp.Compiler; @@ -31,7 +32,7 @@ public AxProject(string axProjectFolder) ProjectFolder = axProjectFolder; ProjectFile = Path.Combine(ProjectFolder, "apax.yml"); SrcFolder = Path.Combine(axProjectFolder, "src"); - ProjectInfo = Apax.CreateApax(ProjectFile); + ProjectInfo = Apax.CreateApaxDto(ProjectFile); Sources = Directory.GetFiles(Path.Combine(ProjectFolder, "src"), "*.st", SearchOption.AllDirectories) .Select(p => new SourceFileText(p)); } @@ -51,7 +52,7 @@ public AxProject(string axProjectFolder, string[] sourceFiles) ProjectFolder = axProjectFolder; ProjectFile = Path.Combine(ProjectFolder, "apax.yml"); SrcFolder = Path.Combine(axProjectFolder, "src"); - ProjectInfo = Apax.CreateApax(ProjectFile); + ProjectInfo = Apax.CreateApaxDto(ProjectFile); Sources = sourceFiles.Select(p => new SourceFileText(p)); } @@ -80,32 +81,90 @@ public AxProject(string axProjectFolder, string[] sourceFiles) /// public string SrcFolder { get; } + /// + /// Contains list of near-by project in the directory structure (-2 levels up). + /// + private static List nearByProjects; + + private class NearByProjects + { + public Apax Apax { get; set; } + public FileInfo ApaxFile { get; set; } + } + + private class InstalledDependencies + { + public Apax Apax { get; set; } + public CompanionInfo Companion { get; set; } + + public FileInfo ApaxFile { get; set; } + } + /// /// Gets paths of this project's references to other ix projects. /// - public IEnumerable AXSharpReferences + public IEnumerable AXSharpReferences => GetProjectDependencies(); + + private IEnumerable GetProjectDependencies() { - get + var dependencies = ProjectInfo.Dependencies ?? new Dictionary(); + var installedDependencies = + dependencies.Select(p => Path.Combine(ProjectFolder, ".apax", "packages", + p.Key.Replace('/', Path.DirectorySeparatorChar))) + .Select(p => new InstalledDependencies() + { + Apax = Apax.TryCreateApaxDto(Path.Combine(p, "apax.yml")), + Companion = CompanionInfo.TryFromFile(Path.Combine(p, CompanionInfo.COMPANIONS_FILE_NAME)), + ApaxFile = new FileInfo(Path.Combine(p, "apax.yml")) + }).ToList(); + + + nearByProjects ??= Directory.EnumerateFiles( + Path.GetFullPath(Path.Combine(this.ProjectFolder, "../../..")), + "apax.yml", SearchOption.AllDirectories) + .Select(p => new FileInfo(p)) + .Where(p => !p.Directory.FullName.Contains(".apax")) + .Select(a => new NearByProjects() { Apax = Apax.TryCreateApaxDto(a.FullName), ApaxFile = a }) + .ToList(); + + var projectDependencies = new List(); + + foreach (var dependency in dependencies) { - var dependencies = ProjectInfo.Dependencies ?? new Dictionary(); + var hasSuchProject = + nearByProjects.FirstOrDefault(p => p.Apax.Name == dependency.Key && p.Apax.Version == dependency.Value); + if (hasSuchProject != null) + { + var pathAXSharpConfig = + Path.Combine(hasSuchProject.ApaxFile.Directory.FullName, AXSharpConfig.CONFIG_FILE_NAME); + if (File.Exists(pathAXSharpConfig)) + { + projectDependencies.Add((AXSharpConfig.RetrieveAXSharpConfig(pathAXSharpConfig))); + } + } + } - var packagesDirectories = - dependencies.Select(p => Path.Combine(ProjectFolder, ".apax", "packages", p.Key.Replace('/',Path.DirectorySeparatorChar))); + foreach (var dependency in dependencies) + { + var dependencyWithCompanion = installedDependencies + .FirstOrDefault(p => p.Apax != null && p.Apax.Name == dependency.Key && p.Apax.Version == dependency.Value); - - var retVal = packagesDirectories - .Where(p => Directory.Exists(p)) - .Select(p => new DirectoryInfo(p)) - .Select(p => Directory.EnumerateFiles(p.LinkTarget ?? p.FullName, AXSharpConfig.CONFIG_FILE_NAME, SearchOption.TopDirectoryOnly)) - .SelectMany(p => p).Select(c => AXSharpConfig.RetrieveIxConfig(c)); - if (retVal.Count() == 0) + if (dependencyWithCompanion?.Companion != null) { - Log.Logger.Information("Retrieving possible project references from .apax packages did not produce results. " + - "If you have referenced AX# projects, the packages must be previously installed by 'apax install'"); + var packageFile = + Path.Combine(dependencyWithCompanion.ApaxFile.Directory.FullName, "package.json"); + if(File.Exists(packageFile)) + projectDependencies.Add(dependencyWithCompanion.Companion); } + } - return retVal; + if (!projectDependencies.Any()) + { + Log.Logger.Information("Retrieving possible project references from .apax packages did not produce results. " + + "If you have referenced AX# projects, the packages must be previously installed by 'apax install'"); } + + return projectDependencies; } } \ No newline at end of file diff --git a/src/AXSharp.compiler/src/AXSharp.Compiler/CompanionInfo.cs b/src/AXSharp.compiler/src/AXSharp.Compiler/CompanionInfo.cs new file mode 100644 index 00000000..b4dc934f --- /dev/null +++ b/src/AXSharp.compiler/src/AXSharp.Compiler/CompanionInfo.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using Newtonsoft.Json; + + namespace AXSharp.Compiler + { + public class CompanionInfo + { + + public const string COMPANIONS_FILE_NAME = "axsharp.companion.json"; + + public string Id { get; set; } + public string Version { get; set; } + + private static string ToJson(CompanionInfo info) + { + return JsonConvert.SerializeObject(info); + } + + private static CompanionInfo FromJson(string json) + { + return JsonConvert.DeserializeObject(json); + } + + // Serialize the object to a file + public static void ToFile(CompanionInfo info, string filePath) + { + var json = ToJson(info); + File.WriteAllText(filePath, json); + } + + // Deserialize the object from a file + public static CompanionInfo? FromFile(string filePath) + { + var json = File.ReadAllText(filePath); + return FromJson(json); + } + + public static CompanionInfo? TryFromFile(string filePath) + { + if (!File.Exists(filePath)) + return null; + + var json = File.ReadAllText(filePath); + return FromJson(json); + } + } + } + + diff --git a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/CsProject.cs b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/CsProject.cs index 6cd11b05..50971480 100644 --- a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/CsProject.cs +++ b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/CsProject.cs @@ -5,8 +5,11 @@ // https://github.com/ix-ax/axsharp/blob/dev/LICENSE // Third party licenses: https://github.com/ix-ax/axsharp/blob/master/notices.md +using System.Diagnostics; using System.Reflection; +using System.Xml; using System.Xml.Linq; +using System.Xml.XPath; using AXSharp.Compiler.Cs.Exceptions; using Microsoft.CodeAnalysis.CSharp; using NuGet.Configuration; @@ -83,13 +86,32 @@ private void EnsureCsProjFile() { if (AxSharpProject.AxProject.ProjectInfo.Name != null) { - var expectedCsProjFile = Path.Combine(AxSharpProject.OutputFolder, - $"{MakeValidFileName(AxSharpProject.AxProject.ProjectInfo.Name)}.csproj"); + string expectedCsProjFileFullPath = string.Empty; + string expectedCsProjFile = string.Empty; + if (string.IsNullOrEmpty(this.AxSharpProject.CompilerOptions?.ProjectFile)) + { + expectedCsProjFile = $"{MakeValidFileName(AxSharpProject.AxProject.ProjectInfo.Name)}.csproj"; + expectedCsProjFileFullPath = Path.Combine(AxSharpProject.OutputFolder, + expectedCsProjFile); + } + else + { + expectedCsProjFile = this.AxSharpProject.CompilerOptions.ProjectFile; + expectedCsProjFileFullPath = Path.Combine(AxSharpProject.OutputFolder, + expectedCsProjFile); + } + + var compilerOptions = this.AxSharpProject.CompilerOptions; + if (compilerOptions != null) + { + compilerOptions.ProjectFile = expectedCsProjFile; + AXSharpConfig.UpdateAndGetAXSharpConfig(AxSharpProject.AxProject.ProjectFolder, compilerOptions); + } var defaultCsProjectWhenNotProvidedByTemplate = $@" - net6.0 + net7.0 enable enable @@ -110,9 +132,9 @@ private void EnsureCsProjFile() .WaitAndRetry(5, a => TimeSpan.FromMilliseconds(500)) .Execute(() => { - if (!File.Exists(expectedCsProjFile)) + if (!File.Exists(expectedCsProjFileFullPath)) { - using (var swr = new StreamWriter(expectedCsProjFile)) + using (var swr = new StreamWriter(expectedCsProjFileFullPath)) { swr.Write(defaultCsProjectWhenNotProvidedByTemplate); } @@ -170,6 +192,137 @@ private PlcTranslator() /// public string GetMetaDataFolder => Path.Combine(AxSharpProject.OutputFolder, ".meta"); + public static string GetRelativePath(string fromPath, string toPath) + { + var fromUri = new Uri(fromPath); + var toUri = new Uri(toPath); + + if (fromUri.Scheme != toUri.Scheme) + { + // Handle different schemes. + // You could throw an exception here or return the `toPath` as is, + // depending on your needs. + return toPath; + } + + Uri relativeUri = fromUri.MakeRelativeUri(toUri); + var relativePath = Uri.UnescapeDataString(relativeUri.ToString()); + + return relativePath.Replace('/', System.IO.Path.DirectorySeparatorChar); + } + + private static bool ProjectReferenceExists(string mainProjectPath, string referenceProjectPath) + { + var xDocument = XDocument.Load(mainProjectPath); + + // Using XPath to search for the ProjectReference with a specific Include path + var projectReferenceElements = xDocument.XPathSelectElements($"//ProjectReference[@Include='{referenceProjectPath}']"); + + return projectReferenceElements.Any(); + } + + private static void AddProjectReference(string mainProjectPath, string referenceProjectPath) + { + if (ProjectReferenceExists(mainProjectPath, referenceProjectPath)) + return; + + using (var process = new Process()) + { + process.StartInfo.FileName = "dotnet"; + process.StartInfo.Arguments = $"add \"{mainProjectPath}\" reference \"{referenceProjectPath}\""; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + + process.OutputDataReceived += (sender, data) => { if (!string.IsNullOrEmpty(data.Data)) { Console.WriteLine(data.Data); } }; + process.ErrorDataReceived += (sender, data) => { if (!string.IsNullOrEmpty(data.Data)) { Console.WriteLine(data.Data); } }; + + process.Start(); + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + process.WaitForExit(); + } + } + + private static bool PackageReferenceExists(string projectFilePath, string packageName, string version) + { + var xDocument = XDocument.Load(projectFilePath); + + var package + = PackageReference.GetVersionFromCentralPackageManagement(projectFilePath)? + .FirstOrDefault(p => p.include == packageName); + + + // Using XPath to search for the PackageReference with a specific Include attribute and Version child element + + return xDocument.XPathSelectElements( + $"//PackageReference[@Include='{packageName}']/Version[text()='{version}']").Any() + || + (xDocument.XPathSelectElements( + $"//PackageReference[@Include='{packageName}']").Any() && package != null && package?.version == version); + } + + private static void AddNuGetPackageReference(string projectPath, string packageName, string version = null) + { + + if (PackageReferenceExists(projectPath, packageName, version)) + return; + + using (var process = new Process()) + { + process.StartInfo.FileName = "dotnet"; + process.StartInfo.Arguments = $"add \"{projectPath}\" package {packageName}" + (string.IsNullOrEmpty(version) ? "" : $" --version {version}"); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + + process.OutputDataReceived += (sender, data) => { if (!string.IsNullOrEmpty(data.Data)) { Console.WriteLine(data.Data); } }; + process.ErrorDataReceived += (sender, data) => { if (!string.IsNullOrEmpty(data.Data)) { Console.WriteLine(data.Data); } }; + + process.Start(); + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + process.WaitForExit(); + } + } + + /// + /// Installs dependencies to the companion twin project from using dependencies from `apax.yml` file of a given AX project. + /// + /// + public void InstallAXSharpDependencies(IEnumerable dependencies) + { + var compilerOptions = this.AxSharpProject.CompilerOptions; + if (compilerOptions != null && compilerOptions.NoDependencyUpdate) return; + + var compilerOptionsProjectFile = this.AxSharpProject.CompilerOptions?.ProjectFile; + + if (compilerOptionsProjectFile != null) + { + var dependent = Path.Combine(this.AxSharpProject.OutputFolder, compilerOptionsProjectFile); + foreach (var dependency in dependencies) + { + + switch (dependency) + { + case CompanionInfo package: + AddNuGetPackageReference(dependent, package.Id, package.Version); + break; + case AXSharpConfig project: + var projectPath = Path.GetFullPath(Path.Combine(project.AxProjectFolder, project.OutputProjectFolder, project.ProjectFile)); + AddProjectReference(dependent, GetRelativePath(dependent, projectPath)); + break; + } + } + } + } + /// /// Retrieves references from csproj file associated with given project. /// @@ -336,4 +489,34 @@ private static IEnumerable ProjectReferences(XDocument csproj, strin } #endregion + + static string GetPackageId(string csprojPath) + { + XDocument xDocument = XDocument.Load(csprojPath); + + var packageIdElement = xDocument.Descendants("PackageId").FirstOrDefault(); + + if (packageIdElement != null) + { + return packageIdElement.Value; + } + + // If PackageId element is not found, default to the project's name + return Path.GetFileNameWithoutExtension(csprojPath); + } + + public void GenerateCompanionData() + { + var compilerOptions = this.AxSharpProject.CompilerOptions; + if (compilerOptions != null) + { + if (compilerOptions.ProjectFile != null) + { + var packageId = GetPackageId(Path.Combine(this.AxSharpProject.OutputFolder, + compilerOptions.ProjectFile)); + + CompanionInfo.ToFile(new CompanionInfo() { Id = packageId, Version = this.AxSharpProject.AxProject.ProjectInfo.Version }, Path.Combine(this.AxSharpProject.AxProject.ProjectFolder, CompanionInfo.COMPANIONS_FILE_NAME)); + } + } + } } \ No newline at end of file diff --git a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/PackageReference.cs b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/PackageReference.cs index 267d716f..6d526084 100644 --- a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/PackageReference.cs +++ b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/PackageReference.cs @@ -20,7 +20,7 @@ public class PackageReference : IPackageReference private static readonly string NugetDir = SettingsUtility.GetGlobalPackagesFolder(Settings.LoadDefaultSettings(null)); - private static IEnumerable<(string? include, string? version)> GetVersionFromCentralPackageManagement(string csprojFile) + internal static IEnumerable<(string? include, string? version)> GetVersionFromCentralPackageManagement(string csprojFile) { var scFile = new FileInfo(csprojFile); string? currentDirectory = scFile.DirectoryName; diff --git a/src/AXSharp.compiler/src/ixc/Options.cs b/src/AXSharp.compiler/src/ixc/Options.cs index 921cd5ad..ce0fe9ad 100644 --- a/src/AXSharp.compiler/src/ixc/Options.cs +++ b/src/AXSharp.compiler/src/ixc/Options.cs @@ -25,5 +25,13 @@ internal class Options : ICompilerOptions [Option('b', "use-base-symbol", Required = false, Default = false, HelpText = "Will use base symbol in inherited types")] public bool UseBase { get; set; } + + [Option('p', "project-file", Required = false, Default = "", + HelpText = "Output project file")] + public string? ProjectFile { get; set; } + + [Option('u', "no-dependency-update", Required = false, Default = false, + HelpText = "Prevent dependency of twins from apax")] + public bool NoDependencyUpdate { get; set; } } diff --git a/src/AXSharp.compiler/src/ixc/Properties/launchSettings.json b/src/AXSharp.compiler/src/ixc/Properties/launchSettings.json index 1df7aa4a..47ad35ea 100644 --- a/src/AXSharp.compiler/src/ixc/Properties/launchSettings.json +++ b/src/AXSharp.compiler/src/ixc/Properties/launchSettings.json @@ -19,6 +19,10 @@ "ax-connectors-test-project": { "commandName": "Project", "workingDirectory": "C:\\W\\Develop\\gh\\ix-ax\\axsharp\\src\\AXSharp.connectors\\tests\\ax-test-project\\" + }, + "app-withref": { + "commandName": "Project", + "workingDirectory": "c:\\W\\Develop\\gh\\ix-ax\\axopen\\src\\.application\\app\\" } } } \ No newline at end of file diff --git a/src/AXSharp.compiler/src/ixd/Options.cs b/src/AXSharp.compiler/src/ixd/Options.cs index 34041049..5e4f5321 100644 --- a/src/AXSharp.compiler/src/ixd/Options.cs +++ b/src/AXSharp.compiler/src/ixd/Options.cs @@ -22,5 +22,13 @@ internal class Options : ICompilerOptions [Option('b', "use-base-symbol", Required = false, Default = false, HelpText = "Will use base symbol in inherited types")] public bool UseBase { get; set; } + + [Option('u', "no-dependency-update", Required = false, Default = false, + HelpText = "Prevent dependency of twins from apax")] + public bool NoDependencyUpdate { get; set; } + + [Option('p', "project-file", Required = false, Default = "", + HelpText = "Output project file")] + public string? ProjectFile { get; set; } } } diff --git a/src/AXSharp.compiler/src/ixr/Options.cs b/src/AXSharp.compiler/src/ixr/Options.cs index 91399908..8e7bec74 100644 --- a/src/AXSharp.compiler/src/ixr/Options.cs +++ b/src/AXSharp.compiler/src/ixr/Options.cs @@ -18,8 +18,18 @@ internal class Options : ICompilerOptions [Option('o', "output-project-folder", Required = false, HelpText = "Output project folder where compiler emits result.")] public string? OutputProjectFolder { get; set; } - [Option('b', "use-base-symbol", Required = false, Default = false, + [Option('p', "project-file", Required = false, Default = false, + HelpText = "Output project file")] + public string? ProjectFile { get; set; } + + [Option('b', "use-base-symbol", Required = false, Default = "", HelpText = "Will use base symbol in inherited types")] public bool UseBase { get; set; } + + [Option('u', "no-dependency-update", Required = false, Default = false, + HelpText = "Prevent dependency of twins from apax")] + public bool NoDependencyUpdate { get; set; } + + } } diff --git a/src/AXSharp.compiler/src/ixr/Program.cs b/src/AXSharp.compiler/src/ixr/Program.cs index c2f7dfe9..6a185c80 100644 --- a/src/AXSharp.compiler/src/ixr/Program.cs +++ b/src/AXSharp.compiler/src/ixr/Program.cs @@ -65,7 +65,7 @@ void Generate(Options o) var axProject = new AxProject(axProjectFolder); var axProjectConfig = - AXSharpConfig.RetrieveIxConfig(Path.Combine(axProject.ProjectFolder, AXSharpConfig.CONFIG_FILE_NAME)); + AXSharpConfig.RetrieveAXSharpConfig(Path.Combine(axProject.ProjectFolder, AXSharpConfig.CONFIG_FILE_NAME)); (string folder, string file) output = string.IsNullOrEmpty(axProjectConfig.OutputProjectFolder) ? (string.Empty, o.OutputProjectFolder) diff --git a/src/AXSharp.compiler/tests/AXSharp.CompilerTests/ApaxTests.cs b/src/AXSharp.compiler/tests/AXSharp.CompilerTests/ApaxTests.cs index 3e7a1046..59435e5e 100644 --- a/src/AXSharp.compiler/tests/AXSharp.CompilerTests/ApaxTests.cs +++ b/src/AXSharp.compiler/tests/AXSharp.CompilerTests/ApaxTests.cs @@ -35,7 +35,7 @@ var executingAssemblyFileInfo [Fact] public void should_load_and_parse_apax_workspace_file() { - var apaxWorkspaceFile = Apax.CreateApax(Path.Combine(testFolder, @"samples//plt//apax.yml")); + var apaxWorkspaceFile = Apax.CreateApaxDto(Path.Combine(testFolder, @"samples//plt//apax.yml")); Assert.Equal("plt", apaxWorkspaceFile.Name); Assert.Equal("workspace", apaxWorkspaceFile.Type); @@ -45,7 +45,7 @@ public void should_load_and_parse_apax_workspace_file() [Fact()] public void should_load_and_parse_apax_library_file() { - var apaxWorkspaceFile = Apax.CreateApax(Path.Combine(testFolder, @"samples//plt//lib2//apax.yml")); + var apaxWorkspaceFile = Apax.CreateApaxDto(Path.Combine(testFolder, @"samples//plt//lib2//apax.yml")); Assert.Equal("plt-lib2", apaxWorkspaceFile.Name); Assert.Equal("lib", apaxWorkspaceFile.Type); @@ -60,7 +60,7 @@ public void should_load_and_parse_apax_library_file() [Fact()] public void should_load_and_parse_apax_app_file() { - var apaxWorkspaceFile = Apax.CreateApax(Path.Combine(testFolder, @"samples//plt//app//apax.yml")); + var apaxWorkspaceFile = Apax.CreateApaxDto(Path.Combine(testFolder, @"samples//plt//app//apax.yml")); Assert.Equal("plt-app", apaxWorkspaceFile.Name); Assert.Equal("app", apaxWorkspaceFile.Type); @@ -76,13 +76,13 @@ public void should_load_and_parse_apax_app_file() [Fact()] public void should_update_apax_version() { - var apaxWorkspaceFile = Apax.CreateApax(Path.Combine(testFolder, @"samples//plt1//app//apax.yml")); + var apaxWorkspaceFile = Apax.CreateApaxDto(Path.Combine(testFolder, @"samples//plt1//app//apax.yml")); Assert.Equal("plt-app", apaxWorkspaceFile.Name); Assert.Equal("app", apaxWorkspaceFile.Type); Assert.Equal("0.1.0", apaxWorkspaceFile.Version); Apax.UpdateVersion(Path.Combine(testFolder, @"samples//plt1//app//apax.yml"), "33.88.50"); - apaxWorkspaceFile = Apax.CreateApax(Path.Combine(testFolder, @"samples//plt1//app//apax.yml")); + apaxWorkspaceFile = Apax.CreateApaxDto(Path.Combine(testFolder, @"samples//plt1//app//apax.yml")); Assert.Equal("plt-app", apaxWorkspaceFile.Name); Assert.Equal("app", apaxWorkspaceFile.Type); diff --git a/src/AXSharp.compiler/tests/AXSharp.CompilerTests/IxConfigTests.cs b/src/AXSharp.compiler/tests/AXSharp.CompilerTests/IxConfigTests.cs index bb5744ad..ad578ffd 100644 --- a/src/AXSharp.compiler/tests/AXSharp.CompilerTests/IxConfigTests.cs +++ b/src/AXSharp.compiler/tests/AXSharp.CompilerTests/IxConfigTests.cs @@ -42,7 +42,7 @@ public void UpdateAndGetIxConfig_should_create_config_file_if_does_not_exist() File.Delete(ixConfigFile); } - var result = AXSharpConfig.UpdateAndGetIxConfig(apaxFolder); + var result = AXSharpConfig.UpdateAndGetAXSharpConfig(apaxFolder); Assert.True(File.Exists(ixConfigFile)); @@ -56,7 +56,7 @@ public void UpdateAndGetIxConfig_shoud_retrieve_existing_config_file() var apaxFolder = Path.Combine(testFolder, "samples", "plt2","lib"); var ixConfigFile = Path.Combine(apaxFolder, "AXSharp.config.json"); Assert.True(File.Exists(ixConfigFile)); - var result = AXSharpConfig.UpdateAndGetIxConfig(apaxFolder); + var result = AXSharpConfig.UpdateAndGetAXSharpConfig(apaxFolder); Assert.True(File.Exists(ixConfigFile)); Assert.Equal($"..{Path.DirectorySeparatorChar}ix", result.OutputProjectFolder); Assert.Equal(apaxFolder, result.AxProjectFolder); @@ -69,7 +69,7 @@ public void UpdateAndGetIxConfig_should_retrieve_existing_config_and_update_from var ixConfigFile = Path.Combine(apaxFolder, "AXSharp.config.json"); Assert.True(File.Exists(ixConfigFile)); #pragma warning disable CS0618 - var result = AXSharpConfig.UpdateAndGetIxConfig(apaxFolder, new AXSharpConfig() + var result = AXSharpConfig.UpdateAndGetAXSharpConfig(apaxFolder, new AXSharpConfig() #pragma warning restore CS0618 { AxProjectFolder = "hoho", OutputProjectFolder = "hehe"}); Assert.True(File.Exists(ixConfigFile)); @@ -83,7 +83,7 @@ public void RetrieveIxConfig_should_read_existing_config() var apaxFolder = Path.Combine(testFolder, "samples", "plt","lib3"); var ixConfigFile = Path.Combine(apaxFolder, "AXSharp.config.json"); Assert.True(File.Exists(ixConfigFile)); - var result = AXSharpConfig.RetrieveIxConfig(ixConfigFile); + var result = AXSharpConfig.RetrieveAXSharpConfig(ixConfigFile); Assert.True(File.Exists(ixConfigFile)); Assert.Equal($"..{Path.DirectorySeparatorChar}ix", result.OutputProjectFolder); Assert.True(result.AxProjectFolder.EndsWith(Path.Combine("samples", "plt", "lib3"))); @@ -94,7 +94,7 @@ public void RetrieveIxConfig_should_throw_exception_when_unable_to_process_confi { var apaxFolder = Path.Combine(testFolder, "samples", "plt","lib3"); var ixConfigFile = Path.Combine(apaxFolder, "AXSharp.config.json1"); - Assert.Throws(() =>AXSharpConfig.RetrieveIxConfig(ixConfigFile)); + Assert.Throws(() =>AXSharpConfig.RetrieveAXSharpConfig(ixConfigFile)); } } } \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/AXSharp.CompilerTests/IxProjectTests.cs b/src/AXSharp.compiler/tests/AXSharp.CompilerTests/IxProjectTests.cs index 48c490e2..5a5c8fdf 100644 --- a/src/AXSharp.compiler/tests/AXSharp.CompilerTests/IxProjectTests.cs +++ b/src/AXSharp.compiler/tests/AXSharp.CompilerTests/IxProjectTests.cs @@ -384,6 +384,16 @@ public void GenerateResources() } + public void GenerateCompanionData() + { + + } + + public void InstallAXSharpDependencies(IEnumerable dependencies) + { + + } + public IEnumerable LoadReferences() { return new List(); diff --git a/src/AXSharp.compiler/tests/AXSharp.ixc.Tests/CliProgramTest.cs b/src/AXSharp.compiler/tests/AXSharp.ixc.Tests/CliProgramTest.cs index 964a7d3d..94f6c063 100644 --- a/src/AXSharp.compiler/tests/AXSharp.ixc.Tests/CliProgramTest.cs +++ b/src/AXSharp.compiler/tests/AXSharp.ixc.Tests/CliProgramTest.cs @@ -62,7 +62,7 @@ public void should_run_with_default_settings() public void should_run_with_setting_retrieved_from_config_file_settings() { var axProjectFolder = Path.Combine(TestFolder, "samples","plt","app"); - var config = AXSharpConfig.UpdateAndGetIxConfig(axProjectFolder); + var config = AXSharpConfig.UpdateAndGetAXSharpConfig(axProjectFolder); var outputDirectory = Path.GetFullPath(Path.Combine(axProjectFolder, config.OutputProjectFolder)); if (Directory.Exists(outputDirectory)) @@ -96,7 +96,7 @@ public void should_run_with_setting_retrieved_from_config_file_settings() public void should_run_with_setting_retrieved_from_config_file_settings_but_override_from_cli() { var axProjectFolder = Path.Combine(TestFolder, "samples","plt","lib"); - var config = AXSharpConfig.UpdateAndGetIxConfig(axProjectFolder); + var config = AXSharpConfig.UpdateAndGetAXSharpConfig(axProjectFolder); var outputDirectory = Path.GetFullPath(Path.Combine(axProjectFolder, $"..{Path.DirectorySeparatorChar}ix-lib-override")); if (Directory.Exists(outputDirectory)) diff --git a/src/AXSharp.compiler/tests/integration/actual/app/AXSharp.config.json b/src/AXSharp.compiler/tests/integration/actual/app/AXSharp.config.json index 2e5862ea..3640cb80 100644 --- a/src/AXSharp.compiler/tests/integration/actual/app/AXSharp.config.json +++ b/src/AXSharp.compiler/tests/integration/actual/app/AXSharp.config.json @@ -1 +1 @@ -{"OutputProjectFolder":"ix","UseBase":false} \ No newline at end of file +{"OutputProjectFolder":"ix","UseBase":false,"NoDependencyUpdate":false,"ProjectFile":"app.csproj"} \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/integration/actual/app/axsharp.companion.json b/src/AXSharp.compiler/tests/integration/actual/app/axsharp.companion.json new file mode 100644 index 00000000..16d006cd --- /dev/null +++ b/src/AXSharp.compiler/tests/integration/actual/app/axsharp.companion.json @@ -0,0 +1 @@ +{"Id":"app","Version":"0.0.0"} \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/integration/actual/lib1/AXSharp.config.json b/src/AXSharp.compiler/tests/integration/actual/lib1/AXSharp.config.json index 2e5862ea..e329f0d1 100644 --- a/src/AXSharp.compiler/tests/integration/actual/lib1/AXSharp.config.json +++ b/src/AXSharp.compiler/tests/integration/actual/lib1/AXSharp.config.json @@ -1 +1 @@ -{"OutputProjectFolder":"ix","UseBase":false} \ No newline at end of file +{"OutputProjectFolder":"ix","UseBase":false,"NoDependencyUpdate":false,"ProjectFile":"lib1.csproj"} \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/integration/actual/lib1/axsharp.companion.json b/src/AXSharp.compiler/tests/integration/actual/lib1/axsharp.companion.json new file mode 100644 index 00000000..8f3bf1dd --- /dev/null +++ b/src/AXSharp.compiler/tests/integration/actual/lib1/axsharp.companion.json @@ -0,0 +1 @@ +{"Id":"lib1","Version":"0.0.0"} \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/integration/actual/lib2/AXSharp.config.json b/src/AXSharp.compiler/tests/integration/actual/lib2/AXSharp.config.json index 2e5862ea..fbe02572 100644 --- a/src/AXSharp.compiler/tests/integration/actual/lib2/AXSharp.config.json +++ b/src/AXSharp.compiler/tests/integration/actual/lib2/AXSharp.config.json @@ -1 +1 @@ -{"OutputProjectFolder":"ix","UseBase":false} \ No newline at end of file +{"OutputProjectFolder":"ix","UseBase":false,"NoDependencyUpdate":false,"ProjectFile":"lib2.csproj"} \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/integration/actual/lib2/axsharp.companion.json b/src/AXSharp.compiler/tests/integration/actual/lib2/axsharp.companion.json new file mode 100644 index 00000000..40855e89 --- /dev/null +++ b/src/AXSharp.compiler/tests/integration/actual/lib2/axsharp.companion.json @@ -0,0 +1 @@ +{"Id":"lib2","Version":"0.0.0"} \ No newline at end of file