Browse Source
Implement fetching from a packed repository over http/https using the dumb server support files. I consider some parts of the logic should be in a separate C program, but it appears to work with my simple tests. I have backburnered it for a bit too long for my liking, so let's throw it out in the open and see what happens. Signed-off-by: Junio C Hamano <junkio@cox.net>maint
Junio C Hamano
20 years ago
4 changed files with 188 additions and 4 deletions
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
#!/bin/sh |
||||
# |
||||
# Copyright (c) 2005, Junio C Hamano |
||||
# |
||||
# Called by git-fetch-script |
||||
# Exits 2 when the remote site does not support dumb server protocol. |
||||
|
||||
# Usage: git-fetch-dumb-http <head-SHA1> <repo> [ <head> | tag <tag> ] |
||||
|
||||
. git-sh-setup-script || die "Not a git archive" |
||||
head="$1" |
||||
shift |
||||
. git-parse-remote "$@" |
||||
|
||||
merge_repo="$_remote_repo" |
||||
merge_head="$_remote_head" |
||||
merge_store="$_remote_store" |
||||
|
||||
if [ -n "$GIT_SSL_NO_VERIFY" ]; then |
||||
curl_extra_args="-k" |
||||
fi |
||||
http_fetch () { |
||||
# $1 = Remote, $2 = Local |
||||
curl -ns $curl_extra_args "$1" >"$2" |
||||
} |
||||
|
||||
# Try dumb server protocol |
||||
|
||||
clone_tmp=".git/clone-tmp$$" && |
||||
mkdir -p "$clone_tmp" || exit 1 |
||||
trap "rm -rf $clone_tmp" 0 1 2 3 15 |
||||
http_fetch "$merge_repo/info/refs" "$clone_tmp/refs" && |
||||
http_fetch "$merge_repo/objects/info/packs" "$clone_tmp/packs" && |
||||
http_fetch "$merge_repo/info/rev-cache" "$clone_tmp/rev-cache" || exit 2 |
||||
|
||||
# Which packs are we interested in? |
||||
has_missing=, |
||||
while read tag num sha1 type |
||||
do |
||||
case "$tag" in |
||||
T) ;; |
||||
*) continue ;; |
||||
esac |
||||
git-cat-file -t "$sha1" >/dev/null || has_missing="$has_missing$num," |
||||
done <$clone_tmp/packs |
||||
|
||||
# Slurp the pack index we do not have all objects for. |
||||
pack_ix=0 |
||||
may_want_pack_count=0 |
||||
while read tag pack |
||||
do |
||||
case "$tag" in |
||||
P) ;; |
||||
*) break ;; # P records always come first. |
||||
esac |
||||
case "$has_missing" in |
||||
*",$pack_ix,"*) |
||||
name=`expr "$pack" : '\(.*\)\.pack$'` && |
||||
idx="$name.idx" && |
||||
http_fetch "$merge_repo/objects/pack/$idx" "$clone_tmp/$idx" && |
||||
# Note that idx file is sorted --- otherwise we need to sort it here. |
||||
git-show-index <"$clone_tmp/$idx" | |
||||
sed -e 's/^[^ ]* //' >"$clone_tmp/$name.toc" || |
||||
exit 1 |
||||
may_want_pack_count=`expr "$may_want_pack_count" + 1` |
||||
;; |
||||
esac |
||||
pack_ix=`expr "$pack_ix" + 1` |
||||
done <$clone_tmp/packs |
||||
|
||||
case "$may_want_pack_count" in |
||||
0) |
||||
exit 0 ;; |
||||
esac |
||||
|
||||
# We want $head. What are the head objects we are missing? |
||||
git-missing-revs $clone_tmp/rev-cache $head >$clone_tmp/missing-revs && |
||||
sort -o $clone_tmp/missing-revs $clone_tmp/missing-revs || exit 2 |
||||
|
||||
for toc in $clone_tmp/*.toc |
||||
do |
||||
name=`expr $toc : '.*/\([^/]*\)\.toc'` && |
||||
comm -12 $clone_tmp/missing-revs $toc >$clone_tmp/$name.can |
||||
# FIXME: this is stupid. |
||||
if test -s $clone_tmp/$name.can |
||||
then |
||||
pack="$name.pack" idx="$name.idx" && |
||||
http_fetch "$merge_repo/objects/pack/$pack" "$clone_tmp/$pack" && |
||||
git-verify-pack "$clone_tmp/$pack" && |
||||
mkdir -p "$GIT_OBJECT_DIRECTORY/pack" && |
||||
mv "$clone_tmp/$pack" "$clone_tmp/$idx" \ |
||||
"$GIT_OBJECT_DIRECTORY/pack/" || { |
||||
# remote may just have a stale dumb server information files. |
||||
# and normal pull might succeed. |
||||
exit 2 |
||||
} |
||||
fi |
||||
done |
||||
|
||||
exit 0 |
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
#include "cache.h" |
||||
#include "rev-cache.h" |
||||
|
||||
static const char missing_revs_usage[] = |
||||
"git-missing-revs <rev-cache-file> <want-sha1>..."; |
||||
|
||||
#define REV_WANT 01 |
||||
#define REV_HAVE 02 |
||||
|
||||
static void process(struct rev_cache *head_list) |
||||
{ |
||||
while (head_list) { |
||||
struct rev_cache *rc = head_list; |
||||
struct rev_list_elem *e; |
||||
head_list = rc->head_list; |
||||
rc->head_list = NULL; |
||||
if (has_sha1_file(rc->sha1)) { |
||||
rc->work |= REV_HAVE; |
||||
continue; |
||||
} |
||||
if (rc->work & (REV_WANT|REV_HAVE)) |
||||
continue; |
||||
rc->work |= REV_WANT; |
||||
printf("%s\n", sha1_to_hex(rc->sha1)); |
||||
for (e = rc->parents; e; e = e->next) { |
||||
if (e->ri->work & REV_HAVE) |
||||
continue; |
||||
e->ri->head_list = head_list; |
||||
head_list = e->ri; |
||||
} |
||||
} |
||||
} |
||||
|
||||
int main(int ac, char **av) |
||||
{ |
||||
const char *rev_cache_file; |
||||
struct rev_cache *head_list = NULL; |
||||
int i; |
||||
|
||||
if (ac < 3) |
||||
usage(missing_revs_usage); |
||||
rev_cache_file = av[1]; |
||||
read_rev_cache(rev_cache_file, NULL, 0); |
||||
for (i = 2; i < ac; i++) { |
||||
unsigned char sha1[20]; |
||||
int pos; |
||||
struct rev_cache *rc; |
||||
if (get_sha1_hex(av[i], sha1)) |
||||
die("%s: not an SHA1", av[i]); |
||||
if ((pos = find_rev_cache(sha1)) < 0) { |
||||
/* We could be asked for tags, which would not |
||||
* appear in the rev-cache. |
||||
*/ |
||||
puts(av[i]); |
||||
continue; |
||||
} |
||||
rc = rev_cache[pos]; |
||||
rc->head_list = head_list; |
||||
head_list = rc; |
||||
} |
||||
process(head_list); |
||||
return 0; |
||||
} |
Loading…
Reference in new issue