RPM Package Manager, CVS Repository http://rpm5.org/cvs/ ____________________________________________________________________________
Server: rpm5.org Name: Jeff Johnson Root: /v/rpm/cvs Email: j...@rpm5.org Module: rpm Date: 16-Jul-2013 00:11:42 Branch: rpm-5_4 Handle: 2013071522114200 Modified files: (Branch: rpm-5_4) rpm/rpmio rpmgit.c Log: - git: catch up to examples/status.c on tip. Summary: Revision Changes Path 2.1.2.32 +369 -102 rpm/rpmio/rpmgit.c ____________________________________________________________________________ patch -p0 <<'@@ .' Index: rpm/rpmio/rpmgit.c ============================================================================ $ cvs diff -u -r2.1.2.31 -r2.1.2.32 rpmgit.c --- rpm/rpmio/rpmgit.c 9 Jul 2013 02:27:44 -0000 2.1.2.31 +++ rpm/rpmio/rpmgit.c 15 Jul 2013 22:11:42 -0000 2.1.2.32 @@ -1489,96 +1489,321 @@ /*==============================================================*/ #if defined(WITH_LIBGIT2) -static int status_long_cb(const char *path, unsigned int status, void *data) +enum { + FORMAT_DEFAULT = 0, + FORMAT_LONG = 1, + FORMAT_SHORT = 2, + FORMAT_PORCELAIN = 3, +}; + +static void check(int error, const char *message, const char *extra) { - FILE * fp = stdout; - rpmgit git = (rpmgit) data; - int state = git->state; - int rc = 0; - - if (!(state & 0x1)) { - fprintf(fp, "# On branch master\n" - "#\n" - "# Initial commit\n"); - state |= 0x1; - } - -#define _INDEX_MASK \ - (GIT_STATUS_INDEX_NEW|GIT_STATUS_INDEX_MODIFIED|GIT_STATUS_INDEX_DELETED) -#define _WT_MASK \ - ( GIT_STATUS_WT_MODIFIED|GIT_STATUS_WT_DELETED) - if (status & _INDEX_MASK) { - if (!(state & 0x2)) { - fprintf(fp, "#\n" - "# Changes to be committed:\n" - "# (use \"git rm --cached <file>...\" to unstage)\n" - "#\n"); - state |= 0x2; - } - if (status & GIT_STATUS_INDEX_NEW) - fprintf(fp, "# new file: %s\n", path); - if (status & GIT_STATUS_INDEX_MODIFIED) /* XXX untested */ - fprintf(fp, "# ?M? file: %s\n", path); - if (status & GIT_STATUS_INDEX_DELETED) /* XXX untested */ - fprintf(fp, "# ?D? file: %s\n", path); + const git_error *lg2err; + const char *lg2msg = ""; + const char *lg2spacer = ""; + + if (!error) + return; + + if ((lg2err = giterr_last()) != NULL && lg2err->message != NULL) { + lg2msg = lg2err->message; + lg2spacer = " - "; + } + + if (extra) + fprintf(stderr, "%s '%s' [%d]%s%s\n", + message, extra, error, lg2spacer, lg2msg); + else + fprintf(stderr, "%s [%d]%s%s\n", + message, error, lg2spacer, lg2msg); + + exit(1); +} + +static void show_branch(git_repository *repo, int format) +{ + int error = 0; + const char *branch = NULL; + git_reference *head = NULL; + + error = git_repository_head(&head, repo); + + if (error == GIT_EORPHANEDHEAD || error == GIT_ENOTFOUND) + branch = NULL; + else if (!error) { + branch = git_reference_name(head); + if (!strncmp(branch, "refs/heads/", strlen("refs/heads/"))) + branch += strlen("refs/heads/"); } else - if (status & _WT_MASK) { - if (!(state & 0x4)) { - fprintf(fp, "#\n" - "# Changed but not updated:\n" - "# (use \"git add/rm <file>...\" to update what will be committed)\n" - "# (use \"git checkout -- <file>...\" to discard changes in working directory)\n" - "#\n"); - state |= 0x4; + check(error, "failed to get current branch", NULL); + + if (format == FORMAT_LONG) + printf("# On branch %s\n", + branch ? branch : "Not currently on any branch."); + else + printf("## %s\n", branch ? branch : "HEAD (no branch)"); + + git_reference_free(head); +} + +static void print_long(git_repository *repo, git_status_list *status) +{ + size_t maxi = git_status_list_entrycount(status); + size_t i; + const git_status_entry *s; + int header = 0; + int changes_in_index = 0; + int changed_in_workdir = 0; + int rm_in_workdir = 0; + const char *old_path; + const char *new_path; + + (void)repo; + + /* print index changes */ + + for (i = 0; i < maxi; ++i) { + char *istatus = NULL; + + s = git_status_byindex(status, i); + + if (s->status == GIT_STATUS_CURRENT) + continue; + + if (s->status & GIT_STATUS_WT_DELETED) + rm_in_workdir = 1; + + if (s->status & GIT_STATUS_INDEX_NEW) + istatus = "new file: "; + if (s->status & GIT_STATUS_INDEX_MODIFIED) + istatus = "modified: "; + if (s->status & GIT_STATUS_INDEX_DELETED) + istatus = "deleted: "; + if (s->status & GIT_STATUS_INDEX_RENAMED) + istatus = "renamed: "; + if (s->status & GIT_STATUS_INDEX_TYPECHANGE) + istatus = "typechange:"; + + if (istatus == NULL) + continue; + + if (!header) { + printf("# Changes to be committed:\n"); + printf("# (use \"git reset HEAD <file>...\" to unstage)\n"); + printf("#\n"); + header = 1; } - if (status & GIT_STATUS_WT_MODIFIED) - fprintf(fp, "# modified: %s\n", path); + + old_path = s->head_to_index->old_file.path; + new_path = s->head_to_index->new_file.path; + + if (old_path && new_path && strcmp(old_path, new_path)) + printf("#\t%s %s -> %s\n", istatus, old_path, new_path); else - if (status & GIT_STATUS_WT_DELETED) - fprintf(fp, "# deleted: %s\n", path); - } else - if (status & GIT_STATUS_WT_NEW) { - if (!(state & 0x8)) { - fprintf(fp, - "#\n" - "# Untracked files:\n" - "# (use \"git add <file>...\" to include in what will be committed)\n" - "#\n"); - state |= 0x8; + printf("#\t%s %s\n", istatus, old_path ? old_path : new_path); + } + + if (header) { + changes_in_index = 1; + printf("#\n"); + } + header = 0; + + /* print workdir changes to tracked files */ + + for (i = 0; i < maxi; ++i) { + char *wstatus = NULL; + + s = git_status_byindex(status, i); + + if (s->status == GIT_STATUS_CURRENT || s->index_to_workdir == NULL) + continue; + + if (s->status & GIT_STATUS_WT_MODIFIED) + wstatus = "modified: "; + if (s->status & GIT_STATUS_WT_DELETED) + wstatus = "deleted: "; + if (s->status & GIT_STATUS_WT_RENAMED) + wstatus = "renamed: "; + if (s->status & GIT_STATUS_WT_TYPECHANGE) + wstatus = "typechange:"; + + if (wstatus == NULL) + continue; + + if (!header) { + printf("# Changes not staged for commit:\n"); + printf("# (use \"git add%s <file>...\" to update what will be committed)\n", rm_in_workdir ? "/rm" : ""); + printf("# (use \"git checkout -- <file>...\" to discard changes in working directory)\n"); + printf("#\n"); + header = 1; } - fprintf(fp, "# %s\n", path); + + old_path = s->index_to_workdir->old_file.path; + new_path = s->index_to_workdir->new_file.path; + + if (old_path && new_path && strcmp(old_path, new_path)) + printf("#\t%s %s -> %s\n", wstatus, old_path, new_path); + else + printf("#\t%s %s\n", wstatus, old_path ? old_path : new_path); } - git->state = state; + if (header) { + changed_in_workdir = 1; + printf("#\n"); + } + header = 0; - return rc; + /* print untracked files */ + + header = 0; + + for (i = 0; i < maxi; ++i) { + s = git_status_byindex(status, i); + + if (s->status == GIT_STATUS_WT_NEW) { + + if (!header) { + printf("# Untracked files:\n"); + printf("# (use \"git add <file>...\" to include in what will be committed)\n"); + printf("#\n"); + header = 1; + } + + printf("#\t%s\n", s->index_to_workdir->old_file.path); + } + } + + header = 0; + + /* print ignored files */ + + for (i = 0; i < maxi; ++i) { + s = git_status_byindex(status, i); + + if (s->status == GIT_STATUS_IGNORED) { + + if (!header) { + printf("# Ignored files:\n"); + printf("# (use \"git add -f <file>...\" to include in what will be committed)\n"); + printf("#\n"); + header = 1; + } + + printf("#\t%s\n", s->index_to_workdir->old_file.path); + } + } + + if (!changes_in_index && changed_in_workdir) + printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"); } -static int status_short_cb(const char *path, unsigned int status, void *data) +static void print_short(git_repository *repo, git_status_list *status) { - FILE * fp = stdout; - rpmgit git = (rpmgit) data; - char Istatus = '?'; - char Wstatus = ' '; - int rc = 0; - - if (status & GIT_STATUS_INDEX_NEW) - Istatus = 'A'; - else if (status & GIT_STATUS_INDEX_MODIFIED) - Istatus = 'M'; /* XXX untested */ - else if (status & GIT_STATUS_INDEX_DELETED) - Istatus = 'D'; /* XXX untested */ - - if (status & GIT_STATUS_WT_NEW) - Wstatus = '?'; - else if (status & GIT_STATUS_WT_MODIFIED) - Wstatus = 'M'; - else if (status & GIT_STATUS_WT_DELETED) - Wstatus = 'D'; -fprintf(fp, "%c%c %s\n", Istatus, Wstatus, path); + size_t maxi = git_status_list_entrycount(status); + size_t i; + const git_status_entry *s; + char istatus; + char wstatus; + const char *extra; + const char *a; + const char *b; + const char *c; - git->state = rc; - return rc; + for (i = 0; i < maxi; ++i) { + s = git_status_byindex(status, i); + + if (s->status == GIT_STATUS_CURRENT) + continue; + + a = b = c = NULL; + istatus = wstatus = ' '; + extra = ""; + + if (s->status & GIT_STATUS_INDEX_NEW) + istatus = 'A'; + if (s->status & GIT_STATUS_INDEX_MODIFIED) + istatus = 'M'; + if (s->status & GIT_STATUS_INDEX_DELETED) + istatus = 'D'; + if (s->status & GIT_STATUS_INDEX_RENAMED) + istatus = 'R'; + if (s->status & GIT_STATUS_INDEX_TYPECHANGE) + istatus = 'T'; + + if (s->status & GIT_STATUS_WT_NEW) { + if (istatus == ' ') + istatus = '?'; + wstatus = '?'; + } + if (s->status & GIT_STATUS_WT_MODIFIED) + wstatus = 'M'; + if (s->status & GIT_STATUS_WT_DELETED) + wstatus = 'D'; + if (s->status & GIT_STATUS_WT_RENAMED) + wstatus = 'R'; + if (s->status & GIT_STATUS_WT_TYPECHANGE) + wstatus = 'T'; + + if (s->status & GIT_STATUS_IGNORED) { + istatus = '!'; + wstatus = '!'; + } + + if (istatus == '?' && wstatus == '?') + continue; + + if (s->index_to_workdir && + s->index_to_workdir->new_file.mode == GIT_FILEMODE_COMMIT) + { + git_submodule *sm = NULL; + unsigned int smstatus = 0; + + if (!git_submodule_lookup( &sm, repo, s->index_to_workdir->new_file.path) + && !git_submodule_status(&smstatus, sm)) + { + if (smstatus & GIT_SUBMODULE_STATUS_WD_MODIFIED) + extra = " (new commits)"; + else if (smstatus & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) + extra = " (modified content)"; + else if (smstatus & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) + extra = " (modified content)"; + else if (smstatus & GIT_SUBMODULE_STATUS_WD_UNTRACKED) + extra = " (untracked content)"; + } + } + + if (s->head_to_index) { + a = s->head_to_index->old_file.path; + b = s->head_to_index->new_file.path; + } + if (s->index_to_workdir) { + if (!a) + a = s->index_to_workdir->old_file.path; + if (!b) + b = s->index_to_workdir->old_file.path; + c = s->index_to_workdir->new_file.path; + } + + if (istatus == 'R') { + if (wstatus == 'R') + printf("%c%c %s %s %s%s\n", istatus, wstatus, a, b, c, extra); + else + printf("%c%c %s %s%s\n", istatus, wstatus, a, b, extra); + } else { + if (wstatus == 'R') + printf("%c%c %s %s%s\n", istatus, wstatus, a, c, extra); + else + printf("%c%c %s%s\n", istatus, wstatus, a, extra); + } + } + + for (i = 0; i < maxi; ++i) { + s = git_status_byindex(status, i); + + if (s->status == GIT_STATUS_WT_NEW) + printf("?? %s\n", s->index_to_workdir->old_file.path); + } } #endif /* defined(WITH_LIBGIT2) */ @@ -1586,63 +1811,105 @@ { int rc = RPMRC_FAIL; #if defined(WITH_LIBGIT2) - git_status_options opts = { GIT_STATUS_OPTIONS_VERSION, 0, 0, { NULL, 0} }; + git_status_options opt = { GIT_STATUS_OPTIONS_VERSION, 0, 0, { NULL, 0} }; const char * status_untracked_files = xstrdup("all"); + const char * status_ignore_submodules = xstrdup("all"); enum { - _STATUS_SHORT = (1 << 0), + _STATUS_BRANCH = (1 << 0), _STATUS_ZERO = (1 << 1), + _STATUS_IGNORED = (1 << 2), }; int status_flags = 0; #define STATUS_ISSET(_a) (status_flags & _STATUS_##_a) + int format = FORMAT_DEFAULT; /* XXX git->format? */ struct poptOption statusOpts[] = { - { "short", 's', POPT_BIT_SET, &status_flags, _STATUS_SHORT, + { "short", 's', POPT_ARG_VAL, &format, FORMAT_SHORT, N_("Give the output in the short-format."), NULL }, - { "porcelain", '\0', POPT_BIT_SET, &status_flags, _STATUS_SHORT, + { "long", 's', POPT_ARG_VAL, &format, FORMAT_LONG, + N_("Give the output in the long-format."), NULL }, + { "porcelain", '\0', POPT_ARG_VAL, &format, FORMAT_PORCELAIN, N_("Give the output in a stable, easy-to-parse format for scripts."), NULL }, + { "branch", 'b', POPT_BIT_SET, &status_flags, _STATUS_BRANCH, + N_("."), NULL }, + { NULL, 'z', POPT_BIT_SET, &status_flags, _STATUS_ZERO, + N_("."), NULL }, + { "ignored", '\0', POPT_BIT_SET, &status_flags, _STATUS_IGNORED, + N_("."), NULL }, { "untracked-files", 'u', POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT, &status_untracked_files, 0, N_("Show untracked files."), N_("{no|normal|all}") }, - { NULL, 'z', POPT_BIT_SET, &status_flags, _STATUS_ZERO, - N_(""), NULL }, + { "ignore-submodules", '\0', POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT, &status_ignore_submodules, 0, + N_("Ignore sub-modules."), N_("{all}") }, + /* --git-dir */ POPT_AUTOALIAS POPT_AUTOHELP POPT_TABLEEND }; rpmgit git = rpmgitNew(argv, 0, statusOpts); + git_status_list * list = NULL; int xx = -1; - opts.show = STATUS_ISSET(SHORT) - ? GIT_STATUS_SHOW_INDEX_AND_WORKDIR - : GIT_STATUS_SHOW_INDEX_THEN_WORKDIR; - - opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED; - opts.flags |= GIT_STATUS_OPT_INCLUDE_UNMODIFIED; - opts.flags &= ~GIT_STATUS_OPT_EXCLUDE_SUBMODULES; + opt.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; + if (STATUS_ISSET(ZERO)) { + if (format == FORMAT_DEFAULT) + format = FORMAT_PORCELAIN; + } + + opt.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; + opt.flags |= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX; + opt.flags |= GIT_STATUS_OPT_SORT_CASE_SENSITIVELY; + + if (STATUS_ISSET(IGNORED)) { + opt.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED; + } if (!strcmp(status_untracked_files, "no")) { - opts.flags &= ~GIT_STATUS_OPT_INCLUDE_UNTRACKED; - opts.flags &= ~GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; + opt.flags &= ~GIT_STATUS_OPT_INCLUDE_UNTRACKED; + opt.flags &= ~GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; } else if (!strcmp(status_untracked_files, "normal")) { - opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; - opts.flags &= ~GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; + opt.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; + opt.flags &= ~GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; } else if (!strcmp(status_untracked_files, "all")) { - opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; - opts.flags |= GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; + opt.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED; + opt.flags |= GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; + } + if (!strcmp(status_ignore_submodules, "all")) { + opt.flags |= GIT_STATUS_OPT_EXCLUDE_SUBMODULES; + } + + if (format == FORMAT_DEFAULT) + format = FORMAT_LONG; + if (format == FORMAT_LONG) + status_flags |= _STATUS_BRANCH; + if (git->ac > 0) { + opt.pathspec.strings = (char **) git->av; + opt.pathspec.count = git->ac; } git->state = 0; - if (STATUS_ISSET(SHORT)) - xx = chkgit(git, "git_status_foreach_ext", - git_status_foreach_ext(git->R, &opts, status_short_cb, (void *)git)); + xx = chkgit(git, "git_status_list_new", + git_status_list_new(&list, git->R, &opt)); + + if (STATUS_ISSET(BRANCH)) + show_branch(git->R, format); + + if (format == FORMAT_LONG) + print_long(git->R, list); else - xx = chkgit(git, "git_status_foreach_ext", - git_status_foreach_ext(git->R, &opts, status_long_cb, (void *)git)); + print_short(git->R, list); + goto exit; /* XXX GCC warning */ exit: rc = (xx ? RPMRC_FAIL : RPMRC_OK); SPEW(0, rc, git); + + if (list) { + git_status_list_free(list); + list = NULL; + } status_untracked_files = _free(status_untracked_files); + status_ignore_submodules = _free(status_ignore_submodules); git = rpmgitFree(git); #endif /* defined(WITH_LIBGIT2) */ @@ . ______________________________________________________________________ RPM Package Manager http://rpm5.org CVS Sources Repository rpm-cvs@rpm5.org