Source code

Revision control

Other Tools

1
#!/usr/bin/python
2
# This Source Code Form is subject to the terms of the Mozilla Public
3
# License, v. 2.0. If a copy of the MPL was not distributed with this
4
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6
from __future__ import absolute_import, print_function
7
8
LIBFFI_DIRS = (('js/ctypes/libffi', 'libffi'),)
9
HG_EXCLUSIONS = ['.hg', '.hgignore', '.hgtags']
10
11
CVSROOT_LIBFFI = ':pserver:anoncvs@sources.redhat.com:/cvs/libffi'
12
13
import os
14
import sys
15
import datetime
16
import shutil
17
import glob
18
from optparse import OptionParser
19
from subprocess import check_call
20
21
topsrcdir = os.path.dirname(__file__)
22
if topsrcdir == '':
23
topsrcdir = '.'
24
25
def check_call_noisy(cmd, *args, **kwargs):
26
print("Executing command:", cmd)
27
check_call(cmd, *args, **kwargs)
28
29
def do_hg_pull(dir, repository, hg):
30
fulldir = os.path.join(topsrcdir, dir)
31
# clone if the dir doesn't exist, pull if it does
32
if not os.path.exists(fulldir):
33
check_call_noisy([hg, 'clone', repository, fulldir])
34
else:
35
cmd = [hg, 'pull', '-u', '-R', fulldir]
36
if repository is not None:
37
cmd.append(repository)
38
check_call_noisy(cmd)
39
check_call([hg, 'parent', '-R', fulldir,
40
'--template=Updated to revision {node}.\n'])
41
42
def do_hg_replace(dir, repository, tag, exclusions, hg):
43
"""
44
Replace the contents of dir with the contents of repository, except for
45
files matching exclusions.
46
"""
47
fulldir = os.path.join(topsrcdir, dir)
48
if os.path.exists(fulldir):
49
shutil.rmtree(fulldir)
50
51
assert not os.path.exists(fulldir)
52
check_call_noisy([hg, 'clone', '-u', tag, repository, fulldir])
53
54
for thing in exclusions:
55
for excluded in glob.iglob(os.path.join(fulldir, thing)):
56
if os.path.isdir(excluded):
57
shutil.rmtree(excluded)
58
else:
59
os.remove(excluded)
60
61
def do_cvs_export(modules, tag, cvsroot, cvs):
62
"""Check out a CVS directory without CVS metadata, using "export"
63
modules is a list of directories to check out and the corresponding
64
cvs module, e.g. (('js/ctypes/libffi', 'libffi'),)
65
"""
66
for module_tuple in modules:
67
module = module_tuple[0]
68
cvs_module = module_tuple[1]
69
fullpath = os.path.join(topsrcdir, module)
70
if os.path.exists(fullpath):
71
print("Removing '%s'" % fullpath)
72
shutil.rmtree(fullpath)
73
74
(parent, leaf) = os.path.split(module)
75
print("CVS export begin: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC"))
76
check_call_noisy([cvs, '-d', cvsroot,
77
'export', '-r', tag, '-d', leaf, cvs_module],
78
cwd=os.path.join(topsrcdir, parent))
79
print("CVS export end: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC"))
80
81
def toggle_trailing_blank_line(depname):
82
"""If the trailing line is empty, then we'll delete it.
83
Otherwise we'll add a blank line."""
84
lines = open(depname, "r").readlines()
85
if not lines:
86
print("unexpected short file", file=sys.stderr)
87
return
88
89
if not lines[-1].strip():
90
# trailing line is blank, removing it
91
open(depname, "wb").writelines(lines[:-1])
92
else:
93
# adding blank line
94
open(depname, "ab").write("\n")
95
96
def get_trailing_blank_line_state(depname):
97
lines = open(depname, "r").readlines()
98
if not lines:
99
print("unexpected short file", file=sys.stderr)
100
return "no blank line"
101
102
if not lines[-1].strip():
103
return "has blank line"
104
else:
105
return "no blank line"
106
107
def update_nspr_or_nss(tag, depfile, destination, hgpath):
108
destination = destination.rstrip('/')
109
permanent_patch_dir = destination + '/patches'
110
temporary_patch_dir = destination + '.patches'
111
if os.path.exists(temporary_patch_dir):
112
print("please clean up leftover directory " + temporary_patch_dir)
113
sys.exit(2)
114
warn_if_patch_exists(permanent_patch_dir)
115
# protect patch directory from being removed by do_hg_replace
116
if os.path.exists(permanent_patch_dir):
117
shutil.move(permanent_patch_dir, temporary_patch_dir)
118
# now update the destination
119
print("reverting to HG version of %s to get its blank line state" % depfile)
120
check_call_noisy([options.hg, 'revert', depfile])
121
old_state = get_trailing_blank_line_state(depfile)
122
print("old state of %s is: %s" % (depfile, old_state))
123
do_hg_replace(destination, hgpath, tag, HG_EXCLUSIONS, options.hg)
124
new_state = get_trailing_blank_line_state(depfile)
125
print("new state of %s is: %s" % (depfile, new_state))
126
if old_state == new_state:
127
print("toggling blank line in: ", depfile)
128
toggle_trailing_blank_line(depfile)
129
tag_file = destination + "/TAG-INFO"
130
with open(tag_file, 'w') as f:
131
f.write(tag)
132
# move patch directory back to a subdirectory
133
if os.path.exists(temporary_patch_dir):
134
shutil.move(temporary_patch_dir, permanent_patch_dir)
135
136
def warn_if_patch_exists(path):
137
# If the given patch directory exists and contains at least one file,
138
# then print warning and wait for the user to acknowledge.
139
if os.path.isdir(path) and os.listdir(path):
140
print("========================================")
141
print("WARNING: At least one patch file exists")
142
print("in directory: " + path)
143
print("You must manually re-apply all patches")
144
print("after this script has completed!")
145
print("========================================")
146
raw_input("Press Enter to continue...")
147
return
148
149
o = OptionParser(usage="client.py [options] update_nspr tagname | update_nss tagname | update_libffi tagname")
150
o.add_option("--skip-mozilla", dest="skip_mozilla",
151
action="store_true", default=False,
152
help="Obsolete")
153
154
o.add_option("--cvs", dest="cvs", default=os.environ.get('CVS', 'cvs'),
155
help="The location of the cvs binary")
156
o.add_option("--cvsroot", dest="cvsroot",
157
help="The CVSROOT for libffi (default : %s)" % CVSROOT_LIBFFI)
158
o.add_option("--hg", dest="hg", default=os.environ.get('HG', 'hg'),
159
help="The location of the hg binary")
160
o.add_option("--repo", dest="repo",
161
help="the repo to update from (default: upstream repo)")
162
163
try:
164
options, args = o.parse_args()
165
action = args[0]
166
except IndexError:
167
o.print_help()
168
sys.exit(2)
169
170
if action in ('checkout', 'co'):
171
print >>sys.stderr, "Warning: client.py checkout is obsolete."
172
pass
173
elif action in ('update_nspr'):
174
tag, = args[1:]
175
depfile = "nsprpub/config/prdepend.h"
176
if not options.repo:
178
update_nspr_or_nss(tag, depfile, 'nsprpub', options.repo)
179
elif action in ('update_nss'):
180
tag, = args[1:]
181
depfile = "security/nss/coreconf/coreconf.dep"
182
if not options.repo:
184
update_nspr_or_nss(tag, depfile, 'security/nss', options.repo)
185
elif action in ('update_libffi'):
186
tag, = args[1:]
187
if not options.cvsroot:
188
options.cvsroot = CVSROOT_LIBFFI
189
do_cvs_export(LIBFFI_DIRS, tag, options.cvsroot, options.cvs)
190
else:
191
o.print_help()
192
sys.exit(2)