Datei: NDOEnhancer/NDOEnhancer/EnhancerMain.cs

Last Commit (cf66d4f)
1 //
2 // Copyright (c) 2002-2024 Mirko Matytschak
3 // (www.netdataobjects.de)
4 //
5 // Author: Mirko Matytschak
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8 // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
10 // Software, and to permit persons to whom the Software is furnished to do so, subject to the following
11 // conditions:
12
13 // The above copyright notice and this permission notice shall be included in all copies or substantial portions
14 // of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
17 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21
22
23 using System;
24 using System.IO;
25 using System.Reflection;
26 using System.Linq;
27 //using NDO.Provider;
28 using System.Globalization;
29 using Microsoft.Extensions.DependencyInjection;
30 using Microsoft.Extensions.Hosting;
31 using Microsoft.Extensions.Logging;
32 using NDO.ProviderFactory;
33 using NDOInterfaces;
34 //using NDO.SqlPersistenceHandling;
35
36 namespace NDOEnhancer
37 {
38 ····[Serializable]
39 ····public class EnhancerMain
40 ····{
41 ····
42 ········static bool verboseMode;
43 ········ProjectDescription projectDescription;
44 ········private IServiceProvider serviceProvider;
45
46 ········public static int Main( string[] args )
47 ········{
48 ············int result = 0;
49 ············// Make the culture invariant, otherwise .NET tries to load .resources assemblies.
50 ············System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
51 ············System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
52
53 ············try
54 ············{
55 ················if (args.Length < 2)
56 ····················throw new Exception( "usage: NDOEnhancer <file_name> <target_framework>\n" );
57
58 ················string ndoProjFilePath = args[0];
59 ················string targetFramework = args[1];
60
61 #if DEBUG
62 ····················Console.WriteLine( "Domain base directory is: " + AppDomain.CurrentDomain.BaseDirectory );
63 ····················Console.WriteLine( "Running as " + ( IntPtr.Size * 8 ) + " bit app." );
64 #endif
65
66 ····················new EnhancerMain().InternalStart( ndoProjFilePath, targetFramework );
67 ············}
68 ············catch (Exception ex)
69 ············{
70 ················Console.Error.WriteLine( "Error: " + ex.ToString() );
71 ················result = -1;
72 ············}
73 ············return result;
74 ········}
75
76 ········void Build( Action<IServiceCollection> configure = null )
77 ········{
78 ············var builder = Host.CreateDefaultBuilder();
79 ············builder.ConfigureServices( services =>
80 ············{
81 ················services.AddLogging( b =>
82 ················{
83 ····················b.ClearProviders();
84 ····················b.AddConsole();
85 ················} );
86
87 ················services.AddSingleton<INDOProviderFactory, NDOProviderFactory>();
88 ················services.AddSingleton<IProviderPathFinder, ProviderPathFinder>();
89 ················if (configure != null)
90 ····················configure( services );
91 ············} );
92
93 ············var host = builder.Build();
94 ············this.serviceProvider = host.Services;
95 ········}
96
97 ········void CopyFile(string source, string dest)
98 ········{
99 ············if (verboseMode)
100 ················Console.WriteLine("Copying: " + source + "->" + dest);
101
102 ············File.Copy(source, dest, true);
103 ········}
104
105
106 ········public void InternalStart(string ndoProjFilePath, string targetFramework)
107 ········{
108 ············Console.WriteLine("Runtime: " + typeof(string).Assembly.FullName);············
109 ············ConfigurationOptions options;
110
111 ············if (!File.Exists(ndoProjFilePath))
112 ············{
113 ················throw new Exception("Can't find file '" + ndoProjFilePath + "'");
114 ············}
115
116 #if DEBUG
117 ············Console.WriteLine( $"Loading Project Description from {ndoProjFilePath}..." );
118 #endif
119 ············this.projectDescription = new ProjectDescription( ndoProjFilePath, targetFramework );
120
121 ············AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
122 ············//NDOContainer.Instance.RegisterType<IProviderPathFinder,ProviderPathFinder>();
123 ············//// This is needed as parameter for ProviderPathFinder
124 ············//NDOContainer.Instance.RegisterInstance( this.projectDescription );
125
126 ············options = projectDescription.ConfigurationOptions;
127
128 ············if (!options.EnableAddIn)
129 ················return;
130
131 #if DEBUG
132 ············Console.WriteLine("Loading Project Description ready.");
133
134 ············verboseMode = true;
135 #else
136 ············verboseMode = options.VerboseMode;
137
138 ············// In Debug Mode the base directory is printed in the Main method
139 ············if (verboseMode)
140 ············{
141 ················Console.WriteLine( "Domain base directory is: " + AppDomain.CurrentDomain.BaseDirectory );
142 ············}
143 #endif
144 ············// We should consider using the following code to determine the version:
145 ············//public static string? GetInformationalVersion() =>
146 ············//····Assembly
147 ············//········.GetEntryAssembly()
148 ············//········?.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
149 ············//········?.InformationalVersion;
150 ············// The PatchNdoVersion tool is able to enter the informational version.
151
152
153 ············Console.WriteLine( EnhDate.String, "NDO Enhancer", new AssemblyName( GetType().Assembly.FullName ).Version.ToString() );
 
 
154
155 ············if (options.EnableEnhancer)
156 ················this.projectDescription.References.Add(projectDescription.AssemblyName, new NDOReference(projectDescription.AssemblyName, projectDescription.BinFile, true));
157
158 ············MessageAdapter messages = new MessageAdapter();
159
160 ············var basePath = Path.GetDirectoryName( this.projectDescription.BinFile );
161 ············var loadContext = new ManagedLoadContext( basePath, verboseMode );
162 ············using (loadContext.EnterContextualReflection())
163 ············{
164 ················new Enhancer( this.projectDescription, messages, NDOProviderFactory.Instance ).DoIt();
165 ················loadContext.Unload();
166 ············}
167
168 ············if (options.EnableEnhancer)
169 ············{
170 ················string tempDir = Path.Combine(this.projectDescription.ObjPath, "ndotemp");
171 ················string enhObjFile = Path.Combine(tempDir, Path.GetFileName(this.projectDescription.BinFile));
172 ················string enhPdbFile = Path.ChangeExtension(enhObjFile, ".pdb");
173 ················string binPdbFile = Path.ChangeExtension(this.projectDescription.BinFile, ".pdb");
174 ················string objFile = Path.Combine(this.projectDescription.ObjPath, Path.GetFileName(this.projectDescription.BinFile));
175 ················string objPdbFile = Path.Combine(this.projectDescription.ObjPath, Path.GetFileName(binPdbFile));
176 ················bool objPathDifferent = String.Compare(objFile, this.projectDescription.BinFile, true) != 0;
177 ················if (File.Exists( enhObjFile ))
178 ················{
179 ····················if (objPathDifferent)
180 ························CopyFile( enhObjFile, objFile );
181
182 ····················if (File.Exists( enhPdbFile ))
183 ····················{
184 ························CopyFile( enhPdbFile, binPdbFile );
185
186 ························if (objPathDifferent)
187 ····························CopyFile( enhPdbFile, objPdbFile );
188 ························try
189 ························{
190 ····························File.Delete( enhPdbFile );
191 ························}
192 ························catch (Exception ex)
193 ························{
194 ····························if (verboseMode)
195 ································Console.WriteLine( "Warning: Ignored Exception: " + ex.ToString() );
196 ························}
197 ····················}
198 ················}
199
200 ················Console.WriteLine( "Enhancer ready" );
201 ············}
202 ········}
203
204 ········string GetPackageLibPath( string assyName )
205 ········{
206 ············if (this.projectDescription == null)
207 ················throw new Exception( "Project Description is not defined" );
208
209 ············var packageName = assyName.ToLowerInvariant();
210 ············if (assyName.Equals( "NDO", StringComparison.OrdinalIgnoreCase ))
211 ················packageName = "ndo.dll";
212
213 ············var path = new NugetProps(this.projectDescription).DefaultNugetPackageFolder;
214 ············if (path == null)
215 ················return null;
216
217 ············return Path.Combine( path, new ProjectAssets(this.projectDescription).GetPackageDir( packageName ) );
218 ········}
219
220 ········/// <summary>
221 ········/// This is called, if an assembly can't be found in the bin directory
222 ········/// </summary>
223 ········/// <param name="sender"></param>
224 ········/// <param name="args"></param>
225 ········/// <returns></returns>
226 ········Assembly OnAssemblyResolve( object sender, ResolveEventArgs args )
227 ········{
228 ············if (verboseMode)
229 ················Console.WriteLine( $"AssemblyResolve: {args?.Name}" );
230
231 ············var assyName = args?.Name?.Split(',').FirstOrDefault();
232 ············if (assyName == null)
233 ················return null;
234
235 ············string path = GetPackageLibPath( assyName );
236
237 ············if (path == null)
238 ················return null;
239
240 ············Console.WriteLine( "Location: " + path );
241 ············if (File.Exists( path ))
242 ············{
243 ················return Assembly.LoadFrom( path );
244 ············}
245
246 ············return null;
247 ········}
248
249
250 ········public EnhancerMain()
251 ········{
252 ········}
253 ····}
254 }
255
New Commit (7e08240)
1 //
2 // Copyright (c) 2002-2024 Mirko Matytschak
3 // (www.netdataobjects.de)
4 //
5 // Author: Mirko Matytschak
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8 // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
10 // Software, and to permit persons to whom the Software is furnished to do so, subject to the following
11 // conditions:
12
13 // The above copyright notice and this permission notice shall be included in all copies or substantial portions
14 // of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
17 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21
22
23 using System;
24 using System.IO;
25 using System.Reflection;
26 using System.Linq;
27 //using NDO.Provider;
28 using System.Globalization;
29 using Microsoft.Extensions.DependencyInjection;
30 using Microsoft.Extensions.Hosting;
31 using Microsoft.Extensions.Logging;
32 using NDO.ProviderFactory;
33 using NDOInterfaces;
34 //using NDO.SqlPersistenceHandling;
35
36 namespace NDOEnhancer
37 {
38 ····[Serializable]
39 ····public class EnhancerMain
40 ····{
41 ····
42 ········static bool verboseMode;
43 ········ProjectDescription projectDescription;
44 ········private IServiceProvider serviceProvider;
45
46 ········public static int Main( string[] args )
47 ········{
48 ············int result = 0;
49 ············// Make the culture invariant, otherwise .NET tries to load .resources assemblies.
50 ············System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
51 ············System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
52
53 ············try
54 ············{
55 ················if (args.Length < 2)
56 ····················throw new Exception( "usage: NDOEnhancer <file_name> <target_framework>\n" );
57
58 ················string ndoProjFilePath = args[0];
59 ················string targetFramework = args[1];
60
61 #if DEBUG
62 ····················Console.WriteLine( "Domain base directory is: " + AppDomain.CurrentDomain.BaseDirectory );
63 ····················Console.WriteLine( "Running as " + ( IntPtr.Size * 8 ) + " bit app." );
64 #endif
65
66 ····················new EnhancerMain().InternalStart( ndoProjFilePath, targetFramework );
67 ············}
68 ············catch (Exception ex)
69 ············{
70 ················Console.Error.WriteLine( "Error: " + ex.ToString() );
71 ················result = -1;
72 ············}
73 ············return result;
74 ········}
75
76 ········void Build( Action<IServiceCollection> configure = null )
77 ········{
78 ············var builder = Host.CreateDefaultBuilder();
79 ············builder.ConfigureServices( services =>
80 ············{
81 ················services.AddLogging( b =>
82 ················{
83 ····················b.ClearProviders();
84 ····················b.AddConsole();
85 ················} );
86
87 ················services.AddSingleton<INDOProviderFactory, NDOProviderFactory>();
88 ················services.AddSingleton<IProviderPathFinder, ProviderPathFinder>();
89 ················if (configure != null)
90 ····················configure( services );
91 ············} );
92
93 ············var host = builder.Build();
94 ············this.serviceProvider = host.Services;
95 ········}
96
97 ········void CopyFile(string source, string dest)
98 ········{
99 ············if (verboseMode)
100 ················Console.WriteLine("Copying: " + source + "->" + dest);
101
102 ············File.Copy(source, dest, true);
103 ········}
104
105
106 ········public void InternalStart(string ndoProjFilePath, string targetFramework)
107 ········{
 
108 ············ConfigurationOptions options;
109
110 ············if (!File.Exists(ndoProjFilePath))
111 ············{
112 ················throw new Exception("Can't find file '" + ndoProjFilePath + "'");
113 ············}
114
115 #if DEBUG
116 ············Console.WriteLine( $"Loading Project Description from {ndoProjFilePath}..." );
117 #endif
118 ············this.projectDescription = new ProjectDescription( ndoProjFilePath, targetFramework );
119
120 ············AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
121 ············//NDOContainer.Instance.RegisterType<IProviderPathFinder,ProviderPathFinder>();
122 ············//// This is needed as parameter for ProviderPathFinder
123 ············//NDOContainer.Instance.RegisterInstance( this.projectDescription );
124
125 ············options = projectDescription.ConfigurationOptions;
126
127 ············if (!options.EnableAddIn)
128 ················return;
129
130 #if DEBUG
131 ············Console.WriteLine("Loading Project Description ready.");
132
133 ············verboseMode = true;
134 #else
135 ············verboseMode = options.VerboseMode;
136
137 ············// In Debug Mode the base directory is printed in the Main method
138 ············if (verboseMode)
139 ············{
140 ················Console.WriteLine( "Domain base directory is: " + AppDomain.CurrentDomain.BaseDirectory );
141 ············}
142 #endif
143 ············// We should consider using the following code to determine the version:
144 ············//public static string? GetInformationalVersion() =>
145 ············//····Assembly
146 ············//········.GetEntryAssembly()
147 ············//········?.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
148 ············//········?.InformationalVersion;
149 ············// The PatchNdoVersion tool is able to enter the informational version.
150
151
152 ············Console.WriteLine( EnhDate.String, "NDO Enhancer", new AssemblyName( GetType().Assembly.FullName ).Version.ToString() );
153 ············if (verboseMode)
154 ················Console.WriteLine( $"Parameters: {ndoProjFilePath}, {targetFramework}" );
155
156 ············if (options.EnableEnhancer)
157 ················this.projectDescription.References.Add(projectDescription.AssemblyName, new NDOReference(projectDescription.AssemblyName, projectDescription.BinFile, true));
158
159 ············MessageAdapter messages = new MessageAdapter();
160
161 ············var basePath = Path.GetDirectoryName( this.projectDescription.BinFile );
162 ············var loadContext = new ManagedLoadContext( basePath, verboseMode );
163 ············using (loadContext.EnterContextualReflection())
164 ············{
165 ················new Enhancer( this.projectDescription, messages, NDOProviderFactory.Instance ).DoIt();
166 ················loadContext.Unload();
167 ············}
168
169 ············if (options.EnableEnhancer)
170 ············{
171 ················string tempDir = Path.Combine(this.projectDescription.ObjPath, "ndotemp");
172 ················string enhObjFile = Path.Combine(tempDir, Path.GetFileName(this.projectDescription.BinFile));
173 ················string enhPdbFile = Path.ChangeExtension(enhObjFile, ".pdb");
174 ················string binPdbFile = Path.ChangeExtension(this.projectDescription.BinFile, ".pdb");
175 ················string objFile = Path.Combine(this.projectDescription.ObjPath, Path.GetFileName(this.projectDescription.BinFile));
176 ················string objPdbFile = Path.Combine(this.projectDescription.ObjPath, Path.GetFileName(binPdbFile));
177 ················bool objPathDifferent = String.Compare(objFile, this.projectDescription.BinFile, true) != 0;
178 ················if (File.Exists( enhObjFile ))
179 ················{
180 ····················if (objPathDifferent)
181 ························CopyFile( enhObjFile, objFile );
182
183 ····················if (File.Exists( enhPdbFile ))
184 ····················{
185 ························CopyFile( enhPdbFile, binPdbFile );
186
187 ························if (objPathDifferent)
188 ····························CopyFile( enhPdbFile, objPdbFile );
189 ························try
190 ························{
191 ····························File.Delete( enhPdbFile );
192 ························}
193 ························catch (Exception ex)
194 ························{
195 ····························if (verboseMode)
196 ································Console.WriteLine( "Warning: Ignored Exception: " + ex.ToString() );
197 ························}
198 ····················}
199 ················}
200
201 ················Console.WriteLine( "Enhancer ready" );
202 ············}
203 ········}
204
205 ········string GetPackageLibPath( string assyName )
206 ········{
207 ············if (this.projectDescription == null)
208 ················throw new Exception( "Project Description is not defined" );
209
210 ············var packageName = assyName.ToLowerInvariant();
211 ············if (assyName.Equals( "NDO", StringComparison.OrdinalIgnoreCase ))
212 ················packageName = "ndo.dll";
213
214 ············var path = new NugetProps(this.projectDescription).DefaultNugetPackageFolder;
215 ············if (path == null)
216 ················return null;
217
218 ············return Path.Combine( path, new ProjectAssets(this.projectDescription).GetPackageDir( packageName ) );
219 ········}
220
221 ········/// <summary>
222 ········/// This is called, if an assembly can't be found in the bin directory
223 ········/// </summary>
224 ········/// <param name="sender"></param>
225 ········/// <param name="args"></param>
226 ········/// <returns></returns>
227 ········Assembly OnAssemblyResolve( object sender, ResolveEventArgs args )
228 ········{
229 ············if (verboseMode)
230 ················Console.WriteLine( $"AssemblyResolve: {args?.Name}" );
231
232 ············var assyName = args?.Name?.Split(',').FirstOrDefault();
233 ············if (assyName == null)
234 ················return null;
235
236 ············string path = GetPackageLibPath( assyName );
237
238 ············if (path == null)
239 ················return null;
240
241 ············Console.WriteLine( "Location: " + path );
242 ············if (File.Exists( path ))
243 ············{
244 ················return Assembly.LoadFrom( path );
245 ············}
246
247 ············return null;
248 ········}
249
250
251 ········public EnhancerMain()
252 ········{
253 ········}
254 ····}
255 }
256