launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #17857
Re: [Merge] lp:~wgrant/launchpad/xbia into lp:launchpad
Diff comments:
> === modified file 'lib/lp/soyuz/adapters/buildarch.py'
> --- lib/lp/soyuz/adapters/buildarch.py 2015-02-11 10:43:58 +0000
> +++ lib/lp/soyuz/adapters/buildarch.py 2015-02-11 10:43:59 +0000
> @@ -36,29 +36,62 @@
> dpkg_architecture = DpkgArchitectureCache()
>
>
> -def determine_architectures_to_build(hintlist, valid_archs,
> +def resolve_arch_spec(hintlist, valid_archs):
> + hint_archs = set(hintlist.split())
> + # 'all' is only used if it's a purely arch-indep package.
> + if hint_archs == set(["all"]):
> + return set(), True
> + return (
> + set(dpkg_architecture.findAllMatches(valid_archs, hint_archs)), False)
> +
> +
> +def determine_architectures_to_build(hint_list, indep_hint_list, need_archs,
> nominated_arch_indep, need_arch_indep):
> """Return a set of architectures to build.
>
> - :param hintlist: A string of the architectures this source package
> + :param hint_list: a string of the architectures this source package
> specifies it builds for.
> - :param valid_archs: a list of all architecture tags that we can
> - create builds for.
> - :param nominated_arch_indep: a preferred architecture tag for
> - architecture-independent builds. May be None.
> - :return: a set of architecture tags for which the source publication in
> - question should be built.
> + :param indep_hint_list: a string of the architectures this source package
> + specifies it can build architecture-independent packages on.
> + :param need_archs: an ordered list of all architecture tags that we can
> + create builds for. the first usable one gets the arch-indep flag.
> + :param nominated_arch_indep: the default architecture tag for
> + arch-indep-only packages. may be None.
> + :param need_arch_indep: should an arch-indep build be created if possible?
> + :return: a map of architecture tag to arch-indep flag for each build
> + that should be created.
> """
> - hint_archs = set(hintlist.split())
> - build_archs = set(
> - dpkg_architecture.findAllMatches(valid_archs, hint_archs))
> -
> - # 'all' is only used as a last resort, to create an arch-indep build
> - # where no builds would otherwise exist.
> - if need_arch_indep and len(build_archs) == 0 and 'all' in hint_archs:
> - if nominated_arch_indep in valid_archs:
> - return set([nominated_arch_indep])
> - else:
> - return set()
> -
> - return build_archs
> + build_archs, indep_only = resolve_arch_spec(hint_list, need_archs)
> +
> + # Use the indep hint list if it's set, otherwise fall back to the
> + # main architecture list. If that's not set either (ie. it's just
> + # "all"), default to nominatedarchindep.
> + if indep_hint_list:
> + indep_archs, _ = resolve_arch_spec(indep_hint_list, need_archs)
> + elif not indep_only:
> + indep_archs = set(build_archs)
> + elif nominated_arch_indep in need_archs:
> + indep_archs = set([nominated_arch_indep])
> + else:
> + indep_archs = set()
> +
> + indep_arch = None
> + if need_arch_indep:
> + # Try to avoid adding a new build if an existing one would work.
> + both_archs = set(build_archs) & set(indep_archs)
> + if both_archs:
> + indep_archs = both_archs
> +
> + # The ideal arch_indep build is nominatedarchindep. But if we're
> + # not creating a build for it, use the first candidate DAS that
> + # made it this far.
> + for arch in [nominated_arch_indep] + need_archs:
> + if arch in indep_archs:
> + indep_arch = arch
> + break
> +
> + # Ensure that we build the indep arch.
> + if indep_arch is not None and indep_arch not in build_archs:
> + build_archs.add(indep_arch)
> +
> + return {arch: arch == indep_arch for arch in build_archs}
>
> === modified file 'lib/lp/soyuz/adapters/tests/test_buildarch.py'
> --- lib/lp/soyuz/adapters/tests/test_buildarch.py 2015-02-11 10:43:58 +0000
> +++ lib/lp/soyuz/adapters/tests/test_buildarch.py 2015-02-11 10:43:59 +0000
> @@ -43,82 +43,140 @@
> """
>
> def assertArchsForHint(self, hint_string, expected_arch_tags,
> - allowed_arch_tags=None):
> + allowed_arch_tags=None, indep_hint_list=None,
> + need_arch_indep=True):
> if allowed_arch_tags is None:
> allowed_arch_tags = ['armel', 'hppa', 'i386']
> arch_tags = determine_architectures_to_build(
> - hint_string, allowed_arch_tags, 'i386', True)
> - self.assertContentEqual(expected_arch_tags, arch_tags)
> + hint_string, indep_hint_list, allowed_arch_tags, 'i386',
> + need_arch_indep)
> + self.assertContentEqual(expected_arch_tags.items(), arch_tags.items())
>
> def test_single_architecture(self):
> # A hint string with a single arch resolves to just that arch.
> - self.assertArchsForHint('hppa', ['hppa'])
> + self.assertArchsForHint('hppa', {'hppa': True})
>
> def test_three_architectures(self):
> # A hint string with multiple archs resolves to just those
> # archs.
> - self.assertArchsForHint('amd64 i386 hppa', ['hppa', 'i386'])
> + self.assertArchsForHint(
> + 'amd64 i386 hppa', {'hppa': False, 'i386': True})
>
> def test_independent(self):
> # 'all' is special, meaning just a single build. The
> # nominatedarchindep architecture is used -- in this case i386.
> - self.assertArchsForHint('all', ['i386'])
> + self.assertArchsForHint('all', {'i386': True})
>
> def test_one_and_independent(self):
> # 'all' is redundant if we have another build anyway.
> - self.assertArchsForHint('hppa all', ['hppa'])
> + self.assertArchsForHint('hppa all', {'hppa': True})
>
> def test_fictional_and_independent(self):
> - # But 'all' is useful if present with an arch that wouldn't
> - # generate a build.
> - self.assertArchsForHint('foo all', ['i386'])
> + # 'all' doesn't make an unbuildable string buildable.
> + self.assertArchsForHint('fiction all', {})
>
> def test_wildcard(self):
> # 'any' is a wildcard that matches all available archs.
> - self.assertArchsForHint('any', ['armel', 'hppa', 'i386'])
> + self.assertArchsForHint(
> + 'any', {'armel': False, 'hppa': False, 'i386': True})
>
> def test_kernel_specific_architecture(self):
> # Since we only support Linux-based architectures, 'linux-foo'
> # is treated the same as 'foo'.
> - self.assertArchsForHint('linux-hppa', ['hppa'])
> + self.assertArchsForHint('linux-hppa', {'hppa': True})
>
> def test_unknown_kernel_specific_architecture(self):
> # Non-Linux architectures aren't supported.
> - self.assertArchsForHint('kfreebsd-hppa', [])
> + self.assertArchsForHint('kfreebsd-hppa', {})
>
> def test_kernel_wildcard_architecture(self):
> # Wildcards work for kernels: 'any-foo' is treated like 'foo'.
> - self.assertArchsForHint('any-hppa', ['hppa'])
> + self.assertArchsForHint('any-hppa', {'hppa': True})
>
> def test_kernel_wildcard_architecture_arm(self):
> # The second part of a wildcard matches the canonical CPU name, not
> # on the Debian architecture, so 'any-arm' matches 'armel'.
> - self.assertArchsForHint('any-arm', ['armel'])
> + self.assertArchsForHint('any-arm', {'armel': True})
>
> def test_kernel_specific_architecture_wildcard(self):
> # Wildcards work for archs too: 'linux-any' is treated like 'any'.
> - self.assertArchsForHint('linux-any', ['armel', 'hppa', 'i386'])
> + self.assertArchsForHint(
> + 'linux-any', {'armel': False, 'hppa': False, 'i386': True})
>
> def test_unknown_kernel_specific_architecture_wildcard(self):
> # But unknown kernels continue to result in nothing.
> - self.assertArchsForHint('kfreebsd-any', [])
> + self.assertArchsForHint('kfreebsd-any', {})
>
> def test_wildcard_and_independent(self):
> # 'all' continues to be ignored alongside a valid wildcard.
> - self.assertArchsForHint('all linux-any', ['armel', 'hppa', 'i386'])
> + self.assertArchsForHint(
> + 'all linux-any', {'armel': False, 'hppa': False, 'i386': True})
>
> def test_kernel_independent_is_invalid(self):
> # 'linux-all' isn't supported.
> - self.assertArchsForHint('linux-all', [])
> + self.assertArchsForHint('linux-all', {})
>
> def test_double_wildcard_is_same_as_single(self):
> # 'any-any' is redundant with 'any', but dpkg-architecture supports
> # it anyway.
> - self.assertArchsForHint('any-any', ['armel', 'hppa', 'i386'])
> + self.assertArchsForHint(
> + 'any-any', {'armel': False, 'hppa': False, 'i386': True})
>
> def test_no_all_builds_when_nominatedarchindep_not_permitted(self):
> # Some archives (eg. armel rebuilds) don't want arch-indep
> # builds. If the nominatedarchindep architecture (normally
> # i386) is omitted, no builds will be created for arch-indep
> # sources.
> - self.assertArchsForHint('all', [], allowed_arch_tags=['hppa'])
> + self.assertArchsForHint('all', {}, allowed_arch_tags=['hppa'])
> +
> + def test_indep_hint_only(self):
> + # Some packages need to build arch-indep builds on a specific
> + # architecture, declared using XS-Build-Indep-Architecture.
> + self.assertArchsForHint('all', {'hppa': True}, indep_hint_list='hppa')
> +
> + def test_indep_hint_only_multiple(self):
> + # The earliest available architecture in the available list (not
> + # the hint list) is chosen.
> + self.assertArchsForHint(
> + 'all', {'armel': True}, indep_hint_list='armel hppa')
> +
> + def test_indep_hint_only_unsatisfiable(self):
> + # An indep hint list that matches nothing results in no builds
> + self.assertArchsForHint('all', {}, indep_hint_list='fiction')
> +
> + def test_indep_hint(self):
> + # Unlike nominatedarchindep, a hinted indep will cause an
> + # additional build to be created if necessary.
> + self.assertArchsForHint(
> + 'armel all', {'armel': False, 'hppa': True},
> + indep_hint_list='hppa')
> +
> + def test_indep_hint_wildcard(self):
> + # An indep hint list can include wildcards.
> + self.assertArchsForHint(
> + 'armel all', {'armel': False, 'hppa': True},
> + indep_hint_list='any-hppa')
> +
> + def test_indep_hint_coalesces(self):
> + # An indep hint list that matches an existing build will avoid
> + # creating another.
> + self.assertArchsForHint(
> + 'hppa all', {'hppa': True}, indep_hint_list='linux-any')
> +
> + def test_indep_hint_unsatisfiable(self):
> + # An indep hint list that matches nothing results in no
> + # additional builds
> + self.assertArchsForHint(
> + 'armel all', {'armel': False}, indep_hint_list='fiction')
> +
> + def test_no_need_arch_indep(self):
> + self.assertArchsForHint(
> + 'armel all', {'armel': False}, need_arch_indep=False)
> +
> + def test_no_need_arch_indep_hint(self):
> + self.assertArchsForHint(
> + 'armel all', {'armel': False}, indep_hint_list='hppa',
> + need_arch_indep=False)
> +
> + def test_no_need_arch_indep_only(self):
> + self.assertArchsForHint('all', {}, need_arch_indep=False)
>
> === modified file 'lib/lp/soyuz/interfaces/sourcepackagerelease.py'
> --- lib/lp/soyuz/interfaces/sourcepackagerelease.py 2014-11-09 23:28:27 +0000
> +++ lib/lp/soyuz/interfaces/sourcepackagerelease.py 2015-02-11 10:43:59 +0000
> @@ -151,6 +151,9 @@
> title=_("Source package recipe build"),
> required=False, readonly=True)
>
> + def getUserDefinedField(name):
> + """Case-insensitively get a user-defined field."""
> +
> def addFile(file, filetype=None):
> """Add the provided library file alias (file) to the list of files
> in this package.
>
> === modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
> --- lib/lp/soyuz/model/binarypackagebuild.py 2015-02-11 10:43:58 +0000
> +++ lib/lp/soyuz/model/binarypackagebuild.py 2015-02-11 10:43:59 +0000
> @@ -1423,56 +1423,44 @@
> # this series already has it set.
> need_arch_indep = not any(bpb.arch_indep for bpb in relevant_builds)
>
> - # Find the architectures for which the source should end up with
> - # binaries, parsing architecturehintlist as you'd expect.
> - # For an architecturehintlist of just 'all', this will
> - # be the current nominatedarchindep if need_arch_indep,
> - # otherwise nothing.
> - valid_archs = list(
> - architectures_available or distroseries.buildable_architectures)
> - valid_archs = self._getAllowedArchitectures(archive, valid_archs)
> + # Find the architectures for which the source chould end up with
> + # new binaries. Exclude architectures not allowed in this
> + # archive and architectures that have already built. Order by
> + # Processor.id so determine_architectures_to_build is
> + # deterministic.
> + # XXX wgrant 2014-11-06: The fact that production's
> + # Processor 1 is i386, a good arch-indep candidate, is a
> + # total coincidence and this isn't a hack. I promise.
> + need_archs = sorted(
> + [das for das in
> + self._getAllowedArchitectures(
> + archive,
> + architectures_available
> + or distroseries.buildable_architectures)
> + if das.architecturetag not in skip_archtags],
> + key=attrgetter('processor.id'))
> nominated_arch_indep_tag = (
> distroseries.nominatedarchindep.architecturetag
> if distroseries.nominatedarchindep else None)
>
> - # Filter the valid archs against the hint list.
> - candidate_arch_tags = determine_architectures_to_build(
> + # Filter the valid archs against the hint list and work out
> + # their arch-indepness.
> + create_tag_map = determine_architectures_to_build(
> sourcepackagerelease.architecturehintlist,
> - [das.architecturetag for das in valid_archs],
> + sourcepackagerelease.getUserDefinedField(
> + 'Build-Indep-Architecture'),
I completely agree. The majority of the columns on SPR should really just be JSON fields, as they're not useful to query on. But there's a lot of migration work.
> + [das.architecturetag for das in need_archs],
> nominated_arch_indep_tag, need_arch_indep)
> - candidate_architectures = set(
> - das for das in valid_archs
> - if das.architecturetag in candidate_arch_tags)
> -
> - # Filter out any architectures for which we earlier found sufficient
> - # builds.
> - needed_architectures = [
> - das for das in candidate_architectures
> - if das.architecturetag not in skip_archtags]
> - if not needed_architectures:
> - return []
> -
> - arch_indep_das = None
> - if need_arch_indep:
> - # The ideal arch_indep build is nominatedarchindep. But if
> - # that isn't a build we would otherwise create, use the DAS
> - # with the lowest Processor.id.
> - # XXX wgrant 2014-11-06: The fact that production's
> - # Processor 1 is i386, a good arch-indep candidate, is a
> - # total coincidence and this isn't a hack. I promise.
> - if distroseries.nominatedarchindep in needed_architectures:
> - arch_indep_das = distroseries.nominatedarchindep
> - else:
> - arch_indep_das = sorted(
> - needed_architectures, key=attrgetter('processor.id'))[0]
>
> # Create builds for the remaining architectures.
> new_builds = []
> - for das in needed_architectures:
> + for das in need_archs:
> + if das.architecturetag not in create_tag_map:
> + continue
> build = self.new(
> source_package_release=sourcepackagerelease,
> distro_arch_series=das, archive=archive, pocket=pocket,
> - arch_indep=das == arch_indep_das)
> + arch_indep=create_tag_map[das.architecturetag])
> new_builds.append(build)
> # Create the builds in suspended mode for disabled archives.
> build_queue = build.queueBuild(suspended=not archive.enabled)
>
> === modified file 'lib/lp/soyuz/model/sourcepackagerelease.py'
> --- lib/lp/soyuz/model/sourcepackagerelease.py 2014-11-09 23:28:27 +0000
> +++ lib/lp/soyuz/model/sourcepackagerelease.py 2015-02-11 10:43:59 +0000
> @@ -170,6 +170,12 @@
> return []
> return simplejson.loads(self._user_defined_fields)
>
> + def getUserDefinedField(self, name):
> + if self.user_defined_fields:
> + for k, v in self.user_defined_fields.iteritems():
> + if k.lower() == name.lower():
> + return v
> +
> @cachedproperty
> def package_diffs(self):
> return list(Store.of(self).find(
>
> === modified file 'lib/lp/soyuz/tests/test_build_set.py'
> --- lib/lp/soyuz/tests/test_build_set.py 2015-02-11 10:43:58 +0000
> +++ lib/lp/soyuz/tests/test_build_set.py 2015-02-11 10:43:59 +0000
> @@ -491,6 +491,19 @@
> new_builds = self.createBuilds(spr, self.distroseries)
> self.assertBuildsMatch({}, new_builds)
>
> + def test_createForSource_build_indep_architecture(self):
> + # A user defined field of Build-Indep-Architecture provides a
> + # custom hint list to override Architecture and
> + # nominatedarchindep for arch-indep purposes.
> + spr = self.factory.makeSourcePackageRelease(
> + architecturehintlist='sparc all',
> + user_defined_fields={'build-indep-architecture': 'avr'})
> + builds = self.createBuilds(spr, self.distroseries2)
> + self.assertBuildsMatch({'sparc': False, 'avr': True}, builds)
> + self.completeBuilds(builds, {'sparc': True, 'avr': True})
> + new_builds = self.createBuilds(spr, self.distroseries)
> + self.assertBuildsMatch({}, new_builds)
> +
>
> class TestFindBuiltOrPublishedBySourceAndArchive(TestCaseWithFactory):
> """Tests for findBuiltOrPublishedBySourceAndArchive()."""
>
--
https://code.launchpad.net/~wgrant/launchpad/xbia/+merge/249296
Your team Launchpad code reviewers is subscribed to branch lp:launchpad.
References