Skip to content

Commit

Permalink
Add indirect branch tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
toddlipcon committed Sep 21, 2009
1 parent 5e27618 commit 8ad4d51
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 8 deletions.
65 changes: 62 additions & 3 deletions crepo.py
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python2.5 #!/usr/bin/env python2.5
# (c) Copyright 2009 Cloudera, Inc. # (c) Copyright 2009 Cloudera, Inc.

from __future__ import with_statement
from contextlib import closing
import os import os
import sys import sys
import optparse import optparse
Expand Down Expand Up @@ -317,8 +318,65 @@ def dump_refs(args):
"origin/" + repo.current_branch(), "origin/" + repo.current_branch(),
indent=2) indent=2)
check_dirty_repo(repo, indent=2) check_dirty_repo(repo, indent=2)



def update_indirect(args):
"""
Change track-indirect projects to point to what you've got them pointed at.
"""
man = load_manifest()


# parse args
force = False
for arg in args:
if arg == "-f":
force = True

# Some markers so we can output status at the end
saw_indirects = False # are there any indirect tracks?
possible_actions = False # were there any where we could take action?

# Come up with the list of indirect projects we might want to twiddle
for project in man.projects.itervalues():
if not isinstance(project.tracker, manifest.TrackIndirect):
continue
saw_indirects = True
repo = project.git_repo
tracker = project.tracker
(left, right) = project.tracking_status

# If we're pointed at what we're supposed to, skip
if left == 0 and right == 0:
continue

possible_actions = True
print "Project %s:" % project.name
print " Indirect file: %s" % tracker.indirection_file
print
project_status(project, indent=2)

cur_revision = repo.rev_parse("HEAD")

# We are strictly ahead of where we should be
if left > 0 and right == 0:
if not force:
print
print "Do you want to update this project to the currently checked out revision?"
print " (revision %s)" % cur_revision
print " (Y/n): ",
sys.stdout.flush()
res = sys.stdin.readline().rstrip().lower()
if res != 'y' and res != '':
continue

with closing(file(tracker.indirection_file, "w")) as f:
print >>f, cur_revision
print "Updated"

if not saw_indirects:
print "No indirect projects!"
elif not possible_actions:
print "All indirect projects are up to date!"


COMMANDS = { COMMANDS = {
'help': help, 'help': help,
Expand All @@ -332,7 +390,8 @@ def dump_refs(args):
'status': status, 'status': status,
'check-dirty': check_dirty, 'check-dirty': check_dirty,
'setup-remotes': ensure_remotes, 'setup-remotes': ensure_remotes,
'dump-refs': dump_refs 'dump-refs': dump_refs,
'update-indirect': update_indirect,
} }


def usage(): def usage():
Expand Down
73 changes: 68 additions & 5 deletions manifest.py
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/usr/bin/env python2.5 #!/usr/bin/env python2.5
# (c) Copyright 2009 Cloudera, Inc. # (c) Copyright 2009 Cloudera, Inc.
from __future__ import with_statement

from contextlib import closing
import logging import logging
import os import os
import simplejson import simplejson
Expand Down Expand Up @@ -52,6 +55,41 @@ def add_project(self, project):
self.projects[project.name] = project self.projects[project.name] = project




class IndirectionDb(object):
# KILL ME?
OPEN_DBS = {}

def __init__(self, path):
self.path = path

for line in file(path).xreadlines():
line = line.rstrip()
key, val = line.split('=', 1)
self.data[key] = val

def dump_to(self, path):
with closing(file(path, "w")) as f:
for key, val in sorted(self.data.iteritems()):
print >>f, "%s=%s\n" % (key, val)

def get_indirection(self, key):
return self.data.get(key)

def set_indirection(self, key, val):
self.data[key] = val

@classmethod
def load(cls, path):
path = os.path.abspath(path)
if path in cls.OPEN_DBS:
return cls.OPEN_DBS[path]
else:
db = IndirectionDb(path)
cls.OPEN_DBS[path] = db
return db



class Remote(object): class Remote(object):
def __init__(self, def __init__(self,
fetch): fetch):
Expand Down Expand Up @@ -99,6 +137,7 @@ def tracking_status(self, repo):
def create_tracking_branch(self, repo): def create_tracking_branch(self, repo):
repo.command(["branch", "crepo", self.hash]) repo.command(["branch", "crepo", self.hash])



