chiark / gitweb /
9dccaf923da4dd8a6408f72f1e552486a0c2b411
[stgit] / stgit / commands / imprt.py
1 __copyright__ = """
2 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License version 2 as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 """
17
18 import sys, os
19 from optparse import OptionParser, make_option
20
21 from stgit.commands.common import *
22 from stgit.utils import *
23 from stgit import stack, git
24
25
26 help = 'import a GNU diff file as a new patch'
27 usage = """%prog [options] [<file>]
28
29 Create a new patch and apply the given GNU diff file (or the standard
30 input). By default, the file name is used as the patch name but this
31 can be overriden with the '--name' option. The patch can either be a
32 normal file with the description at the top or it can have standard
33 mail format, the Subject, From and Date headers being used for
34 generating the patch information.
35
36 The patch description has to be separated from the data with a '---'
37 line. For a normal file, if no author information is given, the first
38 'Signed-off-by:' line is used."""
39
40 options = [make_option('-m', '--mail',
41                        help = 'import the patch from a standard e-mail file',
42                        action = 'store_true'),
43            make_option('-n', '--name',
44                        help = 'use NAME as the patch name'),
45            make_option('-e', '--edit',
46                        help = 'invoke an editor for the patch description',
47                        action = 'store_true'),
48            make_option('-a', '--author', metavar = '"NAME <EMAIL>"',
49                        help = 'use "NAME <EMAIL>" as the author details'),
50            make_option('--authname',
51                        help = 'use AUTHNAME as the author name'),
52            make_option('--authemail',
53                        help = 'use AUTHEMAIL as the author e-mail'),
54            make_option('--authdate',
55                        help = 'use AUTHDATE as the author date'),
56            make_option('--commname',
57                        help = 'use COMMNAME as the committer name'),
58            make_option('--commemail',
59                        help = 'use COMMEMAIL as the committer e-mail')]
60
61
62 def __parse_mail(filename = None):
63     """Parse the input file in a mail format and return (description,
64     authname, authemail, authdate)
65     """
66     if filename:
67         f = file(filename)
68     else:
69         f = sys.stdin
70
71     descr = authname = authemail = authdate = None
72
73     # parse the headers
74     for line in f:
75         line = line.strip()
76         if re.match('from:\s+', line, re.I):
77             auth = re.findall('^.*?:\s+(.*)$', line)[0]
78             authname, authemail = name_email(auth)
79         elif re.match('date:\s+', line, re.I):
80             authdate = re.findall('^.*?:\s+(.*)$', line)[0]
81         elif re.match('subject:\s+', line, re.I):
82             descr = re.findall('^.*?:\s+(.*)$', line)[0]
83         elif line == '':
84             # end of headers
85             break
86
87     # remove the '[*PATCH*]' expression in the subject
88     if descr:
89         descr = re.findall('^(\[[^\s]*PATCH.*?\])?\s*(.*)$', descr)[0][1]
90         descr += '\n\n'
91     else:
92         raise CmdException, 'Subject: line not found'
93
94     # the rest of the patch description
95     for line in f:
96         if re.match('---\s*$', line) or re.match('diff -', line):
97             break
98         else:
99             descr += line
100     descr.rstrip()
101
102     if filename:
103         f.close()
104
105     return (descr, authname, authemail, authdate)
106
107 def __parse_patch(filename = None):
108     """Parse the input file and return (description, authname,
109     authemail, authdate)
110     """
111     if filename:
112         f = file(filename)
113     else:
114         f = sys.stdin
115
116     authname = authemail = authdate = None
117
118     descr = ''
119     for line in f:
120         # the first 'Signed-of-by:' is the author
121         if not authname and re.match('signed-off-by:\s+', line, re.I):
122             auth = re.findall('^.*?:\s+(.*)$', line)[0]
123             authname, authemail = name_email(auth)
124
125         if re.match('---\s*$', line) or re.match('diff -', line):
126             break
127         else:
128             descr += line
129     descr.rstrip()
130
131     if descr == '':
132         descr = None
133
134     if filename:
135         f.close()
136
137     return (descr, authname, authemail, authdate)
138
139 def func(parser, options, args):
140     """Import a GNU diff file as a new patch
141     """
142     if len(args) > 1:
143         parser.error('incorrect number of arguments')
144
145     check_local_changes()
146     check_conflicts()
147     check_head_top_equal()
148
149     if len(args) == 1:
150         filename = args[0]
151     else:
152         filename = None
153
154     if options.name:
155         patch = options.name
156     elif filename:
157         patch = os.path.basename(filename)
158     else:
159         raise CmdException, 'Unkown patch name'
160
161     # the defaults
162     message = author_name = author_email = author_date = committer_name = \
163               committer_email = None
164
165     if options.author:
166         options.authname, options.authemail = name_email(options.author)
167
168     if options.mail:
169         message, author_name, author_email, author_date = \
170                  __parse_mail(filename)
171     else:
172         message, author_name, author_email, author_date = \
173                  __parse_patch(filename)
174
175     # new_patch() will invoke the editor in this case
176     if not message:
177         edit = False
178
179     # override the automatically parsed settings
180     if options.authname:
181         author_name = options.authname
182     if options.authemail:
183         author_email = options.authemail
184     if options.authdate:
185         author_date = options.authdate
186     if options.commname:
187         committer_name = options.commname
188     if options.commemail:
189         committer_email = options.commemail
190
191     crt_series.new_patch(patch, message = message,
192                          author_name = author_name,
193                          author_email = author_email,
194                          author_date = author_date,
195                          committer_name = committer_name,
196                          committer_email = committer_email)
197
198     print 'Importing patch %s...' % patch,
199     sys.stdout.flush()
200
201     git.apply_patch(filename)
202     crt_series.refresh_patch(edit = options.edit)
203
204     print 'done'
205     print_crt_patch()