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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
# frozen_string_literal: true
#
# Copyright (C) 2014-2016 Harald Sitter <sitter@kde.org>
# Copyright (C) 2014-2016 Rohan Garg <rohan@garg.io>
# Copyright (C) 2015 Jonathan Riddell <jr@jriddell.org>
# Copyright (C) 2015 Bhushan Shah <bshah@kde.org>
# Copyright (C) 2017 Philip Muskovac <yofel@kubuntu.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) version 3, or any
# later version accepted by the membership of KDE e.V. (or its
# successor approved by the membership of KDE e.V.), which shall
# act as a proxy defined in Section 6 of version 3 of the license.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
require 'fileutils'
require 'forwardable' # For cleanup_uri delegation
require 'json'
require_relative 'ci/git'
require_relative 'ci/overrides'
require_relative 'ci/upstream_scm'
require_relative 'debian/control'
require_relative 'debian/source'
require_relative 'kde'
require_relative 'retry'
require_relative 'deprecate'
# A thing that gets built.
class Project
class Error < RuntimeError; end
class BranchError < RuntimeError; end
class TransactionError < Error; end
class BzrTransactionError < TransactionError; end
extend Deprecate
# Name of the thing (e.g. the repo name)
attr_reader :name
# Super component (e.g. plasma)
attr_reader :component
# Scm instance describing the upstream SCM associated with this project.
# FIXME: should this really be writable? need this for projects to force
# a different scm which is slightly meh
attr_accessor :upstream_scm
# Array of binary packages (debs) provided by this project
attr_reader :provided_binaries
# Array of package dependencies, initialized by default from control file
attr_reader :dependencies
# Array of package dependees, empty Array by default
attr_reader :dependees
# Array of branch names that are series specific. May be empty if there are
# none.
attr_reader :series_branches
# Bool whether this project uses autopkgtest
attr_reader :autopkgtest
# Packaging SCM instance
attr_reader :packaging_scm
# CI Build type of this project instance
attr_reader :build_type
DEFAULT_URL = 'git.debian.org:/git/pkg-kde'.freeze
@default_url = DEFAULT_URL
class << self
attr_accessor :default_url
# TODO: drop cleanup_uri
extend Deprecate
extend Forwardable
def_delegator CI::SCM, :cleanup_uri, :cleanup_uri
deprecate :cleanup_uri, 'SCM::CI::cleanup_uri', 2016, 02
end
# Init
# @param name name of the project (this is equal to the name of the packaging
# repo)
# @param component component within which the project resides (i.e. directory
# part of the repo path)
# @param url_base the base path of the full repo URI. Combined with name and
# component this should form a repo URI
# @param branch branch name in packaging repository to use
# branches.
# @param type the type of integration project (unstable/stable..).
# This indicates whether to look for kubuntu_unstable or kubuntu_stable
# NB: THIS is mutually exclusive with branch!
def initialize(name, component, url_base = self.class.default_url,
type: nil,
branch: "kubuntu_#{type}")
variable_deprecation(:type, :branch) unless type.nil?
@name = name
@component = component
@packaging_component = component
@upstream_scm = nil
@provided_binaries = []
@dependencies = []
@dependees = []
@series_branches = []
@autopkgtest = false
@packaging_branch = branch
@working_directory = Dir.pwd
# FIXME: this should run at the end. test currently assume it isn't though
validate!
cache_dir = init_packaging_scm(url_base, branch)
@override_rule = CI::Overrides.new.rules_for_scm(@packaging_scm)
override_apply('packaging_scm')
@name = @override_rule['name'] if @override_rule.key?('name')
Dir.chdir(cache_dir) do
get
Dir.chdir(name) do
update(branch)
# FIXME: shouldn't this raise something?
next unless File.exist?('debian/control')
init_from_source(Dir.pwd)
end
end
@override_rule.each do |member, _|
override_apply(member)
end
end
private
def validate!
# Jenkins doesn't like slashes. Nor should it have to, any sort of ordering
# would be the result of component/name, which is precisely why neither must
# contain additional slashes as then they'd be $pathtype/$pathtype which
# often will need different code (mkpath vs. mkdir).
if @name.include?('/')
raise NameError, "name value contains a slash: #{@name}"
end
if @component.include?('/')
raise NameError, "component contains a slash: #{@component}"
end
end
def init_from_source(directory)
control = Debian::Control.new(directory)
# TODO: raise? return?
control.parse!
init_from_control(control)
if @component != 'launchpad'
# NOTE: assumption is that launchpad always is native even when
# otherwise noted in packaging. This is somewhat meh and probably
# should be looked into at some point.
# Primary motivation are compound UDD branches as well as shit
# packages that are dpkg-source v1...
unless Debian::Source.new(directory).format.type == :native
set_upstream_from_package
end
end
end
def set_upstream_from_package
kde = Kde.new(@name, @working_directory)
begin
kde.parse
@component = kde.component
branch = kde.branch_dev
# use stable branch if there is one
if @packaging_branch == 'kubuntu_stable' && !kde.branch_stable.strip.empty?
branch = kde.branch_stable
end
rescue Kde::ParseError
branch = kde.branch_dev
end
# if upstream has master set as stable, then we re-use the
# unstable build for stable
@component = 'frameworks' if kde.branch_stable == kde.branch_dev
# for manual overrides, please edit ppa_copy_package.rb
if branch == kde.branch_dev && @packaging_branch == 'kubuntu_stable'
# we don't have a valid branch, so throw error if there's no override
message = "#{branch} not allowed for #{@packaging_branch} build"
raise BranchError, message unless @override_rule.key?('upstream_scm')
raise BranchError, message unless @override_rule['upstream_scm'].key?('branch')
end
@upstream_scm = CI::UpstreamSCM.new(@packaging_scm.url,
@packaging_scm.branch,
Dir.pwd,
branch)
end
def init_deps_from_control(control)
fields = %w(build-depends)
# Do not cover indep for Qt because Qt packages have a dep loop in them.
unless control.source.fetch('Source', '').include?('-opensource-src')
fields << 'build-depends-indep'
end
fields.each do |field|
control.source.fetch(field, []).each do |dep|
@dependencies << dep.name
end
end
end
def init_from_control(control)
init_deps_from_control(control)
control.binaries.each do |binary|
@provided_binaries << binary['package']
end
# FIXME: Probably should be converted to a symbol at a later point
# since xs-testsuite could change to random other string in the
# future
@autopkgtest = control.source['xs-testsuite'] == 'autopkgtest'
end
def render_override(erb)
# Versions would be a float. Coerce into string.
ERB.new(erb.to_s).result(binding)
end
def override_rule_for(member)
@override_rule.delete(member) || {}
end
# TODO: this doesn't do deep-application. So we can override attributes of
# our instance vars, but not of the instance var's instance vars.
# (no use case right now)
# TODO: when overriding with value nil the thing should be undefined
# TODO: when overriding with an object that object should be used instead
# e.g. when the yaml has one !ruby/object:CI::UpstreamSCM...
# FIXME: failure not test covered as we cannot supply a broken override
# without having one in the live data.
def override_apply(member)
return unless @override_rule
member_override = override_rule_for(member)
return unless member_override.respond_to?(:each)
return unless (object = instance_variable_get("@#{member}"))
member_override.each do |var, value|
next unless (value = render_override(value))
# TODO: object.override! can jump in here and do what it wants
object.instance_variable_set("@#{var}", value)
end
rescue => e
warn "Failed to override #{member} of #{name} with rule #{rule}"
raise e
end
class << self
def get_bzr(uri, dest)
return if File.exist?(dest)
return if system("bzr checkout #{uri} #{dest}")
raise BzrTransactionError, "Could not checkout #{uri}"
end
def update_bzr(_branch)
return if ENV.include?('NO_UPDATE')
return if system('bzr up')
raise BzrTransactionError, 'Failed to update'
end
end
def init_packaging_scm_git(url_base, branch)
# Assume git
# Never assume.
# We need to check for launchpad. Adjust accordingly.
if @component == 'launchpadgit'
@packaging_scm = CI::SCM.new('git',
"#{url_base}/kubuntu-packaging/+git/#{@name}",
branch)
else
# Clean up path to remove useless slashes and colons.
@packaging_scm = CI::SCM.new('git',
"#{url_base}/#{@component}/#{@name}",
branch)
end
component_dir = "git/#{@component}"
FileUtils.mkdir_p(component_dir) unless Dir.exist?(component_dir)
component_dir
end
def init_packaging_scm_bzr(url_base)
packaging_scm_url = if url_base.end_with?(':')
"#{url_base}#{@name}"
else
"#{url_base}/#{@name}"
end
@packaging_scm = CI::SCM.new('bzr', packaging_scm_url)
component_dir = 'launchpad'
FileUtils.mkdir_p(component_dir) unless Dir.exist?(component_dir)
component_dir
end
# @return component_dir to use for cloning etc.
def init_packaging_scm(url_base, branch)
# FIXME: git dir needs to be set somewhere, somehow, somewhat, lol, kittens?
if @component == 'launchpadgit'
init_packaging_scm_git(url_base, branch)
elsif @component == 'launchpad'
init_packaging_scm_bzr(url_base)
else
init_packaging_scm_git(url_base, branch)
end
end
def get
Retry.retry_it(errors: [TransactionError], times: 2, sleep: 5) do
if @component == 'launchpad'
self.class.get_bzr(@packaging_scm.url, @name)
else
CI::Git.get(@packaging_scm.url, @name)
end
end
end
def update(branch)
Retry.retry_it(errors: [TransactionError], times: 2, sleep: 5) do
if @component == 'launchpad'
self.class.update_bzr(branch)
else
CI::Git.update(branch)
# FIXME: We are not sure this is even useful anymore. It certainly was
# not actively used since utopic.
branches = `git for-each-ref --format='%(refname)' refs/remotes/origin/#{branch}_\*`.strip.lines
branches.each do |b|
@series_branches << b.gsub('refs/remotes/origin/', '')
end
end
end
end
end
|