-
Notifications
You must be signed in to change notification settings - Fork 1
/
vcs_up_to_date.py
182 lines (150 loc) · 5.82 KB
/
vcs_up_to_date.py
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
#!/usr/bin/python3
# Copyright (C) 2022 Jelmer Vernooij <[email protected]>
#
# 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
__all__ = [
'PackageMissingInArchive',
'NewArchiveVersion',
'MissingChangelogError',
'TreeVersionNotInArchive',
'check_up_to_date',
]
import asyncio
import logging
import os
from typing import List
from debian.changelog import Version
from debmutate.changelog import distribution_is_unreleased
from breezy.tree import Tree
from breezy.workingtree import WorkingTree
from breezy.plugins.debian.util import find_changelog, MissingChangelogError
from breezy.plugins.debian.apt_repo import (
Apt,
LocalApt,
RemoteApt,
)
class PackageMissingInArchive(Exception):
def __init__(self, package):
self.package = package
super().__init__(
"package %s is missing in archive" % package)
class NewArchiveVersion(Exception):
def __init__(self, archive_version, tree_version):
self.archive_version = archive_version
self.tree_version = tree_version
super().__init__(
"archive version {} is newer than version {} in tree".format(
archive_version, tree_version))
class TreeVersionNotInArchive(Exception):
def __init__(self, tree_version, archive_versions):
self.tree_version = tree_version
self.archive_versions = archive_versions
super().__init__(
"tree version %s does not appear in archive" %
tree_version
)
def check_up_to_date(tree: Tree, subpath: str, apt: Apt) -> None:
released_tree_versions = []
tree_cl, top_level = find_changelog(tree, subpath, max_blocks=None)
for block in tree_cl:
if distribution_is_unreleased(block.distributions):
continue
try:
released_tree_versions.append(block.version)
except ValueError:
# If the version is invalid, then hopefully it's safe
# to assume it's not in the archive
with apt:
last_archive_version = max(
entry['Version']
for entry in apt.iter_source_by_name(tree_cl.package))
raise TreeVersionNotInArchive(block._raw_version, None)
package = tree_cl.package
released_tree_versions.sort()
if not released_tree_versions:
# Package hasn't made it into the archive yet?
return
last_released_tree_version = released_tree_versions[-1]
archive_versions: List[Version] = []
with apt:
for entry in apt.iter_source_by_name(package):
archive_versions.append(Version(entry['Version']))
archive_versions.sort()
if not archive_versions:
if last_released_tree_version is None:
# Package has not made it into the archive yet
return
raise PackageMissingInArchive(package)
last_archive_version = archive_versions[-1]
if (last_archive_version not in released_tree_versions and
last_archive_version > last_released_tree_version):
raise NewArchiveVersion(
last_archive_version, last_released_tree_version)
if last_released_tree_version not in archive_versions:
raise TreeVersionNotInArchive(
last_released_tree_version, archive_versions)
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
'--apt-repository', type=str,
help='APT repository to use. Defaults to locally configured.',
default=(
os.environ.get('APT_REPOSITORY')
or os.environ.get('REPOSITORIES')))
parser.add_argument(
'--apt-repository-key', type=str,
help=('APT repository key to use for validation, '
'if --apt-repository is set.'),
default=os.environ.get('APT_REPOSITORY_KEY'))
parser.add_argument(
'directory', default='.', nargs='?',
type=str, help='Path to working tree')
import breezy.bzr # noqa: F401
import breezy.git # noqa: F401
args = parser.parse_args()
logging.basicConfig(level=logging.INFO, format='%(message)s')
if args.apt_repository:
apt = RemoteApt.from_string(
args.apt_repository, args.apt_repository_key)
else:
apt = LocalApt()
tree, subpath = WorkingTree.open_containing(args.directory)
try:
check_up_to_date(tree, subpath, apt)
except TreeVersionNotInArchive as exc:
logging.fatal(
'Last released tree version %s not in archive (%s)',
exc.tree_version,
f"latest: {exc.archive_versions[-1]}"
if exc.archive_versions else "not present")
return 1
except NewArchiveVersion as exc:
# TODO(jelmer): Downgrade to a warning if there are only no-op changes
logging.fatal(
'New archive version %s is missing in tree',
exc.archive_version)
return 1
except PackageMissingInArchive as exc:
logging.fatal(
'%s not found in the specified archive', exc.package)
return 1
except MissingChangelogError:
logging.fatal('Unable to find a changelog file')
return 1
return 0
if __name__ == "__main__":
import sys
sys.exit(asyncio.run(main()))