svn: do not use metadata
[yap.git] / plugins / svn.py
blob675ee3daff8ec1e0caec3510599bff9ebdf8d3de
2 from yap import YapPlugin, YapError
3 from yap.util import get_output, takes_options, run_command, run_safely, short_help
4 import os
5 import tempfile
7 class SvnPlugin(YapPlugin):
8 def __init__(self, yap):
9 self.yap = yap
11 def _get_root(self, url):
12 root = get_output("svn info %s 2>/dev/null | gawk '/Repository Root:/{print $3}'" % url)
13 if not root:
14 raise YapError("Not an SVN repo: %s" % url)
15 return root[0]
17 def _configure_repo(self, url):
18 root = self._get_root(url)
19 os.system("git config svn-remote.svn.url %s" % root)
20 trunk = url.replace(root, '').strip('/')
21 os.system("git config svn-remote.svn.fetch %s:refs/remotes/svn/trunk"
22 % trunk)
23 branches = trunk.replace('trunk', 'branches')
24 os.system("git config svn-remote.svn.branches %s/*:refs/remotes/svn/*"
25 % branches)
26 tags = trunk.replace('trunk', 'tags')
27 os.system("git config svn-remote.svn.tags %s/*:refs/tags/*" % tags)
28 self.yap.cmd_repo("svn", url)
29 os.system("git config yap.svn.enabled 1")
31 def _clone_svn(self, url, directory=None, **flags):
32 url = url.rstrip('/')
33 if directory is None:
34 directory = url.rsplit('/')[-1]
35 directory = directory.replace('.git', '')
37 try:
38 os.mkdir(directory)
39 except OSError:
40 raise YapError("Directory exists: %s" % directory)
41 os.chdir(directory)
43 self.yap.cmd_init()
44 run_command("git config svn-remote.svn.noMetadata 1")
45 self._configure_repo(url)
46 os.system("git svn fetch -r %s:HEAD" % flags.get('-r', '1'))
48 def _push_svn(self, branch, **flags):
49 if '-d' in flags:
50 raise YapError("Deleting svn branches not supported")
51 print "Verifying branch is up-to-date"
52 run_safely("git svn fetch svn")
54 branch = branch.replace('refs/heads/', '')
55 rev = get_output("git rev-parse --verify refs/remotes/svn/%s" % branch)
57 # Create the branch if requested
58 if not rev:
59 if '-c' not in flags:
60 raise YapError("No matching branch on the repo. Use -c to create a new branch there.")
61 src = get_output("git svn info | gawk '/URL:/{print $2}'")[0]
62 brev = get_output("git svn info | gawk '/Revision:/{print $2}'")[0]
63 root = get_output("git config svn-remote.svn.url")[0]
64 branch_path = get_output("git config svn-remote.svn.branches")[0].split(':')[0]
65 branch_path = branch_path.rstrip('/*')
66 dst = '/'.join((root, branch_path, branch))
68 # Create the branch in svn
69 run_safely("svn cp -r%s %s %s -m 'create branch %s'"
70 % (brev, src, dst, branch))
71 run_safely("git svn fetch svn")
72 rev = get_output("git rev-parse refs/remotes/svn/%s 2>/dev/null" % branch)
73 base = get_output("git svn find-rev r%s" % brev)
75 # Apply our commits to the new branch
76 try:
77 fd, tmpfile = tempfile.mkstemp("yap")
78 os.close(fd)
79 print base[0]
80 os.system("git format-patch -k --stdout '%s' > %s"
81 % (base[0], tmpfile))
82 start = get_output("git rev-parse HEAD")
83 self.yap.cmd_point("refs/remotes/svn/%s"
84 % branch, **{'-f': True})
86 stat = os.stat(tmpfile)
87 size = stat[6]
88 if size > 0:
89 rc = run_command("git am -3 %s" % tmpfile)
90 if (rc):
91 self.yap.cmd_point(start[0], **{'-f': True})
92 raise YapError("Failed to port changes to new svn branch")
93 finally:
94 os.unlink(tmpfile)
96 base = get_output("git merge-base HEAD %s" % rev[0])
97 if base[0] != rev[0]:
98 raise YapError("Branch not up-to-date. Update first.")
99 current = get_output("git symbolic-ref HEAD")
100 if not current:
101 raise YapError("Not on a branch!")
102 current = current[0].replace('refs/heads/', '')
103 self.yap._confirm_push(current, branch, "svn")
104 if run_command("git update-index --refresh"):
105 raise YapError("Can't push with uncommitted changes")
107 master = get_output("git rev-parse --verify refs/heads/master 2>/dev/null")
108 os.system("git svn dcommit")
109 run_safely("git svn rebase")
110 if not master:
111 master = get_output("git rev-parse --verify refs/heads/master 2>/dev/null")
112 if master:
113 run_safely("git update-ref -d refs/heads/master %s" % master[0])
115 def _enabled(self):
116 enabled = get_output("git config yap.svn.enabled")
117 return bool(enabled)
119 # Ensure users don't accidentally kill our "svn" repo
120 def pre_repo(self, *args, **flags):
121 if not self._enabled():
122 return
123 if '-d' in flags and args and args[0] == "svn":
124 raise YapError("Refusing to delete special svn repository")
126 @takes_options("r:")
127 def cmd_clone(self, *args, **flags):
128 if args and not run_command("svn info %s" % args[0]):
129 self._clone_svn(*args, **flags)
130 else:
131 self.yap._call_base("cmd_commit", *args, **flags)
133 def cmd_fetch(self, *args, **flags):
134 if self._enabled():
135 if args and args[0] == 'svn':
136 os.system("git svn fetch svn")
137 return
138 elif not args:
139 current = get_output("git symbolic-ref HEAD")
140 if not current:
141 raise YapError("Not on a branch!")
143 current = current[0].replace('refs/heads/', '')
144 remote, merge = self.yap._get_tracking(current)
145 if remote == "svn":
146 os.system("git svn fetch svn")
147 return
148 self.yap._call_base("cmd_fetch", *args, **flags)
150 def cmd_push(self, *args, **flags):
151 if self._enabled():
152 if args and args[0] == 'svn':
153 if len (args) < 2:
154 raise YapError("Need a branch name")
155 self._push_svn(args[1], **flags)
156 return
157 elif not args:
158 current = get_output("git symbolic-ref HEAD")
159 if not current:
160 raise YapError("Not on a branch!")
162 current = current[0].replace('refs/heads/', '')
163 remote, merge = self.yap._get_tracking(current)
164 if remote == "svn":
165 self._push_svn(merge, **flags)
166 return
168 self.yap._call_base("cmd_push", *args, **flags)
170 @short_help("change options for the svn plugin")
171 def cmd_svn(self, subcmd):
172 "enable"
174 if subcmd not in ["enable"]:
175 raise TypeError
177 if "svn" in [x[0] for x in self.yap._list_remotes()]:
178 raise YapError("A remote named 'svn' already exists")
181 if not run_command("git config svn-remote.svn.branches"):
182 raise YapError("Cannot currently enable in a repository with svn branches")
184 url = get_output("git config svn-remote.svn.url")
185 if not url:
186 raise YapError("Not a git-svn repository?")
187 fetch = get_output("git config svn-remote.svn.fetch")
188 assert fetch
189 lhs, rhs = fetch[0].split(':')
192 rev = get_output("git rev-parse %s" % rhs)
193 assert rev
194 run_safely("git update-ref refs/remotes/svn/trunk %s" % rev[0])
196 url = '/'.join((url[0], lhs))
197 self._configure_repo(url)
198 run_safely("git update-ref -d %s %s" % (rhs, rev[0]))