Repository navigation
Expand file tree
/
Copy pathProgram.cs
More file actions
161 lines (138 loc) · 6.08 KB
/
Copy pathProgram.cs
File metadata and controls
161 lines (138 loc) · 6.08 KB
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
// Copyright DotNet API Diff Project Contributors - SPDX Identifier: MIT
using DotNetApiDiff.Commands;
using DotNetApiDiff.ExitCodes;
using DotNetApiDiff.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Spectre.Console.Cli;
namespace DotNetApiDiff;
/// <summary>
/// Main entry point for the DotNet API Diff tool
/// </summary>
public class Program
{
/// <summary>
/// Application entry point
/// </summary>
/// <param name="args">Command line arguments</param>
/// <returns>Exit code (0 for success, non-zero for failure)</returns>
public static int Main(string[] args)
{
// Set up dependency injection
var services = new ServiceCollection();
ConfigureServices(services);
var serviceProvider = services.BuildServiceProvider();
var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
var exceptionHandler = serviceProvider.GetRequiredService<IGlobalExceptionHandler>();
// Set up global exception handling
exceptionHandler.SetupGlobalExceptionHandling();
try
{
// Log application start with version information
var version = typeof(Program).Assembly.GetName().Version;
var buildTime = GetBuildTime();
logger.LogInformation(
"DotNet API Diff Tool v{Version} started at {Time} (Build: {BuildTime})",
version,
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
buildTime);
// Log environment information
logger.LogDebug(
"Environment: OS={OS}, Framework={Framework}, ProcessorCount={ProcessorCount}",
Environment.OSVersion,
Environment.Version,
Environment.ProcessorCount);
// Get the exit code manager
var exitCodeManager = serviceProvider.GetRequiredService<IExitCodeManager>();
// Configure Spectre.Console command app
var app = new CommandApp(new TypeRegistrar(serviceProvider));
app.Configure(config =>
{
config.SetApplicationName("dotnet-api-diff");
config.PropagateExceptions();
config.AddExample(new[] { "compare", "source.dll", "target.dll" });
config.AddExample(new[] { "compare", "source.dll", "target.dll", "--output", "json" });
config.AddExample(new[] { "compare", "source.dll", "target.dll", "--config", "config.json" });
config.SetExceptionHandler(ex =>
{
// Use our centralized exception handler
return exceptionHandler.HandleException(ex, "Command execution");
});
// Register the compare command
config.AddCommand<CompareCommand>("compare")
.WithDescription("Compare two .NET assemblies and report API differences")
.WithExample(new[] { "compare", "source.dll", "target.dll" })
.WithExample(new[] { "compare", "source.dll", "target.dll", "--output", "json" })
.WithExample(new[] { "compare", "source.dll", "target.dll", "--filter", "System.Collections" });
});
// Run the command and return the exit code
return app.Run(args);
}
catch (Exception ex)
{
// Use our centralized exception handler for any unhandled exceptions
return exceptionHandler.HandleException(ex, "Application startup");
}
}
/// <summary>
/// Gets the build time of the assembly from the file timestamp
/// </summary>
/// <returns>Build time as a string</returns>
private static string GetBuildTime()
{
try
{
var assembly = typeof(Program).Assembly;
var assemblyLocation = assembly.Location;
if (!string.IsNullOrEmpty(assemblyLocation))
{
var buildTime = File.GetLastWriteTime(assemblyLocation);
return buildTime.ToString("yyyy-MM-dd HH:mm:ss");
}
}
catch (Exception)
{
// Ignore errors getting build time
}
return "Unknown";
}
/// <summary>
/// Configures dependency injection services for the root container
/// Only includes services needed for command instantiation
/// </summary>
/// <param name="services">Service collection to configure</param>
public static void ConfigureServices(IServiceCollection services)
{
// Configure logging with structured logging support
services.AddLogging(builder =>
{
builder.AddConsole(options =>
{
// Use ConsoleFormatterOptions instead of deprecated ConsoleLoggerOptions
options.FormatterName = "simple";
});
// Configure the simple console formatter
builder.AddSimpleConsole(options =>
{
options.IncludeScopes = true;
options.TimestampFormat = "[yyyy-MM-dd HH:mm:ss] ";
options.SingleLine = false;
options.UseUtcTimestamp = false;
});
// Set minimum level based on environment variable if present
var logLevelEnv = Environment.GetEnvironmentVariable("DOTNET_API_DIFF_LOG_LEVEL");
var logLevel = LogLevel.Information; // Default level
if (!string.IsNullOrEmpty(logLevelEnv) &&
Enum.TryParse<LogLevel>(logLevelEnv, true, out var parsedLevel))
{
logLevel = parsedLevel;
}
builder.SetMinimumLevel(logLevel);
});
// Register only services needed for command instantiation
services.AddSingleton<IExitCodeManager, ExitCodeManager>();
services.AddSingleton<IGlobalExceptionHandler, GlobalExceptionHandler>();
// Note: Business logic services (AssemblyLoader, ApiExtractor, etc.) will be registered
// in the command-specific container to avoid configuration timing issues
}
}