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/.
6 from __future__
import absolute_import
, print_function
8 LIBFFI_DIRS
= (("js/ctypes/libffi", "libffi"),)
9 HG_EXCLUSIONS
= [".hg", ".hgignore", ".hgtags"]
11 CVSROOT_LIBFFI
= ":pserver:anoncvs@sources.redhat.com:/cvs/libffi"
18 from optparse
import OptionParser
19 from subprocess
import check_call
21 topsrcdir
= os
.path
.dirname(__file__
)
26 def check_call_noisy(cmd
, *args
, **kwargs
):
27 print("Executing command:", cmd
)
28 check_call(cmd
, *args
, **kwargs
)
31 def do_hg_pull(dir, repository
, hg
):
32 fulldir
= os
.path
.join(topsrcdir
, dir)
33 # clone if the dir doesn't exist, pull if it does
34 if not os
.path
.exists(fulldir
):
35 check_call_noisy([hg
, "clone", repository
, fulldir
])
37 cmd
= [hg
, "pull", "-u", "-R", fulldir
]
38 if repository
is not None:
39 cmd
.append(repository
)
42 [hg
, "parent", "-R", fulldir
, "--template=Updated to revision {node}.\n"]
46 def do_hg_replace(dir, repository
, tag
, exclusions
, hg
):
48 Replace the contents of dir with the contents of repository, except for
49 files matching exclusions.
51 fulldir
= os
.path
.join(topsrcdir
, dir)
52 if os
.path
.exists(fulldir
):
53 shutil
.rmtree(fulldir
)
55 assert not os
.path
.exists(fulldir
)
56 check_call_noisy([hg
, "clone", "-u", tag
, repository
, fulldir
])
58 for thing
in exclusions
:
59 for excluded
in glob
.iglob(os
.path
.join(fulldir
, thing
)):
60 if os
.path
.isdir(excluded
):
61 shutil
.rmtree(excluded
)
66 def do_cvs_export(modules
, tag
, cvsroot
, cvs
):
67 """Check out a CVS directory without CVS metadata, using "export"
68 modules is a list of directories to check out and the corresponding
69 cvs module, e.g. (('js/ctypes/libffi', 'libffi'),)
71 for module_tuple
in modules
:
72 module
= module_tuple
[0]
73 cvs_module
= module_tuple
[1]
74 fullpath
= os
.path
.join(topsrcdir
, module
)
75 if os
.path
.exists(fullpath
):
76 print("Removing '%s'" % fullpath
)
77 shutil
.rmtree(fullpath
)
79 (parent
, leaf
) = os
.path
.split(module
)
82 + datetime
.datetime
.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
85 [cvs
, "-d", cvsroot
, "export", "-r", tag
, "-d", leaf
, cvs_module
],
86 cwd
=os
.path
.join(topsrcdir
, parent
),
90 + datetime
.datetime
.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
94 def toggle_trailing_blank_line(depname
):
95 """If the trailing line is empty, then we'll delete it.
96 Otherwise we'll add a blank line."""
97 lines
= open(depname
, "r").readlines()
99 print("unexpected short file", file=sys
.stderr
)
102 if not lines
[-1].strip():
103 # trailing line is blank, removing it
104 open(depname
, "wb").writelines(lines
[:-1])
107 open(depname
, "ab").write(b
"\n")
110 def get_trailing_blank_line_state(depname
):
111 lines
= open(depname
, "r").readlines()
113 print("unexpected short file", file=sys
.stderr
)
114 return "no blank line"
116 if not lines
[-1].strip():
117 return "has blank line"
118 return "no blank line"
121 def update_nspr_or_nss(tag
, depfile
, destination
, hgpath
):
122 destination
= destination
.rstrip("/")
123 permanent_patch_dir
= destination
+ "/patches"
124 temporary_patch_dir
= destination
+ ".patches"
125 if os
.path
.exists(temporary_patch_dir
):
126 print("please clean up leftover directory " + temporary_patch_dir
)
128 warn_if_patch_exists(permanent_patch_dir
)
129 # protect patch directory from being removed by do_hg_replace
130 if os
.path
.exists(permanent_patch_dir
):
131 shutil
.move(permanent_patch_dir
, temporary_patch_dir
)
132 # now update the destination
133 print("reverting to HG version of %s to get its blank line state" % depfile
)
134 check_call_noisy([options
.hg
, "revert", depfile
])
135 old_state
= get_trailing_blank_line_state(depfile
)
136 print("old state of %s is: %s" % (depfile
, old_state
))
137 do_hg_replace(destination
, hgpath
, tag
, HG_EXCLUSIONS
, options
.hg
)
138 new_state
= get_trailing_blank_line_state(depfile
)
139 print("new state of %s is: %s" % (depfile
, new_state
))
140 if old_state
== new_state
:
141 print("toggling blank line in: ", depfile
)
142 toggle_trailing_blank_line(depfile
)
143 tag_file
= destination
+ "/TAG-INFO"
144 with
open(tag_file
, "w") as f
:
146 # move patch directory back to a subdirectory
147 if os
.path
.exists(temporary_patch_dir
):
148 shutil
.move(temporary_patch_dir
, permanent_patch_dir
)
151 def warn_if_patch_exists(path
):
152 # If the given patch directory exists and contains at least one file,
153 # then print warning and wait for the user to acknowledge.
154 if os
.path
.isdir(path
) and os
.listdir(path
):
155 print("========================================")
156 print("WARNING: At least one patch file exists")
157 print("in directory: " + path
)
158 print("You must manually re-apply all patches")
159 print("after this script has completed!")
160 print("========================================")
161 input("Press Enter to continue...")
166 usage
="client.py [options] update_nspr tagname | update_nss tagname | update_libffi tagname"
179 default
=os
.environ
.get("CVS", "cvs"),
180 help="The location of the cvs binary",
185 help="The CVSROOT for libffi (default : %s)" % CVSROOT_LIBFFI
,
190 default
=os
.environ
.get("HG", "hg"),
191 help="The location of the hg binary",
194 "--repo", dest
="repo", help="the repo to update from (default: upstream repo)"
198 options
, args
= o
.parse_args()
204 if action
in ("checkout", "co"):
205 print("Warning: client.py checkout is obsolete.", file=sys
.stderr
)
207 elif action
in ("update_nspr"):
209 depfile
= "nsprpub/config/prdepend.h"
211 options
.repo
= "https://hg.mozilla.org/projects/nspr"
212 update_nspr_or_nss(tag
, depfile
, "nsprpub", options
.repo
)
213 elif action
in ("update_nss"):
215 depfile
= "security/nss/coreconf/coreconf.dep"
217 options
.repo
= "https://hg.mozilla.org/projects/nss"
218 update_nspr_or_nss(tag
, depfile
, "security/nss", options
.repo
)
219 elif action
in ("update_libffi"):
221 if not options
.cvsroot
:
222 options
.cvsroot
= CVSROOT_LIBFFI
223 do_cvs_export(LIBFFI_DIRS
, tag
, options
.cvsroot
, options
.cvs
)