The Gaudi Framework
master (bdbe7744)
Toggle main menu visibility
Loading...
Searching...
No Matches
make_patch.py
Go to the documentation of this file.
1
#!/usr/bin/env python3
2
12
13
import
logging
14
import
os
15
import
re
16
import
sys
17
from
fnmatch
import
fnmatch
18
from
subprocess
import
PIPE, Popen
19
20
21
def
command
(cmd, *args, **kwargs):
22
"""
23
Simple wrapper to execute a command and return standard output and standard error.
24
"""
25
d = {
"stdout"
: PIPE,
"stderr"
: PIPE}
26
d.update(kwargs)
27
cmd = [cmd] + list(args)
28
logging.debug(
"Execute command: %r %r"
,
" "
.join(cmd), kwargs)
29
proc = Popen(cmd, **d)
30
return
proc.communicate()
31
32
33
def
cmt
(*args, **kwargs):
34
return
command
(
"cmt"
, *args, **kwargs)
35
36
37
def
cvs
(*args, **kwargs):
38
return
command
(
"cvs"
, *args, **kwargs)
39
40
41
def
svn
(*args, **kwargs):
42
return
command
(
"svn"
, *args, **kwargs)
43
44
45
def
broadcast_packages
():
46
"""
47
Find the local packages the current one depends on (using 'cmt broadcast').
48
Returns a list of pairs ("package name","path to the cmt directory").
49
"""
50
# make cmt print one line per package with python syntax
51
if
not
sys.platform.startswith(
"win"
):
52
pkg_dirs = (
53
"[\n"
+
cmt
(
"broadcast"
,
r'echo "(\"<package>\", \"$PWD\"),"'
)[0] +
"]"
54
)
55
else
:
56
pkg_dirs = (
57
"[\n"
58
+
cmt
(
"broadcast"
,
r'echo ("<package>", r"%<package>root%\cmt"),'
)[0]
59
+
"]"
60
)
61
# Clean up a bit the output (actually needed only on Windows because of the newlines)
62
pkg_dirs =
"\n"
.join(
63
[l.strip()
for
l
in
pkg_dirs.splitlines()
if
not
l.startswith(
"#"
)]
64
)
65
return
eval(pkg_dirs)
66
67
68
def
matches
(filename, patterns):
69
"""
70
Returns True if any of the specified glob patterns (list of strings) matched
71
the string 'filename'.
72
"""
73
for
p
in
patterns:
74
if
fnmatch(filename, p):
75
logging.debug(
"Excluding file: %r"
, filename)
76
return
True
77
return
False
78
79
80
def
expand_dirs
(files, basepath=""):
81
"""
82
Replace the entries in files that correspond to directories with the list of
83
files in those directories.
84
"""
85
if
basepath:
86
lb = len(basepath) + 1
87
else
:
88
lb = 0
89
newlist = []
90
for
f
in
files:
91
base = os.path.join(basepath, f)
92
if
os.path.isdir(base):
93
for
root, ds, fs
in
os.walk(base):
94
for
ff
in
fs:
95
newlist.append(os.path.join(root, ff)[lb:])
96
else
:
97
newlist.append(f)
98
return
newlist
99
100
101
def
revision_diff_cmd
(cwd):
102
if
os.path.isdir(os.path.join(cwd,
"CVS"
)):
103
return
cvs
(
"diff"
,
"-upN"
, cwd=cwd)
104
else
:
105
# special treatment to show new files in a way compatible with CVS
106
out, err =
svn
(
"status"
, cwd=cwd)
107
108
newfiles = [l
for
l
in
out.splitlines()
if
l.startswith(
"? "
)]
109
out, err =
svn
(
"diff"
, cwd=cwd)
110
if
newfiles:
111
out =
"\n"
.join(newfiles) +
"\n"
+ out
112
return
out, err
113
114
115
def
diff_pkg
(name, cmtdir, exclusions=[]):
116
"""
117
Return the patch data for a package.
118
"""
119
rootdir = os.path.dirname(cmtdir)
120
out, err =
revision_diff_cmd
(cwd=rootdir)
121
# extract new files
122
new_files = [l.split(
None
, 1)[1]
for
l
in
out.splitlines()
if
l.startswith(
"? "
)]
123
new_files =
expand_dirs
(new_files, rootdir)
124
new_files = [f
for
f
in
new_files
if
not
matches
(f, exclusions)]
125
# make diff segments for added files
126
for
f
in
new_files:
127
logging.info(
"Added file %r"
, f)
128
# out += "diff -u -p -N %s\n" % os.path.basename(f)
129
# out += command("diff", "-upN", "/dev/null", f,
130
# cwd = rootdir)[0]
131
out += f
"Index: {f}\n"
132
out +=
"===================================================================\n"
133
out +=
command
(
"diff"
,
"-upN"
,
"/dev/null"
, f, cwd=rootdir)[0]
134
# extract removed files
135
removed_files = [l.split()[-1]
for
l
in
err.splitlines()
if
"cannot find"
in
l]
136
removed_files = [f
for
f
in
removed_files
if
not
matches
(f, exclusions)]
137
# make diff segments for removed files (more tricky)
138
for
f
in
removed_files:
139
logging.info(
"Removed file %r"
, f)
140
# retrieve the original content from CVS
141
orig =
cvs
(
"up"
,
"-p"
, f, cwd=rootdir)[0]
142
out += f
"diff -u -p -N {os.path.basename(f)}\n"
143
out += f
"--- {f}\t1 Jan 1970 00:00:00 -0000\n"
144
out +=
"+++ /dev/null\t1 Jan 1970 00:00:00 -0000\n"
145
lines = orig.splitlines()
146
out += f
"@@ -1,{len(lines)} +0,0 @@\n"
147
for
l
in
lines:
148
out += f
"-{l}\n"
149
# Fix the paths to have the package names
150
rex = re.compile(
r"^(Index: |\? |\+\+\+ |--- (?!/dev/null))"
, re.MULTILINE)
151
out = rex.sub(rf
"\1{name}/"
, out)
152
return
out
153
154
155
def
main
():
156
from
optparse
import
OptionParser
157
158
parser = OptionParser(
159
description=
"Produce a patch file from a CMT project. "
160
"The patch contains the changes with respect "
161
"to the CVS repository, including new files "
162
"that are present only locally. Run the script "
163
"from the cmt directory of a package."
164
)
165
parser.add_option(
166
"-x"
,
167
"--exclude"
,
168
action=
"append"
,
169
type=
"string"
,
170
metavar=
"PATTERN"
,
171
dest=
"exclusions"
,
172
help=
"Pattern to exclude new files from the patch"
,
173
)
174
parser.add_option(
175
"-o"
,
176
"--output"
,
177
action=
"store"
,
178
type=
"string"
,
179
help=
"Name of the file to send the output to. Standard "
180
"output is used if not specified"
,
181
)
182
parser.add_option(
183
"-v"
,
184
"--verbose"
,
185
action=
"store_true"
,
186
help=
"Print some progress information on standard error"
,
187
)
188
parser.add_option(
189
"--debug"
, action=
"store_true"
, help=
"Print debug information on standard error"
190
)
191
parser.set_defaults(exclusions=[])
192
193
opts, args = parser.parse_args()
194
195
if
opts.debug:
196
logging.basicConfig(level=logging.DEBUG)
197
elif
opts.verbose:
198
logging.basicConfig(level=logging.INFO)
199
200
# default exclusions
201
opts.exclusions += [
202
"*.py[co]"
,
203
"*.patch"
,
204
"cmt/cleanup.*"
,
205
"cmt/setup.*"
,
206
"cmt/*.make"
,
207
"cmt/Makefile"
,
208
"cmt/*.nmake"
,
209
"cmt/*.nmakesav"
,
210
"cmt/NMake"
,
211
"cmt/install*.history"
,
212
"cmt/build.*.log"
,
213
"cmt/version.cmt"
,
214
"genConf"
,
215
"slc3_ia32_gcc323*"
,
216
"slc4_ia32_gcc34*"
,
217
"slc4_amd64_gcc34*"
,
218
"slc4_amd64_gcc43*"
,
219
"win32_vc71*"
,
220
"i686-slc[34567]-[ig]cc*"
,
221
"i686-slc[34567]-clang*"
,
222
"x86_64-slc[34567]-[ig]cc*"
,
223
"x86_64-slc[34567]-clang*"
,
224
".eclipse"
,
225
]
226
if
"CMTCONFIG"
in
os.environ:
227
opts.exclusions.append(os.environ[
"CMTCONFIG"
])
228
229
# check if we are in the cmt directory before broadcasting
230
if
not
(os.path.basename(os.getcwd()) ==
"cmt"
and
os.path.exists(
"requirements"
)):
231
logging.error(
232
"This script must be executed from the cmt directory of a package."
233
)
234
return
1
235
236
pkgs =
broadcast_packages
()
237
num_pkgs = len(pkgs)
238
count = 0
239
240
patch =
""
241
for
name, path
in
pkgs:
242
count += 1
243
logging.info(
244
"Processing %s from %s (%d/%d)"
,
245
name,
246
os.path.dirname(path),
247
count,
248
num_pkgs,
249
)
250
patch +=
diff_pkg
(name, path, opts.exclusions)
251
252
if
sys.platform.startswith(
"win"
):
253
# fix newlines chars
254
patch = patch.replace(
"\r"
,
""
)
255
256
if
opts.output:
257
logging.info(
"Writing patch file %r"
, opts.output)
258
open(opts.output,
"w"
).write(patch)
259
else
:
260
sys.stdout.write(patch)
261
return
0
262
263
264
if
__name__ ==
"__main__"
:
265
sys.exit(
main
())
make_patch.matches
matches(filename, patterns)
Definition
make_patch.py:68
make_patch.revision_diff_cmd
revision_diff_cmd(cwd)
Definition
make_patch.py:101
make_patch.main
main()
Definition
make_patch.py:155
make_patch.broadcast_packages
broadcast_packages()
Definition
make_patch.py:45
make_patch.command
command(cmd, *args, **kwargs)
Definition
make_patch.py:21
make_patch.expand_dirs
expand_dirs(files, basepath="")
Definition
make_patch.py:80
make_patch.diff_pkg
diff_pkg(name, cmtdir, exclusions=[])
Definition
make_patch.py:115
make_patch.svn
svn(*args, **kwargs)
Definition
make_patch.py:41
make_patch.cmt
cmt(*args, **kwargs)
Definition
make_patch.py:33
make_patch.cvs
cvs(*args, **kwargs)
Definition
make_patch.py:37
GaudiKernel
scripts
make_patch.py
Generated on
for The Gaudi Framework by
1.17.0