Code

Merge branch 'ml/worktree'
authorJunio C Hamano <gitster@pobox.com>
Sun, 1 Jul 2007 20:11:01 +0000 (13:11 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 1 Jul 2007 20:11:01 +0000 (13:11 -0700)
* ml/worktree:
  make git barf when an alias changes environment variables

1  2 
git.c

diff --combined git.c
index b6bf5ad5ec97699f0a1f4d6c6616c7c9a240d144,33edd6277da584a75bbc88167eb363eb7bdc1ba6..696a97edca0f2765a7b417de404d103b7802dcf6
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -28,7 -28,7 +28,7 @@@ static void prepend_to_path(const char 
        free(path);
  }
  
- static int handle_options(const char*** argv, int* argc)
+ static int handle_options(const char*** argv, int* argc, int* envchanged)
  {
        int handled = 0;
  
                                usage(git_usage_string);
                        }
                        setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
+                       if (envchanged)
+                               *envchanged = 1;
                        (*argv)++;
                        (*argc)--;
                        handled++;
                } else if (!prefixcmp(cmd, "--git-dir=")) {
                        setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
+                       if (envchanged)
+                               *envchanged = 1;
                } else if (!strcmp(cmd, "--work-tree")) {
                        if (*argc < 2) {
                                fprintf(stderr, "No directory given for --work-tree.\n" );
                                usage(git_usage_string);
                        }
                        setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
+                       if (envchanged)
+                               *envchanged = 1;
                        (*argv)++;
                        (*argc)--;
                } else if (!prefixcmp(cmd, "--work-tree=")) {
                        setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
+                       if (envchanged)
+                               *envchanged = 1;
                } else if (!strcmp(cmd, "--bare")) {
                        static char git_dir[PATH_MAX+1];
                        setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
+                       if (envchanged)
+                               *envchanged = 1;
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(git_usage_string);
@@@ -160,7 -170,7 +170,7 @@@ static int split_cmdline(char *cmdline
  
  static int handle_alias(int *argcp, const char ***argv)
  {
-       int nongit = 0, ret = 0, saved_errno = errno;
+       int nongit = 0, envchanged = 0, ret = 0, saved_errno = errno;
        const char *subdir;
        int count, option_count;
        const char** new_argv;
                            alias_string + 1, alias_command);
                }
                count = split_cmdline(alias_string, &new_argv);
-               option_count = handle_options(&new_argv, &count);
+               option_count = handle_options(&new_argv, &count, &envchanged);
+               if (envchanged)
+                       die("alias '%s' changes environment variables\n"
+                                "You can use '!git' in the alias to do this.",
+                                alias_command);
                memmove(new_argv - option_count, new_argv,
                                count * sizeof(char *));
                new_argv -= option_count;
@@@ -226,53 -240,14 +240,53 @@@ const char git_version_string[] = GIT_V
   */
  #define NEED_WORK_TREE        (1<<2)
  
 -static void handle_internal_command(int argc, const char **argv, char **envp)
 +struct cmd_struct {
 +      const char *cmd;
 +      int (*fn)(int, const char **, const char *);
 +      int option;
 +};
 +
 +static int run_command(struct cmd_struct *p, int argc, const char **argv)
 +{
 +      int status;
 +      struct stat st;
 +      const char *prefix;
 +
 +      prefix = NULL;
 +      if (p->option & RUN_SETUP)
 +              prefix = setup_git_directory();
 +      if (p->option & USE_PAGER)
 +              setup_pager();
 +      if ((p->option & NEED_WORK_TREE) &&
 +          (!is_inside_work_tree() || is_inside_git_dir()))
 +              die("%s must be run in a work tree", p->cmd);
 +      trace_argv_printf(argv, argc, "trace: built-in: git");
 +
 +      status = p->fn(argc, argv, prefix);
 +      if (status)
 +              return status;
 +
 +      /* Somebody closed stdout? */
 +      if (fstat(fileno(stdout), &st))
 +              return 0;
 +      /* Ignore write errors for pipes and sockets.. */
 +      if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
 +              return 0;
 +
 +      /* Check for ENOSPC and EIO errors.. */
 +      if (fflush(stdout))
 +              die("write failure on standard output: %s", strerror(errno));
 +      if (ferror(stdout))
 +              die("unknown write failure on standard output");
 +      if (fclose(stdout))
 +              die("close failed on standard output: %s", strerror(errno));
 +      return 0;
 +}
 +
 +static void handle_internal_command(int argc, const char **argv)
  {
        const char *cmd = argv[0];
 -      static struct cmd_struct {
 -              const char *cmd;
 -              int (*fn)(int, const char **, const char *);
 -              int option;
 -      } commands[] = {
 +      static struct cmd_struct commands[] = {
                { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
                { "annotate", cmd_annotate, RUN_SETUP | USE_PAGER },
                { "apply", cmd_apply },
  
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
                struct cmd_struct *p = commands+i;
 -              const char *prefix;
                if (strcmp(p->cmd, cmd))
                        continue;
 -
 -              prefix = NULL;
 -              if (p->option & RUN_SETUP)
 -                      prefix = setup_git_directory();
 -              if (p->option & USE_PAGER)
 -                      setup_pager();
 -              if ((p->option & NEED_WORK_TREE) &&
 -                              (!is_inside_work_tree() || is_inside_git_dir()))
 -                      die("%s must be run in a work tree", cmd);
 -              trace_argv_printf(argv, argc, "trace: built-in: git");
 -
 -              exit(p->fn(argc, argv, prefix));
 +              exit(run_command(p, argc, argv));
        }
  }
  
 -int main(int argc, const char **argv, char **envp)
 +int main(int argc, const char **argv)
  {
        const char *cmd = argv[0] ? argv[0] : "git-help";
        char *slash = strrchr(cmd, '/');
        if (!prefixcmp(cmd, "git-")) {
                cmd += 4;
                argv[0] = cmd;
 -              handle_internal_command(argc, argv, envp);
 +              handle_internal_command(argc, argv);
                die("cannot handle %s internally", cmd);
        }
  
        /* Look for flags.. */
        argv++;
        argc--;
-       handle_options(&argv, &argc);
+       handle_options(&argv, &argc, NULL);
        if (argc > 0) {
                if (!prefixcmp(argv[0], "--"))
                        argv[0] += 2;
  
        while (1) {
                /* See if it's an internal command */
 -              handle_internal_command(argc, argv, envp);
 +              handle_internal_command(argc, argv);
  
                /* .. then try the external ones */
                execv_git_cmd(argv);