OLD | NEW |
---|---|
(Empty) | |
1 import optparse | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
+ #!/usr/bin/env python
+ # Copyright ...
Emily Fortuna
2012/05/08 17:33:27
Done.
| |
2 import os | |
3 import platform | |
4 import subprocess | |
5 import sys | |
6 | |
7 """A script used to revert one or a sequence of consecutive CLs, for svn and | |
8 git-svn users.""" | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
wrap """ to next line (not sure if this is in the
Emily Fortuna
2012/05/08 17:33:27
Done.
| |
9 | |
10 def parse_args(): | |
11 parser = optparse.OptionParser() | |
12 parser.add_option('--range', '-r', dest='rev_range', action='store', | |
Emily Fortuna
2012/05/08 00:40:01
Yes, this could/should have been a positional argu
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
maybe rename it to --revisions instead of range?
Emily Fortuna
2012/05/08 17:33:27
Done.
| |
13 default=None, help='The revision number(s) of the commits ' | |
14 'you wish to undo. An individual number, or a range 8-10.') | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
in git it's common to specify a range as A..B, may
Emily Fortuna
2012/05/08 17:33:27
Done.
| |
15 args, _ = parser.parse_args() | |
16 revision_range = args.rev_range | |
17 if revision_range == None: | |
18 fail('You must specify at least one revision number to revert.') | |
19 if revision_range.find('-') > -1 or revision_range.find(':') > -1: | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
oh - I guess I'm suggesting a third syntax :).
Ei
Emily Fortuna
2012/05/08 17:33:27
Done. Yes, the colon version is svn-like, so I'll
| |
20 # We have a range of commits to revert. | |
21 split = revision_range.split('-') | |
22 if len(revision_range.split('-')) == 1: | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
len(revision_range.split('-')) => len(split)
Emily Fortuna
2012/05/08 17:33:27
Done.
| |
23 split = revision_range.split(':') | |
24 start = int(split[0]) | |
25 end = int(split[1]) | |
26 if start > end: | |
27 temp = start | |
28 start = end | |
29 end = temp | |
30 fail('Warning: are you sure you want to revert a range of revisions? If ' | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
maybe check if start != end (if they are equal, we
Emily Fortuna
2012/05/08 17:33:27
Done, though it will be strange if someone specifi
| |
31 'you just want to revert one CL, only specify one revision number.', | |
32 user_input=True) | |
33 else: | |
34 start = end = int(revision_range) | |
35 return start, end | |
36 | |
37 def fail(error_msg, user_input=False): | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
fail => maybe_fail? or prompt_user?
Emily Fortuna
2012/05/08 17:33:27
Done.
Emily Fortuna
2012/05/08 17:33:27
Done.
| |
38 """Determine if we have encountered a condition upon which our script cannot | |
39 continue, and abort if so. | |
40 Args: | |
41 - error_msg: The error message to print. | |
42 - user_input: True if we require user confirmation to continue. We assume | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
in this case, the message is not necessarily an er
Emily Fortuna
2012/05/08 17:33:27
Done.
| |
43 that the user must enter y to proceed. | |
44 """ | |
45 if user_input: | |
46 force = raw_input(error_msg + ' (y/N)') | |
47 if force != 'y': | |
48 sys.exit(0) | |
49 else: | |
50 print error_msg | |
51 sys.exit(1) | |
52 | |
53 def has_new_code(is_git): | |
54 """Tests if there are any newer versions of files on the server. | |
55 Args: | |
56 - is_git: True if we are working in a git repository. | |
57 """ | |
58 os.chdir(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath( | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
join seems unnecessary?
Emily Fortuna
2012/05/08 17:33:27
Oops, that was a refactoring gone wrong that I mis
| |
59 __file__))))) | |
60 if not is_git: | |
61 results = run_cmd(['svn', 'st']) | |
62 else: | |
63 results = run_cmd(['git', 'status']) | |
64 for line in results.split('\n'): | |
65 if not is_git and (not line.strip().startswith('?') and line != ''): | |
66 return True | |
67 elif is_git and ('Changes to be committed' in line or | |
68 'Changes not staged for commit:' in line): | |
69 return True | |
70 if is_git: | |
71 p = subprocess.Popen(['git', 'log'], stdout=subprocess.PIPE) | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
should we add here '-1' to this git log command? I
Emily Fortuna
2012/05/08 17:33:27
When there are local commits, a commit name is lis
| |
72 output, _ = p.communicate() | |
73 if find_git_info(output) == None: | |
74 return True | |
75 return False | |
76 | |
77 def run_cmd(cmd_list): | |
78 """Run the specified command and print out any output to stdout.""" | |
79 print ' '.join(cmd_list) | |
80 out = subprocess.PIPE | |
81 p = subprocess.Popen(cmd_list, stdout=out, stderr=subprocess.PIPE, | |
82 stdin=subprocess.PIPE, | |
83 shell=(platform.system()=='Windows')) | |
84 output, stderr = p.communicate() | |
85 if output: | |
86 print output | |
87 if stderr: | |
88 print stderr | |
89 return output | |
90 | |
91 def runs_git(): | |
92 """Returns True if we're standing in an svn-git repository.""" | |
93 p = subprocess.Popen(['svn', 'info'], stdout=subprocess.PIPE, | |
94 stderr=subprocess.PIPE) | |
95 output, err = p.communicate() | |
96 if err != None and 'is not a working copy' in err: | |
97 p = subprocess.Popen(['git', 'status'], stdout=subprocess.PIPE) | |
98 output, _ = p.communicate() | |
99 if 'fatal: Not a git repository' in output: | |
100 fail('Error: not running git or svn.') | |
101 else: | |
102 return True | |
103 return False | |
104 | |
105 def find_git_info(git_log, rev_num=None): | |
106 """Determine the latest svn revision number if rev_num = None, or find the | |
107 git commit_id that corresponds to a particular svn revision number.""" | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
wrap """ to next line
Emily Fortuna
2012/05/08 17:33:27
Done.
| |
108 for line in git_log.split('\n'): | |
109 tokens = line.split() | |
110 if len(tokens) == 2 and tokens[0] == 'commit': | |
111 current_commit_id = tokens[1] | |
112 elif len(tokens) > 0 and tokens[0] == 'git-svn-id:': | |
113 revision_number = int(tokens[1].split('@')[1]) | |
114 if revision_number == rev_num: | |
115 return current_commit_id | |
116 if rev_num == None: | |
117 return revision_number | |
118 | |
119 def revert(start, end, is_git): | |
120 """Revert the sequence of CLs. | |
121 Args: | |
122 - start: The first CL to revert. | |
123 - end: The last CL to revert. | |
124 - is_git: True if we are in a git-svn checkout. | |
125 """ | |
126 if not is_git: | |
127 run_cmd(['svn', 'merge', '-r', '%d:%d' % (end, start-1), '.']) | |
128 else: | |
129 # If we're running git, we have to use the log feature to find the commit | |
130 # id(s) that correspond to the particular revision number(s). | |
131 output = run_cmd(['git', 'log', '-1']) | |
132 current_revision = find_git_info(output) | |
133 distance = (current_revision-start) + 1 | |
134 reverts = [start] | |
135 commit_msg = '"Reverting %d"' % start | |
136 if end != start: | |
137 reverts = range(start, end + 1) | |
138 reverts.reverse() | |
Emily Fortuna
2012/05/08 00:40:01
these two lines (137-138) could certainly be done
| |
139 commit_msg = '%s-%d"' % (commit_msg[:-1], end) | |
140 for revert in reverts: | |
141 git_commit_id = find_git_info(output, revert) | |
142 run_cmd(['git', 'revert', '-n', git_commit_id]) | |
143 run_cmd(['git', 'commit', '-m', commit_msg]) | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
this command shouldn't be necessary (there shouldn
Emily Fortuna
2012/05/08 17:33:27
This is done because when I run git revert, I pass
Siggi Cherem (dart-lang)
2012/05/08 17:48:23
Ah - got it. It might be better to do it without t
| |
144 | |
145 def main(): | |
146 revisions = parse_args() | |
147 git_user = runs_git() | |
148 if has_new_code(git_user): | |
149 fail('WARNING: This checkout has local modifications!! This could result ' | |
150 'in a CL that is not just a revert and/or you could lose your local ' | |
151 'changes! Are you **SURE** you want to continue? ', user_input=True) | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
In the case of git, I feel that we should just not
| |
152 if git_user: | |
153 run_cmd(['git', 'cl', 'rebase']) | |
154 run_cmd(['gclient', 'sync']) | |
155 revert(revisions[0], revisions[1], git_user) | |
Siggi Cherem (dart-lang)
2012/05/08 01:16:07
after this, should we print a message saying: now
Emily Fortuna
2012/05/08 17:33:27
Done.
Emily Fortuna
2012/05/08 17:33:27
Done.
| |
156 | |
157 if __name__ == '__main__': | |
158 main() | |
OLD | NEW |