2
# -*- coding: utf-8 -*-
3
# Copyright (C) 2012-2014 Canonical
8
# This program is free software; you can redistribute it and/or modify it under
9
# the terms of the GNU General Public License as published by the Free Software
10
# Foundation; version 3.
12
# This program is distributed in the hope that it will be useful, but WITHOUT
13
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17
# You should have received a copy of the GNU General Public License along with
18
# this program; if not, write to the Free Software Foundation, Inc.,b
19
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27
from cupstream2distro import branchhandling, launchpadmanager, packageinppamanager, packagemanager, silomanager, tools
28
from cupstream2distro.stacks import get_stack_packaging_change_status
29
from cupstream2distro.tools import generate_xml_artefacts, get_previous_distro_version_from_config, mark_project_as_published
30
from cupstream2distro.settings import PUBLISHER_ARTEFACTS_FILENAME, PACKAGE_LIST_RSYNC_FILENAME_FORMAT, SRU_PPA, SILO_BUILTCHECKED, SILO_PUBLISHED, PROPOSED_URL
31
from cupstream2distro.utils import ignored
34
if __name__ == '__main__':
36
parser = argparse.ArgumentParser(description="Watch for published package in a ppa. Create a xml artefact if manual copy is needed.")
38
parser.add_argument("publisher", help="Launchpad nickname of the person publishing that package.")
39
parser.add_argument("--ackpackaging", action='store_true', help="Publish even if there are packaging change. Only done after manual reviews of the diff.")
40
parser.add_argument("--ignoremissingprojects", action='store_true', help="Ignore if some projects that are going to be published are missing from the initial set (can be a second publication for instance).")
41
parser.add_argument("--ignorestep", action='store_true', help="Ignore if previous step didn't successfully end.")
42
parser.add_argument("--ignoreversiondestination", action='store_true', help="Ignore if the latest version in destination doesn't match when prepare was started.")
43
parser.add_argument('-d', '--debug', action='store_true', default=False, help="Enable debug infos")
45
args = parser.parse_args()
47
logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO,
48
format="%(asctime)s %(levelname)s %(message)s")
50
logging.debug("Debug mode enabled")
52
silo_config = silomanager.load_config()
53
silomanager.set_config_status(silo_config, "Publishing")
54
series = launchpadmanager.get_resource_from_token(silo_config["global"]["series"]).name
55
src_ppa = launchpadmanager.get_resource_from_token(silo_config["global"]["ppa"])
56
src_ppa_name = "{}/{}".format(src_ppa.owner.name, src_ppa.name)
57
src_pocket = 'Release'
58
dest_link = silo_config["global"]["dest"]
59
publisher_nickname = args.publisher
61
base_path = os.path.abspath('.')
63
if silomanager.get_config_step(silo_config) != SILO_BUILTCHECKED:
65
logging.info("Last step didn't finish successfully, but the ignore flag is set.")
67
logging.error("Last step didn't finish successfully. You need to either ignore that the previous step didn't finished successfully or ensuring that prepare, build and checked passed.")
68
silomanager.set_config_status(silo_config, "Can't publish: wrong status or parameters for job.")
71
if not silomanager.set_config_step(silo_config, SILO_BUILTCHECKED):
72
logging.error("Couldn't reset the step in the configuration file.")
73
silomanager.set_config_status(silo_config, "Publication failed: couldn't reset status or parameters for job.")
75
all_silo_projects = silomanager.get_all_projects(silo_config)
77
# check the publisher exists
79
launchpadmanager.get_person(publisher_nickname)
81
message = "{} isn't a valid launchpad user name. Can't publish the silo".format(publisher_nickname)
82
logging.error(message)
83
silomanager.set_config_status(silo_config, "Publication failed: {}".format(message))
86
logging.info("Publishing as {}.".format(publisher_nickname))
88
# getting the archives and series objects
89
is_sru = not launchpadmanager.is_series_current(series)
90
dest_archive = launchpadmanager.get_resource_from_token(dest_link)
91
if not launchpadmanager.is_dest_ubuntu_archive(dest_link):
92
dest_pocket = 'Release'
93
logging.info("Direct copy from {src_archive} ({src_pocket}) to {dest_archive} ({dest_pocket}) for {series} series".format(
94
src_archive=src_ppa.name, src_pocket=src_pocket, dest_archive=dest_archive.name, dest_pocket=dest_pocket,
97
logging.info("Copy from {src_archive} ({src_pocket}) to {series} series in distro".format(
98
src_archive=src_ppa.name, src_pocket=src_pocket, series=series))
99
distro = launchpadmanager.get_resource_from_token(dest_link)
100
distro_pocket = 'Proposed'
101
src_ppa_pocket = src_pocket
103
logging.info("This upload is part of a SRU. Please do not free the silo until the package lands in the archive!")
105
manual_publish_cause_list = []
107
all_packages_uploaded = packageinppamanager.get_all_packages_uploaded()
109
# Generate global packaging change status
110
manual_publish_cause_list.extend(get_stack_packaging_change_status(all_packages_uploaded))
112
# we only go on manual publishing if we have something to publish
113
if not args.ackpackaging and all_packages_uploaded and manual_publish_cause_list:
114
logging.info("Don't upload the silo automatically.")
115
generate_xml_artefacts("Publisher", manual_publish_cause_list, PUBLISHER_ARTEFACTS_FILENAME)
116
silomanager.set_config_status(silo_config, "Publication needs action: some packaging changes needs manual acking. See them at {}".format(os.getenv('BUILD_URL')), add_url=False)
119
packagelist_to_copy = []
120
src_version_check_fail = False
121
dest_version_check_fail = False
123
error_pushing_branch = False
125
published_packagelist = {}
127
# check and generate metadata
128
# TODO: we loop on all_packages_uploaded which is based on .project files. We should loop first on the config content (but still have a warning if we have more .project files)
129
for (source, version, tip_rev, branch) in all_packages_uploaded:
130
logging.info("Checking {} ({})".format(source, version))
132
all_silo_projects.remove(source)
134
# TODO: make that check first in its own loop
135
# TODO2: add an option to say "it's ok, please remove from file system everything that's not mentionned in the config file"
136
message = "{} wasn't in the initiale configuration.\nUnknown state. Please reconfigure and reprepare the whole silo.".format(source)
137
logging.error(message)
138
silomanager.set_config_status(silo_config, "Can't publish: " + message)
140
supposed_dest_version = get_previous_distro_version_from_config(source)
142
# check source version
143
version_in_src = packagemanager.get_current_version_for_series(source, series, dest=src_ppa)
144
if version_in_src != version:
145
logging.error("Version in {}/{} ({}) is not the last one prepared ({}) (direct upload?).".format(src_ppa.owner.name, src_ppa.name, version_in_src, version))
146
src_version_check_fail = True
148
published_packagelist[source] = version
150
# check destination version
151
message = "Previous available version ({}) is not the latest version anymore in [] ([]).\nPlease ensure that this version has been merged back in trunk and relaunch prepare or use ignore version destination option.".format(supposed_dest_version)
152
if launchpadmanager.is_dest_ubuntu_archive(dest_link):
153
# Check that we don't skip a version unintendly
154
version_in_dest = packagemanager.get_current_version_for_series(source, series, dest=launchpadmanager.get_ubuntu_archive())
155
if not version_in_dest == supposed_dest_version:
156
logging.error(message.replace('[]', '{}').format("the archive", version_in_dest))
157
dest_version_check_fail = True
158
packagelist_to_copy.append("{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}".format(src_ppa_name, src_ppa_pocket, series, distro_pocket, series, source, version, version_in_dest, publisher_nickname))
160
if source in silo_config["mps"]:
161
branch_uri = os.path.join(base_path, source)
162
lp_project_name = launchpadmanager.get_resource_from_token(silo_config["mps"][source][0]).target_branch.project.name
163
proposed_branch = PROPOSED_URL.format(lp_project_name, series)
164
logging.info("Pushing {} to {}".format(source, proposed_branch))
165
if not branchhandling.push_to_branch(branch_uri, proposed_branch, overwrite=True):
166
logging.error("We couldn't push {} to {}".format(source, proposed_branch))
167
error_pushing_branch = True
170
version_in_dest = packagemanager.get_current_version_for_series(source, series, dest=dest_archive)
171
if not version_in_dest == supposed_dest_version:
172
logging.warning(message.replace('[]', '{}').format(dest_archive.name, version_in_dest))
173
dest_version_check_fail = True
175
if error_pushing_branch:
176
message = "We had some branches that couldn't be pushed to their proposed location."
177
logging.error(message)
178
silomanager.set_config_status(silo_config, "Can't publish: " + message)
181
# remove eventual already published projects:
182
for source in tools.get_published_to_distro_projects():
183
with ignored(ValueError):
184
all_silo_projects.remove(source)
186
if all_silo_projects:
187
message = "Some projects ({}) that were in the silo configuration list were not built. ".format(", ".join(all_silo_projects))
188
if args.ignoremissingprojects:
189
logging.info(message + "The ignore missing projects flag was set.")
191
logging.error(message + "Prepare either prepare the latest missing projects or use the ignore missing projects flag which will release the lock on them.")
192
silomanager.set_config_status(silo_config, "Can't publish: " + message)
195
if src_version_check_fail:
196
message = "Some packages in the ppa are not at the latest version. Please rerun the prepare job, eventually only with that project."
197
logging.error(message)
198
silomanager.set_config_status(silo_config, "Can't publish: " + message)
201
if dest_version_check_fail:
202
if args.ignoreversiondestination:
203
logging.info("Some version destination don't match the latest available in dest, but ignore flag was set.")
205
message = "Not all versions when starting prepare are the latest at destination. Read above and either use ignore version destination option or rerun prepare"
206
logging.error(message)
207
silomanager.set_config_status(silo_config, "Can't publish: " + message)
210
# now ack the changes (if copy is needed)
211
if not launchpadmanager.is_dest_ubuntu_archive(dest_link):
212
for (source, version, tip_rev, branch) in all_packages_uploaded:
213
dest_archive.copyPackage(from_archive=src_ppa, from_pocket=src_pocket, from_series=series,
214
include_binaries=True, to_pocket=dest_pocket, to_series=series,
215
source_name=source, version=version)
216
# generate a file for distro that will be rsynced from another place
217
if packagelist_to_copy:
218
package_list_rsync_file = PACKAGE_LIST_RSYNC_FILENAME_FORMAT.format(os.path.abspath('').split(os.path.sep)[-1], series)
219
logging.info("Writing {} for being able to rsync from main machine".format(package_list_rsync_file))
220
with open(package_list_rsync_file, 'w') as f:
221
f.write("\n".join(packagelist_to_copy))
223
# mark now all packages as published
224
for (source, version, tip_rev, branch) in all_packages_uploaded:
225
mark_project_as_published(source, version)
226
generate_xml_artefacts("Publisher", [], PUBLISHER_ARTEFACTS_FILENAME)
227
if not silomanager.set_config_step(silo_config, SILO_PUBLISHED):
228
message = "Couldn't save the step in the configuration file."
229
logging.error(message)
230
silomanager.set_config_status(silo_config, "Publication failed: " + message)
233
silomanager.set_config_pkgversionlist(silo_config, published_packagelist)
234
silomanager.set_config_status(silo_config, "Packages migrating to destination. Wait a couple of hours and click merge & clean", add_url=False)