class TrackTag(object): class TrackTag(object):
def __init__(self, tag): def __init__(self, tag):
self.tag = tag self.tag = tag
Expand All @@ -119,6 +158,27 @@ def create_tracking_branch(self, repo):
repo.command(["branch", self.tag, self.remote_ref]) repo.command(["branch", self.tag, self.remote_ref])




class TrackIndirect(object):
def __init__(self, indirection_file):
self.indirection_file = os.path.abspath(indirection_file)

@property
def tracking_branch(self):
return "crepo"

@property
def remote_ref(self):
return file(self.indirection_file).read().strip()

def tracking_status(self, repo):
return repo.tracking_status(
self.tracking_branch, self.remote_ref)

def create_tracking_branch(self, repo):
repo.command(["branch", self.tracking_branch, self.remote_ref])



class Project(object): class Project(object):
def __init__(self, def __init__(self,
name=None, name=None,
Expand Down Expand Up @@ -159,31 +219,34 @@ def from_dict(manifest, name, data):
track_tag = data.get('track-tag') track_tag = data.get('track-tag')
track_branch = data.get('track-branch') track_branch = data.get('track-branch')
track_hash = data.get('track-hash') track_hash = data.get('track-hash')
track_indirect = data.get('track-indirect')


if len(filter(None, [track_tag, track_branch, track_hash])) > 1: if len(filter(None, [track_tag, track_branch, track_hash, track_indirect])) > 1:
raise Exception( raise Exception(
"Cannot specify more than one of track-branch, track-tag, " + "Cannot specify more than one of track-branch, track-tag, " +
"or track-hash for project %s" % name) "track-hash, or track-indirect for project %s" % name)


# This is old and deprecated # This is old and deprecated
ref = data.get('refspec') ref = data.get('refspec')
if not track_tag and not track_branch and not track_hash: if not track_tag and not track_branch and not track_hash and not track_indirect:
if ref: if ref:
logging.warn("'ref' is deprecated - use either track-branch or track-tag " + logging.warn("'ref' is deprecated - use either track-branch or track-tag " +
"for project %s" % name) "for project %s" % name)
track_branch = ref track_branch = ref
else: else:
track_branch = "master" track_branch = "master"

if track_tag: if track_tag:
tracker = TrackTag(track_tag) tracker = TrackTag(track_tag)
elif track_branch: elif track_branch:
tracker = TrackBranch(from_remote, track_branch) tracker = TrackBranch(from_remote, track_branch)
elif track_hash: elif track_hash:
tracker = TrackHash(track_hash) tracker = TrackHash(track_hash)
elif track_indirect:
tracker = TrackIndirect(track_indirect)
else: else:
assert False and "Cannot get here!" assert False and "Cannot get here!"



return Project(name=name, return Project(name=name,
manifest=manifest, manifest=manifest,
Expand Down
69 changes: 69 additions & 0 deletions shell-tests/follow_indirect.sh
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/bin/bash -x

set -e

BINDIR=$(readlink -f $(dirname $0))
CREPO=$BINDIR/../crepo.py

TESTDIR=${TESTDIR:-/tmp/follow_indirect.$$}
mkdir -p $TESTDIR
cd $TESTDIR


################
# REPO A
################
mkdir repo_a
pushd repo_a
git init
echo "First commit" > file_a
git add . && git commit -a -m '1'

echo "Second commit" > file_b
git add . && git commit -a -m '2'
git tag commit_b

echo "Third commit" >> file_a
git add . && git commit -a -m '3'
COMMIT_C_HASH=$(git rev-parse HEAD)
REPO_A=`pwd`

popd

##############
# Run crepo in a new dir
##############
mkdir tests
pushd tests

cat > manifest.json <<EOF
{
"remotes":
{"origin": { "fetch": "$TESTDIR/%(name)s" }},
"projects":
{"repo_a": { "track-indirect": ".crepo/repo_a" }}
}
EOF

mkdir .crepo
echo "commit_b" > .crepo/repo_a

$CREPO sync

## Check that the checkout is correct
pushd repo_a
test "$(git rev-parse HEAD)" == "$(git rev-parse refs/tags/commit_b)"
test $(git remote) == "origin"
test -f file_a
popd

# Now go check out the new guy
pushd repo_a
git reset --hard $COMMIT_C_HASH
popd

# And update the indirects
$CREPO update-indirect -f

test "$(cat .crepo/repo_a)" == "$COMMIT_C_HASH"

0 comments on commit 8ad4d51

Please sign in to comment.