#!/usr/bin/env python3 # # Tests the toplevel crate with *every* combination of cargo features. # (But, not any sets that don't include any `minimal-*` feature.) # # This script, obviously, runs cargo a number of times which is # *exponential* in the number of cargo features. # # But, most of those builds don't do very much, because cargo caches # builds of a particular crate with particular features separately, # and can retain multiple versions. # # And the set of combinations that cargo needs to build for is also # reduced a bit because it's the *effective* feature set that counts. # # In practice a from scratch run of this script currently takes 65s # on my laptop. That seems fine. But this is why we're just running # `cargo check` and not actually running any of the tests. import argparse import subprocess import toml.decoder from typing import Iterable, Tuple, TypeVar from itertools import chain, combinations T = TypeVar('T') # Copied from https://docs.python.org/3/library/itertools.html # retrieved 2024-06-21. Licence there is as follows: # This page is licensed under # the Python Software Foundation License Version 2. # Examples, recipes, and other code in the documentation are # additionally licensed under the Zero Clause BSD License. def powerset(iterable: Iterable[T]) -> Iterable[Iterable[T]]: "powerset([1,2,3]) → () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)" s = list(iterable) return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) def main() -> None: parser = argparse.ArgumentParser() args = parser.parse_args() t = toml.decoder.load('Cargo.toml') features = list(t['features']) print(repr(features)) for f in features: print('found feature %s' % f) combs = [] for feats in powerset(features): print("considering: %s" % ' '.join(feats)) if not(any([s.startswith('minimal-') for s in feats])): print('no minimal-* feature enabled') continue combs.append(feats) for i, feats in enumerate(combs): print('==================== %d/%d ====================' % (i, len(combs)), flush=True) scriptlet = ''' ${CARGO-cargo} check --no-default-features $1 ''' cmd = ['sh','-xec', scriptlet, 'x', '--features=' + ','.join(feats)] subprocess.run(cmd, check=True) print('==================== %d complete, ok ====================' % len(combs)) main()