-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
352 lines (287 loc) · 11.4 KB
/
Copy pathProgram.cs
File metadata and controls
352 lines (287 loc) · 11.4 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
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
using System.Text;
using DotMake.CommandLine;
using SenfCli.Handlers;
namespace SenfCli;
public static class Program
{
public static async Task Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
Logger.EnableFromEnvironment();
Logger.Info("Senf CLI started.");
var invocation = args.Length == 0 ? "senf" : $"senf {string.Join(" ", args)}";
Logger.Info($"Invocation: {invocation}");
Logger.Info($"Working directory: {Directory.GetCurrentDirectory()}");
if (Logger.IsActive)
ConsoleHelper.WriteWarning("SENF_LOG is enabled. Sensitive data will be written to .senf/logs/senf-*.log. Only use for debugging");
try
{
await Cli.RunAsync<RootCommand>(args);
}
catch (Exception e)
{
ConsoleHelper.WriteError($"An error occurred while executing your command: {e.Message}", e);
}
finally
{
Logger.Info("Senf CLI finished.");
}
}
}
[CliCommand(Description = "Senf - Environment file management CLI")]
public class RootCommand
{
public void Run()
=> ConsoleHelper.WriteInfo("Use 'senf --help' to see available commands");
}
[CliCommand(Description = "Initialize a new project", Name = "init", Parent = typeof(RootCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class InitCommand
{
[CliArgument(Description = "Path to the .env file")]
public string EnvPath { get; set; } = null!;
[CliArgument(Description = "Project name")]
public string ProjectName { get; set; } = null!;
[CliOption(Description = "Optional profile to use (uses default if not specified)")]
public string? UserProfile { get; set; }
public async Task RunAsync()
=> await InitCommandHandler.Init(EnvPath, ProjectName, UserProfile);
}
[CliCommand(Description = "Push current env file to the server", Name = "push", Parent = typeof(RootCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class PushCommand
{
public async Task RunAsync()
=> await SyncCommandHandler.Push();
}
[CliCommand(Description = "Pull env file from the server", Name = "pull", Parent = typeof(RootCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class PullCommand
{
public async Task RunAsync()
=> await SyncCommandHandler.Pull();
}
[CliCommand(Description = "Interactively reconcile local and remote env files", Name = "reconcile",
Parent = typeof(RootCommand), ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class ReconcileCommand
{
public async Task RunAsync()
=> await SyncCommandHandler.Reconcile();
}
[CliCommand(Description = "Manage authentication profiles", Name = "profile", Parent = typeof(RootCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class ProfileCommand
{
public void Run()
=> ConsoleHelper.WriteInfo("Use 'senf profile --help' to see available subcommands");
}
[CliCommand(Description = "Create or update a profile", Name = "set", Parent = typeof(ProfileCommand))]
public class ProfileSetCommand
{
[CliArgument(Description = "Profile name")]
public string Name { get; set; } = null!;
[CliOption(Description = "SSH username")]
public string? Username { get; set; }
[CliOption(Description = "Path to SSH private key")]
public string? SshKey { get; set; }
[CliOption(Description = "API URL for the backend")]
public string? ApiUrl { get; set; }
[CliOption(Description = "Set as default profile")]
public bool Default { get; set; }
public async Task RunAsync()
=> await ProfileCommandHandler.CreateOrUpdateProfile(Name, Username, SshKey, ApiUrl, Default);
}
[CliCommand(Description = "List all profiles", Name = "list", Parent = typeof(ProfileCommand))]
public class ProfileListCommand
{
public void Run()
=> ProfileCommandHandler.ListProfiles();
}
[CliCommand(Description = "Delete a profile", Name = "delete", Parent = typeof(ProfileCommand))]
public class ProfileDeleteCommand
{
[CliArgument(Description = "Profile name to delete")]
public string Name { get; set; } = null!;
public void Run()
=> ProfileCommandHandler.DeleteProfile(Name);
}
[CliCommand(Description = "Set default profile", Name = "default", Parent = typeof(ProfileCommand))]
public class ProfileDefaultCommand
{
[CliArgument(Description = "Profile name to set as default")]
public string Name { get; set; } = null!;
public void Run()
=> ProfileCommandHandler.SetDefaultProfile(Name);
}
[CliCommand(Description = "Manage project settings", Name = "project", Parent = typeof(RootCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class ProjectCommand
{
public void Run()
=> ConsoleHelper.WriteInfo("Use 'senf project --help' to see available subcommands");
}
[CliCommand(Description = "Set profile for current project", Name = "set-profile", Parent = typeof(ProjectCommand))]
public class ProjectSetProfileCommand
{
[CliArgument(Description = "Profile name (or use --clear to unset)", Required = false)]
public string? Name { get; set; }
[CliOption(Description = "Clear profile (use default)")]
public bool Clear { get; set; }
public void Run()
=> ProjectCommandHandler.SetProjectProfile(Clear ? null : Name);
}
[CliCommand(Description = "Manage SSH keys on the server", Name = "key", Parent = typeof(RootCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class KeyCommand
{
public void Run()
=> ConsoleHelper.WriteInfo("Use 'senf key --help' to see available subcommands");
}
[CliCommand(Description = "List all SSH keys", Name = "list", Parent = typeof(KeyCommand))]
public class KeyListCommand
{
[CliOption(Description = "Profile to use (defaults to default profile)", Required = false)]
public string? Profile { get; set; }
public async Task RunAsync()
=> await KeyCommandHandler.ListSshKeys(Profile);
}
[CliCommand(Description = "Add an SSH public key", Name = "add", Parent = typeof(KeyCommand))]
public class KeyAddCommand
{
[CliArgument(Description = "Key name")]
public string Name { get; set; } = null!;
[CliArgument(Description = "Public key content (read from stdin if not provided)", Required = false)]
public string? PublicKey { get; set; }
[CliOption(Description = "Profile to use (defaults to default profile)", Required = false)]
public string? Profile { get; set; }
public async Task RunAsync()
{
string publicKey;
if (!string.IsNullOrEmpty(PublicKey))
publicKey = PublicKey;
else
publicKey = await Console.In.ReadToEndAsync();
publicKey = publicKey?.Trim() ?? string.Empty;
await KeyCommandHandler.AddSshKey(publicKey, Name, Profile);
}
}
[CliCommand(Description = "Delete an SSH key by ID", Name = "delete", Parent = typeof(KeyCommand))]
public class KeyDeleteCommand
{
[CliArgument(Description = "Key ID to delete")]
public int KeyId { get; set; }
[CliOption(Description = "Profile to use (defaults to default profile)", Required = false)]
public string? Profile { get; set; }
public async Task RunAsync()
=> await KeyCommandHandler.DeleteSshKey(KeyId, Profile);
}
[CliCommand(Description = "Manage env file sharing", Name = "share", Parent = typeof(RootCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class ShareCommand
{
public void Run()
=> ConsoleHelper.WriteInfo("Use 'senf share --help' to see available subcommands");
}
[CliCommand(Description = "Create a share for the current project", Name = "create", Parent = typeof(ShareCommand))]
public class ShareCreateCommand
{
public async Task RunAsync()
=> await ShareCommandHandler.CreateShare();
}
[CliCommand(Description = "Show share status", Name = "status", Parent = typeof(ShareCommand))]
public class ShareStatusCommand
{
[CliOption(Description = "Show all active shares")]
public bool All { get; set; }
public async Task RunAsync()
=> await ShareCommandHandler.ShowStatus(All);
}
[CliCommand(Description = "Remove a share for the current project", Name = "remove", Parent = typeof(ShareCommand))]
public class ShareRemoveCommand
{
public async Task RunAsync()
=> await ShareCommandHandler.RemoveShare();
}
[CliCommand(Description = "Admin operations", Name = "admin", Parent = typeof(RootCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class AdminCommand
{
public void Run()
=> ConsoleHelper.WriteInfo("Use 'senf admin --help' to see available subcommands");
}
[CliCommand(Description = "Manage invites", Name = "invite", Parent = typeof(AdminCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class AdminInviteCommand
{
public void Run()
=> ConsoleHelper.WriteInfo("Use 'senf admin invite --help' to see available subcommands");
}
[CliCommand(Description = "Create a new invite", Name = "create", Parent = typeof(AdminInviteCommand))]
public class AdminInviteCreateCommand
{
[CliOption(Description = "Profile to use (defaults to default profile)", Required = false)]
public string? Profile { get; set; }
public async Task RunAsync()
=> await InviteCommandHandler.CreateInvite(Profile);
}
[CliCommand(Description = "List invites", Name = "list", Parent = typeof(AdminInviteCommand))]
public class AdminInviteListCommand
{
[CliOption(Description = "Profile to use (defaults to default profile)", Required = false)]
public string? Profile { get; set; }
public async Task RunAsync()
=> await InviteCommandHandler.ListInvites(Profile);
}
[CliCommand(Description = "Remove an invite", Name = "remove", Parent = typeof(AdminInviteCommand))]
public class AdminInviteRemoveCommand
{
[CliArgument(Description = "Invite token")]
public string Token { get; set; } = null!;
[CliOption(Description = "Profile to use (defaults to default profile)", Required = false)]
public string? Profile { get; set; }
public async Task RunAsync()
=> await InviteCommandHandler.RemoveInvite(Token, Profile);
}
[CliCommand(Description = "Manage users", Name = "users", Parent = typeof(AdminCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class AdminUsersCommand
{
public void Run()
=> ConsoleHelper.WriteInfo("Use 'senf admin users --help' to see available subcommands");
}
[CliCommand(Description = "List users", Name = "list", Parent = typeof(AdminUsersCommand))]
public class AdminUsersListCommand
{
[CliOption(Description = "Profile to use (defaults to default profile)", Required = false)]
public string? Profile { get; set; }
public async Task RunAsync()
=> await AdminUsersCommandHandler.ListUsers(Profile);
}
[CliCommand(Description = "Remove a user", Name = "remove", Parent = typeof(AdminUsersCommand))]
public class AdminUsersRemoveCommand
{
[CliArgument(Description = "User ID to delete")]
public int UserId { get; set; }
[CliOption(Description = "Profile to use (defaults to default profile)", Required = false)]
public string? Profile { get; set; }
public async Task RunAsync()
=> await AdminUsersCommandHandler.RemoveUser(UserId, Profile);
}
[CliCommand(Description = "Join with an invite", Name = "join", Parent = typeof(RootCommand),
ShortFormAutoGenerate = CliNameAutoGenerate.None)]
public class JoinCommand
{
[CliOption(Description = "API URL for the backend", Required = false)]
public string? ApiUrl { get; set; }
[CliOption(Description = "Invite token", Required = false)]
public string? Token { get; set; }
[CliOption(Description = "Username to join as", Required = false)]
public string? Username { get; set; }
[CliOption(Description = "SSH public key (repeatable)", Required = false)]
public string[]? Key { get; set; }
[CliOption(Description = "Path to SSH public key file (repeatable)", Required = false)]
public string[]? KeyFile { get; set; }
public async Task RunAsync()
=> await JoinCommandHandler.Join(ApiUrl, Token, Username,
Key?.ToList(), KeyFile?.ToList());
}