Browse Source

Update tests and CI to use HTTP repo

default_compile_flags
vector-of-bool 4 years ago
parent
commit
9b639bd187
9 changed files with 3290 additions and 6634 deletions
  1. +3161
    -2360
      catalog.json
  2. +0
    -4141
      catalog.old.json
  3. +24
    -0
      src/dds.main.cpp
  4. +19
    -12
      tests/conftest.py
  5. +10
    -4
      tests/dds.py
  6. +11
    -17
      tests/deps/deps_test.py
  7. +16
    -14
      tools/ci.py
  8. +24
    -66
      tools/gen-catalog-json.py
  9. +25
    -20
      tools/self_build.py

+ 3161
- 2360
catalog.json
File diff suppressed because it is too large
View File


+ 0
- 4141
catalog.old.json
File diff suppressed because it is too large
View File


+ 24
- 0
src/dds.main.cpp View File

@@ -1076,7 +1076,31 @@ struct cli_build {
{"out"},
dds::fs::current_path() / "_build"};

args::ValueFlagList<std::string> add_repos{
cmd,
"<repo-url>",
"Add the given repositories to the catalog before executing (Implies '--update-repos')",
{"add-repo"}};

args::Flag update_repos{cmd,
"update-repos",
"Update repositories before building",
{"update-repos", 'U'}};

int run() {
if (!add_repos.Get().empty()) {
auto cat = cat_path.open();
for (auto& str : add_repos.Get()) {
auto repo = dds::remote_repository::connect(str);
repo.store(cat.database());
}
}

if (update_repos.Get() || !add_repos.Get().empty()) {
auto cat = cat_path.open();
dds::update_all_remotes(cat.database());
}

dds::sdist_build_params main_params = {
.subdir = "",
.build_tests = !no_tests.Get(),

+ 19
- 12
tests/conftest.py View File

@@ -2,14 +2,28 @@ from contextlib import ExitStack
from typing import Optional
from pathlib import Path
import shutil
from subprocess import check_call

import pytest

from tests import scoped_dds, DDSFixtureParams


@pytest.fixture(scope='session')
def dds_exe() -> Path:
return Path(__file__).absolute().parent.parent / '_build/dds'


@pytest.yield_fixture(scope='session')
def dds_pizza_catalog(dds_exe: Path, tmp_path_factory) -> Path:
tmpdir: Path = tmp_path_factory.mktemp(basename='dds-catalog')
cat_path = tmpdir / 'catalog.db'
check_call([str(dds_exe), 'repo', 'add', 'https://dds.pizza/repo', '--update', f'--catalog={cat_path}'])
yield cat_path


@pytest.yield_fixture
def dds(request, tmp_path: Path, worker_id: str, scope: ExitStack):
def dds(request, dds_exe: Path, tmp_path: Path, worker_id: str, scope: ExitStack):
test_source_dir = Path(request.fspath).absolute().parent
test_root = test_source_dir

@@ -29,8 +43,7 @@ def dds(request, tmp_path: Path, worker_id: str, scope: ExitStack):
project_dir = test_root / params.subdir

# Create the instance. Auto-clean when we're done
yield scope.enter_context(
scoped_dds(test_root, project_dir, request.function.__name__))
yield scope.enter_context(scoped_dds(dds_exe, test_root, project_dir, request.function.__name__))


@pytest.fixture
@@ -41,15 +54,11 @@ def scope():

def pytest_addoption(parser):
parser.addoption(
'--test-deps',
action='store_true',
default=False,
help='Run the exhaustive and intensive dds-deps tests')
'--test-deps', action='store_true', default=False, help='Run the exhaustive and intensive dds-deps tests')


def pytest_configure(config):
config.addinivalue_line(
'markers', 'deps_test: Deps tests are slow. Enable with --test-deps')
config.addinivalue_line('markers', 'deps_test: Deps tests are slow. Enable with --test-deps')


def pytest_collection_modifyitems(config, items):
@@ -60,6 +69,4 @@ def pytest_collection_modifyitems(config, items):
continue
item.add_marker(
pytest.mark.skip(
reason=
'Exhaustive deps tests are slow and perform many Git clones. Use --test-deps to run them.'
))
reason='Exhaustive deps tests are slow and perform many Git clones. Use --test-deps to run them.'))

