Compare commits
8 commits
4e3d6f9b4a
...
a205314c69
| Author | SHA1 | Date | |
|---|---|---|---|
| a205314c69 | |||
| 4bcbaa4549 | |||
| 1f96830f10 | |||
| 73c2acd37e | |||
| 5e0e140b09 | |||
| 4a008a82b0 | |||
| 28da6575e6 | |||
| f31076baf8 |
9 changed files with 328 additions and 49 deletions
Binary file not shown.
5
Makefile
5
Makefile
|
|
@ -2,13 +2,12 @@ include config.mk
|
||||||
|
|
||||||
# flags and incs
|
# flags and incs
|
||||||
PKGS = $(GITLIB)
|
PKGS = $(GITLIB)
|
||||||
CFLAGS = -DVERSION=\"$(VERSION)\" -Wall -pedantic -O3 $(GIT) $(ERR) $(EXPLAIN)
|
CFLAGS = -DVERSION=\"$(VERSION)\" -Wall -pedantic -O3 $(GIT) $(GITHASH) $(ERR) $(PERF) $(EXPLAIN)
|
||||||
LIBS = `$(PKG_CONFIG) --libs --cflags $(PKGS)`
|
LIBS = `$(PKG_CONFIG) --libs --cflags $(PKGS)`
|
||||||
|
|
||||||
all: XD
|
all: XD
|
||||||
XD: XD.o
|
XD: XD.o hash.o helpers.o
|
||||||
$(CC) *.o $(CFLAGS) $(LIBS) -o $@
|
$(CC) *.o $(CFLAGS) $(LIBS) -o $@
|
||||||
XD.o: XD.c
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f XD *.o
|
rm -f XD *.o
|
||||||
|
|
|
||||||
9
XD.1
9
XD.1
|
|
@ -12,9 +12,12 @@
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
Displays information using a smiley face like so: :)
|
Displays information using a smiley face like so: :)
|
||||||
to interpret it refer to the following tables:
|
.Nm
|
||||||
Displays information using a smiley face.
|
does some special caching to run as fast as possible but there's only so much
|
||||||
to interpret XD's output refer to the following tables (or
|
that can be done without relying on an external daemon. Therefore when new
|
||||||
|
changes are made in very large repositories it may take a few seconds to
|
||||||
|
determine if there are any changes. To interpret XD's output refer to the
|
||||||
|
following tables (or
|
||||||
.Nm
|
.Nm
|
||||||
\fB-e\fR):
|
\fB-e\fR):
|
||||||
.Ss Eyes
|
.Ss Eyes
|
||||||
|
|
|
||||||
94
XD.c
94
XD.c
|
|
@ -1,7 +1,9 @@
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#ifdef ERR
|
#ifdef ERR
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
@ -16,42 +18,11 @@
|
||||||
#include <git2.h>
|
#include <git2.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
#define P(X) fwrite(X, 1, 1, stdout)
|
#define P(X) fwrite(X, 1, 1, stdout)
|
||||||
|
|
||||||
#if defined(ERR) || defined(EXPLAIN)
|
|
||||||
void
|
|
||||||
l(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
|
|
||||||
fputc(' ', stderr);
|
|
||||||
perror(NULL);
|
|
||||||
} else {
|
|
||||||
fputc('\n', stderr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ERR
|
|
||||||
#define L(...) l(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define L(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef EXPLAIN
|
|
||||||
static int explain = 0;
|
|
||||||
#define E(...) if (explain) { \
|
|
||||||
l(__VA_ARGS__); \
|
|
||||||
} else
|
|
||||||
#else
|
|
||||||
#define E(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef GIT
|
#ifdef GIT
|
||||||
/**
|
/**
|
||||||
* @brief search all parent directories for a git repo
|
* @brief search all parent directories for a git repo
|
||||||
|
|
@ -61,6 +32,7 @@ static int explain = 0;
|
||||||
char
|
char
|
||||||
*find_git_repo(void)
|
*find_git_repo(void)
|
||||||
{
|
{
|
||||||
|
PS();
|
||||||
char path[PATH_MAX] = ".", fstr[PATH_MAX], *rpath, *res;
|
char path[PATH_MAX] = ".", fstr[PATH_MAX], *rpath, *res;
|
||||||
struct stat s;
|
struct stat s;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
@ -70,6 +42,7 @@ char
|
||||||
rpath = realpath(path, NULL);
|
rpath = realpath(path, NULL);
|
||||||
if (!rpath) {
|
if (!rpath) {
|
||||||
L("realpath: %s", strerror(errno));
|
L("realpath: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
for (i = c = 0; i < strlen(rpath); i++) {
|
for (i = c = 0; i < strlen(rpath); i++) {
|
||||||
|
|
@ -86,22 +59,26 @@ char
|
||||||
/* if there seems to be a git directory return the directory it was found in */
|
/* if there seems to be a git directory return the directory it was found in */
|
||||||
if (stat(path, &s) == 0) {
|
if (stat(path, &s) == 0) {
|
||||||
if (S_ISDIR(s.st_mode)) {
|
if (S_ISDIR(s.st_mode)) {
|
||||||
|
PE();
|
||||||
return realpath(path, NULL);
|
return realpath(path, NULL);
|
||||||
} else if (S_ISREG(s.st_mode)) {
|
} else if (S_ISREG(s.st_mode)) {
|
||||||
/* we do some special magic here to check if we're in a submodule */
|
/* we do some special magic here to check if we're in a submodule */
|
||||||
f = fopen(path, "r");
|
f = fopen(path, "r");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
L("fopen: %s", strerror(errno));
|
L("fopen: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
res = fgets(fstr, PATH_MAX, f);
|
res = fgets(fstr, PATH_MAX, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
L("fgets: %s", strerror(errno));
|
L("fgets: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (strncmp(fstr, "gitdir: ", strlen("gitdir: ")) == 0) {
|
if (strncmp(fstr, "gitdir: ", strlen("gitdir: ")) == 0) {
|
||||||
fstr[strlen(fstr) - 1] = '\0';
|
fstr[strlen(fstr) - 1] = '\0';
|
||||||
|
PE();
|
||||||
return realpath(fstr + strlen("gitdir: "), NULL);
|
return realpath(fstr + strlen("gitdir: "), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -112,6 +89,7 @@ char
|
||||||
memset(&path[strlen(path) - 2], 0, 2);
|
memset(&path[strlen(path) - 2], 0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PE();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,11 +101,13 @@ char
|
||||||
git_repository
|
git_repository
|
||||||
*init_git(void)
|
*init_git(void)
|
||||||
{
|
{
|
||||||
|
PS();
|
||||||
char *buf;
|
char *buf;
|
||||||
git_repository *repo;
|
git_repository *repo;
|
||||||
|
|
||||||
/* check for a repo before loading libgit2 */
|
/* check for a repo before loading libgit2 */
|
||||||
if ((buf = find_git_repo()) == NULL) {
|
if ((buf = find_git_repo()) == NULL) {
|
||||||
|
PE();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,17 +123,20 @@ git_repository
|
||||||
/* initialize the git library and repository */
|
/* initialize the git library and repository */
|
||||||
if (git_libgit2_init() < 0) {
|
if (git_libgit2_init() < 0) {
|
||||||
L("Failed to initalize libgit2, proceeding without git functionality enabled.");
|
L("Failed to initalize libgit2, proceeding without git functionality enabled.");
|
||||||
|
PE();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (git_repository_open(&repo, buf) < 0) {
|
if (git_repository_open(&repo, buf) < 0) {
|
||||||
L("Failed to open git repo: %s", git_error_last()->message);
|
L("Failed to open git repo: %s", git_error_last()->message);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
PE();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get rid of object containing git repo path and return the repo */
|
/* get rid of object containing git repo path and return the repo */
|
||||||
free(buf);
|
free(buf);
|
||||||
|
PE();
|
||||||
return repo;
|
return repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,20 +149,24 @@ git_repository
|
||||||
int
|
int
|
||||||
has_stashes(git_repository *repo)
|
has_stashes(git_repository *repo)
|
||||||
{
|
{
|
||||||
|
PS();
|
||||||
git_reference *stash = NULL;
|
git_reference *stash = NULL;
|
||||||
int e;
|
int e;
|
||||||
|
|
||||||
e = git_reference_lookup(&stash, repo, "refs/stash");
|
e = git_reference_lookup(&stash, repo, "refs/stash");
|
||||||
if (e == GIT_ENOTFOUND) {
|
if (e == GIT_ENOTFOUND) {
|
||||||
|
PE();
|
||||||
return 0;
|
return 0;
|
||||||
} else if (e < 0) {
|
} else if (e < 0) {
|
||||||
L("Error looking up stash reference: %s", git_error_last()->message);
|
L("Error looking up stash reference: %s", git_error_last()->message);
|
||||||
|
PE();
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
e = 1;
|
e = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
git_reference_free(stash);
|
git_reference_free(stash);
|
||||||
|
PE();
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,27 +179,45 @@ has_stashes(git_repository *repo)
|
||||||
int
|
int
|
||||||
has_untracked(git_repository *repo)
|
has_untracked(git_repository *repo)
|
||||||
{
|
{
|
||||||
|
PS();
|
||||||
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
||||||
git_status_list *list = NULL;
|
git_status_list *list = NULL;
|
||||||
|
repohash *storedhash;
|
||||||
|
uint64_t newhash = generate_hash(repo);
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
/* FIXME: this is really slow in large git repos :( */
|
#ifdef GITHASH
|
||||||
opts.show = GIT_STATUS_SHOW_WORKDIR_ONLY;
|
if ((storedhash = read_hash(repo))
|
||||||
|
&& storedhash->hash == newhash) {
|
||||||
|
r = storedhash->changes;
|
||||||
|
free(storedhash);
|
||||||
|
PE();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* if we need to regen the hash then we need to do a hard check on the real
|
||||||
|
* git repository */
|
||||||
|
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
|
||||||
opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
|
opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
|
||||||
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
|
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
|
||||||
|
GIT_STATUS_OPT_UPDATE_INDEX |
|
||||||
GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH;
|
GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH;
|
||||||
|
|
||||||
if (git_status_list_new(&list, repo, &opts) < 0) {
|
if (git_status_list_new(&list, repo, &opts) < 0) {
|
||||||
L("Error checking for untracked changes: %s", git_error_last()->message);
|
L("Error checking for untracked changes: %s", git_error_last()->message);
|
||||||
|
PE();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if any changes are found return 1 */
|
/* if any changes are found return 1 */
|
||||||
if (git_status_list_entrycount(list) > 0) {
|
r = git_status_list_entrycount(list) > 0;
|
||||||
r = 1;
|
#ifdef GITHASH
|
||||||
}
|
write_hash(repo, (repohash){ .hash = newhash, .changes = r });
|
||||||
|
#endif
|
||||||
|
|
||||||
git_status_list_free(list);
|
git_status_list_free(list);
|
||||||
|
PE();
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,6 +230,7 @@ has_untracked(git_repository *repo)
|
||||||
int
|
int
|
||||||
has_staged(git_repository *repo)
|
has_staged(git_repository *repo)
|
||||||
{
|
{
|
||||||
|
PS();
|
||||||
git_status_entry entry;
|
git_status_entry entry;
|
||||||
git_status_list *list = NULL;
|
git_status_list *list = NULL;
|
||||||
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
||||||
|
|
@ -235,6 +241,7 @@ has_staged(git_repository *repo)
|
||||||
|
|
||||||
if (git_status_list_new(&list, repo, &opts) < 0) {
|
if (git_status_list_new(&list, repo, &opts) < 0) {
|
||||||
L("Error checking for staged changes: %s", git_error_last()->message);
|
L("Error checking for staged changes: %s", git_error_last()->message);
|
||||||
|
PE();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,6 +260,7 @@ has_staged(git_repository *repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
git_status_list_free(list);
|
git_status_list_free(list);
|
||||||
|
PE();
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -260,17 +268,20 @@ has_staged(git_repository *repo)
|
||||||
inline unsigned
|
inline unsigned
|
||||||
numcat(unsigned x, unsigned y)
|
numcat(unsigned x, unsigned y)
|
||||||
{
|
{
|
||||||
|
PS();
|
||||||
unsigned pow = 10;
|
unsigned pow = 10;
|
||||||
while(y >= pow) {
|
while(y >= pow) {
|
||||||
pow *= 10;
|
pow *= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PE();
|
||||||
return (x * pow) + y;
|
return (x * pow) + y;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
str_to_int(char *str)
|
str_to_int(char *str)
|
||||||
{
|
{
|
||||||
|
PS();
|
||||||
int res = -1;
|
int res = -1;
|
||||||
char *c;
|
char *c;
|
||||||
|
|
||||||
|
|
@ -282,17 +293,20 @@ str_to_int(char *str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PE();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
PS();
|
||||||
int code = -1;
|
int code = -1;
|
||||||
|
|
||||||
/* print version information */
|
/* print version information */
|
||||||
if (argc > 1 && strcmp(argv[1], "-v") == 0) {
|
if (argc > 1 && strcmp(argv[1], "-v") == 0) {
|
||||||
printf("XD [number] %s\n", VERSION);
|
printf("XD [number] %s\n", VERSION);
|
||||||
|
PE();
|
||||||
return 0;
|
return 0;
|
||||||
#ifdef EXPLAIN
|
#ifdef EXPLAIN
|
||||||
} else if (argc > 1 && strcmp(argv[1], "-e") == 0) {
|
} else if (argc > 1 && strcmp(argv[1], "-e") == 0) {
|
||||||
|
|
@ -344,6 +358,7 @@ main(int argc, char *argv[])
|
||||||
code = str_to_int(argv[argc - 1]);
|
code = str_to_int(argv[argc - 1]);
|
||||||
if (code < 0) {
|
if (code < 0) {
|
||||||
L("Return code, %d, not valid", code);
|
L("Return code, %d, not valid", code);
|
||||||
|
PE();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -377,5 +392,6 @@ main(int argc, char *argv[])
|
||||||
P("|"); /* no code info */
|
P("|"); /* no code info */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PE();
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
config.mk
24
config.mk
|
|
@ -1,4 +1,4 @@
|
||||||
VERSION = `git describe --tags --abbrev=0`
|
VERSION := `git describe --tags --dirty`
|
||||||
|
|
||||||
PKG_CONFIG = pkg-config
|
PKG_CONFIG = pkg-config
|
||||||
|
|
||||||
|
|
@ -7,15 +7,21 @@ PREFIX = /usr/local
|
||||||
MANDIR = $(PREFIX)/share/man
|
MANDIR = $(PREFIX)/share/man
|
||||||
|
|
||||||
GIT =
|
GIT =
|
||||||
|
GITHASH =
|
||||||
GITLIB =
|
GITLIB =
|
||||||
# comment to disable git support
|
# comment to disable git support
|
||||||
GIT = -DGIT
|
GIT = -DGIT
|
||||||
|
GITHASH = -DGITHASH
|
||||||
GITLIB = libgit2
|
GITLIB = libgit2
|
||||||
|
|
||||||
ERR =
|
ERR =
|
||||||
# uncomment to enable errors
|
# uncomment to enable errors
|
||||||
# ERR = -DERR
|
# ERR = -DERR
|
||||||
|
|
||||||
|
PERF =
|
||||||
|
# uncomment to enable performance logging
|
||||||
|
# PERF = -DPERF
|
||||||
|
|
||||||
EXPLAIN =
|
EXPLAIN =
|
||||||
# comment to disable explinations
|
# comment to disable explinations
|
||||||
EXPLAIN = -DEXPLAIN
|
EXPLAIN = -DEXPLAIN
|
||||||
|
|
@ -24,15 +30,25 @@ EXPLAIN = -DEXPLAIN
|
||||||
ifneq ($(GIT),)
|
ifneq ($(GIT),)
|
||||||
VERSION := $(VERSION)"\\nlibgit2 "`$(PKG_CONFIG) --modversion $(GITLIB)`
|
VERSION := $(VERSION)"\\nlibgit2 "`$(PKG_CONFIG) --modversion $(GITLIB)`
|
||||||
endif
|
endif
|
||||||
ifeq ($(ERR),)
|
ifeq ($(GITHASH),)
|
||||||
VERSION := $(VERSION)"\\nerrors disabled"
|
VERSION := $(VERSION)"\\ngit hashing disabled"
|
||||||
else
|
else
|
||||||
VERSION := $(VERSION)"\\nerrors enabled"
|
VERSION := $(VERSION)"\\ngit hashing enabled"
|
||||||
endif
|
endif
|
||||||
ifeq ($(EXPLAIN),)
|
ifeq ($(EXPLAIN),)
|
||||||
VERSION := $(VERSION)"\\nexplinations disabled"
|
VERSION := $(VERSION)"\\nexplinations disabled"
|
||||||
else
|
else
|
||||||
VERSION := $(VERSION)"\\nexplinations enabled"
|
VERSION := $(VERSION)"\\nexplinations enabled"
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(ERR),)
|
||||||
|
VERSION := $(VERSION)"\\nerrors disabled"
|
||||||
|
else
|
||||||
|
VERSION := $(VERSION)"\\nerrors enabled"
|
||||||
|
endif
|
||||||
|
ifeq ($(PERF),)
|
||||||
|
VERSION := $(VERSION)"\\nperformance logging disabled"
|
||||||
|
else
|
||||||
|
VERSION := $(VERSION)"\\nperformance logging enabled"
|
||||||
|
endif
|
||||||
|
|
||||||
CC = cc
|
CC = cc
|
||||||
|
|
|
||||||
152
hash.c
Normal file
152
hash.c
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
#include <git2/repository.h>
|
||||||
|
#include <git2/types.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
|
#ifdef GITHASH
|
||||||
|
static uint64_t
|
||||||
|
murmur64(uint64_t k)
|
||||||
|
{
|
||||||
|
PS();
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= 0xff51afd7ed558ccdLLU;
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= 0xc4ceb9fe1a85ec53LLU;
|
||||||
|
k ^= k >> 33;
|
||||||
|
|
||||||
|
PE();
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
generate_hash(git_repository *repo)
|
||||||
|
{
|
||||||
|
PS();
|
||||||
|
struct stat dir, index;
|
||||||
|
char path[PATH_MAX] = { 0 };
|
||||||
|
|
||||||
|
const char *gitpath = git_repository_path(repo);
|
||||||
|
if (strlen(gitpath) + strlen("/..") > PATH_MAX - 1) {
|
||||||
|
L("strlen: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(path, gitpath);
|
||||||
|
if (stat(path, &index) < 0) {
|
||||||
|
PE();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcat(path, "/..");
|
||||||
|
if (stat(path, &dir) < 0) {
|
||||||
|
PE();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PE();
|
||||||
|
return murmur64(dir.st_mtim.tv_nsec ^ index.st_mtim.tv_nsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
repohash
|
||||||
|
*read_hash(git_repository *repo)
|
||||||
|
{
|
||||||
|
PS();
|
||||||
|
FILE *f;
|
||||||
|
uint64_t data;
|
||||||
|
uint8_t changes;
|
||||||
|
repohash *hash = malloc(sizeof(repohash));
|
||||||
|
char path[PATH_MAX] = { 0 };
|
||||||
|
|
||||||
|
const char *gitpath = git_repository_path(repo);
|
||||||
|
if (strlen(gitpath) + strlen(XD_HASH_PATH) > PATH_MAX - 1) {
|
||||||
|
L("strlen: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
strcat(path, gitpath);
|
||||||
|
strcat(path, XD_HASH_PATH);
|
||||||
|
|
||||||
|
f = fopen(path, "r");
|
||||||
|
if (!f) {
|
||||||
|
L("fopen: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(&data, sizeof(uint64_t), 1, f) != 1) {
|
||||||
|
L("fread: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(f, sizeof(uint64_t), SEEK_SET) < 0) {
|
||||||
|
L("fseek: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(&changes, sizeof(uint8_t), 1, f) != 1) {
|
||||||
|
L("fread: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
hash->hash = data;
|
||||||
|
hash->changes = changes;
|
||||||
|
PE();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
write_hash(git_repository *repo, repohash hash)
|
||||||
|
{
|
||||||
|
PS();
|
||||||
|
FILE *f;
|
||||||
|
char path[PATH_MAX] = { 0 };
|
||||||
|
|
||||||
|
const char *gitpath = git_repository_path(repo);
|
||||||
|
if (strlen(gitpath) + strlen(XD_HASH_PATH) > PATH_MAX - 1) {
|
||||||
|
L("strlen: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
strcat(path, gitpath);
|
||||||
|
strcat(path, XD_HASH_PATH);
|
||||||
|
|
||||||
|
f = fopen(path, "wb");
|
||||||
|
if (!f) {
|
||||||
|
L("fopen: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwrite(&hash.hash, sizeof(uint64_t), 1, f) != 1) {
|
||||||
|
L("fwrite: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(f, sizeof(uint64_t), SEEK_SET) < 0) {
|
||||||
|
L("fseek: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwrite(&hash.changes, sizeof(uint8_t), 1, f) != 1) {
|
||||||
|
L("fwrite: %s", strerror(errno));
|
||||||
|
PE();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
PE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
37
hash.h
Normal file
37
hash.h
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <git2/repository.h>
|
||||||
|
|
||||||
|
#ifdef GIT
|
||||||
|
typedef struct {
|
||||||
|
uint64_t hash;
|
||||||
|
bool changes;
|
||||||
|
} repohash;
|
||||||
|
|
||||||
|
#define XD_HASH_PATH "/XDhash"
|
||||||
|
/**
|
||||||
|
* @brief generate a hash from the repository state
|
||||||
|
*
|
||||||
|
* @param repo the git repository
|
||||||
|
* @return the hash
|
||||||
|
*/
|
||||||
|
uint64_t generate_hash(git_repository *repo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief read the hash from the git repo
|
||||||
|
*
|
||||||
|
* @param repo the git repository
|
||||||
|
* @return the hash
|
||||||
|
*/
|
||||||
|
repohash *read_hash(git_repository *repo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief write a new hash to the repository
|
||||||
|
*
|
||||||
|
* @param repo the repository
|
||||||
|
* @param hash the hash to write
|
||||||
|
*/
|
||||||
|
int write_hash(git_repository *repo, repohash hash);
|
||||||
|
#endif
|
||||||
28
helpers.c
Normal file
28
helpers.c
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
|
#ifdef EXPLAIN
|
||||||
|
int explain = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ERR) || defined(EXPLAIN)
|
||||||
|
void
|
||||||
|
l(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
|
||||||
|
fputc(' ', stderr);
|
||||||
|
perror(NULL);
|
||||||
|
} else {
|
||||||
|
fputc('\n', stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
28
helpers.h
Normal file
28
helpers.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(ERR) || defined(EXPLAIN)
|
||||||
|
void l(const char *fmt, ...);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ERR
|
||||||
|
#define L(...) l(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define L(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef EXPLAIN
|
||||||
|
extern int explain;
|
||||||
|
#define E(...) if (explain) { \
|
||||||
|
l(__VA_ARGS__); \
|
||||||
|
} else
|
||||||
|
#else
|
||||||
|
#define E(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PERF
|
||||||
|
#define PS() long __start = clock()
|
||||||
|
#define PE() l("%s: %fs", __func__, ((double) (clock() - __start)) / CLOCKS_PER_SEC)
|
||||||
|
#else
|
||||||
|
#define PS()
|
||||||
|
#define PE()
|
||||||
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue