Skip to content

Commit

Permalink
Merge branch 'sr/transport-helper-fix'
Browse files Browse the repository at this point in the history
* sr/transport-helper-fix: (21 commits)
  transport-helper: die early on encountering deleted refs
  transport-helper: implement marks location as capability
  transport-helper: Use capname for refspec capability too
  transport-helper: change import semantics
  transport-helper: update ref status after push with export
  transport-helper: use the new done feature where possible
  transport-helper: check status code of finish_command
  transport-helper: factor out push_update_refs_status
  fast-export: support done feature
  fast-import: introduce 'done' command
  git-remote-testgit: fix error handling
  git-remote-testgit: only push for non-local repositories
  remote-curl: accept empty line as terminator
  remote-helpers: export GIT_DIR variable to helpers
  git_remote_helpers: push all refs during a non-local export
  transport-helper: don't feed bogus refs to export push
  git-remote-testgit: import non-HEAD refs
  t5800: document some non-functional parts of remote helpers
  t5800: use skip_all instead of prereq
  t5800: factor out some ref tests
  ...
  • Loading branch information
Junio C Hamano committed Aug 1, 2011
2 parents 1df561f + 105fe3e commit 59d9ba8
Show file tree
Hide file tree
Showing 15 changed files with 475 additions and 187 deletions.
4 changes: 4 additions & 0 deletions Documentation/git-fast-export.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ marks the same across runs.
allow that. So fake a tagger to be able to fast-import the
output.

--use-done-feature::
Start the stream with a 'feature done' stanza, and terminate
it with a 'done' command.

--no-data::
Skip output of blob objects and instead refer to blobs via
their original SHA-1 hash. This is useful when rewriting the
Expand Down
25 changes: 25 additions & 0 deletions Documentation/git-fast-import.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ OPTIONS
when the `cat-blob` command is encountered in the stream.
The default behaviour is to write to `stdout`.

--done::
Require a `done` command at the end of the stream.
This option might be useful for detecting errors that
cause the frontend to terminate before it has started to
write a stream.

--export-pack-edges=<file>::
After creating a packfile, print a line of data to
<file> listing the filename of the packfile and the last
Expand Down Expand Up @@ -331,6 +337,11 @@ and control the current import process. More detailed discussion
standard output. This command is optional and is not needed
to perform an import.

`done`::
Marks the end of the stream. This command is optional
unless the `done` feature was requested using the
`--done` command line option or `feature done` command.

`cat-blob`::
Causes fast-import to print a blob in 'cat-file --batch'
format to the file descriptor set with `--cat-blob-fd` or
Expand Down Expand Up @@ -1021,6 +1032,11 @@ notes::
Versions of fast-import not supporting notes will exit
with a message indicating so.

done::
Error out if the stream ends without a 'done' command.
Without this feature, errors causing the frontend to end
abruptly at a convenient point in the stream can go
undetected.

`option`
~~~~~~~~
Expand Down Expand Up @@ -1050,6 +1066,15 @@ not be passed as option:
* cat-blob-fd
* force

`done`
~~~~~~
If the `done` feature is not in use, treated as if EOF was read.
This can be used to tell fast-import to finish early.

If the `--done` command line option or `feature done` command is
in use, the `done` command is mandatory and marks the end of the
stream.

Crash Reports
-------------
If fast-import is supplied invalid input it will terminate with a
Expand Down
3 changes: 3 additions & 0 deletions Documentation/git-remote-helpers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ arguments. The first argument specifies a remote repository as in git;
it is either the name of a configured remote or a URL. The second
argument specifies a URL; it is usually of the form
'<transport>://<address>', but any arbitrary string is possible.
The 'GIT_DIR' environment variable is set up for the remote helper
and can be used to determine where to store additional data or from
which directory to invoke auxiliary git commands.

When git encounters a URL of the form '<transport>://<address>', where
'<transport>' is a protocol that it cannot handle natively, it
Expand Down
9 changes: 9 additions & 0 deletions builtin/fast-export.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ static int progress;
static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT;
static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT;
static int fake_missing_tagger;
static int use_done_feature;
static int no_data;
static int full_tree;