+ 10
- 4
tests/dds.py View File

@@ -2,7 +2,7 @@ import os
import itertools
from contextlib import contextmanager, ExitStack
from pathlib import Path
from typing import Iterable, Union, Any, Dict, NamedTuple, ContextManager
from typing import Iterable, Union, Any, Dict, NamedTuple, ContextManager, Optional
import subprocess
import shutil

@@ -80,24 +80,31 @@ class DDS:
args,
])

def repo_add(self, url: str) -> None:
return self.run(['repo', 'add', url, '--update', self.catalog_path_arg])

def build(self,
*,
toolchain: str = None,
apps: bool = True,
warnings: bool = True,
catalog_path: Optional[Path] = None,
tests: bool = True,
more_args: proc.CommandLine = [],
check: bool = True) -> subprocess.CompletedProcess:
catalog_path = catalog_path or self.catalog_path.relative_to(self.source_root)
return self.run(
[
'build',
f'--out={self.build_dir}',
f'--toolchain={toolchain or self.default_builtin_toolchain}',
f'--catalog={self.catalog_path.relative_to(self.source_root)}',
f'--catalog={catalog_path}',
f'--repo-dir={self.repo_dir.relative_to(self.source_root)}',
['--no-tests'] if not tests else [],
['--no-apps'] if not apps else [],
['--no-warnings'] if not warnings else [],
self.project_dir_arg,
more_args,
],
check=check,
)
@@ -162,8 +169,7 @@ class DDS:


@contextmanager
def scoped_dds(test_dir: Path, project_dir: Path, name: str):
dds_exe = Path(__file__).absolute().parent.parent / '_build/dds'
def scoped_dds(dds_exe: Path, test_dir: Path, project_dir: Path, name: str):
if os.name == 'nt':
dds_exe = dds_exe.with_suffix('.exe')
with ExitStack() as scope:

+ 11
- 17
tests/deps/deps_test.py View File

@@ -23,23 +23,19 @@ class DepsCase(NamedTuple):
'depends': [self.dep],
}).encode()))
dds.scope.enter_context(
fileutil.set_contents(
dds.source_root / 'library.json',
json.dumps({
'name': 'test',
'uses': [self.usage],
}).encode()))
dds.scope.enter_context(
fileutil.set_contents(dds.source_root / 'src/test.test.cpp',
self.source.encode()))
fileutil.set_contents(dds.source_root / 'library.json',
json.dumps({
'name': 'test',
'uses': [self.usage],
}).encode()))
dds.scope.enter_context(fileutil.set_contents(dds.source_root / 'src/test.test.cpp', self.source.encode()))


CASES: List[DepsCase] = []


def get_default_pkg_versions(pkg: str) -> Sequence[str]:
catalog_json = Path(
__file__).resolve().parent.parent.parent / 'catalog.json'
catalog_json = Path(__file__).resolve().parent.parent.parent / 'catalog.json'
catalog_dict = json.loads(catalog_json.read_text())
return list(catalog_dict['packages'][pkg].keys())

