Skip to content

Commit 993ea1d

Browse files
IX-BOTPTKu
andauthored
[NEW-FEATURE] Explore possible nuget package installation during ixc run from apax package (#242)
* Create draft PR for #241 * [wip] installs project and package dependencies from apax.yml into twin companion project --------- Co-authored-by: PTKu <[email protected]> Co-authored-by: Peter <[email protected]>
1 parent 8ec3ea7 commit 993ea1d

File tree

24 files changed

+448
-55
lines changed

24 files changed

+448
-55
lines changed

src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/ICompilerOptions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ namespace AXSharp.Compiler;
1010
public interface ICompilerOptions
1111
{
1212
string? OutputProjectFolder { get; set; }
13+
string? ProjectFile { get; set; }
1314
bool UseBase { get; set; }
15+
16+
bool NoDependencyUpdate { get; set; }
1417
}

src/AXSharp.compiler/src/AXSharp.Compiler.Abstractions/TargetProject/ITargetProject.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,9 @@ public interface ITargetProject
2525

2626
void GenerateResources();
2727

28+
void GenerateCompanionData();
29+
30+
void InstallAXSharpDependencies(IEnumerable<object> dependencies);
31+
2832
IEnumerable<IReference> LoadReferences();
2933
}

src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpConfig.cs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class AXSharpConfig : ICompilerOptions
2020
/// <summary>
2121
/// Creates new instance of IxConfig object.
2222
/// </summary>
23-
[Obsolete("Use 'Create IxConfig' instead.")]
23+
[Obsolete($"Use 'Create {nameof(RetrieveAXSharpConfig)} instead.")]
2424
public AXSharpConfig()
2525
{
2626

@@ -31,7 +31,9 @@ public AXSharpConfig()
3131
/// </summary>
3232
public const string CONFIG_FILE_NAME = "AXSharp.config.json";
3333

34-
34+
35+
36+
3537
private string _outputProjectFolder = "ix";
3638

3739
/// <summary>
@@ -43,8 +45,18 @@ public string OutputProjectFolder
4345
set => _outputProjectFolder = value;
4446
}
4547

48+
/// <summary>
49+
/// Gets or sets whether compiler should use $base for base types of a class.
50+
/// </summary>
4651
public bool UseBase { get; set; }
4752

53+
public bool NoDependencyUpdate { get; set; }
54+
55+
56+
/// <summary>
57+
/// Gets or sets name of the output project file.
58+
/// </summary>
59+
public string? ProjectFile { get; set; }
4860

4961
private string _axProjectFolder;
5062

@@ -62,9 +74,9 @@ public string AxProjectFolder
6274
/// Gets updated or creates default config for given AX project.
6375
/// </summary>
6476
/// <param name="directory">AX project directory</param>
65-
/// <param name="cliCompilerOptions">Compiler options.</param>
77+
/// <param name="newCompilerOptions">Compiler options.</param>
6678
/// <returns>Ix configuration for given AX project.</returns>
67-
public static AXSharpConfig UpdateAndGetIxConfig(string directory, ICompilerOptions? cliCompilerOptions = null)
79+
public static AXSharpConfig UpdateAndGetAXSharpConfig(string directory, ICompilerOptions? newCompilerOptions = null)
6880
{
6981
var ixConfigFilePath = Path.Combine(directory, CONFIG_FILE_NAME);
7082

@@ -81,7 +93,7 @@ public static AXSharpConfig UpdateAndGetIxConfig(string directory, ICompilerOpti
8193
if (AXSharpConfig != null)
8294
{
8395
AXSharpConfig.AxProjectFolder = directory;
84-
OverridesFromCli(AXSharpConfig, cliCompilerOptions);
96+
OverridesFromCli(AXSharpConfig, newCompilerOptions);
8597
}
8698

8799
using (StreamWriter file = File.CreateText(ixConfigFilePath))
@@ -107,7 +119,7 @@ public static AXSharpConfig UpdateAndGetIxConfig(string directory, ICompilerOpti
107119
}
108120

109121

110-
public static AXSharpConfig RetrieveIxConfig(string ixConfigFilePath)
122+
public static AXSharpConfig RetrieveAXSharpConfig(string ixConfigFilePath)
111123
{
112124
try
113125
{
@@ -128,13 +140,15 @@ public static AXSharpConfig RetrieveIxConfig(string ixConfigFilePath)
128140

129141
}
130142

131-
private static void OverridesFromCli(ICompilerOptions fromConfig, ICompilerOptions? fromCli)
143+
private static void OverridesFromCli(ICompilerOptions fromConfig, ICompilerOptions? newCompilerOptions)
132144
{
133145
// No CLI params
134-
if (fromCli == null)
146+
if (newCompilerOptions == null)
135147
return;
136148

137149
// Items to override from the CLI
138-
fromConfig.OutputProjectFolder = fromCli.OutputProjectFolder ?? fromConfig.OutputProjectFolder;
150+
fromConfig.OutputProjectFolder = newCompilerOptions.OutputProjectFolder ?? fromConfig.OutputProjectFolder;
151+
fromConfig.ProjectFile = string.IsNullOrEmpty(newCompilerOptions.ProjectFile) ? fromConfig.ProjectFile : newCompilerOptions.ProjectFile;
152+
fromConfig.NoDependencyUpdate = newCompilerOptions.NoDependencyUpdate;
139153
}
140154
}

src/AXSharp.compiler/src/AXSharp.Compiler/AXSharpProject.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Third party licenses: https://github.com/ix-ax/axsharp/blob/master/notices.md
77

88
using System.Text;
9+
using System.Xml.Linq;
910
using AX.ST.Semantic;
1011
using AX.ST.Semantic.Model.Declarations;
1112
using AX.ST.Semantic.Model.Declarations.Types;
@@ -14,6 +15,7 @@
1415
using AX.Text;
1516
using AXSharp.Compiler.Core;
1617
using AXSharp.Compiler.Exceptions;
18+
using Microsoft.CodeAnalysis.Diagnostics;
1719
using Newtonsoft.Json;
1820
using Polly;
1921

@@ -42,16 +44,15 @@ public class AXSharpProject : IAXSharpProject
4244
public AXSharpProject(AxProject axProject, IEnumerable<Type> builderTypes, Type targetProjectType, ICompilerOptions? cliCompilerOptions = null)
4345
{
4446
AxProject = axProject;
45-
CompilerOptions = AXSharpConfig.UpdateAndGetIxConfig(axProject.ProjectFolder, cliCompilerOptions);
47+
CompilerOptions = AXSharpConfig.UpdateAndGetAXSharpConfig(axProject.ProjectFolder, cliCompilerOptions);
4648
OutputFolder = Path.GetFullPath(Path.Combine(AxProject.ProjectFolder, CompilerOptions.OutputProjectFolder));
4749
if (cliCompilerOptions != null) UseBaseSymbol = cliCompilerOptions.UseBase;
4850
BuilderTypes = builderTypes;
4951
TargetProject = Activator.CreateInstance(targetProjectType, this) as ITargetProject ?? throw new
5052
InvalidOperationException("Target project type must implement ITargetProject interface.");
5153
}
5254

53-
54-
55+
5556
/// <summary>
5657
/// Get AX project.
5758
/// </summary>
@@ -134,9 +135,12 @@ public void Generate()
134135
TargetProject.ProvisionProjectStructure();
135136
GenerateMetadata(compilation);
136137
TargetProject.GenerateResources();
138+
TargetProject.GenerateCompanionData();
137139
Log.Logger.Information($"Compilation of project '{AxProject.SrcFolder}' done.");
138140
}
139141

142+
143+
140144
/// <summary>
141145
/// Cleans all output files from the output directory
142146
/// </summary>
@@ -207,7 +211,8 @@ private IEnumerable<ISyntaxTree> GetReferences()
207211

208212
private void CompileProjectReferences(IEnumerable<IReference> referencedDependencies)
209213
{
210-
foreach (var ixProjectReference in AxProject.AXSharpReferences)
214+
TargetProject.InstallAXSharpDependencies(AxProject.AXSharpReferences);
215+
foreach (var ixProjectReference in AxProject.AXSharpReferences.OfType<AXSharpConfig>())
211216
{
212217

213218
if (compiled.Contains(ixProjectReference.AxProjectFolder))

src/AXSharp.compiler/src/AXSharp.Compiler/Apax.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public Apax()
6767
/// <param name="projectFile">Project file from which the ApaxFile object will be created.</param>
6868
/// <returns></returns>
6969
/// <exception cref="FileNotFoundException"></exception>
70-
public static Apax CreateApax(string projectFile)
70+
public static Apax CreateApaxDto(string projectFile)
7171
{
7272
try
7373
{
@@ -85,6 +85,27 @@ public static Apax CreateApax(string projectFile)
8585
}
8686
}
8787

88+
public static Apax TryCreateApaxDto(string projectFile)
89+
{
90+
try
91+
{
92+
if (!File.Exists(projectFile))
93+
return null;
94+
95+
var deserializer = new DeserializerBuilder()
96+
.WithNamingConvention(CamelCaseNamingConvention.Instance)
97+
.IgnoreUnmatchedProperties()
98+
.Build();
99+
100+
return deserializer.Deserialize<Apax>(File.ReadAllText(projectFile));
101+
}
102+
catch (FileNotFoundException)
103+
{
104+
throw new FileNotFoundException(
105+
"'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)");
106+
}
107+
}
108+
88109
/// <summary>
89110
/// Update version in an apax.yml file
90111
/// </summary>
@@ -95,7 +116,7 @@ public static void UpdateVersion(string apaxFile, string version)
95116
{
96117
try
97118
{
98-
var apax = CreateApax(apaxFile);
119+
var apax = CreateApaxDto(apaxFile);
99120
apax.Version = version;
100121

101122

src/AXSharp.compiler/src/AXSharp.Compiler/AxProject.cs

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using YamlDotNet.Serialization;
1010
using YamlDotNet.Serialization.NamingConventions;
1111
using System.IO;
12+
using System;
1213

1314
namespace AXSharp.Compiler;
1415

@@ -31,7 +32,7 @@ public AxProject(string axProjectFolder)
3132
ProjectFolder = axProjectFolder;
3233
ProjectFile = Path.Combine(ProjectFolder, "apax.yml");
3334
SrcFolder = Path.Combine(axProjectFolder, "src");
34-
ProjectInfo = Apax.CreateApax(ProjectFile);
35+
ProjectInfo = Apax.CreateApaxDto(ProjectFile);
3536
Sources = Directory.GetFiles(Path.Combine(ProjectFolder, "src"), "*.st", SearchOption.AllDirectories)
3637
.Select(p => new SourceFileText(p));
3738
}
@@ -51,7 +52,7 @@ public AxProject(string axProjectFolder, string[] sourceFiles)
5152
ProjectFolder = axProjectFolder;
5253
ProjectFile = Path.Combine(ProjectFolder, "apax.yml");
5354
SrcFolder = Path.Combine(axProjectFolder, "src");
54-
ProjectInfo = Apax.CreateApax(ProjectFile);
55+
ProjectInfo = Apax.CreateApaxDto(ProjectFile);
5556
Sources = sourceFiles.Select(p => new SourceFileText(p));
5657
}
5758

@@ -80,32 +81,90 @@ public AxProject(string axProjectFolder, string[] sourceFiles)
8081
/// </summary>
8182
public string SrcFolder { get; }
8283

84+
/// <summary>
85+
/// Contains list of near-by project in the directory structure (-2 levels up).
86+
/// </summary>
87+
private static List<NearByProjects> nearByProjects;
88+
89+
private class NearByProjects
90+
{
91+
public Apax Apax { get; set; }
92+
public FileInfo ApaxFile { get; set; }
93+
}
94+
95+
private class InstalledDependencies
96+
{
97+
public Apax Apax { get; set; }
98+
public CompanionInfo Companion { get; set; }
99+
100+
public FileInfo ApaxFile { get; set; }
101+
}
102+
83103
/// <summary>
84104
/// Gets paths of this project's references to other ix projects.
85105
/// </summary>
86-
public IEnumerable<AXSharpConfig> AXSharpReferences
106+
public IEnumerable<object> AXSharpReferences => GetProjectDependencies();
107+
108+
private IEnumerable<object> GetProjectDependencies()
87109
{
88-
get
110+
var dependencies = ProjectInfo.Dependencies ?? new Dictionary<string, string>();
111+
var installedDependencies =
112+
dependencies.Select(p => Path.Combine(ProjectFolder, ".apax", "packages",
113+
p.Key.Replace('/', Path.DirectorySeparatorChar)))
114+
.Select(p => new InstalledDependencies()
115+
{
116+
Apax = Apax.TryCreateApaxDto(Path.Combine(p, "apax.yml")),
117+
Companion = CompanionInfo.TryFromFile(Path.Combine(p, CompanionInfo.COMPANIONS_FILE_NAME)),
118+
ApaxFile = new FileInfo(Path.Combine(p, "apax.yml"))
119+
}).ToList();
120+
121+
122+
nearByProjects ??= Directory.EnumerateFiles(
123+
Path.GetFullPath(Path.Combine(this.ProjectFolder, "../../..")),
124+
"apax.yml", SearchOption.AllDirectories)
125+
.Select(p => new FileInfo(p))
126+
.Where(p => !p.Directory.FullName.Contains(".apax"))
127+
.Select(a => new NearByProjects() { Apax = Apax.TryCreateApaxDto(a.FullName), ApaxFile = a })
128+
.ToList();
129+
130+
var projectDependencies = new List<object>();
131+
132+
foreach (var dependency in dependencies)
89133
{
90-
var dependencies = ProjectInfo.Dependencies ?? new Dictionary<string, string>();
134+
var hasSuchProject =
135+
nearByProjects.FirstOrDefault(p => p.Apax.Name == dependency.Key && p.Apax.Version == dependency.Value);
136+
if (hasSuchProject != null)
137+
{
138+
var pathAXSharpConfig =
139+
Path.Combine(hasSuchProject.ApaxFile.Directory.FullName, AXSharpConfig.CONFIG_FILE_NAME);
140+
if (File.Exists(pathAXSharpConfig))
141+
{
142+
projectDependencies.Add((AXSharpConfig.RetrieveAXSharpConfig(pathAXSharpConfig)));
143+
}
144+
}
145+
}
91146

92-
var packagesDirectories =
93-
dependencies.Select(p => Path.Combine(ProjectFolder, ".apax", "packages", p.Key.Replace('/',Path.DirectorySeparatorChar)));
147+
foreach (var dependency in dependencies)
148+
{
149+
var dependencyWithCompanion = installedDependencies
150+
.FirstOrDefault(p => p.Apax != null && p.Apax.Name == dependency.Key && p.Apax.Version == dependency.Value);
94151

95-
96-
var retVal = packagesDirectories
97-
.Where(p => Directory.Exists(p))
98-
.Select(p => new DirectoryInfo(p))
99-
.Select(p => Directory.EnumerateFiles(p.LinkTarget ?? p.FullName, AXSharpConfig.CONFIG_FILE_NAME, SearchOption.TopDirectoryOnly))
100-
.SelectMany(p => p).Select(c => AXSharpConfig.RetrieveIxConfig(c));
101152

102-
if (retVal.Count() == 0)
153+
if (dependencyWithCompanion?.Companion != null)
103154
{
104-
Log.Logger.Information("Retrieving possible project references from .apax packages did not produce results. " +
105-
"If you have referenced AX# projects, the packages must be previously installed by 'apax install'");
155+
var packageFile =
156+
Path.Combine(dependencyWithCompanion.ApaxFile.Directory.FullName, "package.json");
157+
if(File.Exists(packageFile))
158+
projectDependencies.Add(dependencyWithCompanion.Companion);
106159
}
160+
}
107161

108-
return retVal;
162+
if (!projectDependencies.Any())
163+
{
164+
Log.Logger.Information("Retrieving possible project references from .apax packages did not produce results. " +
165+
"If you have referenced AX# projects, the packages must be previously installed by 'apax install'");
109166
}
167+
168+
return projectDependencies;
110169
}
111170
}

0 commit comments

Comments
 (0)