Expand Down Expand Up @@ -627,6 +628,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
"Fake a tagger when tags lack one"),
OPT_BOOLEAN(0, "full-tree", &full_tree,
"Output full tree for each commit"),
OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
"Use the done feature to terminate the stream"),
{ OPTION_NEGBIT, 0, "data", &no_data, NULL,
"Skip output of blob data",
PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 },
Expand All @@ -648,6 +651,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (argc > 1)
usage_with_options (fast_export_usage, options);

if (use_done_feature)
printf("feature done\n");

if (import_filename)
import_marks(import_filename);

Expand Down Expand Up @@ -675,5 +681,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (export_filename)
export_marks(export_filename);

if (use_done_feature)
printf("done\n");

return 0;
}
8 changes: 8 additions & 0 deletions fast-import.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ static unsigned int cmd_save = 100;
static uintmax_t next_mark;
static struct strbuf new_data = STRBUF_INIT;
static int seen_data_command;
static int require_explicit_termination;

/* Signal handling */
static volatile sig_atomic_t checkpoint_requested;
Expand Down Expand Up @@ -3140,6 +3141,8 @@ static int parse_one_feature(const char *feature, int from_stream)
relative_marks_paths = 1;
} else if (!strcmp(feature, "no-relative-marks")) {
relative_marks_paths = 0;
} else if (!strcmp(feature, "done")) {
require_explicit_termination = 1;
} else if (!strcmp(feature, "force")) {
force_update = 1;
} else if (!strcmp(feature, "notes") || !strcmp(feature, "ls")) {
Expand Down Expand Up @@ -3290,6 +3293,8 @@ int main(int argc, const char **argv)
parse_reset_branch();
else if (!strcmp("checkpoint", command_buf.buf))
parse_checkpoint();
else if (!strcmp("done", command_buf.buf))
break;
else if (!prefixcmp(command_buf.buf, "progress "))
parse_progress();
else if (!prefixcmp(command_buf.buf, "feature "))
Expand All @@ -3309,6 +3314,9 @@ int main(int argc, const char **argv)
if (!seen_data_command)
parse_argv();

if (require_explicit_termination && feof(stdin))
die("stream ends early");

end_packfile();

dump_branches();
Expand Down
62 changes: 35 additions & 27 deletions git-remote-testgit.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def get_repo(alias, url):
prefix = 'refs/testgit/%s/' % alias
debug("prefix: '%s'", prefix)

repo.gitdir = ""
repo.gitdir = os.environ["GIT_DIR"]
repo.alias = alias
repo.prefix = prefix

Expand Down Expand Up @@ -70,9 +70,19 @@ def do_capabilities(repo, args):

print "import"
print "export"
print "gitdir"
print "refspec refs/heads/*:%s*" % repo.prefix

dirname = repo.get_base_path(repo.gitdir)

if not os.path.exists(dirname):
os.makedirs(dirname)

path = os.path.join(dirname, 'testgit.marks')

print "*export-marks %s" % path
if os.path.exists(path):
print "*import-marks %s" % path

print # end capabilities


Expand Down Expand Up @@ -121,8 +131,24 @@ def do_import(repo, args):
if not repo.gitdir:
die("Need gitdir to import")

ref = args[0]
refs = [ref]

while True:
line = sys.stdin.readline()
if line == '\n':
break
if not line.startswith('import '):
die("Expected import line.")

# strip of leading 'import '
ref = line[7:].strip()
refs.append(ref)

repo = update_local_repo(repo)
repo.exporter.export_repo(repo.gitdir)
repo.exporter.export_repo(repo.gitdir, refs)

print "done"


def do_export(repo, args):
Expand All @@ -132,40 +158,22 @@ def do_export(repo, args):
if not repo.gitdir:
die("Need gitdir to export")

dirname = repo.get_base_path(repo.gitdir)

if not os.path.exists(dirname):
os.makedirs(dirname)

path = os.path.join(dirname, 'testgit.marks')
print path
if os.path.exists(path):
print path
else:
print ""
sys.stdout.flush()

update_local_repo(repo)
repo.importer.do_import(repo.gitdir)
repo.non_local.push(repo.gitdir)


def do_gitdir(repo, args):
"""Stores the location of the gitdir.
"""
changed = repo.importer.do_import(repo.gitdir)

if not args:
die("gitdir needs an argument")
if not repo.local:
repo.non_local.push(repo.gitdir)

repo.gitdir = ' '.join(args)
for ref in changed:
print "ok %s" % ref
print


COMMANDS = {
'capabilities': do_capabilities,
'list': do_list,
'import': do_import,
'export': do_export,
'gitdir': do_gitdir,
}


Expand Down
15 changes: 10 additions & 5 deletions git_remote_helpers/git/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import subprocess
import sys

from git_remote_helpers.util import check_call


class GitExporter(object):
"""An exporter for testgit repositories.
Expand All @@ -15,16 +17,21 @@ def __init__(self, repo):

self.repo = repo

def export_repo(self, base):
def export_repo(self, base, refs=None):
"""Exports a fast-export stream for the given directory.
Simply delegates to git fast-epxort and pipes it through sed
to make the refs show up under the prefix rather than the
default refs/heads. This is to demonstrate how the export
data can be stored under it's own ref (using the refspec
capability).
If None, refs defaults to ["HEAD"].
"""

if not refs:
refs = ["HEAD"]

dirname = self.repo.get_base_path(base)
path = os.path.abspath(os.path.join(dirname, 'testgit.marks'))

Expand All @@ -42,12 +49,10 @@ def export_repo(self, base):
if os.path.exists(path):
args.append("--import-marks=" + path)

args.append("HEAD")
args.extend(refs)

p1 = subprocess.Popen(args, stdout=subprocess.PIPE)

args = ["sed", "s_refs/heads/_" + self.repo.prefix + "_g"]

child = subprocess.Popen(args, stdin=p1.stdout)
if child.wait() != 0:
raise CalledProcessError
check_call(args, stdin=p1.stdout)
32 changes: 29 additions & 3 deletions git_remote_helpers/git/importer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import os
import subprocess

from git_remote_helpers.util import check_call, check_output


class GitImporter(object):
"""An importer for testgit repositories.
Expand All @@ -14,6 +16,18 @@ def __init__(self, repo):