@@ -158,8 +154,7 @@ add_cases(
## ## ## ##
## ## ## ##
"""
add_cases(
'fmt', 'fmt/fmt', ['auto'], r'''
add_cases('fmt', 'fmt/fmt', ['auto'], r'''
#include <fmt/core.h>

int main() {
@@ -546,8 +541,7 @@ add_cases(
## ## ## ## ## ## ## ## ## ##
###### ## ######## ######## ####### ######
"""
add_cases(
'spdlog', 'spdlog/spdlog', ['auto'], r'''
add_cases('spdlog', 'spdlog/spdlog', ['auto'], r'''
#include <spdlog/spdlog.h>

int main() {
@@ -582,6 +576,6 @@ add_cases(

@pytest.mark.deps_test
@pytest.mark.parametrize('case', CASES, ids=[c.dep for c in CASES])
def test_dep(case: DepsCase, dds: DDS) -> None:
def test_dep(case: DepsCase, dds_pizza_catalog: Path, dds: DDS) -> None:
case.setup_root(dds)
dds.build()
dds.build(catalog_path=dds_pizza_catalog)

+ 16
- 14
tools/ci.py View File

@@ -9,7 +9,7 @@ import subprocess
import urllib.request
import shutil

from self_build import self_build
from self_build import self_build, dds_build
from dds_ci import paths, proc


@@ -35,8 +35,7 @@ def _do_bootstrap_download() -> None:
'freebsd12': 'dds-freebsd-x64',
}.get(sys.platform)
if filename is None:
raise RuntimeError(f'We do not have a prebuilt DDS binary for '
f'the "{sys.platform}" platform')
raise RuntimeError(f'We do not have a prebuilt DDS binary for the "{sys.platform}" platform')
url = f'https://github.com/vector-of-bool/dds/releases/download/0.1.0-alpha.4/{filename}'

print(f'Downloading prebuilt DDS executable: {url}')
@@ -72,9 +71,7 @@ def main(argv: Sequence[str]) -> int:
required=True,
)
parser.add_argument(
'--build-only',
action='store_true',
help='Only build the `dds` executable. Skip second-phase and tests.')
'--build-only', action='store_true', help='Only build the `dds` executable. Skip second-phase and tests.')
parser.add_argument(
'--no-clean',
action='store_false',
@@ -106,25 +103,30 @@ def main(argv: Sequence[str]) -> int:
paths.PREBUILT_DDS,
toolchain=opts.toolchain,
cat_path=old_cat_path,
cat_json_path=Path('catalog.old.json'),
cat_json_path=Path('catalog.json'),
dds_flags=[('--repo-dir', ci_repo_dir)])
print('Main build PASSED!')
print(f'A `dds` executable has been generated: {paths.CUR_BUILT_DDS}')

if args.build_only:
print(
f'`--build-only` was given, so second phase and tests will not execute'
)
print('`--build-only` was given, so second phase and tests will not execute')
return 0

print('Bootstrapping myself:')
new_cat_path = paths.BUILD_DIR / 'catalog.db'
new_repo_dir = paths.BUILD_DIR / 'ci-repo'
self_build(
new_repo_dir = paths.BUILD_DIR / 'ci-repo-2'
if new_cat_path.is_file():
new_cat_path.unlink()
if new_repo_dir.is_dir():
shutil.rmtree(new_repo_dir)
dds_build(
paths.CUR_BUILT_DDS,
toolchain=opts.toolchain,
cat_path=new_cat_path,
dds_flags=[f'--repo-dir={new_repo_dir}'])
more_flags=[
f'--repo-dir={new_repo_dir}',
f'--catalog={new_cat_path}',
'--add-repo=https://dds.pizza/repo',
])
print('Bootstrap test PASSED!')

return pytest.main([

+ 24
- 66
tools/gen-catalog-json.py View File

@@ -117,13 +117,6 @@ class Git(NamedTuple):
d['auto-lib'] = self.auto_lib
return d

def to_dict_2(self) -> str:
url = f'git+{self.url}'
if self.auto_lib:
url += f'?lm={self.auto_lib}'
url += f'#{self.ref}'
return url


RemoteInfo = Union[Git]

@@ -143,15 +136,6 @@ class Version(NamedTuple):
ret['git'] = self.remote.to_dict()
return ret

def to_dict_2(self) -> dict:
ret: dict = {
'description': self.description,
'depends': list(self.depends),
'transform': [f.to_dict() for f in self.remote.transforms],
}
ret['url'] = self.remote.to_dict_2()
return ret


class VersionSet(NamedTuple):
version: str
@@ -175,8 +159,7 @@ def github_http_get(url: str):
raise RuntimeError(f'Request is outside of api.github.com [{url}]')
resp = request.urlopen(req)
if resp.status != 200:
raise RuntimeError(
f'Request to [{url}] failed [{resp.status} {resp.reason}]')
raise RuntimeError(f'Request to [{url}] failed [{resp.status} {resp.reason}]')
return json5.loads(resp.read())


@@ -188,8 +171,7 @@ def _get_github_tree_file_content(url: str) -> bytes:
return content


def _version_for_github_tag(pkg_name: str, desc: str, clone_url: str,
tag) -> Version:
def _version_for_github_tag(pkg_name: str, desc: str, clone_url: str, tag) -> Version:
print(f'Loading tag {tag["name"]}')
commit = github_http_get(tag['commit']['url'])
tree = github_http_get(commit['commit']['tree']['url'])
@@ -201,12 +183,9 @@ def _version_for_github_tag(pkg_name: str, desc: str, clone_url: str,
package_json_fname = cand
break
else:
raise RuntimeError(
f'No package JSON5 file in tag {tag["name"]} for {pkg_name} (One of {tree_content.keys()})'
)
raise RuntimeError(f'No package JSON5 file in tag {tag["name"]} for {pkg_name} (One of {tree_content.keys()})')

package_json = json5.loads(
_get_github_tree_file_content(tree_content[package_json_fname]['url']))
package_json = json5.loads(_get_github_tree_file_content(tree_content[package_json_fname]['url']))
version = package_json['version']
if pkg_name != package_json['name']:
raise RuntimeError(f'package name in repo "{package_json["name"]}" '
@@ -221,14 +200,10 @@ def _version_for_github_tag(pkg_name: str, desc: str, clone_url: str,
elif depends is None:
pairs = []
else:
raise RuntimeError(
f'Unknown "depends" object from json file: {depends!r}')
raise RuntimeError(f'Unknown "depends" object from json file: {depends!r}')

remote = Git(url=clone_url, ref=tag['name'])
return Version(version,
description=desc,
depends=list(pairs),
remote=remote)
return Version(version, description=desc, depends=list(pairs), remote=remote)


def github_package(name: str, repo: str, want_tags: Iterable[str]) -> Package:
@@ -239,15 +214,12 @@ def github_package(name: str, repo: str, want_tags: Iterable[str]) -> Package:

missing_tags = set(want_tags) - set(t['name'] for t in avail_tags)
if missing_tags:
raise RuntimeError(
'One or more wanted tags do not exist in '
f'the repository "{repo}" (Missing: {missing_tags})')
raise RuntimeError('One or more wanted tags do not exist in '
f'the repository "{repo}" (Missing: {missing_tags})')

tag_items = (t for t in avail_tags if t['name'] in want_tags)

versions = HTTP_POOL.map(
lambda tag: _version_for_github_tag(name, desc, repo_data['clone_url'],
tag), tag_items)
versions = HTTP_POOL.map(lambda tag: _version_for_github_tag(name, desc, repo_data['clone_url'], tag), tag_items)

return Package(name, list(versions))

@@ -260,11 +232,11 @@ def simple_packages(name: str,
*,
tag_fmt: str = '{}') -> Package:
return Package(name, [
Version(ver.version,
description=description,
remote=Git(
git_url, tag_fmt.format(ver.version), auto_lib=auto_lib),
depends=ver.depends) for ver in versions
Version(
ver.version,
description=description,
remote=Git(git_url, tag_fmt.format(ver.version), auto_lib=auto_lib),
depends=ver.depends) for ver in versions
])


@@ -277,12 +249,11 @@ def many_versions(name: str,
transforms: Sequence[FSTransform] = (),
description='(No description was provided)') -> Package:
return Package(name, [
Version(ver,
description='\n'.join(textwrap.wrap(description)),
remote=Git(url=git_url,
ref=tag_fmt.format(ver),
auto_lib=auto_lib,
transforms=transforms)) for ver in versions
Version(
ver,
description='\n'.join(textwrap.wrap(description)),
remote=Git(url=git_url, ref=tag_fmt.format(ver), auto_lib=auto_lib, transforms=transforms))
for ver in versions
])


@@ -290,7 +261,7 @@ def many_versions(name: str,
PACKAGES = [
github_package('neo-buffer', 'vector-of-bool/neo-buffer',
['0.2.1', '0.3.0', '0.4.0', '0.4.1', '0.4.2']),
github_package('neo-compress', 'vector-of-bool/neo-compress', ['0.1.0', '0.1.1']),
github_package('neo-compress', 'vector-of-bool/neo-compress', ['0.1.0', '0.1.1', '0.2.0']),
github_package('neo-url', 'vector-of-bool/neo-url',
['0.1.0', '0.1.1', '0.1.2', '0.2.0', '0.2.1', '0.2.2']),
github_package('neo-sqlite3', 'vector-of-bool/neo-sqlite3',
@@ -954,22 +925,9 @@ if __name__ == "__main__":
args = parser.parse_args()

data = {
'version': 2,
'packages': {
pkg.name: {ver.version: ver.to_dict_2()
for ver in pkg.versions}
for pkg in PACKAGES
}
}
old_data = {
'version': 1,
'packages': {
pkg.name: {ver.version: ver.to_dict()
for ver in pkg.versions}
for pkg in PACKAGES
}
'packages': {pkg.name: {ver.version: ver.to_dict()
for ver in pkg.versions}
for pkg in PACKAGES}
}
json_str = json.dumps(data, indent=2, sort_keys=True)
Path('catalog.json').write_text(json_str)
Path('catalog.old.json').write_text(
json.dumps(old_data, indent=2, sort_keys=True))
Path('catalog.json').write_text(json.dumps(data, indent=2, sort_keys=True))

+ 25
- 20
tools/self_build.py View File

@@ -11,6 +11,15 @@ from dds_ci import cli, proc
ROOT = Path(__file__).parent.parent.absolute()


def dds_build(exe: Path, *, toolchain: str, more_flags: proc.CommandLine = ()):
new_exe = ROOT / '_dds.bootstrap-test.exe'
shutil.copy2(exe, new_exe)
try:
proc.check_run(new_exe, 'build', (f'--toolchain={toolchain}'), more_flags)
finally:
new_exe.unlink()


def self_build(exe: Path,
*,
toolchain: str,
@@ -20,27 +29,23 @@ def self_build(exe: Path,
dds_flags: proc.CommandLine = ()):
# Copy the exe to another location, as windows refuses to let a binary be
# replaced while it is executing
new_exe = ROOT / '_dds.bootstrap-test.exe'
shutil.copy2(exe, new_exe)
try:
proc.check_run(
new_exe,
'catalog',
'import',
f'--catalog={cat_path}',
f'--json={cat_json_path}',
)
proc.check_run(
new_exe,
'build',
f'--catalog={cat_path}',
f'--repo-dir={ROOT}/_build/ci-repo',
dds_flags,
('--toolchain', toolchain),
proc.check_run(
exe,
'catalog',
'import',
f'--catalog={cat_path}',
f'--json={cat_json_path}',
)
dds_build(
exe,
toolchain=toolchain,
more_flags=[
('-I', lmi_path) if lmi_path else (),
)
finally:
new_exe.unlink()
f'--repo-dir={ROOT}/_build/ci-repo',
f'--catalog={cat_path}',
*dds_flags,
],
)


def main(argv: List[str]) -> int:

Loading…
Cancel
Save