From: <sv...@ww...> - 2004-06-05 23:40:01
|
Author: mkrose Date: 2004-06-05 16:39:52 -0700 (Sat, 05 Jun 2004) New Revision: 994 Modified: trunk/CSP/tools/sublib.py trunk/CSP/tools/subset Log: Add a rudimentary diff function to subset. Relies on external tools to actually display the diffs. Under KDE this can be done fairly easily using Konqueror + Kompare. To use this feature, you need to define the SUBSET_DIFF_ONE and/or SUBSET_DIFF_DIR environment variables. The former is run for single diffs (e.g. "subset diff foo/bar.cpp"). Subset generates a unified diff for the specified file, and passes the diff file as an argument to the SUBSET_DIFF_ONE command. Under KDE, you might set this variable to 'kompare'. Some graphical diff viewers (notably tkdiff) can't handle premade diff files. In that case you might can use undiff.py to split the diff into two temporary files. For changes to multiple files (e.g. "svn diff changeset" or just "svn diff"), the various diffs are placed in a temporary directory, along with an index.html file. Subset runs the SUBSET_DIFF_DIR command, passing the temporary directory as an argument. This works nicely with graphical file browsers that understand .diff files. Under KDE, SUBSET_DIFF_DIR='konqueror --profile diff' is a good choice. You should setup your profile to use the index.html file for rendering the directory contents, and customize the default window size. Assuming that everything is installed correctly, clicking on the individual diffs should launch kompare. Modified: trunk/CSP/tools/sublib.py =================================================================== --- trunk/CSP/tools/sublib.py 2004-06-05 20:48:34 UTC (rev 993) +++ trunk/CSP/tools/sublib.py 2004-06-05 23:39:52 UTC (rev 994) @@ -59,6 +59,7 @@ info[line[:idx]] = line[idx+1:].strip() return info + def svn_st(files=None): root = svn_root() if not files: @@ -84,10 +85,12 @@ files.append(File(relpath, root, mode)) return files + #def svn_info(path): # info = os.popen('svn info %s' % path) # app.log.info(info.readlines()) + def svn_rootsvn(): path = '.svn' rootsvn = None @@ -98,10 +101,18 @@ app.log.fatal('must run in a subversion workspace (.svn not found)') return rootsvn + def svn_root(): return os.path.abspath(os.path.dirname(svn_rootsvn())) +def svn_savediff(file, target, context=100): + path = file.path + exit_code, out = runo('svn diff --diff-cmd diff -x "-U %d" %s' % (context, path)) + open(target, 'w').write(''.join(out)) + return exit_code + + def runoe(cmd): process = popen2.Popen3(cmd, capturestderr=1) process.tochild.close() @@ -112,14 +123,17 @@ app.log.debug('run "%s" failed (%d): err=%s, out=%s' % (cmd, exit_code, err, out)) return exit_code, out, err + def runo(cmd): exit_code, out, err = runoe(cmd) return exit_code, out + def run(cmd): exit_code, out, err = runoe(cmd) return exit_code + def svn_submit_review(name, log, contents): info = svn_info() url = info.get('URL', '') Modified: trunk/CSP/tools/subset =================================================================== --- trunk/CSP/tools/subset 2004-06-05 20:48:34 UTC (rev 993) +++ trunk/CSP/tools/subset 2004-06-05 23:39:52 UTC (rev 994) @@ -32,10 +32,7 @@ # TODO # clean up error reporting of review submit -# default changeset? -# use edit function for changeset descriptions (honor save/nosave) -# a changeset diff viewer (extend describe)... maybe a textbased -# diff chooser. also need diffstats +# diffstats # work with tkdiff by piping through undiff @@ -150,16 +147,16 @@ self._date = time.time() self._pending = pending - def describe(self): - print - print 'changelist: %s' % self._name - print 'created on: %s' % self.date() - print - print '\n'.join(self._description) - print + def describe(self, outfile=sys.stdout): + print >>outfile, '' + print >>outfile, 'change set: %s' % self._name + print >>outfile, 'created on: %s' % self.date() + print >>outfile, '' + print >>outfile, '\n'.join(self._description) + print >>outfile, '' if self._files: - for file in self._files: print str(file) - print + for file in self._files: print >>outfile, str(file) + print >>outfile, '' return Result(0) def submit(self): @@ -168,7 +165,7 @@ exitcode = os.system('svn ci -m \'%s\' %s' % (description, ' '.join(files))) if exitcode != 0: - return Error('error submitting changelist') + return Error('error submitting changeset') self._pending = 0 return Result(0) @@ -185,7 +182,7 @@ if new: self._pending = 1 desc = ['<enter a description here>'] - addtext('# changelist : %s' % self._name) + addtext('# change set : %s' % self._name) addtext('# created on : %s' % self.date()) if self._pending: addtext('# status : pending') @@ -362,6 +359,73 @@ self.save() return Result(0) + def diff(self, name): + dircmd = os.environ.get('SUBSET_DIFF_DIR', '') + onecmd = os.environ.get('SUBSET_DIFF_ONE', dircmd) + cs = None + if not name: + files = filter(self._closed, sublib.svn_st()) + elif os.path.exists(name): + files = sublib.svn_st() + path = os.path.abspath(name) + files = [x for x in files if x.abspath() == path] + if not files: + print '%s unmanaged or unchanged' % name + return Result(0) + else: + cs = self.getChangeset(name) + if not cs: + return Error('no changeset "%s"' % name) + files = cs.files() + cs.describe() + if not files: return Result(0) + tmproot = '/tmp/subset.diff.%010d' % random.randint(1, 1000000000) + os.mkdir(tmproot) + cleanup = [] + singleton = not cs and (len(files) == 1) + if singleton and not onecmd: + print 'SUBSET_DIFF_ONE undefined; cannot view diff.' + return Result(1) + if not singleton and not dircmd: + print 'SUBSET_DIFF_DIR undefined; cannot view diff.' + return Result(1) + makeindex = not singleton + if makeindex: + diffindex = os.path.join(tmproot, 'index.html') + index = open(diffindex, 'w') + index.write('<html><body><small>\n') + if cs: + index.write('<h3>Changeset %s</h3>\n' % cs.name()) + index.write('<i>Created on: %s</i><p/>' % cs.date()) + for line in cs.description(): + if line.strip(): + index.write('%s ' % line) + else: + index.write('<p/>\n') + index.write('\n<p/>\n') + else: + index.write('<h3>%s</h3>' % name) + cleanup.append(diffindex) + index.write('<ul>\n') + for file in files: + outbase = file.path.replace(os.path.sep, '~') + '.diff' + outfile = os.path.join(tmproot, outbase) + cleanup.append(outfile) + sublib.svn_savediff(file, outfile) + if makeindex: + index.write('<li><a href="%s">%s</a></li>\n' % (outbase, file.path)) + if makeindex: + index.write('</ul>\n</small></body></html>') + index.close() + if singleton: + os.system('%s %s 2>/dev/null' % (onecmd, cleanup[-1])) + else: + os.system('%s %s 2>/dev/null' % (dircmd, tmproot)) + for path in cleanup: + os.unlink(path) + os.rmdir(tmproot) + return Result(0) + def opened(self, filters=None): files = sublib.svn_st() if filters: @@ -734,6 +798,25 @@ return run('describe', name) +class Diff(Command): + + def _define(self): + self._long = ('diff: generate diffs for files or changesets.\n' + 'usage: %prog diff [changeset|file]') + self._short = 'generate diffs' + self._addKeys('diff') + + def _run(self, options, args): + if len(args) > 1: + self.help() + return 1 + if len(args) == 0: + name = '' + else: + name = args[0] + return run('diff', name) + + class Help(Command): def _define(self): @@ -776,8 +859,18 @@ # register subcommands -Help(), Opened(), Changes(), Assign(), Describe(), Abandon(), Change(), Submit(), Review() +Abandon() +Assign() +Change() +Changes() +Describe() +Diff() +Help() +Opened() +Review() +Submit() + def main(args): if len(args) < 1: app.usage() |