New stg command: assimilate
[stgit] / stgit / commands / assimilate.py
1 # -*- coding: utf-8 -*-
2
3 __copyright__ = """
4 Copyright (C) 2006, Karl Hasselström <kha@treskal.com>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 """
19
20 import sys, os
21 from optparse import OptionParser, make_option
22
23 from stgit.commands.common import *
24 from stgit.utils import *
25 from stgit import stack, git
26
27 help = 'StGIT-ify any GIT commits made on top of your StGIT stack'
28 usage = """%prog [options]
29
30 If you have made GIT commits on top of your stack of StGIT patches,
31 many StGIT commands will refuse to work. This command converts any
32 such commits to StGIT patches, preserving their contents.
33
34 Only GIT commits with exactly one parent can be assimilated; in other
35 words, if you have committed a merge on top of your stack, this
36 command cannot help you."""
37
38 options = []
39
40 def func(parser, options, args):
41 """Assimilate a number of patches.
42 """
43
44 def nothing_to_do():
45 print 'No commits to assimilate'
46
47 top_patch = crt_series.get_current_patch()
48 if not top_patch:
49 return nothing_to_do()
50
51 victims = []
52 victim = git.get_commit(git.get_head())
53 while victim.get_id_hash() != top_patch.get_top():
54 victims.append(victim)
55 parents = victim.get_parents()
56 if not parents:
57 raise CmdException, 'Commit %s has no parents, aborting' % victim
58 elif len(parents) > 1:
59 raise CmdException, 'Commit %s is a merge, aborting' % victim
60 victim = git.get_commit(parents[0])
61
62 if not victims:
63 return nothing_to_do()
64
65 if crt_series.get_protected():
66 raise CmdException(
67 'This branch is protected. Modification is not permitted')
68
69 patch2name = {}
70 name2patch = {}
71
72 def name_taken(name):
73 return name in name2patch or crt_series.patch_exists(name)
74
75 for victim in victims:
76 patchname = make_patch_name(victim.get_log())
77 if not patchname:
78 patchname = 'patch'
79 if name_taken(patchname):
80 suffix = 0
81 while name_taken('%s-%d' % (patchname, suffix)):
82 suffix += 1
83 patchname = '%s-%d' % (patchname, suffix)
84 patch2name[victim] = patchname
85 name2patch[patchname] = victim
86
87 victims.reverse()
88 for victim in victims:
89 print ('Creating patch "%s" from commit %s'
90 % (patch2name[victim], victim))
91 aname, amail, adate = name_email_date(victim.get_author())
92 cname, cmail, cdate = name_email_date(victim.get_committer())
93 crt_series.new_patch(
94 patch2name[victim],
95 can_edit = False, before_existing = False, refresh = False,
96 top = victim.get_id_hash(), bottom = victim.get_parent(),
97 message = victim.get_log(),
98 author_name = aname, author_email = amail, author_date = adate,
99 committer_name = cname, committer_email = cmail)