# -*- python -*- ### Copyright (C) 2006 Sam Vilain ### based on gquilt_quilt.py, which is: ### Copyright (C) 2005 Peter Williams ### This program is free software; you can redistribute it and/or modify ### it under the terms of the GNU General Public License as published by ### the Free Software Foundation; version 2 of the License only. ### This program is distributed in the hope that it will be useful, ### but WITHOUT ANY WARRANTY; without even the implied warranty of ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ### GNU General Public License for more details. ### You should have received a copy of the GNU General Public License ### along with this program; if not, write to the Free Software ### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # This file provides access to "stgit" functionality required by "gquilt" import gquilt_utils, os.path, os, gquilt_tool, gquilt_pfuns, re class stgit_commands(gquilt_utils.cmd_list): def __init__(self): gquilt_utils.cmd_list.__init__(self) def _get_commands(self): res, sop, eop = gquilt_utils.run_cmd("stg --help") if sop == "": return None lines = sop.splitlines() index = 0 found = 0 cmds = [] while True: if found: lcmds = lines[index].split() cmds.push(lcmds[0]) else: if lines[index].match("commands:"): found = 1 index += 1 cmds.sort() return cmds # run a command and log the result to the provided console def _exec_console_cmd(console, cmd, error=gquilt_tool.ERROR): res, so, se = gquilt_utils.run_cmd(cmd) if console is not None: console.log_cmd(cmd + "\n", so, se) if res != 0: return (error, so, se) else: return (gquilt_tool.OK, so, se) def _patch_file_name(patch): # FIXME - cache this res, so, se = gquilt_utils.run_cmd("stg branch") branch = so.strip() return ".git/patches/" + branch + "/patches/" + patch + "/description" # Now implement the tool interface for quilt class interface(gquilt_tool.interface): def __init__(self): gquilt_tool.interface.__init__(self, "stgit") def is_patch_applied(self, patch): res, so, se = gquilt_utils.run_cmd("stg applied") lines = so.splitlines() index = 0 while lines[index]: lines[index].strip() if lines[index] == patch: return 1 return 0 def top_patch(self): res, so, se = gquilt_utils.run_cmd("stg top") if res == 0 or (se.strip() == "" and so.strip() == ""): return so.strip() elif res == 512 and so.strip() == "": return "" else: raise "stgit_specific_error", se def last_patch_in_series(self): res, op, err = gquilt_utils.run_cmd("stg series -s") if res != 0: raise "stgit_specific_error", se lastline = op.splitlines()[-1] return lastline.match(". (.*)")[1] def display_file_diff_in_viewer(self, viewer, file, patch=None): # XXX - not a good enough abstraction for stg. return def get_patch_description(self, patch): pfn = _patch_file_name(patch) if os.path.exists(pfn): res, lines = gquilt_pfuns.get_patch_descr_lines(pfn) if res: return (gquilt_tool.OK, "\n".join(lines) + "\n", "") else: return (gquilt_tool.ERROR, "", "Error reading patch description\n") else: return (gquilt_tool.OK, "", "") def get_patch_status(self, patch): # XXX - not sure what the "needs refresh" stuff was about if self.is_patch_applied(patch): return (gquilt_tool.OK, gquilt_tool.APPLIED, "") else: return (gquilt_tool.OK, gquilt_tool.NOT_APPLIED, "") def get_series(self): res, op, err = gquilt_utils.run_cmd("stg branch") patch_dir = op.strip() res, op, err = gquilt_utils.run_cmd("stg series") if res != 0: return (gquilt_tool.ERROR, (None, None), err) series = [] for line in op.splitlines(): if line[0] == "-": series.append((line[2:], gquilt_tool.NOT_APPLIED)) else: pn = line[2:] #res, status, err = self.get_patch_status(pn) #series.append((pn, status)) series.append((pn, gquilt_tool.APPLIED)) return (gquilt_tool.OK, (patch_dir, series), "") def get_diff(self, filelist=[], patch=None): if patch is None: cmd = "stg diff -r /bottom" else: cmd = "stg diff -r " + patch + "/bottom:" + patch res, so, se = gquilt_utils.run_cmd(" ".join([cmd, " ".join(filelist)])) if res != 0: return (gquilt_tool.ERROR, so, se) return (res, so, se) def get_combined_diff(self, start_patch=None, end_patch=None): cmd = "stg diff -r " if start_patch is None: cmd += "base" else: cmd += start_patch+"/bottom" if end_patch is not None: cmd += ":" + end_patch res, so, se = gquilt_utils.run_cmd(cmd) if res != 0: return (gquilt_tool.ERROR, so, se) return (res, so, se) def get_patch_files(self, patch=None, withstatus=True): if self.top_patch() == "": return (gquilt_tool.OK, "", "") cmd = "stg files" if not withstatus: cmd += " --bare" if patch is not None: cmd += " " + patch res, so, se = gquilt_utils.run_cmd(cmd) if res != 0: return (gquilt_tool.ERROR, so, se) if withstatus: filelist = [] for line in so.splitlines(): if line[0] == "A": filelist.append((line[2:], gquilt_tool.ADDED)) elif line[0] == "D": filelist.append((line[2:], gquilt_tool.DELETED)) else: filelist.append((line[2:], gquilt_tool.EXTANT)) else: filelist = so.splitlines() return (res, filelist, se) def do_set_patch_description(self, console, patch, description): if patch != self.top_patch: return ( gquilt_tool.ERROR, "", "Can only edit top patch description") # FIXME shellquote properly cmd = "stg refresh -m '" + description + "'" res, so, se = gquilt_utils.run_cmd(cmd) if res == 0: res = gquilt_tool.OK se = "" else: res = gquilt_tool.ERROR se = "Error reading patch description\n" if console is not None: console.log_cmd('set description for "' + patch + '"', "\n", se) return (res, "", se) def do_rename_patch(self, console, patch, newname): cmd = "stg rename " + patch + " " + newname res, so, se = gquilt_utils.run_cmd(cmd) if res != 0: return (gquilt_tool.ERROR, so, se) else: return (gquilt_tool.OK, so, se) def do_pop_patch(self, console, force=False): cmd = "stg pop" res, so, se = _exec_console_cmd(console, cmd) if res != 0: return (gquilt_tool.ERROR, so, se) else: return (gquilt_tool.OK, so, se) def do_push_patch(self, console, force=False): cmd = "stg push" res, so, se = _exec_console_cmd(console, cmd) # FIXME - stg push likes to run merge tools rather than # "requiring refresh" on a push that needs a merge. if res != 0: return (gquilt_tool.ERROR, so, se) else: return (gquilt_tool.OK, so, se) def do_pop_to_patch(self, console, patch=None): cmd = "stg pop " if patch is not None: if patch == "": cmd += "-a" else: cmd += "-t " + patch res, so, se = _exec_console_cmd(console, cmd) if res != 0: return (gquilt_tool.ERROR, so, se) else: return (gquilt_tool.OK, so, se) def do_push_to_patch(self, console, patch=None): cmd = "stg push " if patch is not None: if patch == "": cmd += "-a" else: cmd += "-t " + patch res, so, se = _exec_console_cmd(console, cmd) if res != 0: return (gquilt_tool.ERROR, so, se) else: return (gquilt_tool.OK, so, se) def do_refresh_patch(self, console, patch=None, force=False): if patch is not None: if self.top_patch() != patch: return( gquilt_tool.ERROR, "", "Only the top patch can be refreshed") cmd = "stg refresh" res, so, se = _exec_console_cmd(console, cmd) if res != 0: return (gquilt_tool.ERROR, so, se) else: return (gquilt_tool.OK, so, se) def do_create_new_patch(self, console, name): return _exec_console_cmd(console, "stg new -m 'no description' " + name) def do_import_patch(self, console, filename): return _exec_console_cmd(console, "stg import " + filename) # XXX - support this in the UI def do_import_email(self, console, filename): return _exec_console_cmd(console, "stg import -m " + filename) def do_merge_patch(self, console, filename): # XXX - see stg fold -t for three-way merge option return _exec_console_cmd(console, "stg fold " + filename) def do_delete_patch(self, console, patch): return _exec_console_cmd(console, "stg delete " + patch) def do_add_files_to_patch(self, console, filelist, patch=None): if patch is not None: if self.top_patch() != patch: return( gquilt_tool.ERROR, "", "Only the top patch can have files added to it") cmd = "stg add" return _exec_console_cmd(console, " ".join([cmd, " ".join(filelist)])) def do_remove_files_from_patch(self, console, filelist, patch=None): if patch is not None: if self.top_patch() != patch: return( gquilt_tool.ERROR, "", "Only the top patch can have files removed from it") cmd = "stg rm"; return _exec_console_cmd(console, " ".join([cmd, " ".join(filelist)])) def do_exec_tool_cmd(self, console, cmd): return _exec_console_cmd(console, " ".join(["stg", cmd]))