Mercurial > hg > hq
annotate hq/main.py @ 16:b878f4ce93fc
screwed this one up
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Fri, 17 May 2013 03:19:28 -0700 |
parents | 6c4f258fae85 |
children | 44ec940c86a6 |
rev | line source |
---|---|
0 | 1 #!/usr/bin/env python |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
2 |
0 | 3 """ |
14 | 4 mercurial queue extension front-end |
0 | 5 """ |
6 | |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
7 # TODO: migrate to http://k0s.org/hg/CommandParser/ |
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
8 |
0 | 9 import os |
10 import subprocess | |
11 import sys | |
12 | |
15 | 13 from commandparser import CommandParser |
0 | 14 |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
15 call = subprocess.check_output |
0 | 16 |
17 class HQ(object): | |
18 """ | |
19 mercurial queue extension front-end policy manager | |
20 """ | |
21 | |
11 | 22 def __init__(self, network=True, root=None, binary='hg'): |
0 | 23 """initialize global options""" |
24 # TODO: look at hgrc file | |
1 | 25 # for [defaults] repository_host |
5
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
26 # XXX ??? |
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
27 |
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
28 # check for network |
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
29 self.network = network |
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
30 |
12 | 31 # repository root |
32 self.root = root or call(['hg', 'root']).strip() | |
15 | 33 assert os.path.isdir(self.root), "'%s': not a directory!" |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
34 |
12 | 35 # hg binary |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
36 self.binary = binary |
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
37 |
13 | 38 # patch repo; not guaranteed to exit |
14 | 39 self._patch_repo = os.path.join(self.root, '.hg', 'patches') |
13 | 40 |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
41 ### subcommands |
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
42 |
3 | 43 def clone(self, repo, patch=None, queue=None): |
44 """ | |
45 clone the repository and begin a patch queue | |
46 - path: name of a new patch to initiate | |
47 - queue: name of the remote queue | |
48 """ | |
0 | 49 directory = repo.rsplit('/', 1) |
50 call(['hg', 'clone', repo, directory]) | |
51 os.chdir(directory) | |
52 call(['hg', 'qinit', '-c']) | |
3 | 53 if queue: |
4
44ea39c3e98f
add methods for dealing with the patch repositories
Jeff Hammel <jhammel@mozilla.com>
parents:
3
diff
changeset
|
54 # pull from the given repository |
44ea39c3e98f
add methods for dealing with the patch repositories
Jeff Hammel <jhammel@mozilla.com>
parents:
3
diff
changeset
|
55 self._patch_command(*['hg', 'pull', '--update', queue]) |
44ea39c3e98f
add methods for dealing with the patch repositories
Jeff Hammel <jhammel@mozilla.com>
parents:
3
diff
changeset
|
56 else: |
44ea39c3e98f
add methods for dealing with the patch repositories
Jeff Hammel <jhammel@mozilla.com>
parents:
3
diff
changeset
|
57 # (optionally) setup a new repo |
44ea39c3e98f
add methods for dealing with the patch repositories
Jeff Hammel <jhammel@mozilla.com>
parents:
3
diff
changeset
|
58 pass # TODO |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
59 |
0 | 60 if patch: |
4
44ea39c3e98f
add methods for dealing with the patch repositories
Jeff Hammel <jhammel@mozilla.com>
parents:
3
diff
changeset
|
61 # create a new patch |
0 | 62 call(['hg', 'qnew', patch]) |
63 | |
64 def commit(self, message): | |
65 """ | |
66 commit a patch and push it to the master repository | |
5
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
67 - message : commit message |
0 | 68 """ |
69 call(['hg', 'qrefresh']) | |
70 call(['hg', 'qcommit', '-m', message]) | |
5
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
71 if self.network: |
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
72 self._patch_command(*['hg', 'push']) |
0 | 73 |
15 | 74 def pull(self, repo=None, mq=True): |
75 """ | |
76 pull from the root repository | |
77 if mq is true, update the patch queue, if versioned | |
78 """ | |
79 # check for outstanding changes | |
16 | 80 import pdb; pdb.set_trace() |
15 | 81 output = self._call(['st']).strip() |
82 lines = [line for line in output.splitlines() | |
83 if not line.startswith('?')] | |
84 if lines: | |
85 print "Outstanding changes:" | |
86 print output | |
87 raise AssertionError | |
88 | |
89 applied, unapplied = self._series() | |
90 self._call(['qpop', '--all']) | |
91 self._call(['pull'] + (repo and [repo] or [])) | |
92 # TODO: pull queue repo | |
93 for patch in applied: | |
94 self._call(['qpush']) | |
2
dedf4c4c2ba2
add a function to list files (incomplete)
Jeff Hammel <jhammel@mozilla.com>
parents:
1
diff
changeset
|
95 |
3 | 96 def goto(self, patch): |
97 """ | |
5
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
98 go to a specific patch and apply it |
448c248b3738
start the path to using the __init__ function for realz
Jeff Hammel <jhammel@mozilla.com>
parents:
4
diff
changeset
|
99 - patch: name of patch to go to |
3 | 100 """ |
101 # TODO | |
102 process = subprocess.Popen(['hg', 'qapplied'], stdout=subprocess.PIPE) | |
103 stdout, stderr = process.communicate() | |
104 applied = [ i.strip() for i in stdout.splitlines() | |
105 if i ] | |
106 raise NotImplementedError | |
107 | |
2
dedf4c4c2ba2
add a function to list files (incomplete)
Jeff Hammel <jhammel@mozilla.com>
parents:
1
diff
changeset
|
108 def files(self): |
dedf4c4c2ba2
add a function to list files (incomplete)
Jeff Hammel <jhammel@mozilla.com>
parents:
1
diff
changeset
|
109 """ |
dedf4c4c2ba2
add a function to list files (incomplete)
Jeff Hammel <jhammel@mozilla.com>
parents:
1
diff
changeset
|
110 list the files added by the top patch |
dedf4c4c2ba2
add a function to list files (incomplete)
Jeff Hammel <jhammel@mozilla.com>
parents:
1
diff
changeset
|
111 """ |
dedf4c4c2ba2
add a function to list files (incomplete)
Jeff Hammel <jhammel@mozilla.com>
parents:
1
diff
changeset
|
112 # TODO: should only list top-level directories, otherwise it's silly |
15 | 113 process = subprocess.Popen("hg qdiff | grep '^+++ ' | sed 's/+++ b\///'", stdout=subprocess.PIPE, cwd=self._root) |
2
dedf4c4c2ba2
add a function to list files (incomplete)
Jeff Hammel <jhammel@mozilla.com>
parents:
1
diff
changeset
|
114 stdout, stderr = process.communicate() |
dedf4c4c2ba2
add a function to list files (incomplete)
Jeff Hammel <jhammel@mozilla.com>
parents:
1
diff
changeset
|
115 return stdout |
dedf4c4c2ba2
add a function to list files (incomplete)
Jeff Hammel <jhammel@mozilla.com>
parents:
1
diff
changeset
|
116 |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
117 def status(self): |
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
118 """ |
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
119 display status |
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
120 """ |
8 | 121 return '\n'.join([self._call(i).strip() for i in ('root', 'status', 'qseries')]) |
16 | 122 st = status |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
123 |
9 | 124 def directory(self): |
13 | 125 """patch queue directory""" |
126 if os.path.isdir(self._patch_repo): | |
127 return self._patch_repo | |
9 | 128 |
15 | 129 def incoming(self): |
130 """are there incoming changes to the patch queue""" | |
131 if not self._versioned(): | |
132 return False | |
133 try: | |
134 call([self.binary, 'incoming'], cwd=self.directory()) | |
135 return True | |
136 except subprocess.CalledProcessError: | |
137 return False | |
138 | |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
139 ### internals |
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
140 |
15 | 141 def _call(self, *args, **kwargs): |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
142 command = [self.binary] + list(args) |
15 | 143 kwargs.setdefault('cwd', self.root) |
16 | 144 return call(command, **kwargs) |
7
2e77fc6a36e8
add a status command; so much shit to clean
Jeff Hammel <jhammel@mozilla.com>
parents:
6
diff
changeset
|
145 |
15 | 146 def _patch_command(self, *command, **kwargs): |
4
44ea39c3e98f
add methods for dealing with the patch repositories
Jeff Hammel <jhammel@mozilla.com>
parents:
3
diff
changeset
|
147 """perform a command in the patch repository""" |
15 | 148 kwargs.setdefault(cwd=self.directory()) |
16 | 149 return call(command) |
15 | 150 |
151 def _versioned(self): | |
152 """is the patch queue versioned?""" | |
153 return os.path.isdir(os.path.join(self.directory(), '.hg')) | |
0 | 154 |
15 | 155 def _series(self): |
156 """returns a 2-tuple of applied, unapplied""" | |
157 lines = self._command(['qseries']).strip() | |
158 applied = [] | |
159 unapplied = [] | |
160 for line in lines: | |
161 line.strip() | |
162 index, status, name = line.split() | |
163 if status == 'A': | |
164 applied.append(name) | |
165 else: | |
166 assert status == 'U' | |
167 unapplied.append(name) | |
168 return applied, unapplied | |
11 | 169 |
0 | 170 def main(args=sys.argv[1:]): |
171 parser = CommandParser(HQ) | |
172 options, args = parser.parse_args(args) | |
173 parser.invoke(args) | |
174 | |
175 if __name__ == '__main__': | |
176 main() |