Added options to version specs and allow specifying a git ref to build instead of a version.

This commit is contained in:
Patrick 2024-09-11 09:00:03 +02:00
parent bdf063a16c
commit 1b8d6e175b
2 changed files with 56 additions and 13 deletions

View File

@ -1,6 +1,7 @@
import copy
import glob
import inspect
import json
import os
import psutil
@ -11,13 +12,15 @@ import time
class _VersionSpec:
minimum_version = None
maximum_version = None
options = {}
def __init__(self, minimum_version = None, maximum_version = None):
def __init__(self, minimum_version = None, maximum_version = None, options = {}):
self.minimum_version = minimum_version
self.maximum_version = maximum_version
self.options = options
def __str__(self):
return f'Min: {self.minimum_version}, Max: {self.maximum_version}'
return f'Min: {self.minimum_version}, Max: {self.maximum_version}, Options: {self.options}'
class _Dependency:
name: str = ''
@ -53,12 +56,19 @@ def _find_recipe(env: Environment, recipe_name: str):
env['SPP_RECIPES'][recipe_name] = recipe
return recipe
def _run_cook(dependency: _Dependency):
if not dependency.cook_result:
cook_signature = inspect.signature(dependency.recipe.cook)
kwargs = {}
if 'options' in cook_signature.parameters:
kwargs['options'] = dependency.version_spec.options
dependency.cook_result = dependency.recipe.cook(env, dependency.version, **kwargs)
def _cook(env: Environment, recipe_name: str):
dependency = env['SPP_DEPENDENCIES'].get(recipe_name)
if not dependency:
raise Exception(f'Cannot cook {recipe_name} as it was not listed as a dependency.')
if not dependency.cook_result:
dependency.cook_result = dependency.recipe.cook(env, dependency.version)
_run_cook(dependency)
return dependency.cook_result
def _module(env: Environment, file: str):
@ -90,8 +100,7 @@ def _inject_dependency(dependency, kwargs: dict, add_sources: bool = True) -> No
for inner_dependency in dependency['DEPENDENCIES']:
_inject_dependency(inner_dependency, kwargs, False)
elif isinstance(dependency, _Dependency):
if not dependency.cook_result:
dependency.cook_result = dependency.recipe.cook(env, dependency.version)
_run_cook(dependency)
_inject_list(kwargs, dependency.cook_result, 'CPPPATH')
_inject_list(kwargs, dependency.cook_result, 'CPPDEFINES')
_inject_list(kwargs, dependency.cook_result, 'LIBPATH')
@ -185,8 +194,35 @@ def _error(env: Environment, message: str):
print(message, file=sys.stderr)
env.Exit(1)
def _try_merge_dicts(dictA: dict, dictB: dict) -> 'dict|None':
result = {}
for key, valueA in dictA.items():
if key in dictB:
valueB = dictB[key]
if type(valueA) != type(valueB):
return None
elif type(valueA) == list:
result[key] = valueA + valueB
elif type(valueA) == dict:
mergedValue = _try_merge_dicts(valueA, valueB)
if mergedValue is None:
return None
result[key] = mergedValue
elif valueA != valueB:
return None
else:
result[key] = valueA
for key, valueB in dictB.items():
if key not in result:
result[key] = valueB
return result
def _find_common_depenency_version(name: str, versionA: _VersionSpec, versionB: _VersionSpec) -> _VersionSpec:
result_version = _VersionSpec()
options = _try_merge_dicts(versionA.options, versionB.options)
if options is None:
return None
result_version = _VersionSpec(options=options)
if versionA.minimum_version is not None:
if versionB.minimum_version is not None:
result_version.minimum_version = max(versionA.minimum_version, versionB.minimum_version)
@ -209,7 +245,7 @@ def _find_common_depenency_version(name: str, versionA: _VersionSpec, versionB:
return result_version
def _parse_version_spec(version_spec: dict) -> _VersionSpec:
return _VersionSpec(version_spec.get('min'), version_spec.get('max'))
return _VersionSpec(version_spec.get('min'), version_spec.get('max'), version_spec.get('options', {}))
def _can_add_dependency(env: Environment, name: str, version_spec: _VersionSpec) -> bool:
if name not in env['SPP_DEPENDENCIES']:
@ -256,7 +292,11 @@ def _version_matches(version, version_spec: _VersionSpec) -> bool:
def _find_version(env: Environment, dependency: _Dependency):
for update in (False, True):
versions = dependency.recipe.versions(env, update=update)
versions_signature = inspect.signature(dependency.recipe.versions)
kwargs = {}
if 'options' in versions_signature.parameters:
kwargs['options'] = dependency.version_spec.options
versions = dependency.recipe.versions(env, update=update, **kwargs)
_sort_versions(versions)
for version in versions:
if _version_matches(version, dependency.version_spec):

View File

@ -2,7 +2,6 @@
from git import Repo
from git.exc import GitError
import hashlib
import re
from SCons.Script import *
Import('env')
@ -56,7 +55,9 @@ def _git_recipe(env: Environment, globals: dict, repo_name, repo_url, cook_fn, v
_tag_pattern = _make_callable(tag_pattern)
versions_cb = versions and _make_callable(versions)
def _versions(env: Environment, update: bool = False):
def _versions(env: Environment, update: bool = False, options: dict = {}):
if 'ref' in options:
return [(0, 0, 0)] # no versions if compiling from a branch
pattern = _tag_pattern(env)
if pattern:
tags = env.GitTags(repo_name = _repo_name(env), remote_url = _repo_url(env), force_fetch=update)
@ -76,8 +77,10 @@ def _git_recipe(env: Environment, globals: dict, repo_name, repo_url, cook_fn, v
def _dependencies(env: Environment, version) -> 'dict':
return dependencies
def _cook(env: Environment, version) -> dict:
if tag_fn:
def _cook(env: Environment, version, options: dict = {}) -> dict:
if 'ref' in options:
git_ref = options['ref']
elif tag_fn:
git_ref = f'refs/tags/{tag_fn(version)}'
else:
assert ref_fn