4 from subprocess
import Popen, PIPE, STDOUT
5 from fnmatch
import fnmatch
10 Simple wrapper to execute a command and return standard output and standard error.
12 d = {
"stdout": PIPE,
"stderr": PIPE}
14 cmd = [cmd] + list(args)
15 logging.debug(
"Execute command: %r %r",
" ".join(cmd), kwargs)
16 proc = apply(Popen, (cmd,), d)
17 return proc.communicate()
19 cmt =
lambda *args, **kwargs: apply(command, (
"cmt",) + args, kwargs)
20 cvs =
lambda *args, **kwargs: apply(command, (
"cvs",) + args, kwargs)
21 svn =
lambda *args, **kwargs: apply(command, (
"svn",) + args, kwargs)
25 Find the local packages the current one depends on (using 'cmt broadcast').
26 Returns a list of pairs ("package name","path to the cmt directory").
29 if not sys.platform.startswith(
"win"):
30 pkg_dirs =
"[\n" +
cmt(
"broadcast",
r'echo "(\"<package>\", \"$PWD\"),"')[0] +
']'
32 pkg_dirs =
"[\n" +
cmt(
"broadcast",
r'echo ("<package>", r"%<package>root%\cmt"),')[0] +
']'
34 pkg_dirs =
"\n".join([l.strip()
for l
in pkg_dirs.splitlines()
if not l.startswith(
"#")])
39 Returns True if any of the specified glob patterns (list of strings) matched
40 the string 'filename'.
43 if fnmatch(filename, p):
44 logging.debug(
"Excluding file: %r", filename)
50 Replace the entries in files that correspond to directories with the list of
51 files in those directories.
59 base = os.path.join(basepath, f)
60 if os.path.isdir(base):
61 for root, ds, fs
in os.walk(base):
63 newlist.append(os.path.join(root,ff)[lb:])
69 if os.path.isdir(os.path.join(cwd,
"CVS")):
70 return cvs(
"diff",
"-upN", cwd = cwd)
73 out, err =
svn(
"status", cwd = cwd)
76 for l
in out.splitlines()
77 if l.startswith(
"? ") ]
78 out, err =
svn(
"diff", cwd = cwd)
80 out =
"\n".join(newfiles) +
"\n" + out
85 Return the patch data for a package.
87 rootdir = os.path.dirname(cmtdir)
90 new_files = [ l.split(
None,1)[1]
91 for l
in out.splitlines()
92 if l.startswith(
"? ") ]
99 logging.info(
"Added file %r", f)
103 out +=
"Index: %s\n" % f
104 out +=
"===================================================================\n"
105 out +=
command(
"diff",
"-upN",
"/dev/null", f,
108 removed_files = [ l.split()[-1]
109 for l
in err.splitlines()
110 if "cannot find" in l ]
112 for f
in removed_files
113 if not matches(f, exclusions) ]
115 for f
in removed_files:
116 logging.info(
"Removed file %r", f)
118 orig =
cvs(
"up",
"-p", f,
120 out +=
"diff -u -p -N %s\n" % os.path.basename(f)
121 out +=
"--- %s\t1 Jan 1970 00:00:00 -0000\n" % f
122 out +=
"+++ /dev/null\t1 Jan 1970 00:00:00 -0000\n"
123 lines = orig.splitlines()
124 out +=
"@@ -1,%d +0,0 @@\n" % len(lines)
128 rex = re.compile(
r"^(Index: |\? |\+\+\+ |--- (?!/dev/null))", re.MULTILINE)
129 out = rex.sub(
r"\1%s/" % name, out)
133 from optparse
import OptionParser
134 parser = OptionParser(description =
"Produce a patch file from a CMT project. "
135 "The patch contains the changes with respect "
136 "to the CVS repository, including new files "
137 "that are present only locally. Run the script "
138 "from the cmt directory of a package." )
139 parser.add_option(
"-x",
"--exclude", action=
"append", type=
"string",
140 metavar=
"PATTERN", dest=
"exclusions",
141 help=
"Pattern to exclude new files from the patch")
142 parser.add_option(
"-o",
"--output", action=
"store", type=
"string",
143 help=
"Name of the file to send the output to. Standard "
144 "output is used if not specified")
145 parser.add_option(
"-v",
"--verbose", action=
"store_true",
146 help=
"Print some progress information on standard error")
147 parser.add_option(
"--debug", action=
"store_true",
148 help=
"Print debug information on standard error")
149 parser.set_defaults(exclusions = [])
151 opts, args = parser.parse_args()
154 logging.basicConfig(level = logging.DEBUG)
156 logging.basicConfig(level = logging.INFO)
159 opts.exclusions += [
"*.py[co]",
168 "cmt/install*.history",
177 "i686-slc[34567]-[ig]cc*",
178 "i686-slc[34567]-clang*",
179 "x86_64-slc[34567]-[ig]cc*",
180 "x86_64-slc[34567]-clang*",
183 if "CMTCONFIG" in os.environ:
184 opts.exclusions.append(os.environ[
"CMTCONFIG"])
187 if not (os.path.basename(os.getcwd()) ==
"cmt" and os.path.exists(
"requirements")):
188 logging.error(
"This script must be executed from the cmt directory of a package.")
196 for name, path
in pkgs:
198 logging.info(
"Processing %s from %s (%d/%d)",
199 name, os.path.dirname(path), count, num_pkgs)
200 patch +=
diff_pkg(name, path, opts.exclusions)
202 if sys.platform.startswith(
"win"):
204 patch = patch.replace(
"\r",
"")
207 logging.info(
"Writing patch file %r", opts.output)
208 open(opts.output,
"w").write(patch)
210 sys.stdout.write(patch)
213 if __name__ ==
"__main__":
def command(cmd, args, kwargs)
def revision_diff_cmd(cwd)
def matches(filename, patterns)