aboutsummaryrefslogtreecommitdiffhomepage
path: root/gbp/scripts/import_ref.py
blob: fcc10bff7ac8cb5bc43e27217228d34b952c3178 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# vim: set fileencoding=utf-8 :
#
# (C) 2018 Michael Stapelberg <stapelberg@debian.org>
#     2018 Guido Günther <agx@sigxcpu.org>
#    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; either version 2 of the License, or
#    (at your option) any later version.
#
#    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, please see
#    <http://www.gnu.org/licenses/>
#
"""Import a new upstream version from a git branch onto the Debian branch"""

import os
import sys
import gbp.command_wrappers as gbpc
from gbp.deb.git import GitRepositoryError
from gbp.config import GbpOptionParserDebian, GbpOptionGroup
from gbp.errors import GbpError
import gbp.log
from gbp.scripts.common import ExitCodes
from gbp.deb.rollbackgit import RollbackDebianGitRepository

from gbp.scripts.import_orig import (debian_branch_merge,
                                     postimport_hook,
                                     set_bare_repo_options,
                                     rollback)


def get_commit_and_version_to_merge(repo, options):
    """
    Get the commit and version we want to merge based on the
    --upstream-tag setting
    """
    version = options.version
    if options.upstream_tree.upper() == 'VERSION':
        # Determine tag name from given version
        if not options.version:
            raise GbpError("No upstream version given, try -u<version>")
        commit = repo.version_to_tag(options.upstream_tag, options.version)
    elif options.upstream_tree.upper() == 'BRANCH':
        # Use head of upstrem branch
        if not repo.has_branch(options.upstream_branch):
            raise GbpError("%s is not a valid branch" % options.upstream_branch)
        commit = options.upstream_branch
    else:
        # Use whatever is passed in as commitish
        commit = "%s^{commit}" % options.upstream_tree
    return commit, version


def build_parser(name):
    try:
        parser = GbpOptionParserDebian(command=os.path.basename(name), prefix='',
                                       usage='%prog [options] /path/to/upstream-version.tar.gz | --uscan')
    except GbpError as err:
        gbp.log.err(err)
        return None

    import_group = GbpOptionGroup(parser, "import options",
                                  "import related options")
    tag_group = GbpOptionGroup(parser, "tag options",
                               "tag related options ")
    branch_group = GbpOptionGroup(parser, "version and branch naming options",
                                  "version number and branch layout options")
    cmd_group = GbpOptionGroup(parser, "external command options",
                               "how and when to invoke external commands and hooks")
    for group in [import_group, branch_group, tag_group, cmd_group]:
        parser.add_option_group(group)

    branch_group.add_option("-u", "--upstream-version", dest="version",
                            help="The version number to use for the new version, "
                            "default is ''", default='')
    branch_group.add_config_file_option(option_name="debian-branch",
                                        dest="debian_branch")
    branch_group.add_config_file_option(option_name="upstream-branch",
                                        dest="upstream_branch")
    branch_group.add_config_file_option(option_name="upstream-tree",
                                        dest="upstream_tree",
                                        help="Where to merge the upstream changes from.",
                                        default="VERSION")
    branch_group.add_config_file_option(option_name="merge-mode", dest="merge_mode")

    tag_group.add_boolean_config_file_option(option_name="sign-tags",
                                             dest="sign_tags")
    tag_group.add_config_file_option(option_name="keyid",
                                     dest="keyid")
    tag_group.add_config_file_option(option_name="upstream-tag",
                                     dest="upstream_tag")
    import_group.add_config_file_option(option_name="import-msg",
                                        dest="import_msg")
    cmd_group.add_config_file_option(option_name="postimport", dest="postimport")

    parser.add_boolean_config_file_option(option_name="rollback",
                                          dest="rollback")
    parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False,
                      help="verbose command execution")
    parser.add_config_file_option(option_name="color", dest="color", type='tristate')
    parser.add_config_file_option(option_name="color-scheme",
                                  dest="color_scheme")
    return parser


def parse_args(argv):
    """Parse the command line arguments
    @return: options and arguments
    """

    parser = build_parser(argv[0])
    if not parser:
        return None, None

    (options, args) = parser.parse_args(argv[1:])
    gbp.log.setup(options.color, options.verbose, options.color_scheme)

    return options, args


def main(argv):
    ret = 0
    repo = None

    (options, args) = parse_args(argv)
    if not options:
        return ExitCodes.parse_error

    # TODO: honor --filter option
    # TODO: add --filter-with-copyright which takes d/copyright into account
    # TODO: handle automatic versions based on timestamp + sha1
    # TODO: handle updating of upstream branch from remote
    gbp.log.warn("This script is experimental, it might change incompatibly between versions.")
    try:
        try:
            repo = RollbackDebianGitRepository('.')
        except GitRepositoryError:
            raise GbpError("%s is not a git repository" % (os.path.abspath('.')))

        commit, version = get_commit_and_version_to_merge(repo, options)

        is_empty = repo.is_empty()

        (clean, out) = repo.is_clean()
        if not clean and not is_empty:
            gbp.log.err("Repository has uncommitted changes, commit these first: ")
            raise GbpError(out)

        if repo.bare:
            set_bare_repo_options(options)

        try:
            tag = repo.version_to_tag(options.upstream_tag, version)
            if not repo.has_tag(tag):
                gbp.log.info("Upstream tag '%s' not found. Creating it for you." % tag)
                repo.create_tag(name=tag,
                                msg="Upstream version %s" % version,
                                commit="%s^0" % commit,
                                sign=options.sign_tags,
                                keyid=options.keyid)

            if is_empty:
                repo.create_branch(branch=options.debian_branch, rev=commit)
                repo.force_head(options.debian_branch, hard=True)
                # In an empty repo avoid master branch defaulted to by
                # git and check out debian branch instead.
                if not repo.bare:
                    cur = repo.branch
                    if cur != options.debian_branch:
                        repo.set_branch(options.debian_branch)
                        repo.delete_branch(cur)
            else:
                repo.rrr_branch(options.debian_branch)
                debian_branch_merge(repo, tag, version, options)

            # Update working copy and index if we've possibly updated the
            # checked out branch
            current_branch = repo.get_branch()
            if current_branch in [options.upstream_branch,
                                  repo.pristine_tar_branch]:
                repo.force_head(current_branch, hard=True)

            postimport_hook(repo, tag, version, options)
        except (gbpc.CommandExecFailed, GitRepositoryError) as err:
            msg = str(err) or 'Unknown error, please report a bug'
            raise GbpError("Import of %s failed: %s" % (commit, msg))
        except KeyboardInterrupt:
            raise GbpError("Import of %s failed: aborted by user" % (options.git_ref))
    except GbpError as err:
        if str(err):
            gbp.log.err(err)
        ret = 1
        rollback(repo, options)

    if not ret:
        gbp.log.info("Successfully imported version %s" % (version))
    return ret


if __name__ == "__main__":
    sys.exit(main(sys.argv))

# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: