Junio C Hamano
19 years ago
46 changed files with 895 additions and 257 deletions
@ -0,0 +1,295 @@
@@ -0,0 +1,295 @@
|
||||
#include <stdio.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <dirent.h> |
||||
#include <unistd.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
#include <limits.h> |
||||
#include <stdarg.h> |
||||
|
||||
#ifndef PATH_MAX |
||||
# define PATH_MAX 4096 |
||||
#endif |
||||
|
||||
static const char git_usage[] = |
||||
"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; |
||||
|
||||
/* most gui terms set COLUMNS (although some don't export it) */ |
||||
static int term_columns(void) |
||||
{ |
||||
char *col_string = getenv("COLUMNS"); |
||||
int n_cols = 0; |
||||
|
||||
if (col_string && (n_cols = atoi(col_string)) > 0) |
||||
return n_cols; |
||||
|
||||
return 80; |
||||
} |
||||
|
||||
static void oom(void) |
||||
{ |
||||
fprintf(stderr, "git: out of memory\n"); |
||||
exit(1); |
||||
} |
||||
|
||||
static inline void mput_char(char c, unsigned int num) |
||||
{ |
||||
while(num--) |
||||
putchar(c); |
||||
} |
||||
|
||||
static struct cmdname { |
||||
size_t len; |
||||
char name[1]; |
||||
} **cmdname; |
||||
static int cmdname_alloc, cmdname_cnt; |
||||
|
||||
static void add_cmdname(const char *name, int len) |
||||
{ |
||||
struct cmdname *ent; |
||||
if (cmdname_alloc <= cmdname_cnt) { |
||||
cmdname_alloc = cmdname_alloc + 200; |
||||
cmdname = realloc(cmdname, cmdname_alloc * sizeof(*cmdname)); |
||||
if (!cmdname) |
||||
oom(); |
||||
} |
||||
ent = malloc(sizeof(*ent) + len); |
||||
if (!ent) |
||||
oom(); |
||||
ent->len = len; |
||||
memcpy(ent->name, name, len+1); |
||||
cmdname[cmdname_cnt++] = ent; |
||||
} |
||||
|
||||
static int cmdname_compare(const void *a_, const void *b_) |
||||
{ |
||||
struct cmdname *a = *(struct cmdname **)a_; |
||||
struct cmdname *b = *(struct cmdname **)b_; |
||||
return strcmp(a->name, b->name); |
||||
} |
||||
|
||||
static void pretty_print_string_list(struct cmdname **cmdname, int longest) |
||||
{ |
||||
int cols = 1; |
||||
int space = longest + 1; /* min 1 SP between words */ |
||||
int max_cols = term_columns() - 1; /* don't print *on* the edge */ |
||||
int i; |
||||
|
||||
if (space < max_cols) |
||||
cols = max_cols / space; |
||||
|
||||
qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare); |
||||
|
||||
for (i = 0; i < cmdname_cnt; ) { |
||||
int c; |
||||
printf(" "); |
||||
|
||||
for (c = cols; c && i < cmdname_cnt; i++) { |
||||
printf("%s", cmdname[i]->name); |
||||
|
||||
if (--c) |
||||
mput_char(' ', space - cmdname[i]->len); |
||||
} |
||||
putchar('\n'); |
||||
} |
||||
} |
||||
|
||||
static void list_commands(const char *exec_path, const char *pattern) |
||||
{ |
||||
unsigned int longest = 0; |
||||
char path[PATH_MAX]; |
||||
int dirlen; |
||||
DIR *dir = opendir(exec_path); |
||||
struct dirent *de; |
||||
|
||||
if (!dir) { |
||||
fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno)); |
||||
exit(1); |
||||
} |
||||
|
||||
dirlen = strlen(exec_path); |
||||
if (PATH_MAX - 20 < dirlen) { |
||||
fprintf(stderr, "git: insanely long exec-path '%s'\n", |
||||
exec_path); |
||||
exit(1); |
||||
} |
||||
|
||||
memcpy(path, exec_path, dirlen); |
||||
path[dirlen++] = '/'; |
||||
|
||||
while ((de = readdir(dir)) != NULL) { |
||||
struct stat st; |
||||
int entlen; |
||||
|
||||
if (strncmp(de->d_name, "git-", 4)) |
||||
continue; |
||||
strcpy(path+dirlen, de->d_name); |
||||
if (stat(path, &st) || /* stat, not lstat */ |
||||
!S_ISREG(st.st_mode) || |
||||
!(st.st_mode & S_IXUSR)) |
||||
continue; |
||||
|
||||
entlen = strlen(de->d_name); |
||||
|
||||
if (longest < entlen) |
||||
longest = entlen; |
||||
|
||||
add_cmdname(de->d_name + 4, entlen-4); |
||||
} |
||||
closedir(dir); |
||||
|
||||
printf("git commands available in '%s'\n", exec_path); |
||||
printf("----------------------------"); |
||||
mput_char('-', strlen(exec_path)); |
||||
putchar('\n'); |
||||
pretty_print_string_list(cmdname, longest - 4); |
||||
putchar('\n'); |
||||
} |
||||
|
||||
#ifdef __GNUC__ |
||||
static void usage(const char *exec_path, const char *fmt, ...) |
||||
__attribute__((__format__(__printf__, 2, 3), __noreturn__)); |
||||
#endif |
||||
static void usage(const char *exec_path, const char *fmt, ...) |
||||
{ |
||||
if (fmt) { |
||||
va_list ap; |
||||
|
||||
va_start(ap, fmt); |
||||
printf("git: "); |
||||
vprintf(fmt, ap); |
||||
va_end(ap); |
||||
putchar('\n'); |
||||
} |
||||
else |
||||
puts(git_usage); |
||||
|
||||
putchar('\n'); |
||||
|
||||
if(exec_path) |
||||
list_commands(exec_path, "git-*"); |
||||
|
||||
exit(1); |
||||
} |
||||
|
||||
static void prepend_to_path(const char *dir, int len) |
||||
{ |
||||
char *path, *old_path = getenv("PATH"); |
||||
int path_len = len; |
||||
|
||||
if (!old_path) |
||||
old_path = "/usr/local/bin:/usr/bin:/bin"; |
||||
|
||||
path_len = len + strlen(old_path) + 1; |
||||
|
||||
path = malloc(path_len + 1); |
||||
path[path_len + 1] = '\0'; |
||||
|
||||
memcpy(path, dir, len); |
||||
path[len] = ':'; |
||||
memcpy(path + len + 1, old_path, path_len - len); |
||||
|
||||
setenv("PATH", path, 1); |
||||
} |
||||
|
||||
static void show_man_page(char *git_cmd) |
||||
{ |
||||
char *page; |
||||
|
||||
if (!strncmp(git_cmd, "git", 3)) |
||||
page = git_cmd; |
||||
else { |
||||
int page_len = strlen(git_cmd) + 4; |
||||
|
||||
page = malloc(page_len + 1); |
||||
strcpy(page, "git-"); |
||||
strcpy(page + 4, git_cmd); |
||||
page[page_len] = 0; |
||||
} |
||||
|
||||
execlp("man", "man", page, NULL); |
||||
} |
||||
|
||||
int main(int argc, char **argv, char **envp) |
||||
{ |
||||
char git_command[PATH_MAX + 1]; |
||||
char wd[PATH_MAX + 1]; |
||||
int i, len, show_help = 0; |
||||
char *exec_path = getenv("GIT_EXEC_PATH"); |
||||
|
||||
getcwd(wd, PATH_MAX); |
||||
|
||||
if (!exec_path) |
||||
exec_path = GIT_EXEC_PATH; |
||||
|
||||
for (i = 1; i < argc; i++) { |
||||
char *arg = argv[i]; |
||||
|
||||
if (strncmp(arg, "--", 2)) |
||||
break; |
||||
|
||||
arg += 2; |
||||
|
||||
if (!strncmp(arg, "exec-path", 9)) { |
||||
arg += 9; |
||||
if (*arg == '=') |
||||
exec_path = arg + 1; |
||||
else { |
||||
puts(exec_path); |
||||
exit(0); |
||||
} |
||||
} |
||||
else if (!strcmp(arg, "version")) { |
||||
printf("git version %s\n", GIT_VERSION); |
||||
exit(0); |
||||
} |
||||
else if (!strcmp(arg, "help")) |
||||
show_help = 1; |
||||
else if (!show_help) |
||||
usage(NULL, NULL); |
||||
} |
||||
|
||||
if (i >= argc || show_help) { |
||||
if (i >= argc) |
||||
usage(exec_path, NULL); |
||||
|
||||
show_man_page(argv[i]); |
||||
} |
||||
|
||||
if (*exec_path != '/') { |
||||
if (!getcwd(git_command, sizeof(git_command))) { |
||||
fprintf(stderr, |
||||
"git: cannot determine current directory"); |
||||
exit(1); |
||||
} |
||||
len = strlen(git_command); |
||||
|
||||
/* Trivial cleanup */ |
||||
while (!strncmp(exec_path, "./", 2)) { |
||||
exec_path += 2; |
||||
while (*exec_path == '/') |
||||
*exec_path++; |
||||
} |
||||
snprintf(git_command + len, sizeof(git_command) - len, |
||||
"/%s", exec_path); |
||||
} |
||||
else |
||||
strcpy(git_command, exec_path); |
||||
len = strlen(git_command); |
||||
prepend_to_path(git_command, len); |
||||
|
||||
strncat(&git_command[len], "/git-", sizeof(git_command) - len); |
||||
len += 5; |
||||
strncat(&git_command[len], argv[i], sizeof(git_command) - len); |
||||
|
||||
if (access(git_command, X_OK)) |
||||
usage(exec_path, "'%s' is not a git-command", argv[i]); |
||||
|
||||
/* execve() can only ever return if it fails */ |
||||
execve(git_command, &argv[i], envp); |
||||
printf("Failed to run command '%s': %s\n", git_command, strerror(errno)); |
||||
|
||||
return 1; |
||||
} |
@ -1,76 +0,0 @@
@@ -1,76 +0,0 @@
|
||||
#!/bin/sh |
||||
|
||||
cmd= |
||||
path=$(dirname "$0") |
||||
case "$#" in |
||||
0) ;; |
||||
*) cmd="$1" |
||||
shift |
||||
case "$cmd" in |
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version) |
||||
echo "git version @@GIT_VERSION@@" |
||||
exit 0 ;; |
||||
esac |
||||
|
||||
test -x "$path/git-$cmd" && exec "$path/git-$cmd" "$@" |
||||
|
||||
case '@@X@@' in |
||||
'') |
||||
;; |
||||
*) |
||||
test -x "$path/git-$cmd@@X@@" && |
||||
exec "$path/git-$cmd@@X@@" "$@" |
||||
;; |
||||
esac |
||||
;; |
||||
esac |
||||
|
||||
echo "Usage: git COMMAND [OPTIONS] [TARGET]" |
||||
if [ -n "$cmd" ]; then |
||||
echo "git command '$cmd' not found." |
||||
fi |
||||
echo "git commands are:" |
||||
|
||||
fmt <<\EOF | sed -e 's/^/ /' |
||||
add |
||||
apply |
||||
archimport |
||||
bisect |
||||
branch |
||||
checkout |
||||
cherry |
||||
clone |
||||
commit |
||||
count-objects |
||||
cvsimport |
||||
diff |
||||
fetch |
||||
format-patch |
||||
fsck-objects |
||||
get-tar-commit-id |
||||
init-db |
||||
log |
||||
ls-remote |
||||
octopus |
||||
pack-objects |
||||
parse-remote |
||||
patch-id |
||||
prune |
||||
pull |
||||
push |
||||
rebase |
||||
relink |
||||
rename |
||||
repack |
||||
request-pull |
||||
reset |
||||
resolve |
||||
revert |
||||
send-email |
||||
shortlog |
||||
show-branch |
||||
status |
||||
tag |
||||
verify-tag |
||||
whatchanged |
||||
EOF |
@ -0,0 +1,115 @@
@@ -0,0 +1,115 @@
|
||||
#!/bin/sh |
||||
# |
||||
# Copyright (c) 2005 Junio C Hamano |
||||
# |
||||
|
||||
test_description='git-apply handling binary patches |
||||
|
||||
' |
||||
. ./test-lib.sh |
||||
|
||||
# setup |
||||
|
||||
cat >file1 <<EOF |
||||
A quick brown fox jumps over the lazy dog. |
||||
A tiny little penguin runs around in circles. |
||||
There is a flag with Linux written on it. |
||||
A slow black-and-white panda just sits there, |
||||
munching on his bamboo. |
||||
EOF |
||||
cat file1 >file2 |
||||
cat file1 >file4 |
||||
|
||||
git-update-index --add --remove file1 file2 file4 |
||||
git-commit -m 'Initial Version' 2>/dev/null |
||||
|
||||
git-checkout -b binary |
||||
tr 'x' '\0' <file1 >file3 |
||||
cat file3 >file4 |
||||
git-add file2 |
||||
tr '\0' 'v' <file3 >file1 |
||||
rm -f file2 |
||||
git-update-index --add --remove file1 file2 file3 file4 |
||||
git-commit -m 'Second Version' |
||||
|
||||
git-diff-tree -p master binary >B.diff |
||||
git-diff-tree -p -C master binary >C.diff |
||||
|
||||
git-diff-tree -p --full-index master binary >BF.diff |
||||
git-diff-tree -p --full-index -C master binary >CF.diff |
||||
|
||||
test_expect_success 'stat binary diff -- should not fail.' \ |
||||
'git-checkout master |
||||
git-apply --stat --summary B.diff' |
||||
|
||||
test_expect_success 'stat binary diff (copy) -- should not fail.' \ |
||||
'git-checkout master |
||||
git-apply --stat --summary C.diff' |
||||
|
||||
test_expect_failure 'check binary diff -- should fail.' \ |
||||
'git-checkout master |
||||
git-apply --check B.diff' |
||||
|
||||
test_expect_failure 'check binary diff (copy) -- should fail.' \ |
||||
'git-checkout master |
||||
git-apply --check C.diff' |
||||
|
||||
test_expect_failure 'check incomplete binary diff with replacement -- should fail.' \ |
||||
'git-checkout master |
||||
git-apply --check --allow-binary-replacement B.diff' |
||||
|
||||
test_expect_failure 'check incomplete binary diff with replacement (copy) -- should fail.' \ |
||||
'git-checkout master |
||||
git-apply --check --allow-binary-replacement C.diff' |
||||
|
||||
test_expect_success 'check binary diff with replacement.' \ |
||||
'git-checkout master |
||||
git-apply --check --allow-binary-replacement BF.diff' |
||||
|
||||
test_expect_success 'check binary diff with replacement (copy).' \ |
||||
'git-checkout master |
||||
git-apply --check --allow-binary-replacement CF.diff' |
||||
|
||||
# Now we start applying them. |
||||
|
||||
do_reset () { |
||||
rm -f file? |
||||
git-reset --hard |
||||
git-checkout -f master |
||||
} |
||||
|
||||
test_expect_failure 'apply binary diff -- should fail.' \ |
||||
'do_reset |
||||
git-apply B.diff' |
||||
|
||||
test_expect_failure 'apply binary diff -- should fail.' \ |
||||
'do_reset |
||||
git-apply --index B.diff' |
||||
|
||||
test_expect_failure 'apply binary diff (copy) -- should fail.' \ |
||||
'do_reset |
||||
git-apply C.diff' |
||||
|
||||
test_expect_failure 'apply binary diff (copy) -- should fail.' \ |
||||
'do_reset |
||||
git-apply --index C.diff' |
||||
|
||||
test_expect_failure 'apply binary diff without replacement -- should fail.' \ |
||||
'do_reset |
||||
git-apply BF.diff' |
||||
|
||||
test_expect_failure 'apply binary diff without replacement (copy) -- should fail.' \ |
||||
'do_reset |
||||
git-apply CF.diff' |
||||
|
||||
test_expect_success 'apply binary diff.' \ |
||||
'do_reset |
||||
git-apply --allow-binary-replacement --index BF.diff && |
||||
test -z "$(git-diff --name-status binary)"' |
||||
|
||||
test_expect_success 'apply binary diff (copy).' \ |
||||
'do_reset |
||||
git-apply --allow-binary-replacement --index CF.diff && |
||||
test -z "$(git-diff --name-status binary)"' |
||||
|
||||
test_done |
Loading…
Reference in new issue