-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathGenerateCommand.cs
194 lines (159 loc) · 7.99 KB
/
GenerateCommand.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using GirLoader;
using GirLoader.PlatformSupport;
using Repository = GirLoader.Output.Repository;
namespace GirTool;
public partial class GenerateCommand : Command
{
private void Execute(string[] input, string output, string? searchPathLinux, string? searchPathMacos, string? searchPathWindows, bool disableAsync, LogLevel logLevel, InvocationContext invocationContext)
{
try
{
Configuration.SetupLogLevel(logLevel);
var (allNamespaces, generatedNamespaces) = GetNamespaces(
searchPathLinux, searchPathMacos, searchPathWindows, disableAsync, input, invocationContext);
if (disableAsync)
{
foreach (var @namespace in allNamespaces)
PlatformGenerator.Fixup(@namespace);
foreach (var @namespace in generatedNamespaces)
PlatformGenerator.Generate(@namespace, output);
}
else
{
Parallel.ForEach(allNamespaces, PlatformGenerator.Fixup);
Parallel.ForEach(generatedNamespaces, x => PlatformGenerator.Generate(x, output));
}
Log.Information("Done");
}
catch (Exception ex)
{
Log.Exception(ex);
Log.Error("An error occurred while writing files. Please save a copy of your log output and open an issue at: https://github.com/gircore/gir.core/issues/new");
invocationContext.ExitCode = 1;
}
}
private static (IEnumerable<Namespace>, IEnumerable<Namespace>) GetNamespaces(string? searchPathLinux, string? searchPathMacos, string? searchPathWindows, bool disableAsync, string[] input, InvocationContext invocationContext)
{
try
{
(var linuxRepositories, var macosRepositories, var windowsRepositories) = LoadRepositories(searchPathLinux, searchPathMacos, searchPathWindows, disableAsync, input);
var linuxNamespaceNames = linuxRepositories.Repositories.Select(x => GetNamespaceName(x.Namespace));
var macosNamespaceNames = macosRepositories.Repositories.Select(x => GetNamespaceName(x.Namespace));
var windowsNamespaceNames = windowsRepositories.Repositories.Select(x => GetNamespaceName(x.Namespace));
var namespacesNames = linuxNamespaceNames
.Union(macosNamespaceNames)
.Union(windowsNamespaceNames)
.Distinct();
// We only generate code for namespaces that came from the set of inputs
var generatedNamespaceNames = linuxRepositories.InputNamespaceNames
.Concat(macosRepositories.InputNamespaceNames)
.Concat(windowsRepositories.InputNamespaceNames)
.ToHashSet();
var allNamespaces = new List<Namespace>();
var generatedNamespaces = new List<Namespace>();
foreach (var namespaceName in namespacesNames)
{
var linuxNamespace = linuxRepositories.Repositories.FirstOrDefault(x => GetNamespaceName(x.Namespace) == namespaceName)?.Namespace;
var macosNamespace = macosRepositories.Repositories.FirstOrDefault(x => GetNamespaceName(x.Namespace) == namespaceName)?.Namespace;
var windowsNamespace = windowsRepositories.Repositories.FirstOrDefault(x => GetNamespaceName(x.Namespace) == namespaceName)?.Namespace;
if (linuxNamespace is null)
Log.Information($"There is no {namespaceName} repository for linux");
if (macosNamespace is null)
Log.Information($"There is no {namespaceName} repository for macos");
if (windowsNamespace is null)
Log.Information($"There is no {namespaceName} repository for windows");
var @namespace = new Namespace(new PlatformHandler(linuxNamespace, macosNamespace, windowsNamespace));
allNamespaces.Add(@namespace);
if (generatedNamespaceNames.Contains(namespaceName))
{
generatedNamespaces.Add(@namespace);
}
}
return (allNamespaces, generatedNamespaces);
}
catch (FileNotFoundException fileNotFoundException)
{
Log.Exception(fileNotFoundException);
Log.Error("Please make sure that the given input files are readable.");
invocationContext.ExitCode = 1;
}
return (Enumerable.Empty<Namespace>(), Enumerable.Empty<Namespace>());
}
private static (DeserializedInput, DeserializedInput, DeserializedInput) LoadRepositories(string? searchPathLinux, string? searchPathMacos, string? searchPathWindows, bool disableAsync, string[] input)
{
if (searchPathLinux is null && searchPathMacos is null && searchPathWindows is null)
throw new Exception("Please define at least one search parth for a specific platform");
DeserializedInput? linuxRepositories = null;
DeserializedInput? macosRepositories = null;
DeserializedInput? windowsRepositories = null;
void SetLinuxRepositories() => linuxRepositories = DeserializeInput("linux", searchPathLinux, input);
void SetMacosRepositories() => macosRepositories = DeserializeInput("macos", searchPathMacos, input);
void SetWindowsRepositories() => windowsRepositories = DeserializeInput("windows", searchPathWindows, input);
if (disableAsync)
{
SetLinuxRepositories();
SetMacosRepositories();
SetWindowsRepositories();
}
else
{
Parallel.Invoke(
SetLinuxRepositories,
SetMacosRepositories,
SetWindowsRepositories
);
}
return (linuxRepositories!, macosRepositories!, windowsRepositories!);
}
private static DeserializedInput DeserializeInput(string platformName, string? searchPath, string[] input)
{
var repositoryResolver = new RepositoryResolverFactory(
platformName, searchPath, typeof(GenerateCommand).Assembly).Create();
var inputRepositories = input
.Select(fileName => repositoryResolver.ResolveRepository(fileName))
.OfType<GirLoader.Input.Repository>()
.ToList();
// Get the namespaces corresponding to the input gir files.
// There may be more namespaces included in the output if they are resolved from includes.
var inputNamespaces = inputRepositories
.Select(repository => repository.Namespace == null ? "" : GetNamespaceName(repository.Namespace))
.ToList();
var includeResolver = new IncludeResolver(repositoryResolver);
var loader = new GirLoader.Loader(includeResolver.ResolveInclude);
var outputRepositories = loader.Load(inputRepositories).ToList();
return new DeserializedInput(outputRepositories, inputNamespaces);
}
private static string GetNamespaceName(GirModel.Namespace ns)
{
return $"{ns.Name}-{ns.Version}";
}
private static string GetNamespaceName(GirLoader.Input.Namespace ns)
{
return $"{ns.Name}-{ns.Version}";
}
private class DeserializedInput
{
public DeserializedInput(List<Repository> repositories, List<string> inputNamespaceNames)
{
Repositories = repositories;
InputNamespaceNames = inputNamespaceNames;
}
public static DeserializedInput Empty() =>
new DeserializedInput(new List<Repository>(), new List<string>());
/// <summary>
/// All resolved output repositories
/// </summary>
public List<Repository> Repositories { get; }
/// <summary>
/// Namespace names corresponding to the input gir files
/// </summary>
public List<string> InputNamespaceNames { get; }
}
}