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
+can be overridden 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."""
+line."""
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('-b', '--base',
+ help = 'use BASE instead of HEAD for file importing'),
make_option('-e', '--edit',
help = 'invoke an editor for the patch description',
action = 'store_true'),
+ make_option('-s', '--showpatch',
+ help = 'show the patch content in the editor buffer',
+ action = 'store_true'),
make_option('-a', '--author', metavar = '"NAME <EMAIL>"',
help = 'use "NAME <EMAIL>" as the author details'),
make_option('--authname',
help = 'use COMMEMAIL as the committer e-mail')]
+def __end_descr(line):
+ return re.match('---\s*$', line) or re.match('diff -', line) or \
+ re.match('Index: ', line)
+
+def __parse_description(descr):
+ """Parse the patch description and return the new description and
+ author information (if any).
+ """
+ subject = body = ''
+ authname = authemail = authdate = None
+
+ descr_lines = [line.rstrip() for line in descr.split('\n')]
+ if not descr_lines:
+ raise CmdException, "Empty patch description"
+
+ lasthdr = 0
+ end = len(descr_lines)
+
+ # Parse the patch header
+ for pos in range(0, end):
+ if not descr_lines[pos]:
+ continue
+ # check for a "From|Author:" line
+ if re.match('\s*(?:from|author):\s+', descr_lines[pos], re.I):
+ auth = re.findall('^.*?:\s+(.*)$', descr_lines[pos])[0]
+ authname, authemail = name_email(auth)
+ lasthdr = pos + 1
+ continue
+ # check for a "Date:" line
+ if re.match('\s*date:\s+', descr_lines[pos], re.I):
+ authdate = re.findall('^.*?:\s+(.*)$', descr_lines[pos])[0]
+ lasthdr = pos + 1
+ continue
+ if subject:
+ break
+ # get the subject
+ subject = descr_lines[pos]
+ lasthdr = pos + 1
+
+ # get the body
+ if lasthdr < end:
+ body = reduce(lambda x, y: x + '\n' + y, descr_lines[lasthdr:], '')
+
+ return (subject + body, authname, authemail, authdate)
+
def __parse_mail(filename = None):
"""Parse the input file in a mail format and return (description,
authname, authemail, authdate)
descr = authname = authemail = authdate = None
# parse the headers
- for line in f:
+ while True:
+ line = f.readline()
+ if not line:
+ break
line = line.strip()
if re.match('from:\s+', line, re.I):
auth = re.findall('^.*?:\s+(.*)$', line)[0]
# remove the '[*PATCH*]' expression in the subject
if descr:
- descr = re.findall('^(\[[^\s]*PATCH.*?\])?\s*(.*)$', descr)[0][1]
+ descr = re.findall('^(\[[^\s]*[Pp][Aa][Tt][Cc][Hh].*?\])?\s*(.*)$',
+ descr)[0][1]
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):
+ while True:
+ line = f.readline()
+ if not line:
+ break
+ if __end_descr(line):
break
else:
descr += line
if filename:
f.close()
+ # parse the description for author information
+ descr, descr_authname, descr_authemail, descr_authdate = __parse_description(descr)
+ if descr_authname:
+ authname = descr_authname
+ if descr_authemail:
+ authemail = descr_authemail
+ if descr_authdate:
+ authdate = descr_authdate
+
return (descr, authname, authemail, authdate)
def __parse_patch(filename = None):
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)
+ while True:
+ line = f.readline()
+ if not line:
+ break
- if re.match('---\s*$', line) or re.match('diff -', line):
+ if __end_descr(line):
break
else:
descr += line
descr.rstrip()
- if descr == '':
- descr = None
-
if filename:
f.close()
+ descr, authname, authemail, authdate = __parse_description(descr)
+
+ # we don't yet have an agreed place for the creation date.
+ # Just return None
return (descr, authname, authemail, authdate)
def func(parser, options, args):
elif filename:
patch = os.path.basename(filename)
else:
- raise CmdException, 'Unkown patch name'
+ raise CmdException, 'Unknown patch name'
# the defaults
message = author_name = author_email = author_date = committer_name = \
message, author_name, author_email, author_date = \
__parse_patch(filename)
- # new_patch() will invoke the editor in this case
+ # refresh_patch() will invoke the editor in this case, with correct
+ # patch content
if not message:
- edit = False
+ can_edit = False
# override the automatically parsed settings
if options.authname:
if options.commemail:
committer_email = options.commemail
- crt_series.new_patch(patch, message = message,
+ crt_series.new_patch(patch, message = message, can_edit = False,
author_name = author_name,
author_email = author_email,
author_date = author_date,
print 'Importing patch %s...' % patch,
sys.stdout.flush()
- git.apply_patch(filename)
- crt_series.refresh_patch(edit = options.edit)
+ if options.base:
+ git.apply_patch(filename, git_id(options.base))
+ else:
+ git.apply_patch(filename)
+
+ crt_series.refresh_patch(edit = options.edit,
+ show_patch = options.showpatch)
print 'done'
print_crt_patch()