tenseleyflow/gitswitch / b4f7c27

Browse files

feat(main): add init <shell> subcommand and --ssh-agent-info compat alias

Authored by espadonne
SHA
b4f7c271f135c982fc33cd25e83393c7646afc69
Parents
46a7e54
Tree
05fcfde

1 changed file

StatusFile+-
M src/main.c 78 3
src/main.cmodified
@@ -16,6 +16,11 @@
1616
 #include "error.h"
1717
 #include "utils.h"
1818
 #include "git_ops.h"
19
+#include "ssh_manager.h"
20
+
21
+/* Long-only options (no short form). Values above 0xff avoid colliding with
22
+ * ASCII short options handled by getopt_long. */
23
+#define OPT_SSH_AGENT_INFO 0x100
1924
 
2025
 static void print_usage(const char *prog_name) {
2126
     printf("Usage: %s [OPTIONS] [COMMAND] [ARGS]\n", prog_name);
@@ -28,6 +33,7 @@ static void print_usage(const char *prog_name) {
2833
     printf("  status               Show current account status\n");
2934
     printf("  doctor, health       Run comprehensive health check\n");
3035
     printf("  config               Show configuration file information\n");
36
+    printf("  init <shell>         Emit shell integration (fish|bash|zsh|sh)\n");
3137
     printf("  <account>            Switch to specified account\n");
3238
     printf("\nOptions:\n");
3339
     printf("  --global, -g         Use global git scope\n");
@@ -67,6 +73,8 @@ static int handle_status_command(gitswitch_ctx_t *ctx);
6773
 static int handle_switch_command(gitswitch_ctx_t *ctx, const char *identifier);
6874
 static int handle_doctor_command(gitswitch_ctx_t *ctx);
6975
 static int handle_config_command(gitswitch_ctx_t *ctx);
76
+static int handle_init_command(const char *shell);
77
+static const char *detect_shell_from_env(void);
7078
 
7179
 int main(int argc, char *argv[]) {
7280
     gitswitch_ctx_t ctx;
@@ -88,6 +96,9 @@ int main(int argc, char *argv[]) {
8896
         {"dry-run", no_argument, 0, 'n'},
8997
         {"global", no_argument, 0, 'g'},
9098
         {"local", no_argument, 0, 'l'},
99
+        /* Compat alias for the Python gitswitch era. Dispatches to `init`
100
+         * with shell auto-detected from $SHELL so stale rc lines keep working. */
101
+        {"ssh-agent-info", no_argument, 0, OPT_SSH_AGENT_INFO},
91102
         {0, 0, 0, 0}
92103
     };
93104
     
@@ -129,6 +140,11 @@ int main(int argc, char *argv[]) {
129140
             case 'l':
130141
                 /* Local scope - will be handled by command handlers */
131142
                 break;
143
+            case OPT_SSH_AGENT_INFO: {
144
+                int rc = handle_init_command(detect_shell_from_env());
145
+                error_cleanup();
146
+                return rc;
147
+            }
132148
             default:
133149
                 print_usage(argv[0]);
134150
                 error_cleanup();
@@ -211,6 +227,8 @@ int main(int argc, char *argv[]) {
211227
         exit_code = handle_doctor_command(&ctx);
212228
     } else if (strcmp(command, "config") == 0) {
213229
         exit_code = handle_config_command(&ctx);
230
+    } else if (strcmp(command, "init") == 0) {
231
+        exit_code = handle_init_command(arg1 ? arg1 : detect_shell_from_env());
214232
     } else {
215233
         /* Assume it's an account identifier for switching */
216234
         exit_code = handle_switch_command(&ctx, command);
@@ -224,12 +242,13 @@ int main(int argc, char *argv[]) {
224242
             strcmp(command, "rm") == 0 || 
225243
             strcmp(command, "delete") == 0) {
226244
             should_save = true;
227
-        } else if (strcmp(command, "list") != 0 && 
245
+        } else if (strcmp(command, "list") != 0 &&
228246
                    strcmp(command, "ls") != 0 &&
229247
                    strcmp(command, "status") != 0 &&
230248
                    strcmp(command, "doctor") != 0 &&
231249
                    strcmp(command, "health") != 0 &&
232
-                   strcmp(command, "config") != 0) {
250
+                   strcmp(command, "config") != 0 &&
251
+                   strcmp(command, "init") != 0) {
233252
             /* Assume it's a switch command - may have modified default scope */
234253
             should_save = true;
235254
         }
@@ -387,7 +406,63 @@ static int handle_config_command(gitswitch_ctx_t *ctx) {
387406
             display_warning("Configuration file has unsafe permissions (%o)", file_mode & 0777);
388407
         }
389408
     }
390
-    
409
+
391410
     return EXIT_SUCCESS;
392411
 }
393412
 
413
+/* Return the basename of $SHELL, or NULL if it can't be determined. The
414
+ * pointer aliases into the environment string — callers must not free it. */
415
+static const char *detect_shell_from_env(void) {
416
+    const char *shell = getenv("SHELL");
417
+    if (!shell || !*shell) {
418
+        return NULL;
419
+    }
420
+    const char *slash = strrchr(shell, '/');
421
+    return slash ? slash + 1 : shell;
422
+}
423
+
424
+/* Emit shell-integration snippet for `shell` on stdout. The snippet sets
425
+ * SSH_AUTH_SOCK to the stable gitswitch symlink, guarded by a socket test so
426
+ * sourcing before the first switch (or after /tmp is wiped) is silent. */
427
+static int handle_init_command(const char *shell) {
428
+    char sock_path[MAX_PATH_LEN];
429
+    if (ssh_manager_get_auth_sock_path(sock_path, sizeof(sock_path)) != 0) {
430
+        fprintf(stderr, "gitswitch: failed to compute SSH_AUTH_SOCK path: %s\n",
431
+                get_last_error()->message);
432
+        return EXIT_FAILURE;
433
+    }
434
+
435
+    if (!shell || !*shell) {
436
+        fprintf(stderr,
437
+                "gitswitch: could not detect shell; pass one explicitly:\n"
438
+                "  gitswitch init fish | source\n"
439
+                "  eval \"$(gitswitch init bash)\"\n"
440
+                "  eval \"$(gitswitch init zsh)\"\n");
441
+        return EXIT_FAILURE;
442
+    }
443
+
444
+    if (strcmp(shell, "fish") == 0) {
445
+        printf("# gitswitch shell integration (fish)\n");
446
+        printf("set -l __gitswitch_auth_sock %s\n", sock_path);
447
+        printf("if test -S $__gitswitch_auth_sock\n");
448
+        printf("    set -gx SSH_AUTH_SOCK $__gitswitch_auth_sock\n");
449
+        printf("end\n");
450
+        printf("set -e __gitswitch_auth_sock\n");
451
+        return EXIT_SUCCESS;
452
+    }
453
+
454
+    if (strcmp(shell, "bash") == 0 || strcmp(shell, "zsh") == 0 ||
455
+        strcmp(shell, "sh") == 0 || strcmp(shell, "dash") == 0 ||
456
+        strcmp(shell, "ksh") == 0) {
457
+        printf("# gitswitch shell integration (%s)\n", shell);
458
+        printf("__gitswitch_auth_sock=%s\n", sock_path);
459
+        printf("[ -S \"$__gitswitch_auth_sock\" ] && export SSH_AUTH_SOCK=\"$__gitswitch_auth_sock\"\n");
460
+        printf("unset __gitswitch_auth_sock\n");
461
+        return EXIT_SUCCESS;
462
+    }
463
+
464
+    fprintf(stderr,
465
+            "gitswitch: unsupported shell '%s' (supported: fish, bash, zsh, sh, dash, ksh)\n",
466
+            shell);
467
+    return EXIT_FAILURE;
468
+}