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 |