commit 5c860e2997733fa54f69d9b201bc1cf49a3f78b8 from: Stefan Sperling date: Mon Mar 12 12:48:54 2018 UTC add got(1) command code from mpi commit - 5166488913ca69fd4d6c284f8bee054b6bf1d073 commit + 5c860e2997733fa54f69d9b201bc1cf49a3f78b8 blob - /dev/null blob + 0ce0ba7559ff21826796e2eee3bf9e71e2155a0a (mode 644) --- /dev/null +++ got/Makefile @@ -0,0 +1,11 @@ + +PROG= got +SRCS= got.c + +CFLAGS+= -W -Wall -Wstrict-prototypes -Wunused-variable + +# libgit2 +CFLAGS+= -I/usr/local/include +LDADD+= -L/usr/local/lib -lgit2 + +.include blob - /dev/null blob + ccb72f27598eb28ba66f1e58c05bbfe0924d612e (mode 644) --- /dev/null +++ got/got.1 @@ -0,0 +1,44 @@ +.\" +.\" Copyright (c) 2017 Martin Pieuchot +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate$ +.Dt GOT 1 +.Os +.Sh NAME +.Nm got +.Nd simple version control system +.Sh SYNOPSIS +.Nm +.Ar command +.Op Ar arg ... +.Sh DESCRIPTION +The +.Nm +utility is used to manage +.Xr git 5 +repositories. +It prioritizes ease of use and simplicity over flexibility. +.Pp +The commands are as follows: +.Bl -tag -width Ds +.It Cm status +Show current status of files. +.It Cm log +Display history of the repository. +.El +.Sh EXIT STATUS +.Ex -std got +.Sh SEE ALSO +.Xr git 5 blob - /dev/null blob + c18fa2fa6c3903b079ad2f7d4fee3d22ea7c9c1c (mode 644) --- /dev/null +++ got/got.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2017 Martin Pieuchot + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef nitems +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + +struct cmd { + const char *cmd_name; + int (*cmd_main)(int, char *[]); +}; + +__dead void usage(void); + +int cmd_log(int, char *[]); +int cmd_status(int, char *[]); + +struct cmd got_commands[] = { + { "log", cmd_log }, + { "status", cmd_status }, +}; + +int +main(int argc, char *argv[]) +{ + struct cmd *cmd; + unsigned int i; + int ch; + + setlocale(LC_ALL, ""); + + if (pledge("stdio rpath", NULL) == -1) + err(1, "pledge"); + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + default: + usage(); + /* NOTREACHED */ + } + } + + argc -= optind; + argv += optind; + + if (argc <= 0) + usage(); + + for (i = 0; i < nitems(got_commands); i++) { + cmd = &got_commands[i]; + + if (strncmp(cmd->cmd_name, argv[0], strlen(argv[0]))) + continue; + + return got_commands[i].cmd_main(argc, argv); + /* NOTREACHED */ + } + + fprintf(stderr, "%s: unknown command -- %s\n", getprogname(), argv[0]); + return 1; +} + +__dead void +usage(void) +{ + fprintf(stderr, "usage: %s command [arg ...]\n", getprogname()); + exit(1); +} + +int +cmd_log(int argc __unused, char *argv[] __unused) +{ + git_repository *repo = NULL; + git_revwalk *walker = NULL; + git_commit *commit = NULL; + git_oid oid; + + git_libgit2_init(); + + if (git_repository_open_ext(&repo, ".", 0, NULL)) + errx(1, "git_repository_open: %s", giterr_last()->message); + + if (git_revwalk_new(&walker, repo)) + errx(1, "git_revwalk_new: %s", giterr_last()->message); + + if (git_revwalk_push_head(walker)) + errx(1, "git_revwalk_push_head: %s", giterr_last()->message); + + while (git_revwalk_next(&oid, walker) == 0) { + char buf[GIT_OID_HEXSZ + 1]; + const git_signature *sig; + + git_commit_free(commit); + if (git_commit_lookup(&commit, repo, &oid)) + errx(1, "git_commit_lookup: %s", giterr_last()->message); + + printf("-----------------------------------------------\n"); + git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); + printf("commit %s\n", buf); + + if ((sig = git_commit_author(commit)) != NULL) { + printf("Author: %s <%s>\n", sig->name, sig->email); + } + printf("\n%s\n", git_commit_message_raw(commit)); + } + git_commit_free(commit); + + git_repository_free(repo); + git_libgit2_shutdown(); + + return 0; +} + +int +cmd_status(int argc __unused, char *argv[] __unused) +{ + git_repository *repo = NULL; + git_status_list *status; + git_status_options statusopts; + size_t i; + + git_libgit2_init(); + + if (git_repository_open_ext(&repo, ".", 0, NULL)) + errx(1, "git_repository_open: %s", giterr_last()->message); + + if (git_repository_is_bare(repo)) + errx(1, "bar repository"); + + if (git_status_init_options(&statusopts, GIT_STATUS_OPTIONS_VERSION)) + errx(1, "git_status_init_options: %s", giterr_last()->message); + + statusopts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; + statusopts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | + GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX | + GIT_STATUS_OPT_SORT_CASE_SENSITIVELY; + + if (git_status_list_new(&status, repo, &statusopts)) + errx(1, "git_status_list_new: %s", giterr_last()->message); + + for (i = 0; i < git_status_list_entrycount(status); i++) { + const git_status_entry *se; + + se = git_status_byindex(status, i); + switch (se->status) { + case GIT_STATUS_WT_NEW: + printf("? %s\n", se->index_to_workdir->new_file.path); + break; + case GIT_STATUS_WT_MODIFIED: + printf("M %s\n", se->index_to_workdir->new_file.path); + break; + case GIT_STATUS_WT_DELETED: + printf("R %s\n", se->index_to_workdir->new_file.path); + break; + case GIT_STATUS_WT_RENAMED: + printf("m %s -> %s\n", + se->index_to_workdir->old_file.path, + se->index_to_workdir->new_file.path); + break; + case GIT_STATUS_WT_TYPECHANGE: + printf("t %s\n", se->index_to_workdir->new_file.path); + break; + case GIT_STATUS_INDEX_NEW: + printf("A %s\n", se->head_to_index->new_file.path); + break; + case GIT_STATUS_INDEX_MODIFIED: + printf("M %s\n", se->head_to_index->old_file.path); + break; + case GIT_STATUS_INDEX_DELETED: + printf("R %s\n", se->head_to_index->old_file.path); + break; + case GIT_STATUS_INDEX_RENAMED: + printf("m %s -> %s\n", + se->head_to_index->old_file.path, + se->head_to_index->new_file.path); + break; + case GIT_STATUS_INDEX_TYPECHANGE: + printf("t %s\n", se->head_to_index->old_file.path); + break; + case GIT_STATUS_CURRENT: + default: + break; + } + } + + git_status_list_free(status); + git_repository_free(repo); + git_libgit2_shutdown(); + + return 0; +}