self.repo = repo

def get_refs(self, gitdir):
"""Returns a dictionary with refs.
"""
args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
lines = check_output(args).strip().split('\n')
refs = {}
for line in lines:
value, name = line.split(' ')
name = name.strip('commit\t')
refs[name] = value
return refs

def do_import(self, base):
"""Imports a fast-import stream to the given directory.
Expand All @@ -30,11 +44,23 @@ def do_import(self, base):
if not os.path.exists(dirname):
os.makedirs(dirname)

refs_before = self.get_refs(gitdir)

args = ["git", "--git-dir=" + gitdir, "fast-import", "--quiet", "--export-marks=" + path]

if os.path.exists(path):
args.append("--import-marks=" + path)

child = subprocess.Popen(args)
if child.wait() != 0:
raise CalledProcessError
check_call(args)

refs_after = self.get_refs(gitdir)

changed = {}

for name, value in refs_after.iteritems():
if refs_before.get(name) == value:
continue

changed[name] = value

return changed
20 changes: 6 additions & 14 deletions git_remote_helpers/git/non_local.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import subprocess

from git_remote_helpers.util import die, warn
from git_remote_helpers.util import check_call, die, warn


class NonLocalGit(object):
Expand Down Expand Up @@ -29,9 +29,7 @@ def clone(self, base):
os.makedirs(path)
args = ["git", "clone", "--bare", "--quiet", self.repo.gitpath, path]

child = subprocess.Popen(args)
if child.wait() != 0:
raise CalledProcessError
check_call(args)

return path

Expand All @@ -45,14 +43,10 @@ def update(self, base):
die("could not find repo at %s", path)

args = ["git", "--git-dir=" + path, "fetch", "--quiet", self.repo.gitpath]
child = subprocess.Popen(args)
if child.wait() != 0:
raise CalledProcessError
check_call(args)

args = ["git", "--git-dir=" + path, "update-ref", "refs/heads/master", "FETCH_HEAD"]
child = subprocess.Popen(args)
if child.wait() != 0:
raise CalledProcessError
child = check_call(args)

def push(self, base):
"""Pushes from the non-local repo to base.
Expand All @@ -63,7 +57,5 @@ def push(self, base):
if not os.path.exists(path):
die("could not find repo at %s", path)

args = ["git", "--git-dir=" + path, "push", "--quiet", self.repo.gitpath]
child = subprocess.Popen(args)
if child.wait() != 0:
raise CalledProcessError
args = ["git", "--git-dir=" + path, "push", "--quiet", self.repo.gitpath, "--all"]
child = check_call(args)
Loading

0 comments on commit 59d9ba8

Please sign in to comment.