From 0d2cd1e4238e397072360bad902c8a0cff4efcb0 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Wed, 27 Jul 2005 22:17:25 +0100 Subject: [PATCH] Implement an 'import' command This patch implements the 'import' command. Signed-off-by: Catalin Marinas --- stgit/commands/imprt.py | 196 ++++++++++++++++++++++++++++++++++++++++++++++++ stgit/git.py | 21 ++++++ stgit/main.py | 2 + 3 files changed, 219 insertions(+) create mode 100644 stgit/commands/imprt.py diff --git a/stgit/commands/imprt.py b/stgit/commands/imprt.py new file mode 100644 index 0000000..5e3eddd --- /dev/null +++ b/stgit/commands/imprt.py @@ -0,0 +1,196 @@ +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +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 +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'import a GNU diff file as a new patch' +usage = """%prog [options] [] + +Create a new patch and apply the given GNU diff file (or the standard +input). By default, the file name is used as the patch name but this +can be overriden with the '--name' option. The patch can either be a +normal file with the description at the top or it can have standard +mail format, the Subject, From and Date headers being used for +generating the patch information. + +The patch description has to be separated from the data with a '---' +line. For a normal file, if no author information is given, the first +'Signed-off-by:' line is used.""" + +options = [make_option('-m', '--mail', + help = 'import the patch from a standard e-mail file', + action = 'store_true'), + make_option('-n', '--name', + help = 'use NAME as the patch name'), + make_option('-a', '--author', metavar = '"NAME "', + help = 'use "NAME " as the author details'), + make_option('--authname', + help = 'use AUTHNAME as the author name'), + make_option('--authemail', + help = 'use AUTHEMAIL as the author e-mail'), + make_option('--authdate', + help = 'use AUTHDATE as the author date'), + make_option('--commname', + help = 'use COMMNAME as the committer name'), + make_option('--commemail', + help = 'use COMMEMAIL as the committer e-mail')] + + +def __parse_mail(filename = None): + """Parse the input file in a mail format and return (description, + authname, authemail, authdate) + """ + if filename: + f = file(filename) + else: + f = sys.stdin + + descr = authname = authemail = authdate = None + + # parse the headers + for line in f: + line = line.strip() + if re.match('from:\s+', line, re.I): + auth = re.findall('^.*?:\s+(.*)$', line)[0] + authname, authemail = name_email(auth) + elif re.match('date:\s+', line, re.I): + authdate = re.findall('^.*?:\s+(.*)$', line)[0] + elif re.match('subject:\s+', line, re.I): + descr = re.findall('^.*?:\s+(.*)$', line)[0] + elif line == '': + # end of headers + break + + # remove extra '[*PATCH]', 'name:' in the subject + if descr: + descr = re.findall('^(\[[^\s]*PATCH.*?\])?\s*([^\s]*:)?\s*(.*)$', + descr)[0][2] + descr += '\n\n' + else: + raise CmdException, 'Subject: line not found' + + # the rest of the patch description + for line in f: + if re.match('----*\s*$', line) or re.match('diff -', line): + break + else: + descr += line + descr.rstrip() + + if filename: + f.close() + + return (descr, authname, authemail, authdate) + +def __parse_patch(filename = None): + """Parse the input file and return (description, authname, + authemail, authdate) + """ + if filename: + f = file(filename) + else: + f = sys.stdin + + authname = authemail = authdate = None + + descr = '' + for line in f: + # the first 'Signed-of-by:' is the author + if not authname and re.match('signed-off-by:\s+', line, re.I): + auth = re.findall('^.*?:\s+(.*)$', line)[0] + authname, authemail = name_email(auth) + + if re.match('----*\s*$', line) or re.match('diff -', line): + break + else: + descr += line + descr.rstrip() + + if descr == '': + descr = None + + if filename: + f.close() + + return (descr, authname, authemail, authdate) + +def func(parser, options, args): + """Import a GNU diff file as a new patch + """ + if len(args) > 1: + parser.error('incorrect number of arguments') + + check_local_changes() + check_conflicts() + check_head_top_equal() + + if len(args) == 1: + filename = args[0] + patch = os.path.basename(filename) + elif options.name: + filename = None + patch = options.name + else: + raise CmdException, 'Unkown patch name' + + # the defaults + message = author_name = author_email = author_date = committer_name = \ + committer_email = None + + if options.author: + options.authname, options.authemail = name_email(options.author) + + if options.mail: + message, author_name, author_email, author_date = \ + __parse_mail(filename) + else: + message, author_name, author_email, author_date = \ + __parse_patch(filename) + + # override the automatically parsed settings + if options.authname: + author_name = options.authname + if options.authemail: + author_email = options.authemail + if options.authdate: + author_date = options.authdate + if options.commname: + committer_name = options.commname + if options.commemail: + committer_email = options.commemail + + crt_series.new_patch(patch, message = message, + author_name = author_name, + author_email = author_email, + author_date = author_date, + committer_name = committer_name, + committer_email = committer_email) + + print 'Importing patch %s...' % patch, + sys.stdout.flush() + + git.apply_patch(filename) + crt_series.refresh_patch() + + print 'done' + print_crt_patch() diff --git a/stgit/git.py b/stgit/git.py index 634a903..aa7bf1b 100644 --- a/stgit/git.py +++ b/stgit/git.py @@ -91,6 +91,15 @@ def get_conflicts(): else: return None +def _input(cmd, file_desc): + p = popen2.Popen3(cmd) + for line in file_desc: + print line + p.tochild.write(line) + p.tochild.close() + if p.wait(): + raise GitException, '%s failed' % str(cmd) + def _output(cmd): p=popen2.Popen3(cmd) string = p.fromchild.read() @@ -454,3 +463,15 @@ def fetch(location, head = None, tag = None): raise GitException, 'Failed "git fetch %s"' % location return read_string(os.path.join(base_dir, 'FETCH_HEAD')) + +def apply_patch(filename = None): + """Apply a patch onto the current index. There must not be any + local changes in the tree, otherwise the command fails + """ + os.system('git-update-cache --refresh > /dev/null') + + if filename: + if __run('git-apply --index', [filename]) != 0: + raise GitException, 'Patch does not apply cleanly' + else: + _input('git-apply --index', sys.stdin) diff --git a/stgit/main.py b/stgit/main.py index 3e7720d..3fd11a1 100644 --- a/stgit/main.py +++ b/stgit/main.py @@ -35,6 +35,7 @@ import stgit.commands.diff import stgit.commands.clean import stgit.commands.export import stgit.commands.files +import stgit.commands.imprt import stgit.commands.init import stgit.commands.mail import stgit.commands.new @@ -62,6 +63,7 @@ commands = { 'clean': stgit.commands.clean, 'export': stgit.commands.export, 'files': stgit.commands.files, + 'import': stgit.commands.imprt, 'init': stgit.commands.init, 'mail': stgit.commands.mail, 'new': stgit.commands.new, -- 2.11.0