diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 000000000..41f7733bb --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 5822a6aba4640774e6092875d00fb6d6 +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/CHANGELOG/index.html b/CHANGELOG/index.html new file mode 100644 index 000000000..c627112a2 --- /dev/null +++ b/CHANGELOG/index.html @@ -0,0 +1,778 @@ + + + + + + + 6.8 (2023-10-09) + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

+
+

6.8 (2023-10-09)

+
+

Features

+
    +
  • ci: test with both db support and without (af7bfd90)

  • +
  • coverage:

    +
      +
    • test with database support enabled (0b8d6034)

    • +
    • add cli coverage report (64ce9f87)

    • +
    • add wrapped binaries to coverage (d4c6841d)

    • +
    +
  • +
  • db: revert default setting for connect_string to sqlite:// (806520d6)

  • +
+
+
+

Bug Fixes

+
    +
  • use context vars instead of env vars (e3ea47f0)

  • +
  • make github ci actually use its own env vars (e0c7ab67)

  • +
  • use BB_COVERAGE_PATH in .coveragerc (141afafa)

  • +
  • coveragerc requires curly braces for env variables (3ae8b335)

  • +
  • coveragerc requires curly braces for env variables (5b9c9906)

  • +
  • actions: re-raise caught exception (e4bff984, closes #561)

  • +
  • environments: buildah cannot find base images. (eb03c363)

  • +
+

+
+
+
+

6.7 (2023-04-04)

+
+

Features

+
    +
  • run auto-walrus over all of benchbuild’s file (79ac33d8)

  • +
  • add support for auto-walrus as pre-commit hook (d7a2165b)

  • +
  • drop support for python 3.7 and 3.8 (90308f2a)

  • +
  • ci:

    +
      +
    • update setup-python to v4 (3e943df6)

    • +
    • update github setup actions to v3 (dfa4cb81)

    • +
    +
  • +
  • command: use name as default value for a command’s label (07f74dd4)

  • +
  • environments: force base image to alpine:3.17 (fe5d6155)

  • +
  • setup:

    +
      +
    • widen allowed versions to major versions (5d29079a)

    • +
    • unlock latest versions of all packages (7b5a704f)

    • +
    +
  • +
  • wrapping: enforce global defaults for dill module (489e3039)

  • +
+
+
+

Bug Fixes

+
    +
  • python version for setup-python@v4 has to be string (7a1db742)

  • +
  • remove python 3.7 and 3.8 from all workflows (aaabc1b5)

  • +
  • bump pathos & dill to unbreak gitlab ci (bce45d8a)

  • +
  • ci:

    +
      +
    • disable mkdocs in github ci (8540f880)

    • +
    • reorder CI steps (test) (74379d53)

    • +
    • increase verbosity to max for all integation tasks (b6625d31)

    • +
    +
  • +
  • command: use private label when fetching string representation (d83aa666)

  • +
  • commands: preserve workload order when filtering (3648dd5e)

  • +
  • setup: unlock any major version of pygit2 (b09d9248)

  • +
  • wrapping: remove unused code (0d1c890d)

  • +
+
+
+
+

Changelog

+

+
+

6.6.4 (2023-03-16)

+

+
+
+

6.6.3 (2023-03-06)

+

+
+
+

6.6.2 (2023-03-06)

+
+

Bug Fixes

+
    +
  • pin sqlalchemy version <2.0 (86d45043)

  • +
+

+
+
+
+

6.6.1 (2023-01-10)

+
+

Features

+
    +
  • environments:

    +
      +
    • do not overwrite config, if cli option is default (b1a095c1)

    • +
    • improve error handling using result module (fbb69502)

    • +
    +
  • +
  • slurm: make container.runroot/container.root available for slurm customization (616a4c69, closes #528)

  • +
  • source: make sure we manage the archive symlink properly. (7687f0e3)

  • +
  • source/http: add auto-untar http source (84f90e75)

  • +
+
+
+

Bug Fixes

+
    +
  • environments:

    +
      +
    • add missing logging import (aad1b287)

    • +
    • add missing Err import (19c5983c)

    • +
    • notify user when commit of container image fails (78b890af)

    • +
    +
  • +
  • project: version filters should only consider expandable sources (3d546314)

  • +
  • source: enforce sorted order of revisions (ca973ff0)

  • +
+
+
+
+

6.5 (2022-11-03)

+
+

Feat

+
    +
  • source: re-enable project_cls in enumerate_revision interface

  • +
  • versions: enable context-aware SingleVersionFilter

  • +
  • source: only print context-free sources

  • +
  • source: expand public source API

  • +
  • source: introduce type skeleton and prototypes for context-aware version enumeration.

  • +
  • action: replace StepClass metaclass with init_subclass

  • +
  • actions: mark StepTy covariant

  • +
  • actions: use Stepable protocol as bound for StepTy.

  • +
  • actions: accept any varargs in a Step’s call implementation

  • +
+
+
+

Fix

+
    +
  • require dill version to be exactly 0.3.4

  • +
  • linter warning

  • +
  • linter warnings

  • +
  • project: remove debug print

  • +
  • utils: variant -> revision

  • +
  • tests: repair tests after VariantContext replacement.

  • +
  • source: remove runtime_checkable decorator

  • +
  • source: use project class instead of object for enumerate

  • +
  • source: return sequence of variants instead of nestedvariant

  • +
  • source: clean up protocol apis

  • +
  • actions: rename StepTy -> StepTy_co

  • +
  • tests: remove notify_step_begin_end

  • +
  • actions: reduce mypy errors

  • +
  • actions: use mutable generic container

  • +
+
+
+

Refactor

+
    +
  • versions: remove BaseVersionGroup

  • +
  • source: replace VariantContext with Revision

  • +
  • source: remove ExpandableAndFetchableSource from API

  • +
+
+
+
+

6.4 (2022-09-21)

+
+

Feat

+
    +
  • actions: make MultiStep generic.

  • +
  • command: make use of rendered and unrenderer PathToken explicit.

  • +
  • command: safeguard pruning and backup

  • +
  • command: add tests for enable_rollback

  • +
  • command: add support for creates and consumes properties for commands

  • +
  • command: add a label to commands

  • +
  • workload: switch WorkloadSet to varargs instead of kwargs

  • +
  • command: add example OnlyIn for WorkloadSet customization.

  • +
+
+
+

Fix

+
    +
  • command: strictly less than python 3.9

  • +
  • command: use _is_relative_to where needed

  • +
  • command: guard is_relative_to with else

  • +
  • command: do not depend on Path.is_relative_to (<python3.9)

  • +
  • command: make mypy happy.

  • +
  • command: Command.label is Optional

  • +
  • command: use protocols instead of typing.Callable for callback functions

  • +
  • command: Command.getitem used constructor wrong

  • +
  • command: return self._label instead of self.label

  • +
  • command: return Path instead of str or PathToken

  • +
  • command: assign consumed files to consumes attribute

  • +
  • tests: remove missing_ok from unlink (python3.7)

  • +
  • tests: repair test_command tests

  • +
  • tests: make test project pickle’able

  • +
  • tests: add missing pytest-git dependency

  • +
  • command: only might be None

  • +
  • command: access cache path instead of builddir path

  • +
  • command: make sure SupportsUnwrap returns a WorkloadSet

  • +
+
+
+

Refactor

+
    +
  • command: rename enable_rollback -> cleanup

  • +
+
+
+
+

6.3.2 (2022-08-21)

+
+

Feat

+
    +
  • command: rename NullRenderer to RootRenderer

  • +
  • command: hook up token renderer logic with Commands

  • +
  • command: add support for generic path tokens

  • +
  • workload: convert scimark2

  • +
  • command: migrate git-based projects to workload sets

  • +
  • command: add support for WorkloadSet.

  • +
  • command: clear path tracker on fresh ProjectEnvironment

  • +
  • wrapping: avoid wrapping the same command twice.

  • +
  • jobs: add RunJob and RunJobs actions

  • +
  • command: replace source root anywhere in command’s parts

  • +
  • command: pass environment to plumbum command

  • +
  • command: pass args to plumbum command

  • +
  • command: improve args and kwargs handling

  • +
  • add env and str to commands

  • +
  • command: support declarative commands in projects (WIP)

  • +
  • source: add ‘fetch’ support to FetchableSource derivatives

  • +
  • workloads: add properties & tags accessors

  • +
  • workloads: convert benchbuild.xz to support workloads

  • +
+
+
+

Fix

+
    +
  • test must use render()

  • +
  • x264: repair broken cli args

  • +
  • command: actually run the workload

  • +
  • command: check for existence, only after rendering

  • +
  • project: target compile instead of run_tests, when accessing compile

  • +
  • command: remove unused definitions

  • +
  • command: context -> kwargs

  • +
  • typing: python3.7 requires typing_extensions for runtime_checkable / Protocll

  • +
  • command: missing rename job -> workload

  • +
  • command: provide mapping type

  • +
  • workload: strip previous workload draft

  • +
  • workaround a mypy error

  • +
  • correct mypy errors.

  • +
  • wrapping: provide default arg for sprefix

  • +
  • actions: provide default StepResult

  • +
  • command: store args as tuple

  • +
  • bzip2: clean draft marker

  • +
  • actions: repair status print of actions

  • +
  • experiment: initialize CleanExtra correctly

  • +
  • jobs: allow jobs to run as wrapped binaries

  • +
  • use oci_compliant name for image names

  • +
  • workloads: wrong workload type

  • +
  • actions: unbreak tests after list -> scalar conversion

  • +
+
+
+

Refactor

+
    +
  • command: lower-case token str

  • +
  • rename Job -> Workload

  • +
  • command: remove debug prints

  • +
  • source: remove unnecessary ellipsis

  • +
+
+
+
+

6.3.1 (2022-03-01)

+
+

Feat

+
    +
  • actions: clean interfaces of utils/actions

  • +
  • workloads: make object instance accessible to workloads using descriptors

  • +
  • workloads: hook up Compile and Run action to new workload impl

  • +
  • workloads: add simple intersection filter to workloads

  • +
  • workloads: change workload registration decorator style.

  • +
  • workloads: migrate Compile/Run action to run workloads only

  • +
  • project: remove run_tests and compile abstract methods

  • +
  • gzip: convert gzip to workloads

  • +
  • workload: Add prototype support for workloads.

  • +
  • environments: strip container args when entering interactive mode

  • +
+
+
+

Fix

+
    +
  • workloads: typo.

  • +
  • gzip: undo wrong wrap command

  • +
  • actions: project -> obj after rebase

  • +
+
+
+

Refactor

+
    +
  • workloads: remove useless/unused parts

  • +
+
+
+
+

6.3 (2022-02-03)

+
+

Feat

+
    +
  • actions: throw error if RevisionStrings cannot match any Source.

  • +
  • source: add FetchableSource.explore() method

  • +
  • source: only filter context for expandable sources

  • +
  • actions: support partial revisions in SetProjectVersion

  • +
  • source: hook up context_from_revisions to SetProjectVersion

  • +
  • source: provide an easy way to create a variant context

  • +
  • environments: add container image removal to buildah adapter

  • +
  • environments: support custom arguments in RunProjectContainer

  • +
  • actions: track active_variant with SetProjectVersion

  • +
  • project: add MultiVersioned Mixin to Projects

  • +
  • source: symlink active version for http sources

  • +
  • source: Link to active location after version()

  • +
  • actions: Rename AddProjectVersion to SetProjectVersion

  • +
  • actions: add AddProjectVersion action

  • +
  • actions: remove obsolete parameters

  • +
  • actions: remove attrs from utils/actions

  • +
+
+
+

Fix

+
    +
  • tests: eye-breaking code alignment.

  • +
  • environments: do not fail if no entrypoint is set.

  • +
  • environments: supply args as dedicated subcommand args

  • +
  • environments: use a default list factory, instead of a list class

  • +
  • source: replace symlink to directory

  • +
  • actions: obvious type errors in SetProjectVersion

  • +
  • actions: assign active variant

  • +
+
+
+

Refactor

+
    +
  • pylint: remove unused import

  • +
  • pylint: make pylint happy.

  • +
  • pylint: make pylint almost happy.

  • +
+
+
+
+

6.2.7 (2021-09-21)

+
+
+

6.2.6 (2021-09-16)

+
+

Fix

+
    +
  • sources: do not use protocol class as ABC

  • +
+
+
+
+

6.2.5 (2021-09-15)

+
+

Feat

+
    +
  • utils/run: add unbuffered watch commands

  • +
  • source: update git remote revisions. (#434)

  • +
  • log: add force_tty switch to control RichHandler. (#435)

  • +
+
+
+
+

6.2.4 (2021-09-03)

+
+
+

6.2.3 (2021-08-26)

+
+

Fix

+
    +
  • schema: silence SAWarning about caching (#428)

  • +
  • environments: pass format string to logging call (#427)

  • +
+
+
+
+

6.2.2 (2021-07-29)

+
+
+

6.2.1 (2021-07-06)

+
+

Feat

+
    +
  • environments: add an interactive mode for container runs.

  • +
+
+
+

Fix

+
    +
  • logging: make rich log to stderr by default (#415)

  • +
  • settings: BB_ENV is ignored when no config file is loaded” (#414)

  • +
+
+
+
+

6.2 (2021-06-02)

+
+

Fix

+
    +
  • settings: unbreak test cases.

  • +
  • use correct schema version

  • +
  • settings: consistent settings behavior.

  • +
  • environments: notify the user, if image creation fails

  • +
+
+
+
+

6.1.1 (2021-05-11)

+
+

Fix

+
    +
  • project: do not track project classes twice

  • +
+
+
+
+

6.1 (2021-05-11)

+
+

Feat

+
    +
  • environments: just print env var name as error message

  • +
  • environments: warn the user about too long paths for libpod

  • +
  • slurm: support variable number of subcommand arguments

  • +
  • tune down rich’s custom log format

  • +
  • environments: enable debugging of failed image builds

  • +
  • environments: provide more consistent output through rich

  • +
  • environments: add ‘rmi’ subcommand to delete images.

  • +
  • environments: make an error message stand out more clearly

  • +
  • environments: add g++ to base image

  • +
  • environments: split image_exists into 2 implementations

  • +
  • environments: split containers cli into 2 entitie

  • +
  • environments: add basic error handling to environments

  • +
  • environments: emit layer creation events

  • +
  • environments: print layer construction progress

  • +
  • environments: make layers hashable

  • +
  • environments: step-wise image construction

  • +
  • environments: split Repositories and Unit of Work into 2 entities each

  • +
  • utils/slurm: add customizable SLURM templates

  • +
  • cli/project: add details view for a single project

  • +
  • cli/project: change project view to a condensed format

  • +
  • environments: add option to replace container images

  • +
  • add support for –export and –import flags in containers

  • +
+
+
+

Fix

+
    +
  • sources: unshallow only when needed

  • +
  • environments: unshallow git clones before dissociating

  • +
  • environments: remove left-over parameters

  • +
  • ci: typo.

  • +
  • environments: do not overwrite exported images.

  • +
  • environments: remove optional image name argument from podman load

  • +
  • slurm: fix pylint/mypy

  • +
  • environments: reuse same status bar structure for all other cli subcommands

  • +
  • environments: mypy warnings

  • +
  • environments: fix mypy/pylint annotations.

  • +
  • environments: split return turple and baild out on error

  • +
  • environments: mypy warnings

  • +
  • environments: add missing type conversion

  • +
  • environments: rework typing annotations for handlers

  • +
  • environments: fix linter/mypy warnings

  • +
  • environments: make Add & Copy layers hashable

  • +
  • environments: add missing sys import

  • +
  • environments: import Protocol from typing_extensions, if python <= 3.8

  • +
  • environments: handle ‘None’ for MaybeContainer return type

  • +
  • slurm: do not modify slurm_node_dir

  • +
  • environments: deal with multi-line container ids

  • +
  • environments: do not spawn the FromLayer

  • +
  • cli/project: annotate print_layers

  • +
  • cli/project: add neutral element for multiplication with reduce

  • +
  • project: project registration for groups

  • +
  • environments: explicitly state remote registry location

  • +
  • do not use global state to conffigure buildah/podman

  • +
  • x264: use local name of source for lookup

  • +
+
+
+

Refactor

+
    +
  • environments: fix possible unbound variable

  • +
  • slurm: fix type error on cli_process

  • +
  • environments: remove unused sys import

  • +
  • environments: rmeove some linter warnings

  • +
  • environments: replace functools.partial with custom closure function

  • +
  • environments: unsplit image from layer creation

  • +
  • enviroments: remove debug print

  • +
  • environments: remove unused commands

  • +
  • cli/project: remove version counting from project view

  • +
  • cli/project: force use of str

  • +
  • cli/project: add documentation to print_project

  • +
  • cli/project: add type annotation for set_limit

  • +
  • cli/project: add a default list limit for versions (10)

  • +
  • cli/project: provide better layout of project information

  • +
  • cli/project: use a multi-line string

  • +
  • cli/project: use named fields

  • +
  • project: provide correct type annotations

  • +
+
+
+
+

6.0.1 (2020-12-29)

+
+

Fix

+
    +
  • Avoid useless plugin spam when running with higher verbosity levels

  • +
+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/command/index.html b/_modules/benchbuild/command/index.html new file mode 100644 index 000000000..aba65c14f --- /dev/null +++ b/_modules/benchbuild/command/index.html @@ -0,0 +1,1173 @@ + + + + + + benchbuild.command + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.command

+import logging
+import shutil
+import sys
+import typing as tp
+from contextlib import contextmanager
+from pathlib import Path
+from typing import Protocol, runtime_checkable
+
+from plumbum import local
+from plumbum.commands.base import BoundEnvCommand
+
+from benchbuild.settings import CFG
+from benchbuild.source.base import primary
+from benchbuild.utils.revision_ranges import RevisionRange
+from benchbuild.utils.run import watch
+from benchbuild.utils.wrapping import wrap
+
+if tp.TYPE_CHECKING:
+    import benchbuild.project.Project  # pylint: disable=unused-import
+
+LOG = logging.getLogger(__name__)
+
+
+
+[docs] +@runtime_checkable +class ArgsRenderStrategy(Protocol): + """ + Rendering strategy protocol for command line argument tokens. + """ + + @property + def unrendered(self) -> str: + """ + Returns an unrendered representation of this strategy. + """ + +
+[docs] + def rendered(self, **kwargs: tp.Any) -> tp.Tuple[str, ...]: + """Renders this strategy."""
+
+ + + +
+[docs] +@runtime_checkable +class PathRenderStrategy(Protocol): + """ + Rendering strategy protocol for path components. + """ + + @property + def unrendered(self) -> str: + """ + Returns an unrendered representation of this strategy. + """ + +
+[docs] + def rendered(self, **kwargs: tp.Any) -> Path: + """Renders this strategy."""
+
+ + + +
+[docs] +class RootRenderer: + """ + Renders the root directory. + """ + + @property + def unrendered(self) -> str: + return "/" + +
+[docs] + def rendered(self, **kwargs: tp.Any) -> Path: + del kwargs + return Path("/")
+ + + def __str__(self) -> str: + return self.unrendered + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +class ConstStrRenderer: + """ + Renders a constant string defined by the user. + """ + value: str + + def __init__(self, value: str) -> None: + self.value = value + + @property + def unrendered(self) -> str: + return self.value + +
+[docs] + def rendered(self, **kwargs: tp.Any) -> Path: + del kwargs + return Path(self.value)
+ + + def __str__(self) -> str: + return self.value + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +class BuilddirRenderer: + """ + Renders the build directory of the assigned project. + """ + + @property + def unrendered(self) -> str: + return "<builddir>" + +
+[docs] + def rendered( + self, + project: tp.Optional['benchbuild.project.Project'] = None, + **kwargs: tp.Any + ) -> Path: + """ + Render the project's build directory. + + If rendering is not possible, the unrendered representation is + provided and an error will be loggged. + + Args: + project: the project to render the build directory from. + """ + del kwargs + + if project is None: + LOG.error("Cannot render a build directory without a project.") + return Path(self.unrendered) + + return Path(project.builddir)
+ + + def __str__(self) -> str: + return self.unrendered
+ + + +
+[docs] +class SourceRootRenderer: + """ + Renders the source root of the given local source name. + + The attribute 'local' refers to the local attribute in a project's + source definition. + If the local name cannot be found inside the project's source definition, + it will concatenate the project's builddir with the given name. + """ + local: str + + def __init__(self, local_name: str) -> None: + self.local = local_name + + @property + def unrendered(self) -> str: + return f"<source_of({self.local})>" + +
+[docs] + def rendered( + self, + project: tp.Optional['benchbuild.project.Project'] = None, + **kwargs: tp.Any + ) -> Path: + """ + Render the project's source directory. + + If rendering is not possible, the unrendered representation is + provided and an error will be loggged. + + Args: + project: the project to render the build directory from. + """ + del kwargs + + if project is None: + LOG.error("Cannot render a source directory without a project.") + return Path(self.unrendered) + + if (src_path := project.source_of(self.local)): + return Path(src_path) + return Path(project.builddir) / self.local
+ + + def __str__(self) -> str: + return self.unrendered
+ + + +
+[docs] +class ArgsToken: + """ + Base class for tokens that can be rendered into command-line arguments. + """ + renderer: ArgsRenderStrategy + +
+[docs] + @classmethod + def make_token( + cls, renderer: ArgsRenderStrategy + ) -> 'ArgsToken': + return ArgsToken(renderer)
+ + + def __init__(self, renderer: ArgsRenderStrategy) -> None: + self.renderer = renderer + +
+[docs] + def render(self, **kwargs: tp.Any) -> tp.Tuple[str, ...]: + """ + Renders the PathToken as a standard pathlib Path. + + Any kwargs will be forwarded to the PathRenderStrategy. + """ + return self.renderer.rendered(**kwargs)
+ + + def __str__(self) -> str: + return self.renderer.unrendered + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +class PathToken: + """ + Base class used for command token substitution. + + A path token can use similar to pathlib's Path components. However, each + token can render dynamically based on the given render context. + """ + renderer: PathRenderStrategy + + left: tp.Optional['PathToken'] + right: tp.Optional['PathToken'] + +
+[docs] + @classmethod + def make_token( + cls, renderer: tp.Optional[PathRenderStrategy] = None + ) -> 'PathToken': + if renderer: + return PathToken(renderer) + return PathToken(RootRenderer())
+ + + def __init__( + self, + renderer: PathRenderStrategy, + left: tp.Optional['PathToken'] = None, + right: tp.Optional['PathToken'] = None + ) -> None: + + self.renderer = renderer + self.left = left + self.right = right + + @property + def name(self) -> str: + return Path(str(self)).name + + @property + def dirname(self) -> Path: + return Path(str(self)).parent + +
+[docs] + def exists(self) -> bool: + return Path(str(self)).exists()
+ + +
+[docs] + def render(self, **kwargs: tp.Any) -> Path: + """ + Renders the PathToken as a standard pathlib Path. + + Any kwargs will be forwarded to the PathRenderStrategy. + """ + token = self.renderer.rendered(**kwargs) + p = Path() + + if self.left: + p = self.left.render(**kwargs) + + p = p / token + + if self.right: + p = p / self.right.render(**kwargs) + + return p
+ + + def __truediv__(self, rhs: tp.Union[str, 'PathToken']) -> 'PathToken': + if isinstance(rhs, str): + render_str = ConstStrRenderer(rhs) + rhs_token = PathToken(render_str) + else: + rhs_token = rhs + + if self.right is None: + return PathToken(self.renderer, self.left, rhs_token) + return PathToken(self.renderer, self.left, self.right / rhs_token) + + def __str__(self) -> str: + parts = [self.left, self.renderer.unrendered, self.right] + return str(Path(*[str(part) for part in parts if part is not None])) + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +def source_root(local_name: str) -> PathToken: + """ + Create a SourceRoot token for the given name. + + Args: + local_name (str): The source's local name to access. + """ + return PathToken.make_token(SourceRootRenderer(local_name))
+ + + +SourceRoot = source_root + + +
+[docs] +def project_root() -> PathToken: + return PathToken.make_token(BuilddirRenderer())
+ + + +ProjectRoot = project_root + + +
+[docs] +@runtime_checkable +class SupportsUnwrap(Protocol): + """ + Support unwrapping a WorkloadSet. + + Unwrapping ensures access to a WorkloadSet from any wrapper object. + """ + +
+[docs] + def unwrap(self, project: "benchbuild.project.Project") -> "WorkloadSet": + ...
+
+ + + +
+[docs] +class WorkloadSet: + """An immutable set of workload descriptors. + + A WorkloadSet is immutable and usable as a key in a job mapping. + WorkloadSets support composition through intersection and union. + + Example: + >>> WorkloadSet(1, 0) & WorkloadSet(1) + WorkloadSet({1}) + >>> WorkloadSet(1, 0) & WorkloadSet(2) + WorkloadSet({}) + >>> WorkloadSet(1, 0) | WorkloadSet(2) + WorkloadSet({0, 1, 2}) + >>> WorkloadSet(1, 0) | WorkloadSet("1") + WorkloadSet({0, 1, 1}) + + A workload set is not sorted, therefore, requires no comparability between + inserted values. + """ + + _tags: tp.FrozenSet[tp.Any] + + def __init__(self, *args: tp.Any) -> None: + self._tags = frozenset(args) + + def __iter__(self) -> tp.Iterator[str]: + return [k for k, _ in self._tags].__iter__() + + def __contains__(self, v: tp.Any) -> bool: + return self._tags.__contains__(v) + + def __len__(self) -> int: + return len(self._tags) + + def __and__(self, rhs: "WorkloadSet") -> "WorkloadSet": + lhs_t = self._tags + rhs_t = rhs._tags + + ret = WorkloadSet() + ret._tags = lhs_t & rhs_t + return ret + + def __or__(self, rhs: "WorkloadSet") -> "WorkloadSet": + lhs_t = self._tags + rhs_t = rhs._tags + + ret = WorkloadSet() + ret._tags = lhs_t | rhs_t + return ret + + def __hash__(self) -> int: + return hash(self._tags) + + def __repr__(self) -> str: + repr_str = ", ".join([f"{k}" for k in self._tags]) + + return f"WorkloadSet({{{repr_str}}})" + +
+[docs] + def unwrap(self, project: "benchbuild.project.Project") -> "WorkloadSet": + """ + Implement the `SupportsUnwrap` protocol. + + WorkloadSets only implement identity. + """ + del project + return self
+
+ + + +
+[docs] +class OnlyIn: + """ + Provide a filled `WorkloadSet` only if, given revision is inside the range. + + This makes use of the unwrap protocol and returns the given WorkloadSet, + iff, the Project's revision is included in the range specified by the + RevisionRange. + """ + rev_range: RevisionRange + workload_set: WorkloadSet + + def __init__( + self, rev_range: RevisionRange, workload_set: WorkloadSet + ) -> None: + self.rev_range = rev_range + self.workload_set = workload_set + +
+[docs] + def unwrap(self, project: "benchbuild.project.Project") -> WorkloadSet: + """ + Provide the store WorkloadSet only if our revision is in the range. + """ + source = primary(*project.source) + self.rev_range.init_cache(source.fetch()) + + revision = project.version_of_primary + if revision in set(self.rev_range): + return self.workload_set + return WorkloadSet()
+
+ + + +ArtefactPath = tp.Union[PathToken, str] + + +
+[docs] +class Command: + """ + A command wrapper for benchbuild's commands. + + Commands are defined by a path to an executable binary and it's arguments. + Optional, commands can provide output and output_param parameters to + declare the Command's output behavior. + + Attributes: + path: The binary path of the command + *args: Command arguments. + output_param: A format string that encodes the output parameter argument + using the `output` attribute. + + Example: output_param = f"--out {output}". + BenchBuild will construct the output argument from this. + output: An optional PathToken to declare an output file of the command. + label: An optional Label that can be used to name a command. + creates: A list of PathToken that encodes any artifacts that are + created by this command. + This will include the output PathToken automatically. Any + additional PathTokens provided will be provided for cleanup. + consumes: A list of PathToken that holds any artifacts that will be + consumed by this command. + **kwargs: Any remaining kwargs will be added as environment variables + to the command. + + Base command path: + >>> ROOT = PathToken.make_token() + >>> base_c = Command(ROOT / "bin" / "true") + >>> base_c + Command(path=/bin/true) + >>> str(base_c) + '/bin/true' + + Test environment representations: + >>> env_c = Command(ROOT / "bin"/ "true", BB_ENV_TEST=1) + >>> env_c + Command(path=/bin/true env={'BB_ENV_TEST': 1}) + >>> str(env_c) + 'BB_ENV_TEST=1 /bin/true' + + Argument representations: + >>> args_c = Command(ROOT / "bin" / "true", "--arg1", "--arg2") + >>> args_c + Command(path=/bin/true args=('--arg1', '--arg2')) + >>> str(args_c) + '/bin/true --arg1 --arg2' + + Use str for creates: + >>> cmd = Command(ROOT / "bin" / "true", creates=["tmp/foo"]) + >>> cmd.creates + [<builddir>/tmp/foo] + + Use absolute path-str for creates: + >>> cmd = Command(ROOT / "bin" / "true", creates=["/tmp/foo"]) + >>> cmd.creates + [/tmp/foo] + """ + + _args: tp.Tuple[tp.Any, ...] + _env: tp.Dict[str, str] + _label: tp.Optional[str] + _output: tp.Optional[PathToken] + _output_param: tp.Sequence[str] + _path: PathToken + _creates: tp.Sequence[PathToken] + _consumes: tp.Sequence[PathToken] + + def __init__( + self, + path: PathToken, + *args: tp.Any, + output: tp.Optional[PathToken] = None, + output_param: tp.Optional[tp.Sequence[str]] = None, + label: tp.Optional[str] = None, + creates: tp.Optional[tp.Sequence[ArtefactPath]] = None, + consumes: tp.Optional[tp.Sequence[ArtefactPath]] = None, + **kwargs: str, + ) -> None: + + def _to_pathtoken(token: ArtefactPath) -> PathToken: + if isinstance(token, str): + return ProjectRoot() / token + return token + + self._path = path + self._args = tuple(args) + self._output = output + + self._output_param = output_param if output_param is not None else [] + self._label = label + self._env = kwargs + + _creates = creates if creates is not None else [] + _consumes = consumes if consumes is not None else [] + + self._creates = [_to_pathtoken(token) for token in _creates] + self._consumes = [_to_pathtoken(token) for token in _consumes] + + if output: + self._creates.append(output) + + @property + def name(self) -> str: + return self._path.name + + @property + def path(self) -> PathToken: + return self._path + + @path.setter + def path(self, new_path: PathToken) -> None: + self._path = new_path + + @property + def dirname(self) -> Path: + return self._path.dirname + + @property + def output(self) -> tp.Optional[PathToken]: + return self._output + + @property + def creates(self) -> tp.Sequence[PathToken]: + return self._creates + + @property + def consumes(self) -> tp.Sequence[PathToken]: + return self._consumes + +
+[docs] + def env(self, **kwargs: str) -> None: + self._env.update(kwargs)
+ + + @property + def label(self) -> str: + return self._label if self._label else self.name + + @label.setter + def label(self, new_label: str) -> None: + self._label = new_label + + def __getitem__(self, args: tp.Tuple[tp.Any, ...]) -> "Command": + return Command( + self._path, + *self._args, + *args, + output=self._output, + output_param=self._output_param, + creates=self._creates, + consumes=self._consumes, + **self._env + ) + + def __call__(self, *args: tp.Any, **kwargs: tp.Any) -> tp.Any: + """Run the command in foreground.""" + cmd_w_output = self.as_plumbum(**kwargs) + return watch(cmd_w_output)(*args) + +
+[docs] + def rendered_args(self, **kwargs: tp.Any) -> tp.Tuple[str, ...]: + args: tp.List[str] = [] + + for arg in self._args: + if isinstance(arg, ArgsToken): + args.extend(arg.render(**kwargs)) + else: + args.append(str(arg)) + + return tuple(args)
+ + +
+[docs] + def as_plumbum(self, **kwargs: tp.Any) -> BoundEnvCommand: + """ + Convert this command into a plumbum compatible command. + + This renders all tokens in the command's path and creates a new + plumbum command with the given parameters and environment. + + Args: + **kwargs: parameters passed to the path renderers. + + Returns: + An executable plumbum command. + """ + cmd_path = self.path.render(**kwargs) + assert cmd_path.exists(), f"{str(cmd_path)} doesn't exist!" + + cmd = local[str(cmd_path)] + cmd_w_args = cmd[self.rendered_args(**kwargs)] + cmd_w_output = cmd_w_args + if self.output: + output_path = self.output.render(**kwargs) + output_params = [ + arg.format(output=output_path) for arg in self._output_param + ] + cmd_w_output = cmd_w_args[output_params] + cmd_w_env = cmd_w_output.with_env(**self._env) + + return cmd_w_env
+ + + def __repr__(self) -> str: + repr_str = f"path={self._path}" + + if self._label: + repr_str = f"{self._label} {repr_str}" + if self._args: + repr_str += f" args={tuple(str(arg) for arg in self._args)}" + if self._env: + repr_str += f" env={self._env}" + if self._output: + repr_str += f" output={self._output}" + if self._output_param: + repr_str += f" output_param={self._output_param}" + + return f"Command({repr_str})" + + def __str__(self) -> str: + env_str = " ".join([f"{k}={str(v)}" for k, v in self._env.items()]) + args_str = " ".join(tuple(str(arg) for arg in self._args)) + + command_str = f"{self._path}" + if env_str: + command_str = f"{env_str} {command_str}" + if args_str: + command_str = f"{command_str} {args_str}" + if self._label: + command_str = f"{self._label} {command_str}" + return command_str
+ + + +
+[docs] +class ProjectCommand: + """ProjectCommands associate a command to a benchbuild project. + + A project command can wrap the given command with the assigned + runtime extension. + If the binary is located inside a subdirectory relative to one of the + project's sources, you can provide a path relative to it's local + directory. + A project command will always try to resolve any reference to a local + source directory in a command's path. + + A call to a project command will drop the current configuration inside + the project's build directory and confine the run into the project's + build directory. The binary will be replaced with a wrapper that + calls the project's runtime_extension. + """ + + project: "benchbuild.project.Project" + command: Command + + def __init__( + self, project: "benchbuild.project.Project", command: Command + ) -> None: + self.project = project + self.command = command + + @property + def path(self) -> Path: + return self.command.path.render(project=self.project) + + def __call__(self, *args: tp.Any): + build_dir = self.project.builddir + + CFG.store(Path(build_dir) / ".benchbuild.yml") + with local.cwd(build_dir): + cmd_path = self.path + + wrap(str(cmd_path), self.project) + return self.command.__call__(*args, project=self.project) + + def __repr__(self) -> str: + return f"ProjectCommand({self.project.name}, {self.path})" + + def __str__(self) -> str: + return str(self.command)
+ + + +def _is_relative_to(p: Path, other: Path) -> bool: + return p.is_relative_to(other) + + +def _default_prune(project_command: ProjectCommand) -> None: + command = project_command.command + project = project_command.project + builddir = Path(str(project.builddir)) + + for created in command.creates: + created_path = created.render(project=project) + if created_path.exists() and created_path.is_file(): + if not _is_relative_to(created_path, builddir): + LOG.error("Pruning outside project builddir was rejected!") + else: + created_path.unlink() + + +def _default_backup( + project_command: ProjectCommand, + _suffix: str = ".benchbuild_backup" +) -> tp.List[Path]: + command = project_command.command + project = project_command.project + builddir = Path(str(project.builddir)) + + backup_destinations: tp.List[Path] = [] + for backup in command.consumes: + backup_path = backup.render(project=project) + backup_destination = backup_path.with_suffix(_suffix) + if backup_path.exists(): + if not _is_relative_to(backup_path, builddir): + LOG.error("Backup outside project builddir was rejected!") + else: + shutil.copy(backup_path, backup_destination) + backup_destinations.append(backup_destination) + + return backup_destinations + + +def _default_restore(backup_paths: tp.List[Path]) -> None: + for backup_path in backup_paths: + original_path = backup_path.with_suffix("") + if not original_path.exists() and backup_path.exists(): + backup_path.rename(original_path) + + if not original_path.exists() and not backup_path.exists(): + LOG.error("No backup to restore from. %s missing", str(backup_path)) + + if original_path.exists() and backup_path.exists(): + LOG.error("%s not consumed, ignoring backup", str(original_path)) + + +
+[docs] +class PruneFn(Protocol): + """Prune function protocol.""" + + def __call__(self, project_command: ProjectCommand) -> None: + ...
+ + + +
+[docs] +class BackupFn(Protocol): + """Backup callback function protocol.""" + + def __call__(self, + project_command: ProjectCommand, + _suffix: str = ...) -> tp.List[Path]: + ...
+ + + +
+[docs] +class RestoreFn(Protocol): + """Restore function protocol.""" + + def __call__(self, backup_paths: tp.List[Path]) -> None: + ...
+ + + +
+[docs] +@contextmanager +def cleanup( + project_command: ProjectCommand, + backup: BackupFn = _default_backup, + restore: RestoreFn = _default_restore, + prune: PruneFn = _default_prune +): + """ + Encapsulate a command in automatic backup, restore and prune. + + This will wrap a ProjectCommand inside a contextmanager. All consumed + files inside the project's build directory will be backed up by benchbuild. + You can then run your command as usual. + When you leave the context, all created paths are deleted and all consumed + paths restored. + """ + + backup_paths = backup(project_command) + yield project_command + prune(project_command) + restore(backup_paths)
+ + + +WorkloadIndex = tp.MutableMapping[WorkloadSet, tp.List[Command]] + + +
+[docs] +def unwrap( + index: WorkloadIndex, project: 'benchbuild.project.Project' +) -> WorkloadIndex: + """ + Unwrap all keys in a workload index. + + 'Empty' WorkloadSets will be removed. A WorkloadSet is empty, if it's + boolean representation evaluates to `False`. + """ + return {k: v for k, v in index.items() if bool(k.unwrap(project))}
+ + + +
+[docs] +def filter_workload_index( + only: tp.Optional[WorkloadSet], index: WorkloadIndex +) -> tp.Generator[tp.List[Command], None, None]: + """ + Yield only commands from the index that match the filter. + + This removes all command lists from the index not matching `only`. + """ + + keys = [k for k in index if k and ((only and (k & only)) or (not only))] + for k in keys: + yield index[k]
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/container/index.html b/_modules/benchbuild/container/index.html new file mode 100644 index 000000000..2e3b04c99 --- /dev/null +++ b/_modules/benchbuild/container/index.html @@ -0,0 +1,794 @@ + + + + + + benchbuild.container + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.container

+"""
+Container construction tool.
+
+This tool assists in the creation of customized uchroot containers.
+You can define strategies and apply them on a given container base-image
+to have a fixed way of creating a user-space environment.
+"""
+import logging
+import os
+import sys
+from abc import abstractmethod
+
+from plumbum import FG, TF, ProcessExecutionError, cli, local
+
+from benchbuild.settings import CFG
+from benchbuild.utils import bootstrap, container, download, log, run, uchroot
+from benchbuild.utils import user_interface as ui
+from benchbuild.utils.cmd import bash, mkdir, mv, rm, tar
+from benchbuild.utils.settings import get_number_of_jobs
+
+LOG = logging.getLogger(__name__)
+
+
+
+[docs] +def clean_directories(builddir, in_dir=True, out_dir=True): + """Remove the in and out of the container if confirmed by the user.""" + container_in = local.path(builddir) / "container-in" + container_out = local.path(builddir) / "container-out" + + if in_dir and container_in.exists(): + if ui.ask("Should I delete '{0}'?".format(container_in)): + container_in.delete() + if out_dir and container_out.exists(): + if ui.ask("Should I delete '{0}'?".format(container_out)): + container_out.delete()
+ + + +
+[docs] +def setup_directories(builddir): + """Create the in and out directories of the container.""" + build_dir = local.path(builddir) + in_dir = build_dir / "container-in" + out_dir = build_dir / "container-out" + + if not in_dir.exists(): + in_dir.mkdir() + if not out_dir.exists(): + out_dir.mkdir()
+ + + +
+[docs] +def setup_container(builddir, _container): + """Prepare the container and returns the path where it can be found.""" + build_dir = local.path(builddir) + in_dir = build_dir / "container-in" + container_path = local.path(_container) + with local.cwd(builddir): + container_bin = container_path.basename + container_in = in_dir / container_bin + download.Copy(_container, container_in) + uchrt = uchroot.no_args() + + with local.cwd("container-in"): + uchrt = uchrt["-E", "-A", "-u", "0", "-g", "0", "-C", "-r", "/", + "-w", + os.path.abspath("."), "--"] + + # Check, if we need erlent support for this archive. + has_erlent = bash["-c", + "tar --list -f './{0}' | grep --silent '.erlent'". + format(container_in)] + has_erlent = (has_erlent & TF) + + # Unpack input container to: container-in + if not has_erlent: + cmd = local["/bin/tar"]["xf"] + cmd = uchrt[cmd[container_bin]] + else: + cmd = tar["xf"] + cmd = cmd[container_in] + + with local.cwd("container-in"): + cmd("--exclude=dev/*") + rm(container_in) + return in_dir
+ + + +
+[docs] +def run_in_container(command, container_dir): + """ + Run a given command inside a container. + + Mounts a directory as a container at the given mountpoint and tries to run + the given command inside the new container. + """ + container_p = local.path(container_dir) + with local.cwd(container_p): + uchrt = uchroot.with_mounts() + uchrt = uchrt["-E", "-A", "-u", "0", "-g", "0", "-C", "-w", "/", "-r", + container_p] + uchrt = uchrt["--"] + + cmd_path = container_p / command[0].lstrip('/') + if not cmd_path.exists(): + LOG.error( + "The command does not exist inside the container! %s", cmd_path + ) + raise ValueError('The command does not exist inside the container!') + + cmd = uchrt[command] + return cmd & FG
+ + + +
+[docs] +def pack_container(in_container, out_file): + """ + Pack a container image into a .tar.bz2 archive. + + Args: + in_container (str): Path string to the container image. + out_file (str): Output file name. + """ + container_filename = local.path(out_file).basename + out_container = local.cwd / "container-out" / container_filename + out_dir = out_container.dirname + + # Pack the results to: container-out + with local.cwd(in_container): + tar("cjf", out_container, ".") + c_hash = download.update_hash(out_container) + if out_dir.exists(): + mkdir("-p", out_dir) + mv(out_container, out_file) + mv(out_container + ".hash", out_file + ".hash") + + new_container = {"path": out_file, "hash": str(c_hash)} + CFG["container"]["known"] += new_container
+ + + +
+[docs] +def setup_bash_in_container(builddir, _container, outfile, shell): + """ + Setup a bash environment inside a container. + + Creates a new chroot, which the user can use as a bash to run the wanted + projects inside the mounted container, that also gets returned afterwards. + """ + with local.cwd(builddir): + # Switch to bash inside uchroot + print( + "Entering bash inside User-Chroot. Prepare your image and " + "type 'exit' when you are done. If bash exits with a non-zero" + "exit code, no new container will be stored." + ) + store_new_container = True + try: + run_in_container(shell, _container) + except ProcessExecutionError: + store_new_container = False + + if store_new_container: + print("Packing new container image.") + pack_container(_container, outfile) + config_path = str(CFG["config_file"]) + CFG.store(config_path) + print("Storing config in {0}".format(os.path.abspath(config_path)))
+ + + +
+[docs] +def find_hash(container_db, key): + """Find the first container in the database with the given key.""" + for keyvalue in container_db: + if keyvalue["hash"].startswith(key): + return keyvalue["path"] + return None
+ + + +
+[docs] +def set_input_container(_container, cfg): + """Save the input for the container in the configurations.""" + if not _container: + return False + if _container.exists(): + cfg["container"]["input"] = str(_container) + return True + return False
+ + + +
+[docs] +class MockObj: + """Context object to be used in strategies. + + This object's attributes are initialized on construction. + """ + + def __init__(self, **kwargs): + self.__dict__.update(kwargs)
+ + + +
+[docs] +class ContainerStrategy: + """Interfaces for the different containers chosen by the experiment.""" + +
+[docs] + @abstractmethod + def run(self, context): + """Execute a container strategy. + + Args: + context: A context object with attributes used for the strategy. + """
+
+ + + +
+[docs] +class BashStrategy(ContainerStrategy): + """The user interface for setting up a bash inside the container.""" + +
+[docs] + def run(self, context): + print( + "Entering a shell in the container.\nUse the exit " + "command to leave the container." + ) + setup_bash_in_container( + context.builddir, context.in_container, context.out_container, + context.shell + )
+
+ + + +
+[docs] +class SetupPolyJITGentooStrategy(ContainerStrategy): + """Interface of using gentoo as a container for an experiment.""" + +
+[docs] + def run(self, context): + """Setup a gentoo container suitable for PolyJIT.""" + # Don't do something when running non-interactive. + if not sys.stdout.isatty(): + return + + with local.cwd(context.in_container): + from benchbuild.projects.gentoo import gentoo + gentoo.setup_networking() + gentoo.configure_portage() + + sed_in_chroot = uchroot.uchroot()["/bin/sed"] + sed_in_chroot = run.watch(sed_in_chroot) + emerge_in_chroot = uchroot.uchroot()["/usr/bin/emerge"] + emerge_in_chroot = run.watch(emerge_in_chroot) + has_pkg = uchroot.uchroot()["/usr/bin/qlist", "-I"] + + sed_in_chroot("-i", '/CC=/d', "/etc/portage/make.conf") + sed_in_chroot("-i", '/CXX=/d', "/etc/portage/make.conf") + + want_sync = bool(CFG["container"]["strategy"]["polyjit"]["sync"]) + want_upgrade = bool( + CFG["container"]["strategy"]["polyjit"]["upgrade"] + ) + + packages = \ + CFG["container"]["strategy"]["polyjit"]["packages"].value + with local.env(MAKEOPTS="-j{0}".format(get_number_of_jobs(CFG))): + if want_sync: + LOG.debug("Synchronizing portage.") + emerge_in_chroot("--sync") + if want_upgrade: + LOG.debug("Upgrading world.") + emerge_in_chroot( + "--autounmask-only=y", "-uUDN", "--with-bdeps=y", + "@world" + ) + for pkg in packages: + if has_pkg[pkg["name"]] & TF: + continue + env = pkg["env"] + with local.env(**env): + emerge_in_chroot(pkg["name"]) + + gentoo.setup_benchbuild() + + print("Packing new container image.") + with local.cwd(context.builddir): + pack_container(context.in_container, context.out_container)
+
+ + + +
+[docs] +class Container(cli.Application): + """Manage uchroot containers.""" + + VERSION = str(CFG["version"]) + +
+[docs] + @cli.switch(["-i", "--input-file"], str, help="Input container path") + def input_file(self, _container): + """Find the input path of a uchroot container.""" + p = local.path(_container) + if set_input_container(p, CFG): + return + + p = find_hash(CFG["container"]["known"].value, container) + if set_input_container(p, CFG): + return + + raise ValueError("The path '{0}' does not exist.".format(p))
+ + +
+[docs] + @cli.switch(["-o", "--output-file"], str, help="Output container path") + def output_file(self, _container): + """Find and writes the output path of a chroot container.""" + p = local.path(_container) + if p.exists(): + if not ui.ask("Path '{0}' already exists." " Overwrite?".format(p)): + sys.exit(0) + CFG["container"]["output"] = str(p)
+ + +
+[docs] + @cli.switch(["-s", "--shell"], + str, + help="The shell command we invoke inside the container.") + def shell(self, custom_shell): + """The command to run inside the container.""" + CFG["container"]["shell"] = custom_shell
+ + +
+[docs] + @cli.switch(["-t", "-tmp-dir"], + cli.ExistingDirectory, + help="Temporary directory") + def builddir(self, tmpdir): + """Set the current builddir of the container.""" + CFG["build_dir"] = tmpdir
+ + +
+[docs] + @cli.switch( + ["m", "--mount"], + cli.ExistingDirectory, + list=True, + help="Mount the given directory under / inside the uchroot container" + ) + def mounts(self, user_mount): + """Save the current mount of the container into the settings.""" + CFG["container"]["mounts"] = user_mount
+ + + verbosity = cli.CountOf('-v', help="Enable verbose output") + +
+[docs] + def main(self, *args): + log.configure() + builddir = local.path(str(CFG["build_dir"])) + if not builddir.exists(): + response = ui.ask( + "The build directory {dirname} does not exist yet. " + "Should I create it?".format(dirname=builddir) + ) + + if response: + mkdir("-p", builddir) + print("Created directory {0}.".format(builddir)) + + setup_directories(builddir)
+
+ + + +
+[docs] +@Container.subcommand("run") +class ContainerRun(cli.Application): + """Execute commannds inside a prebuilt container.""" + +
+[docs] + def main(self, *args): + builddir = str(CFG["build_dir"]) + in_container = str(CFG["container"]["input"]) + + if (in_container is None) or not os.path.exists(in_container): + in_is_file = False + in_container = container.Gentoo().local + else: + in_is_file = os.path.isfile(in_container) + if in_is_file: + clean_directories(builddir) + setup_directories(builddir) + in_container = setup_container(builddir, in_container) + + run_in_container(args, in_container) + clean_directories(builddir, in_is_file, False)
+
+ + + +
+[docs] +@Container.subcommand("create") +class ContainerCreate(cli.Application): + """ + Create a new container with a predefined strategy. + + We offer a variety of creation policies for a new container. By default a + basic 'spawn a bash' policy is used. This just leaves you inside a bash + that is started in the extracted container. After customization you can + exit the bash and pack up the result. + """ + + _strategy = BashStrategy() + +
+[docs] + @cli.switch(["-S", "--strategy"], + cli.Set("bash", "polyjit", case_sensitive=False), + help="Defines the strategy used to create a new container.", + mandatory=False) + def strategy(self, strategy): + """Select strategy based on key. + + Args: + strategy (str): The strategy to select. + + Returns: + A strategy object. + """ + self._strategy = { + "bash": BashStrategy(), + "polyjit": SetupPolyJITGentooStrategy() + }[strategy]
+ + +
+[docs] + def main(self, *args): + builddir = str(CFG["build_dir"]) + in_container = str(CFG["container"]["input"]) + out_container = str(CFG["container"]["output"]) + mounts = CFG["container"]["mounts"].value + shell = str(CFG["container"]["shell"]) + + if (in_container is None) or not os.path.exists(in_container): + in_container = container.Gentoo().local + + in_is_file = os.path.isfile(in_container) + if in_is_file: + in_container = setup_container(builddir, in_container) + + self._strategy.run( + MockObj( + builddir=builddir, + in_container=in_container, + out_container=out_container, + mounts=mounts, + shell=shell + ) + ) + clean_directories(builddir, in_is_file, True)
+
+ + + +
+[docs] +@Container.subcommand("bootstrap") +class ContainerBootstrap(cli.Application): + """Check for the needed files.""" + +
+[docs] + def install_cmake_and_exit(self): + """Tell the user to install cmake and aborts the current process.""" + print( + "You need to install cmake via your package manager manually." + " Exiting." + ) + sys.exit(-1)
+ + +
+[docs] + def main(self, *args): + print("Checking container binary dependencies...") + if not bootstrap.find_package("uchroot"): + if not bootstrap.find_package("cmake"): + self.install_cmake_and_exit() + bootstrap.install_uchroot(None) + print("...OK") + config_file = str(CFG["config_file"]) + if not (config_file and os.path.exists(config_file)): + config_file = ".benchbuild.json" + CFG.store(config_file) + print("Storing config in {0}".format(os.path.abspath(config_file))) + print( + "Future container commands from this directory will automatically" + " source the config file." + )
+
+ + + +
+[docs] +@Container.subcommand("list") +class ContainerList(cli.Application): + """Prints a list of the known containers.""" + +
+[docs] + def main(self, *args): + containers = CFG["container"]["known"].value + for c in containers: + print("[{1:.8s}] {0}".format(c["path"], str(c["hash"])))
+
+ + + +
+[docs] +def main(*args): + """Main entry point for the container tool.""" + return Container.run(*args)
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/environments/domain/commands/index.html b/_modules/benchbuild/environments/domain/commands/index.html new file mode 100644 index 000000000..4926f0da4 --- /dev/null +++ b/_modules/benchbuild/environments/domain/commands/index.html @@ -0,0 +1,351 @@ + + + + + + benchbuild.environments.domain.commands + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.environments.domain.commands

+import re
+import typing as tp
+import unicodedata
+
+import attr
+
+from . import declarative, model
+
+
+
+[docs] +def fs_compliant_name(name: str) -> str: + """ + Convert a name to a valid filename. + """ + value = str(name) + value = unicodedata.normalize('NFKD', + value).encode('ascii', + 'ignore').decode('ascii') + value = re.sub(r'[^\w\s-]', '', value.lower()) + return re.sub(r'[-\s]+', '-', value).strip('-_')
+ + + +
+[docs] +def oci_compliant_name(name: str) -> str: + """ + Convert a name to an OCI compliant name. + + For now, we just make sure it is lower-case. This is depending on + the implementation of your container registry. podman/buildah require + lower-case repository names for now. + + Args: + name: the name to convert + + Examples: + >>> oci_compliant_name("foo") + 'foo' + >>> oci_compliant_name("FoO") + 'foo' + """ + # OCI Spec requires image names to be lowercase + return name.lower()
+ + + +# +# Dataclasses are perfectly valid without public methods +# + + +# pylint: disable=too-few-public-methods +
+[docs] +@attr.s(frozen=True, hash=False) +class CreateImage(model.Command): + name: str = attr.ib(converter=oci_compliant_name) + layers: declarative.ContainerImage = attr.ib() + + def __hash__(self) -> int: + return hash(self.name)
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class DeleteImage(model.Command): + name: str = attr.ib(converter=oci_compliant_name)
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class CreateBenchbuildBase(model.Command): + name: str = attr.ib(converter=oci_compliant_name, eq=True) + layers: declarative.ContainerImage = attr.ib() + + def __hash__(self) -> int: + return hash(self.name)
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class RunProjectContainer(model.Command): + image: str = attr.ib(converter=oci_compliant_name) + name: str = attr.ib(converter=oci_compliant_name) + + build_dir: str = attr.ib() + args: tp.Sequence[str] = attr.ib(default=attr.Factory(list))
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class ExportImage(model.Command): + image: str = attr.ib(converter=oci_compliant_name) + out_name: str = attr.ib()
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class ImportImage(model.Command): + image: str = attr.ib(converter=oci_compliant_name) + in_path: str = attr.ib()
+ + + +# pylint: enable=too-few-public-methods +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/environments/domain/declarative/index.html b/_modules/benchbuild/environments/domain/declarative/index.html new file mode 100644 index 000000000..90d7d39dd --- /dev/null +++ b/_modules/benchbuild/environments/domain/declarative/index.html @@ -0,0 +1,495 @@ + + + + + + benchbuild.environments.domain.declarative + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.environments.domain.declarative

+"""
+BenchBuild supports containerized execution of all experiments. This gives you
+full control about the environment your [projects](/concepts/projects/) and
+[experiments](/concepts/experiments/) may run in.
+
+The following example uses the latest ``alpine:latest``:
+
+.. code-block:: python
+
+    ContainerImage().from_('alpine:latest')
+        .run('apk', 'update')
+        .run('apk', 'add', 'python3')
+
+"""
+
+import logging
+import typing as tp
+
+from benchbuild.environments.adapters.common import buildah_version
+from benchbuild.settings import CFG
+
+from . import model
+
+LOG = logging.getLogger(__name__)
+
+
+
+[docs] +class ContainerImage(list): + """ + Define a container image declaratively. + + Start a new image using the ``.from_`` method and provide a base image. + Each method creates a new layer in the container image. + """ + + def __str__(self) -> str: + return "\n".join([str(elt) for elt in self]) + + @property + def base(self) -> str: + layers = [l for l in self if isinstance(l, model.FromLayer)] + if layers: + return layers.pop(0).base + return '' + +
+[docs] + def env(self, **kwargs: str) -> 'ContainerImage': + """ + Create an environment layer in this image. + + Dockerfile syntax: ENV + + Args: + kwargs (str): a dictionary containing name/value pairings to be + set as environment variables. + """ + self.append(model.UpdateEnv(kwargs)) + return self
+ + +
+[docs] + def from_(self, base_image: str) -> 'ContainerImage': + """ + Specify a new base layer for this image. + + Dockerfile syntax: FROM <image> + + Args: + base_image (str): The base image for our new container image. + """ + self.append(model.FromLayer(base_image)) + return self
+ + +
+[docs] + def context(self, func: tp.Callable[[], None]) -> 'ContainerImage': + """ + Interact with the build context of the container. + + Sometimes you have to interact with the build context of a container + image. For example, you need to add artifacts to the build context + before you can add the to the container image. + BenchBuild uses this to add the sources to the container image + automatically. + + Args: + func (tp.Callable[[], None]): A callable that is executed in the + build-context directory. + """ + self.append(model.ContextLayer(func)) + return self
+ + +
+[docs] + def add(self, sources: tp.Iterable[str], tgt: str) -> 'ContainerImage': + """ + Add given files from the source to the container image. + + Dockerfile syntax: ADD <source> [<source>...] <target> + + Args: + sources (tp.Iterable[str]): Source path to add to the target + tgt (str): Absolute target path. + """ + self.append(model.AddLayer(tuple(sources), tgt)) + return self
+ + +
+[docs] + def copy_(self, sources: tp.Iterable[str], tgt: str) -> 'ContainerImage': + """ + Copy given files from the source to the container image. + + Dockerfile syntax: COPY <source> [<source>...] <target> + + Args: + sources (tp.Iterable[str]): Source path to add to the target + tgt (str): Absolute target path. + """ + self.append(model.CopyLayer(tuple(sources), tgt)) + return self
+ + +
+[docs] + def run(self, command: str, *args: str, **kwargs: str) -> 'ContainerImage': + """ + Run a command in the container image. + + Dockerfile syntax: RUN <command> + + Args: + command (str): The binary to execute in the container. + *args (str): Arguments that will be passed to the container. + **kwargs (str): Additional options that will be passed to the + backend run command. + """ + self.append(model.RunLayer(command, args, kwargs)) + return self
+ + +
+[docs] + def workingdir(self, directory: str) -> 'ContainerImage': + """ + Change the working directory in the container. + + Dockerfile syntax: WORKINGDIR <absolute-path> + + All layers that follow this layer will be run with their working + directory set to ``directory``. + + Args: + directory (str): The target directory to set our cwd to. + """ + self.append(model.WorkingDirectory(directory)) + return self
+ + +
+[docs] + def entrypoint(self, *args: str) -> 'ContainerImage': + """ + Set the entrypoint of the container. + + Dockerfile syntax: ENTRYPOINT <command> + + This sets the default binary to run to the given command. + + Args: + *args (str): A list of command components. + """ + self.append(model.EntryPoint(args)) + return self
+ + +
+[docs] + def command(self, *args: str) -> 'ContainerImage': + """ + Set the default command the container runs. + + Dockerfile syntax: CMD <command> + + Args: + *args (str): A list of command components. + """ + self.append(model.SetCommand(args)) + return self
+
+ + + +DEFAULT_BASES: tp.Dict[str, ContainerImage] = { + 'benchbuild:alpine': ContainerImage() \ + .from_("docker.io/alpine:3.17") \ + .run('apk', 'update') \ + .run('apk', 'add', 'python3', 'python3-dev', 'postgresql-dev', + 'linux-headers', 'musl-dev', 'git', 'gcc', 'g++', + 'sqlite-libs', 'libgit2-dev', 'libffi-dev', 'py3-pip') +} + + +
+[docs] +def add_benchbuild_layers(layers: ContainerImage) -> ContainerImage: + """ + Add benchbuild into the given container image. + + This assumes all necessary depenencies are available in the image already. + The installation is done, either using pip from a remote mirror, or using + the source checkout of benchbuild. + + A source installation requires your buildah/podman installation to be + able to complete a bind-mount as the user that runs benchbuild. + + Args: + layers: a container image we will add our install layers to. + + Returns: + the modified container image. + """ + crun = str(CFG['container']['runtime']) + src_dir = str(CFG['container']['source']) + tgt_dir = '/benchbuild' + + def from_source(image: ContainerImage) -> None: + LOG.debug('BenchBuild will be installed from source.') + + mount = f'type=bind,src={src_dir},target={tgt_dir}' + if buildah_version() >= (1, 24, 0): + mount += ',rw' + + # The image requires git, pip and a working python3.7 or better. + image.run('mkdir', f'{tgt_dir}', runtime=crun) + image.run('pip3', 'install', 'setuptools', runtime=crun) + image.run( + 'pip3', + 'install', + '--ignore-installed', + tgt_dir, + mount=mount, + runtime=crun + ) + + def from_pip(image: ContainerImage) -> None: + LOG.debug('installing benchbuild from pip release.') + image.run('pip3', 'install', 'benchbuild', runtime=crun) + + if bool(CFG['container']['from_source']): + from_source(layers) + else: + from_pip(layers) + return layers
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/environments/domain/model/index.html b/_modules/benchbuild/environments/domain/model/index.html new file mode 100644 index 000000000..1b46aef15 --- /dev/null +++ b/_modules/benchbuild/environments/domain/model/index.html @@ -0,0 +1,508 @@ + + + + + + benchbuild.environments.domain.model + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.environments.domain.model

+import abc
+import enum
+import typing as tp
+
+import attr
+
+
+# pylint: disable=too-few-public-methods
+
+[docs] +@attr.s(frozen=True) +class Message: + pass
+ + + +MessageT = tp.Type[Message] + + +
+[docs] +@attr.s(frozen=True) +class Event(Message): + pass
+ + + +
+[docs] +@attr.s(frozen=True) +class Command(Message): + pass
+ + + +
+[docs] +class LayerState(enum.Enum): + PRESENT = 1 + ABSENT = 2
+ + + +
+[docs] +@attr.s(frozen=True) +class Layer(abc.ABC): + """ + A layer represents a filesystem layer in a container image. + + Layers can be 'virtual' in the sense that they do not lead to changes + in the container image filesystem, e.g. setting up the build context. + + This more or less represents commands/statements available in buildah + or Dockerfiles. + + Examples: + buildah add -> AddLayer + buildah copy -> CopyLayer + buildah from -> FromLayer + """
+ + + +# pylint: enable=too-few-public-methods +
+[docs] +@attr.s(frozen=True) +class FromLayer(Layer): + base: str = attr.ib() + + def __str__(self) -> str: + return f'FROM {self.base}'
+ + + +
+[docs] +@attr.s(frozen=True) +class AddLayer(Layer): + sources: tp.Tuple[str, ...] = attr.ib() + destination: str = attr.ib() + + def __str__(self) -> str: + sources = ' '.join(self.sources) + return f'ADD {sources} self.destination'
+ + + +
+[docs] +@attr.s(frozen=True) +class CopyLayer(Layer): + sources: tp.Tuple[str, ...] = attr.ib() + destination: str = attr.ib() + + def __str__(self) -> str: + sources = ' '.join(self.sources) + return f'COPY {sources} {self.destination}'
+ + + +
+[docs] +def immutable_kwargs( + kwargs: tp.Dict[str, str] +) -> tp.Tuple[tp.Tuple[str, str], ...]: + """ + Convert str-typed kwargs into a hashable tuple. + """ + return tuple((k, v) for k, v in kwargs.items())
+ + + +
+[docs] +@attr.s(frozen=True) +class RunLayer(Layer): + command: str = attr.ib() + args: tp.Tuple[str, ...] = attr.ib() + kwargs: tp.Tuple[tp.Tuple[str, str], + ...] = attr.ib(converter=immutable_kwargs) + + def __str__(self) -> str: + args = ' '.join(self.args) + return f'RUN {self.command} {args}'
+ + + +
+[docs] +@attr.s(frozen=True) +class ContextLayer(Layer): + func: tp.Callable[[], None] = attr.ib() + + def __str__(self) -> str: + return 'CONTEXT custom build context modification'
+ + + +
+[docs] +@attr.s(frozen=True) +class UpdateEnv(Layer): + env: tp.Tuple[tp.Tuple[str, str], ...] = attr.ib(converter=immutable_kwargs) + + def __str__(self) -> str: + return f'ENV {len(self.env)} entries'
+ + + +
+[docs] +@attr.s(frozen=True) +class WorkingDirectory(Layer): + directory: str = attr.ib() + + def __str__(self) -> str: + return f'CWD {self.directory}'
+ + + +
+[docs] +@attr.s(frozen=True) +class EntryPoint(Layer): + command: tp.Tuple[str, ...] = attr.ib() + + def __str__(self) -> str: + command = ' '.join(self.command) + return f'ENTRYPOINT {command}'
+ + + +
+[docs] +@attr.s(frozen=True) +class SetCommand(Layer): + command: tp.Tuple[str, ...] = attr.ib() + + def __str__(self) -> str: + command = ' '.join(self.command) + return f'CMD {command}'
+ + + +
+[docs] +@attr.s(frozen=True) +class Mount: + source: str = attr.ib() + target: str = attr.ib() + + def __str__(self) -> str: + return f'{self.source}:{self.target}'
+ + + +
+[docs] +@attr.s(eq=False) +class Image: + name: str = attr.ib() + from_: FromLayer = attr.ib() + layers: tp.List[Layer] = attr.ib() + events: tp.List[Message] = attr.ib(attr.Factory(list)) + env: tp.Dict[str, str] = attr.ib(attr.Factory(dict)) + mounts: tp.List[Mount] = attr.ib(attr.Factory(list)) + layer_index: tp.Dict[Layer, LayerState] = attr.ib(attr.Factory(dict)) + +
+[docs] + def update_env(self, **kwargs: str) -> None: + self.env.update(kwargs)
+ + +
+[docs] + def append(self, *layers: Layer) -> None: + for layer in layers: + self.layers.append(layer) + self.layer_index[layer] = LayerState.ABSENT
+ + +
+[docs] + def present(self, layer: Layer) -> None: + if layer in self.layer_index: + self.layer_index[layer] = LayerState.PRESENT
+ + +
+[docs] + def is_present(self, layer: Layer) -> bool: + return layer in self.layer_index and self.layer_index[ + layer] == LayerState.PRESENT
+ + +
+[docs] + def is_complete(self) -> bool: + return all([ + state == LayerState.PRESENT for state in self.layer_index.values() + ])
+ + +
+[docs] + def prepend(self, layer: Layer) -> None: + old_layers = self.layers + self.layers = [layer] + self.layers.extend(old_layers) + self.layer_index[layer] = LayerState.ABSENT
+
+ + + +MaybeImage = tp.Optional[Image] + + +
+[docs] +@attr.s(eq=False) +class Container: + container_id: str = attr.ib() + image: Image = attr.ib() + context: str = attr.ib() + name: str = attr.ib() + + events: tp.List[Message] = attr.ib(attr.Factory(list))
+ + + +MaybeContainer = tp.Optional[Container] +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/source/base/index.html b/_modules/benchbuild/source/base/index.html new file mode 100644 index 000000000..36474100b --- /dev/null +++ b/_modules/benchbuild/source/base/index.html @@ -0,0 +1,982 @@ + + + + + + benchbuild.source.base + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.source.base

+"""
+Provide a base interface for downloadable sources.
+"""
+import abc
+import itertools
+import sys
+import typing as tp
+from typing import Protocol
+
+import attr
+import plumbum as pb
+
+from benchbuild.settings import CFG
+
+if tp.TYPE_CHECKING:
+    from benchbuild.project import Project
+
+
+
+[docs] +@attr.s(frozen=True, eq=True) +class RevisionStr: # pylint: disable=too-few-public-methods + value: str = attr.ib()
+ + + +
+[docs] +@attr.s(frozen=True, eq=True) +class Variant: + """ + Provide a 'string'-like wrapper around source version information. + + Use this, whenever you need a 'version' string somewhere in benchbuild. + In terms of output/logging or use as program arguments, this should not + carry more semantics than a simple version string. + + However, this wrapper is linked to its 'owner'. The owner serves as + the back-reference to the source code where it originated from. + + This can serve as a 'hook' to deal with version information the + same way as a program variant like a specific configuraiton. + """ + + owner: 'FetchableSource' = attr.ib(eq=False, repr=False) + version: str = attr.ib() + +
+[docs] + def name(self) -> str: + return self.owner.local
+ + +
+[docs] + def source(self) -> 'FetchableSource': + return self.owner
+ + + def __str__(self) -> str: + return str(self.version)
+ + + +NestedVariants = tp.Iterable[tp.Tuple[Variant, ...]] + + +
+[docs] +class Revision: + """ + A revision captures all variants that form a single project revision. + + A project may have an arbitrary number of input sources that are + required for it's defined workloads, e.g., test input files, optional + dependencies, or submodules. + + BenchBuild considers each source to have different version numbers, + encoded as "Variants". The complete set of "Variants" for a project + then forms a project revision. + """ + + project_cls: tp.Type["Project"] + variants: tp.Sequence[Variant] + + def __init__( + self, project_cls: tp.Type["Project"], _primary: Variant, + *variants: Variant + ) -> None: + self.project_cls = project_cls + self.variants = [_primary] + list(variants) + +
+[docs] + def extend(self, *variants: Variant) -> None: + self.variants = list(self.variants) + list(variants)
+ + + def __update_variant(self, variant: Variant) -> None: + + def __replace(elem: Variant): + if elem.name() == variant.name(): + return variant + return elem + + self.variants = list(map(__replace, self.variants)) + +
+[docs] + def update(self, revision: "Revision") -> None: + for variant in revision.variants: + self.__update_variant(variant)
+ + +
+[docs] + def variant_by_name(self, name: str) -> Variant: + """ + Return the variant for the given source name. + + Args: + name: The local name of the source. + + Returns: + then version of the found source. + """ + found_variants = [ + variant for variant in self.variants if variant.owner.key == name + ] + if len(found_variants) > 0: + return found_variants[0] + + raise KeyError(f"Source with name {name} not found.")
+ + +
+[docs] + def has_variant(self, name: str) -> bool: + """ + Check if a variant with the given source name exists. + + Args: + name: The local name of the source. + + Returns: + True, should a variant with the given name exists + """ + return any(variant.owner.key == name for variant in self.variants)
+ + +
+[docs] + def source_by_name(self, name: str) -> 'FetchableSource': + """ + Return the source object that matches the key. + + Args: + name: The local name of the source. + + Returns: + the found source object + + Raises: + KeyError, if we cannot find the source with this name. + """ + found_variants = [ + variant for variant in self.variants if variant.owner.key == name + ] + if len(found_variants) > 0: + return found_variants[0].owner + + raise KeyError(f"Source with name {name} not found.")
+ + + @property + def primary(self) -> Variant: + variants = self.sorted() + return variants[0] + +
+[docs] + def sorted(self) -> tp.Sequence[Variant]: + """ + Return an ordered list of Variants from this revision. + + The order is defined by the order in the SOURCE attribute of the + associated project class. + """ + sources = self.project_cls.SOURCE + sources = [src for src in sources if self.has_variant(src.key)] + + return [self.variant_by_name(src.key) for src in sources]
+ + + def __str__(self) -> str: + variants = self.sorted() + return to_str(*variants) + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +def to_str(*variants: Variant) -> str: + """ + Convert an arbitrary number of variants into their string representation. + + Returns: + string representation of all input variants joined by ','. + """ + return ",".join([str(i) for i in variants])
+ + + +
+[docs] +class Fetchable(Protocol): + + @property + def key(self) -> str: + """ + Return the source's key property. + + This provides you with a key component that identifes a single source. + It should (no guarantee) be unique among all sources for this project. + + While this make no further assumption, but a good candidate is a + file-system name/path. + """ + + @property + def local(self) -> str: + """ + The source location (path-like) after fetching it from its remote. + """ + + @property + def remote(self) -> tp.Union[str, tp.Dict[str, str]]: + """ + The source location in the remote location. + """ + +
+[docs] + def fetch(self) -> pb.LocalPath: + """ + Fetch the necessary source files into benchbuild's cache. + """
+
+ + + +
+[docs] +class Expandable(Protocol): + + @property + def is_expandable(self) -> bool: + """ + Returns true, if this source should take part in version expansion. + + Some sources may only be treated as virtual and would not take part + in the version expansion of an associated project. + """ + +
+[docs] + def versions(self) -> tp.Sequence[Variant]: + """ + List all available versions of this source. + + Returns: + List[str]: The list of all available versions. + """
+
+ + + +
+[docs] +class ContextAwareSource(Protocol): + +
+[docs] + def is_context_free(self) -> bool: + """ + Return, if this source needs context to evaluate it's own + list of available versions. + """
+ + +
+[docs] + def versions_with_context(self, ctx: Revision) -> tp.Sequence[Variant]: + """ + Augment the given revision with new variants associated with this source. + + Args: + ctx: the project revision, containing information about every + context-free variant. + + Returns: + a sequence of project revisions. + """
+
+ + + +
+[docs] +class ContextFreeMixin: + """ + Make a context-free source context-aware. + + This will setup default implementations that avoids interaction with any context. + """ + +
+[docs] + def is_context_free(self) -> bool: + return True
+ + +
+[docs] + def versions_with_context(self, ctx: Revision) -> tp.Sequence[Variant]: + raise AttributeError("Invalid use of versions with context")
+
+ + + +
+[docs] +class Versioned(Protocol): + + @property + def default(self) -> Variant: + """ + The default version for this source. + """ + +
+[docs] + def version(self, target_dir: str, version: str) -> pb.LocalPath: + """ + Fetch the requested version and place it in the target_dir + + Args: + target_dir (str): + The filesystem path where the version should be placed in. + version (str): + The version that should be fetched from the local cache. + + Returns: + str: [description] + """
+ + +
+[docs] + def versions(self) -> tp.Sequence[Variant]: + """ + List all available versions of this source. + + Returns: + List[str]: The list of all available versions. + """
+
+ + + +
+[docs] +class FetchableSource(ContextFreeMixin): + """ + Base class for fetchable sources. + + Subclasses have to provide the following protocols: + - Expandable + - Fetchable + - Versioned + """ + + _local: str + _remote: tp.Union[str, tp.Dict[str, str]] + + def __init__(self, local: str, remote: tp.Union[str, tp.Dict[str, str]]): + super().__init__() + + self._local = local + self._remote = remote + + @property + def local(self) -> str: + return self._local + + @property + def remote(self) -> tp.Union[str, tp.Dict[str, str]]: + return self._remote + + @property + def key(self) -> str: + return self.local + + @property + @abc.abstractmethod + def default(self) -> Variant: + """ + The default version for this source. + """ + raise NotImplementedError() + +
+[docs] + @abc.abstractmethod + def version(self, target_dir: str, version: str) -> pb.LocalPath: + """ + Fetch the requested version and place it in the target_dir + + Args: + target_dir (str): + The filesystem path where the version should be placed in. + version (str): + The version that should be fetched from the local cache. + + Returns: + str: [description] + """ + raise NotImplementedError()
+ + +
+[docs] + @abc.abstractmethod + def versions(self) -> tp.Sequence[Variant]: + """ + List all available versions of this source. + + Returns: + List[str]: The list of all available versions. + """ + raise NotImplementedError()
+ + +
+[docs] + def explore(self) -> tp.Sequence[Variant]: + """ + Explore revisions of this source. + + This provides access to all revisions this source can offer. + BenchBuild own filters will not block any revision here. + + Custom sources or source filters can opt in to block revisions + anyways. + + Returns: + List[str]: The list of versions to explore. + """ + if self.is_context_free(): + return self.versions() + return []
+ + + @property + def is_expandable(self) -> bool: + return True + +
+[docs] + @abc.abstractmethod + def fetch(self) -> pb.LocalPath: + """ + Fetch the necessary source files into benchbuild's cache. + """ + raise NotImplementedError()
+
+ + + +Sources = tp.List['FetchableSource'] + + +
+[docs] +class NoSource(FetchableSource): + + @property + def default(self) -> Variant: + return Variant(owner=self, version='None') + +
+[docs] + def version(self, target_dir: str, version: str) -> pb.LocalPath: + return 'None'
+ + +
+[docs] + def versions(self) -> tp.List[Variant]: + return [Variant(owner=self, version='None')]
+ + +
+[docs] + def fetch(self) -> pb.LocalPath: + return 'None'
+
+ + + +
+[docs] +def nosource() -> NoSource: + return NoSource('NoSource', 'NoSource')
+ + + +
+[docs] +def target_prefix() -> str: + """ + Return the prefix directory for all downloads. + + Returns: + str: the prefix where we download everything to. + """ + return str(CFG['tmp_dir'])
+ + + +SourceT = tp.TypeVar('SourceT') + + +
+[docs] +def primary(*sources: SourceT) -> SourceT: + """ + Return the implicit 'main' source of a project. + + We define the main source as the first source listed in a project. + + If you define a new project and rely on the existence of a 'main' + source code repository, make sure to define it as the first one. + """ + (head, *_) = sources + return head
+ + + +
+[docs] +def secondaries(*sources: SourceT) -> tp.Sequence[SourceT]: + """ + Return the complement to the primary source of a project. + + Returns: + A list of all sources not considered primary. + """ + (_, *tail) = sources + return list(tail)
+ + + +
+[docs] +def product(*sources: Expandable) -> NestedVariants: + """ + Return the cross product of the given sources. + + Returns: + An iterable containing the cross product of all source variants. + """ + + siblings = [source.versions() for source in sources if source.is_expandable] + return itertools.product(*siblings)
+ + + +
+[docs] +class BaseSource(Expandable, Versioned, ContextAwareSource, Protocol): + """ + Composition of source protocols. + """
+ + + +
+[docs] +class EnumeratorFn(Protocol): + + def __call__(self, *source: Expandable) -> NestedVariants: + """ + Return an enumeration of all variants for each source. + + Returns: + a list of version tuples, containing each possible variant. + """
+ + + +def _default_enumerator(*sources: Expandable) -> NestedVariants: + return product(*sources) + + +
+[docs] +class ContextEnumeratorFn(Protocol): + + def __call__( + self, project_cls: tp.Type["Project"], context: Revision, + *sources: ContextAwareSource + ) -> tp.Sequence[Revision]: + """ + Enumerate all revisions that are valid under the given context. + """
+ + + +def _default_caw_enumerator( + project_cls: tp.Type["Project"], context: Revision, + *sources: ContextAwareSource +) -> tp.Sequence[Revision]: + """ + Transform given variant into a list of variants to check. + + This only considers the given context of all context-free sources + per context-sensitive source. + + Args: + context: + *sources: + """ + + variants = [source.versions_with_context(context) for source in sources] + variants = [var for var in variants if var] + + ret = [ + Revision(project_cls, *(list(context.variants) + list(caw_variants))) + for caw_variants in itertools.product(*variants) + ] + return ret + + +
+[docs] +def enumerate_revisions( + project_cls: tp.Type["Project"], + context_free_enumerator: EnumeratorFn = _default_enumerator, + context_aware_enumerator: ContextEnumeratorFn = _default_caw_enumerator +) -> tp.Sequence[Revision]: + """ + Enumerates the given sources. + + The enumeration requires two phases. + 1. A phase for all sources that do not require a context to evaluate. + 2. A phase for all sources that require a static context. + """ + sources = project_cls.SOURCE + + context_free_sources = [ + source for source in sources if source.is_context_free() + ] + context_aware_sources = [ + source for source in sources if not source.is_context_free() + ] + + revisions = context_free_enumerator(*context_free_sources) + project_revisions = [ + Revision(project_cls, *variants) for variants in revisions + ] + + if len(context_aware_sources) > 0: + revs = list( + itertools.chain( + *( + context_aware_enumerator( + project_cls, rev, *context_aware_sources + ) for rev in project_revisions + ) + ) + ) + return revs + + return project_revisions
+ + + +SourceContext = tp.Dict[str, Fetchable] + + +
+[docs] +def sources_as_dict(*sources: Fetchable) -> SourceContext: + """ + Convert fetchables to a dictionary. + + The dictionary will be indexed by the Fetchable's local attribute. + + Args: + *sources: Fetchables stored in the dictionary. + """ + return {src.local: src for src in sources}
+ + + +
+[docs] +def revision_from_str( + revs: tp.Sequence[RevisionStr], project_cls: tp.Type["Project"] +) -> Revision: + """ + Create a Revision from a sequence of revision strings. + + A valid Revision can only be created, if the number of valid revision + strings is equivalent to the number of sources. + A valid revision string is one that has been found in the a source's + version. + It is required that each revision string is found in a different source + version. + + We assume that the first source is the primary source of the revision. + + Args: + revs: sequence of revision strings, e.g. a commit-hash. + *sources: sources of a project. + + Returns: + A variant context. + """ + found: tp.List[Variant] = [] + sources = project_cls.SOURCE + + for source in sources: + if source.is_expandable: + found.extend([ + variant for variant in source.explore() for rev in revs + if variant.version == rev.value + ]) + + if len(found) == 0: + raise ValueError(f'Revisions {revs} not found in any available source.') + + return Revision(project_cls, primary(*found), *secondaries(*found))
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/source/git/index.html b/_modules/benchbuild/source/git/index.html new file mode 100644 index 000000000..8343c8aa1 --- /dev/null +++ b/_modules/benchbuild/source/git/index.html @@ -0,0 +1,427 @@ + + + + + + benchbuild.source.git + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.source.git

+"""
+Declare a git source.
+"""
+import os
+import typing as tp
+import logging
+from pathlib import Path
+
+import plumbum as pb
+from plumbum.commands.base import BoundCommand
+
+from benchbuild.utils.cmd import git, ln, mkdir
+
+from . import base
+
+LOG = logging.getLogger(__name__)
+
+VarRemotes = tp.Union[str, tp.Dict[str, str]]
+Remotes = tp.Dict[str, str]
+
+
+
+[docs] +class Git(base.FetchableSource): + """ + Fetch the downloadable source via git. + """ + + def __init__( + self, + remote: str, + local: str, + clone: bool = True, + limit: tp.Optional[int] = 10, + refspec: str = 'HEAD', + shallow: bool = True, + version_filter: tp.Callable[[str], bool] = lambda version: True + ): + super().__init__(local, remote) + + self.clone = clone + self.limit = limit + self.refspec = refspec + self.shallow = shallow + self.version_filter = version_filter + + @property + def default(self) -> base.Variant: + """ + Return current HEAD as default version for this Git project. + """ + return self.versions()[0] + +
+[docs] + def fetch(self) -> pb.LocalPath: + """ + Clone the repository, if needed. + + This will create a git clone inside the global cache directory. + + Args: + version (Optional[str], optional): [description]. Defaults to None. + + Returns: + str: [description] + """ + prefix = base.target_prefix() + clone = maybe_shallow( + git['clone', '--recurse-submodules'], self.shallow + ) + fetch = git['fetch', '--update-shallow', '--all'] + flat_local = self.local.replace(os.sep, '-') + cache_path = pb.local.path(prefix) / flat_local + + if clone_needed(self.remote, cache_path): + clone(self.remote, cache_path) + else: + with pb.local.cwd(cache_path): + fetch() + + return cache_path
+ + +
+[docs] + def version(self, target_dir: str, version: str = 'HEAD') -> pb.LocalPath: + """ + Create a new git worktree pointing to the requested version. + + Args: + target_dir (str): + The filesystem path where the new worktree should live. + version (str): + The desired version the new worktree needs to point to. + Defaults to 'HEAD'. + + Returns: + str: [description] + """ + src_loc = self.fetch() + active_loc = pb.local.path(target_dir) / self.local + tgt_subdir = f'{self.local}-{version}' + tgt_loc = pb.local.path(target_dir) / tgt_subdir + + clone = git['clone'] + pull = git['pull'] + rev_parse = git['rev-parse'] + checkout = git['checkout'] + + with pb.local.cwd(src_loc): + is_shallow = rev_parse('--is-shallow-repository').strip() + if is_shallow == 'true': + pull('--unshallow') + + if Path(tgt_loc).exists(): + LOG.info( + 'Found target location %s. Going to skip creation and ' + 'repository cloning.', str(tgt_loc) + ) + else: + mkdir('-p', tgt_loc) + with pb.local.cwd(tgt_loc): + clone( + '--dissociate', '--recurse-submodules', '--reference', + src_loc, self.remote, '.' + ) + checkout('--detach', version) + + ln('-nsf', tgt_subdir, active_loc) + return tgt_loc
+ + +
+[docs] + def versions(self) -> tp.List[base.Variant]: + cache_path = self.fetch() + git_rev_list = git['rev-list', '--abbrev-commit', '--abbrev=10'] + + rev_list: tp.List[str] = [] + with pb.local.cwd(cache_path): + rev_list = list(git_rev_list(self.refspec).strip().split('\n')) + + rev_list = list(filter(self.version_filter, rev_list)) + rev_list = rev_list[:self.limit] if self.limit else rev_list + revs = [base.Variant(version=rev, owner=self) for rev in rev_list] + return revs
+
+ + + +
+[docs] +class GitSubmodule(Git): + + @property + def is_expandable(self) -> bool: + """Submodules will not participate in version expansion.""" + return False
+ + + +
+[docs] +def maybe_shallow(cmd: BoundCommand, enable: bool) -> BoundCommand: + """ + Conditionally add the shallow clone to the given git command. + + Args: + cmd (Any): + A git clone command (shallow doesn't make sense anywhere else. + shallow (bool): + Should we add the shallow options? + + Returns: + Any: A new git clone command, with shallow clone enabled, if selected. + """ + if enable: + return cmd['--depth', '1'] + return cmd
+ + + +
+[docs] +def clone_needed(repository: VarRemotes, repo_loc: str) -> bool: + from benchbuild.utils.download import __clone_needed__ + + if not isinstance(repository, str): + raise TypeError('\'remote\' needs to be a git repo string') + + return __clone_needed__(repository, repo_loc)
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/source/http/index.html b/_modules/benchbuild/source/http/index.html new file mode 100644 index 000000000..be908464f --- /dev/null +++ b/_modules/benchbuild/source/http/index.html @@ -0,0 +1,441 @@ + + + + + + benchbuild.source.http + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.source.http

+"""
+Declare a http source.
+"""
+import typing as tp
+
+import plumbum as pb
+
+from benchbuild.source import base
+from benchbuild.utils.cmd import cp, ln, wget, tar, mkdir, mv
+
+VarRemotes = tp.Union[str, tp.Dict[str, str]]
+Remotes = tp.Dict[str, str]
+
+
+
+[docs] +class HTTP(base.FetchableSource): + """ + Fetch the downloadable source via http. + """ + + @property + def default(self) -> base.Variant: + return self.versions()[0] + +
+[docs] + def fetch(self) -> pb.LocalPath: + """ + Fetch via http using default version string. + """ + return self.fetch_version(self.default.version)
+ + +
+[docs] + def fetch_version(self, version: str) -> pb.LocalPath: + """ + Fetch via http using given version string. + + Args: + version: the version string to pull via http. + + Returns: + local path to fetched version. + """ + prefix = base.target_prefix() + remotes = normalize_remotes(self.remote) + + url = remotes[version] + target_name = versioned_target_name(self.local, version) + cache_path = pb.local.path(prefix) / target_name + download_single_version(url, cache_path) + + return cache_path
+ + +
+[docs] + def version(self, target_dir: str, version: str) -> pb.LocalPath: + target_name = versioned_target_name(self.local, version) + cache_path = self.fetch_version(version) + + target_path = pb.local.path(target_dir) / target_name + active_loc = pb.local.path(target_dir) / self.local + + cp('-ar', cache_path, target_path) + ln('-sf', target_name, active_loc) + + return target_path
+ + +
+[docs] + def versions(self) -> tp.List[base.Variant]: + remotes = normalize_remotes(self.remote) + return [base.Variant(version=rev, owner=self) for rev in remotes]
+
+ + + +
+[docs] +class HTTPUntar(HTTP): + """ + Fetch and download source via http and auto-unpack using GNU tar + """ + +
+[docs] + def version(self, target_dir: str, version: str) -> pb.LocalPath: + """ + Setup the given version of this HTTPUntar source. + + This will fetch the given version from the remote source and unpack the + archive into the build directory using tar. + + The location matches the behavior of other sources. However, you need + to consider that benchbuild will return a directory instead of a file path. + + When using workloads, you can refer to a directory with the SourceRootRenderer using + ``benchbuild.command.source_root``. + + Example: + You specify a remote version 1.0 of an archive compression.tar.gz and + a local name of "compression.tar.gz". + The build directory will look as follows: + + <builddir>/1.0-compression.dir/ + <builddir>/1.0-compression.tar.gz + <builddir>/compression.tar.gz -> ./1.0-compression.tar.dir + + The content of the archive is found in the directory compression.tar.gz. + Your workloads need to make sure to reference this directory (e.g. using tokens), + e.g., ``source_root("compression.tar.gz")`` + """ + archive_path = super().version(target_dir, version) + + target_name = str(pb.local.path(archive_path).with_suffix(".dir")) + target_path = pb.local.path(target_dir) / target_name + active_loc = pb.local.path(target_dir) / self.local + + mkdir(target_path) + tar("-x", "-C", target_path, "-f", archive_path) + + ln('-sf', target_path, active_loc) + + return target_path
+
+ + + +
+[docs] +class HTTPMultiple(HTTP): + """ + Fetch and download multiple files via HTTP. + """ + + def __init__( + self, + local: str, + remote: tp.Union[str, tp.Dict[str, str]], + files: tp.List[str] + ): + super().__init__(local, remote) + self._files = files + +
+[docs] + def fetch_version(self, version: str) -> pb.LocalPath: + prefix = base.target_prefix() + remotes = normalize_remotes(self.remote) + + url = remotes[version] + target_name = versioned_target_name(self.local, version) + + cache_path = pb.local.path(prefix) / target_name + mkdir('-p', cache_path) + + for file in self._files: + download_single_version(f'{url}/{file}', cache_path / file) + + return cache_path
+
+ + + +
+[docs] +def normalize_remotes(remote: VarRemotes) -> Remotes: + if isinstance(remote, str): + raise TypeError('\'remote\' needs to be a mapping type') + + # FIXME: What the hell? + _remotes: Remotes = {} + _remotes.update(remote) + return _remotes
+ + + +
+[docs] +def versioned_target_name(target_name: str, version: str) -> str: + return "{}-{}".format(version, target_name)
+ + + +
+[docs] +def download_single_version(url: str, target_path: str) -> str: + if not download_required(target_path): + return target_path + + wget(url, '-O', target_path) + from benchbuild.utils.download import update_hash + update_hash(target_path) + return target_path
+ + + +
+[docs] +def download_required(target_path: str) -> bool: + from benchbuild.utils.download import source_required + return source_required(target_path)
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/utils/actions/index.html b/_modules/benchbuild/utils/actions/index.html new file mode 100644 index 000000000..39f8f5425 --- /dev/null +++ b/_modules/benchbuild/utils/actions/index.html @@ -0,0 +1,1094 @@ + + + + + + benchbuild.utils.actions + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.utils.actions

+"""# Actions
+
+Actions are enhanced callables that are used by `Experiments` to define
+the order of operations a project is put through when the experiment
+executes.
+
+
+## Example
+
+TODO
+```python
+```
+"""
+from __future__ import annotations
+
+import abc
+import enum
+import functools as ft
+import itertools
+import logging
+import os
+import sys
+import textwrap
+import traceback
+import typing as tp
+from datetime import datetime
+
+from plumbum import ProcessExecutionError
+
+from benchbuild import command, signals, source
+from benchbuild.settings import CFG
+from benchbuild.utils import db, run
+from benchbuild.utils.cmd import mkdir, rm, rmdir
+
+LOG = logging.getLogger(__name__)
+
+ReturnType = tp.TypeVar("ReturnType")
+ReturnTypeA = tp.TypeVar("ReturnTypeA")
+ReturnTypeB = tp.TypeVar("ReturnTypeB")
+DecoratedFunction = tp.Callable[..., ReturnType]
+FunctionDecorator = tp.Callable[[DecoratedFunction[ReturnTypeA]],
+                                DecoratedFunction[ReturnTypeB]]
+
+if tp.TYPE_CHECKING:
+    import benchbuild.experiment.Experiment  # pylint: disable=unused-import
+    import benchbuild.project.Project  # pylint: disable=unused-import
+    import benchbuild.utils.schema.Experiment  # pylint: disable=unused-import
+
+
+
+[docs] +@enum.unique +class StepResult(enum.IntEnum): + """Result type for action results.""" + + UNSET = 0 + OK = 1 + CAN_CONTINUE = 2 + ERROR = 3
+ + + +StepResultList = tp.List[StepResult] + + +
+[docs] +def step_has_failed( + result: StepResult, + error_status: tp.Optional[tp.List[StepResult]] = None +) -> bool: + if not error_status: + error_status = [StepResult.ERROR, StepResult.CAN_CONTINUE] + + return result in error_status
+ + + +
+[docs] +def prepend_status(func: DecoratedFunction[str]) -> DecoratedFunction[str]: + """Prepends the output of `func` with the status.""" + + @tp.overload + def wrapper(self: "Step", indent: int) -> str: + ... + + @tp.overload + def wrapper(self: "Step") -> str: + ... + + @ft.wraps(func) + def wrapper(self: "Step", *args: tp.Any, **kwargs: tp.Any) -> str: + """Wrapper stub.""" + res = func(self, *args, **kwargs) + if self.status is not StepResult.UNSET: + res = f"[{self.status.name}]{res}" + return res + + return wrapper
+ + + +
+[docs] +def log_before_after(name: str, + desc: str) -> FunctionDecorator[StepResult, StepResult]: + """Log customized string before & after running func.""" + + def func_decorator( + func: DecoratedFunction[StepResult], + ) -> DecoratedFunction[StepResult]: + """Wrapper stub.""" + + @ft.wraps(func) + def wrapper(*args: tp.Any, **kwargs: tp.Any) -> StepResult: + """Wrapper stub.""" + LOG.info("\n%s - %s", name, desc) + res = func(*args, **kwargs) + msg = f"{name} - {res.name}" + if res != StepResult.ERROR: + LOG.info(msg) + else: + LOG.error(msg) + return res + + return wrapper + + return func_decorator
+ + + +
+[docs] +class Step: + """ + Base class of a step. + + Raises: + StopIteration: If we do not encapsulate more substeps. + """ + + NAME: tp.ClassVar[str] = "" + DESCRIPTION: tp.ClassVar[str] = "" + + status: StepResult + + def __init_subclass__(cls, **kwargs: tp.Any): + super().__init_subclass__(**kwargs) + + setattr( + cls, "__call__", + log_before_after(cls.NAME, cls.DESCRIPTION)(cls.__call__) + ) + setattr(cls, "__str__", prepend_status(cls.__str__)) + + def __init__(self, status: StepResult) -> None: + self.status = status + + def __len__(self) -> int: + return 1 + + def __str__(self, indent: int = 0) -> str: + return f"* Running action {self.NAME} - {self.DESCRIPTION}" + +
+[docs] + def onerror(self) -> None: + """ + Default implementation does nothing. + """
+ + + @abc.abstractmethod + def __call__(self) -> StepResult: + raise NotImplementedError
+ + + +
+[docs] +class ProjectStep(Step): + """Base class of a project step. + + Adds a project attribute to the Step base class and some defaults. + + Raises: + StopIteration: If we do not encapsulate more substeps. + """ + + NAME: tp.ClassVar[str] = "" + DESCRIPTION: tp.ClassVar[str] = "" + + project: "benchbuild.project.Project" + + def __init__(self, project: "benchbuild.project.Project") -> None: + super().__init__(StepResult.UNSET) + self.project = project + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent("* Execute configured action.", indent * " ") + +
+[docs] + def onerror(self) -> None: + Clean(self.project)()
+ + + @abc.abstractmethod + def __call__(self) -> StepResult: + raise NotImplementedError
+ + + +StepTy_co = tp.TypeVar("StepTy_co", bound=Step, covariant=True) + + +
+[docs] +class MultiStep(Step, tp.Generic[StepTy_co]): + """Group multiple actions into one step. + + Usually used to define behavior on error, e.g., execute everything + regardless of any errors, or fail everything upon first error. + """ + + NAME: tp.ClassVar[str] = "" + DESCRIPTION: tp.ClassVar[str] = "" + + actions: tp.MutableSequence[StepTy_co] + + def __init__( + self, + actions: tp.Optional[tp.MutableSequence[StepTy_co]] = None + ) -> None: + super().__init__(StepResult.UNSET) + + self.actions = list(actions) if actions else [] + + def __len__(self) -> int: + return sum([len(x) for x in self.actions]) + 1 + + def __iter__(self) -> tp.Iterator[StepTy_co]: + return self.actions.__iter__() + + @abc.abstractmethod + def __call__(self) -> StepResult: + raise NotImplementedError + + def __str__(self, indent: int = 0) -> str: + raise NotImplementedError + +
+[docs] + def onerror(self) -> None: + pass
+
+ + + +
+[docs] +class Clean(ProjectStep): + NAME = "CLEAN" + DESCRIPTION = "Cleans the build directory" + + def __init__( + self, + project: "benchbuild.project.Project", + check_empty: bool = False + ) -> None: + super().__init__(project) + self.check_empty = check_empty + +
+[docs] + @staticmethod + def clean_mountpoints(root: str) -> None: + """Unmount any remaining mountpoints under :root. + + Args: + root: All UnionFS-mountpoints under this directory will be + unmounted. + """ + import psutil # pylint: disable=import-outside-toplevel + + umount_paths = [] + real_root = os.path.realpath(root) + for part in psutil.disk_partitions(all=True): + if os.path.commonpath([part.mountpoint, real_root]) == real_root: + if not part.fstype == "fuse.unionfs": + LOG.error("NON-UnionFS mountpoint found under %s", root) + else: + umount_paths.append(part.mountpoint)
+ + + def __call__(self) -> StepResult: + if not CFG["clean"]: + LOG.warning("Clean disabled by config.") + return StepResult.OK + if not self.project: + LOG.warning("No object assigned to this action.") + return StepResult.ERROR + obj_builddir = os.path.abspath(self.project.builddir) + if os.path.exists(obj_builddir): + LOG.debug("Path %s exists", obj_builddir) + Clean.clean_mountpoints(obj_builddir) + if self.check_empty: + rmdir(obj_builddir, retcode=None) + else: + rm("-rf", obj_builddir) + else: + LOG.debug("Path %s did not exist anymore", obj_builddir) + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + project = self.project + return textwrap.indent( + f"* {project.name}: Clean the directory: {project.builddir}", + indent * " " + )
+ + + +
+[docs] +class MakeBuildDir(ProjectStep): + NAME = "MKDIR" + DESCRIPTION = "Create the build directory" + + def __call__(self) -> StepResult: + if not self.project: + return StepResult.ERROR + if not os.path.exists(self.project.builddir): + mkdir("-p", self.project.builddir) + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent( + f"* {self.project.name}: Create the build directory", indent * " " + )
+ + + +
+[docs] +class Compile(ProjectStep): + NAME = "COMPILE" + DESCRIPTION = "Compile the project" + + def __call__(self) -> StepResult: + try: + self.project.compile() + + except ProcessExecutionError: + self.status = StepResult.ERROR + raise + self.status = StepResult.OK + + return self.status + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent(f"* {self.project.name}: Compile", indent * " ")
+ + + +
+[docs] +class Run(ProjectStep): + NAME = "RUN" + DESCRIPTION = "Execute the run action" + + experiment: "benchbuild.experiment.Experiment" + + def __init__( + self, + project: "benchbuild.project.Project", + experiment: "benchbuild.experiment.Experiment", + ) -> None: + super().__init__(project) + + self.experiment = experiment + + def __call__(self) -> StepResult: + if CFG["db"]["enabled"]: + group, session = run.begin_run_group(self.project, self.experiment) + signals.handlers.register(run.fail_run_group, group, session) + try: + self.project.run_tests() + if CFG["db"]["enabled"]: + run.end_run_group(group, session) + self.status = StepResult.OK + except ProcessExecutionError: + if CFG["db"]["enabled"]: + run.fail_run_group(group, session) + self.status = StepResult.ERROR + raise + except KeyboardInterrupt: + if CFG["db"]["enabled"]: + run.fail_run_group(group, session) + self.status = StepResult.ERROR + raise + finally: + if CFG["db"]["enabled"]: + signals.handlers.deregister(run.fail_run_group) + + return self.status + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent( + f"* {self.project.name}: Execute run-time tests.", indent * " " + )
+ + + +
+[docs] +class Echo(Step): + NAME = "ECHO" + DESCRIPTION = "Print a message." + + message: str + + def __init__(self, message: str = "") -> None: + super().__init__(StepResult.UNSET) + self.message = message + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent(f"* echo: {self.message}", indent * " ") + + def __call__(self) -> StepResult: + LOG.info(self.message) + return StepResult.OK
+ + + +
+[docs] +def run_any_child(child: Step) -> StepResult: + """Execute child step. + + Args: + child: The child step. + """ + return child()
+ + + +
+[docs] +class Any(MultiStep): + NAME = "ANY" + DESCRIPTION = "Just run all actions, no questions asked." + + def __call__(self) -> StepResult: + length = len(self.actions) + cnt = 0 + results = [StepResult.OK] + for a in self.actions: + cnt = cnt + 1 + result = a() + results.append(result) + + if result == StepResult.ERROR: + LOG.warning("%d actions left in queue", length - cnt) + + self.status = StepResult.OK + if StepResult.ERROR in results: + self.status = StepResult.CAN_CONTINUE + return self.status + + def __str__(self, indent: int = 0) -> str: + sub_actns = "\n".join([a.__str__(indent + 1) for a in self.actions]) + return textwrap.indent("* Execute all of:\n" + sub_actns, indent * " ")
+ + + +
+[docs] +class Experiment(Any): + NAME = "EXPERIMENT" + DESCRIPTION = "Run a experiment, wrapped in a db transaction" + + experiment: "benchbuild.experiment.Experiment" + + def __init__( + self, + experiment: "benchbuild.experiment.Experiment", + actions: tp.Optional[tp.MutableSequence[Step]], + ) -> None: + _actions: tp.MutableSequence[Step] = [ + Echo(message=f"Start experiment: {experiment.name}") + ] + _actions.extend(actions if actions else []) + _actions.extend([ + Echo(message=f"Completed experiment: {experiment.name}") + ]) + + super().__init__(_actions) + self.experiment = experiment + +
+[docs] + def begin_transaction( + self, + ) -> tp.Tuple["benchbuild.utils.schema.Experiment", tp.Any]: + import sqlalchemy as sa # pylint: disable=import-outside-toplevel + experiment, session = db.persist_experiment(self.experiment) + if experiment.begin is None: + experiment.begin = datetime.now() + experiment.end = experiment.begin + else: + experiment.begin = min(experiment.begin, datetime.now()) + session.add(experiment) + try: + session.commit() + except sa.orm.exc.StaleDataError: + LOG.error("Transaction isolation level caused a StaleDataError") + + # React to external signals + signals.handlers.register( + Experiment.end_transaction, experiment, session + ) + + return experiment, session
+ + +
+[docs] + @staticmethod + def end_transaction( + experiment: "benchbuild.utils.schema.Experiment", session: tp.Any + ) -> None: + import sqlalchemy as sa # pylint: disable=import-outside-toplevel + try: + experiment.end = max(experiment.end, datetime.now()) + session.add(experiment) + session.commit() + except sa.exc.InvalidRequestError as inv_req: + LOG.error(inv_req)
+ + + def __run_children(self, num_processes: int) -> tp.List[StepResult]: + # pylint: disable=import-outside-toplevel + import pathos.multiprocessing as mp + + results = [] + actions = self.actions + + try: + with mp.Pool(num_processes) as pool: + results = pool.map(run_any_child, actions) + except KeyboardInterrupt: + LOG.info("Experiment aborting by user request") + results.append(StepResult.ERROR) + except Exception: + LOG.error("Experiment terminates " + "because we got an exception:") + e_type, e_value, e_traceb = sys.exc_info() + lines = traceback.format_exception(e_type, e_value, e_traceb) + LOG.error("".join(lines)) + results.append(StepResult.ERROR) + return results + + def __call__(self) -> StepResult: + results = [] + session = None + if CFG["db"]["enabled"]: + experiment, session = self.begin_transaction() + try: + results = self.__run_children(int(CFG["parallel_processes"])) + finally: + if CFG["db"]["enabled"]: + self.end_transaction(experiment, session) + signals.handlers.deregister(self.end_transaction) + self.status = max(results) if results else StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + sub_actns = "\n".join([a.__str__(indent + 1) for a in self.actions]) + return textwrap.indent( + f"\nExperiment: {self.experiment.name}\n{sub_actns}", indent * " " + )
+ + + +
+[docs] +class RequireAll(MultiStep): + NAME = "REQUIRE ALL" + DESCRIPTION = "All child steps need to succeed" + + def __call__(self) -> StepResult: + results: tp.List[StepResult] = [] + + total_steps = len(self.actions) + + def no_fail(*args: tp.Any, **kwargs: tp.Any): + return StepResult.ERROR not in results + + for i, action in itertools.takewhile(no_fail, enumerate(self.actions)): + result = StepResult.UNSET + try: + result = action() + except ProcessExecutionError as proc_ex: + LOG.error("\n==== ERROR ====") + LOG.error( + "Execution of a binary failed in step: %s", str(action) + ) + LOG.error(str(proc_ex)) + LOG.error("==== ERROR ====\n") + result = StepResult.ERROR + except KeyboardInterrupt: + LOG.info("User requested termination.") + action.onerror() + action.status = StepResult.ERROR + raise + except Exception: + LOG.error( + "Exception in step #%d/%d: %s", + i, + total_steps, + str(action), + exc_info=sys.exc_info(), + ) + result = StepResult.ERROR + + results.append(result) + action.status = result + is_failed = StepResult.ERROR in results + if is_failed: + LOG.error("Execution of: '%s' failed.", str(action)) + LOG.error("'%s' cannot continue.", str(self)) + action.onerror() + + self.status = max(results) if results else StepResult.UNSET + return self.status + + def __str__(self, indent: int = 0) -> str: + sub_actns = "\n".join([a.__str__(indent + 1) for a in self.actions]) + return textwrap.indent(f"* All required:\n{sub_actns}", indent * " ")
+ + + +WorkloadTy = tp.Callable[[], tp.Any] + + +
+[docs] +class RunWorkload(ProjectStep): + NAME = "RUN WORKLOAD" + DESCRIPTION = "Run a project's workload" + + _workload: tp.Optional[WorkloadTy] + + @property + def workload_ref(self) -> WorkloadTy: + # Workaround for MyPy... + assert self._workload is not None, "non-optional optional triggered" + return self._workload + + def __init__( + self, + project: "benchbuild.project.Project", + workload: tp.Optional[WorkloadTy] = None + ) -> None: + super().__init__(project) + + self._workload = workload + + def __call__(self) -> StepResult: + try: + self.workload_ref() + self.status = StepResult.OK + except ProcessExecutionError: + self.status = StepResult.ERROR + raise + except KeyboardInterrupt: + self.status = StepResult.ERROR + raise + return self.status + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent(f"* Run: {str(self.workload_ref)}", indent * " ")
+ + + +
+[docs] +class RunWorkloads(MultiStep): + NAME = "RUN WORKLOADS" + DESCRIPTION = "Generic run all project workloads" + + project: "benchbuild.project.Project" + experiment: "benchbuild.experiment.Experiment" + + def __init__( + self, + project: "benchbuild.project.Project", + experiment: "benchbuild.experiment.Experiment", + run_only: tp.Optional[command.WorkloadSet] = None, + ) -> None: + super().__init__() + + self.project = project + self.experiment = experiment + + index = command.unwrap(project.workloads, project) + workloads = itertools.chain( + *command.filter_workload_index(run_only, index) + ) + + for workload in workloads: + self.actions.extend([ + RunWorkload(project, command.ProjectCommand(project, workload)) + ]) + + def __call__(self) -> StepResult: + if CFG["db"]["enabled"]: + group, session = run.begin_run_group(self.project, self.experiment) + signals.handlers.register(run.fail_run_group, group, session) + try: + self.status = max([workload() for workload in self.actions], + default=StepResult.OK) + if CFG["db"]["enabled"]: + run.end_run_group(group, session) + except ProcessExecutionError: + if CFG["db"]["enabled"]: + run.fail_run_group(group, session) + self.status = StepResult.ERROR + raise + except KeyboardInterrupt: + if CFG["db"]["enabled"]: + run.fail_run_group(group, session) + self.status = StepResult.ERROR + raise + finally: + if CFG["db"]["enabled"]: + signals.handlers.deregister(run.fail_run_group) + + return self.status + + def __str__(self, indent: int = 0) -> str: + sub_actns = "\n".join([a.__str__(indent + 1) for a in self.actions]) + return textwrap.indent( + f"* Require all of {self.project.name}'s workloads:\n{sub_actns}", + indent * " " + )
+ + + +
+[docs] +class CleanExtra(Step): + NAME = "CLEAN EXTRA" + DESCRIPTION = "Cleans the extra directories." + + def __init__(self) -> None: + super().__init__(StepResult.UNSET) + + def __call__(self) -> StepResult: + if not CFG["clean"]: + return StepResult.OK + + paths = CFG["cleanup_paths"].value + for p in paths: + if os.path.exists(p): + rm("-r", p) + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + paths = CFG["cleanup_paths"].value + lines = [] + for p in paths: + lines.append( + textwrap.indent(f"* Clean the directory: {p}", indent * " ") + ) + return "\n".join(lines)
+ + + +
+[docs] +class ProjectEnvironment(ProjectStep): + NAME = "ENV" + DESCRIPTION = "Prepare the project environment." + + def __call__(self) -> StepResult: + project = self.project + project.clear_paths() + + revision = project.revision + + for variant in revision.variants: + name = variant.name() + LOG.info("Fetching %s @ %s", str(name), variant.version) + src = variant.source() + src.version(project.builddir, str(variant)) + + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + project = self.project + revision = project.revision + version_str = str(revision) + + return textwrap.indent( + f"* Project environment for: {project.name} @ {version_str}", + indent * " " + )
+ + + +
+[docs] +class SetProjectVersion(ProjectStep): + NAME = "SET PROJECT VERSION" + DESCRIPTION = "Checkout a project version" + + revision: source.Revision + + def __init__( + self, + project: "benchbuild.project.Project", + *revision_strings: source.base.RevisionStr, + ) -> None: + super().__init__(project) + + self.revision = source.revision_from_str( + revision_strings, type(project) + ) + + def __call__(self) -> StepResult: + project = self.project + revision = project.active_revision + revision.update(self.revision) + + for variant in revision.variants: + name = variant.name() + LOG.info("Fetching %s @ %s", str(name), variant.version) + src = variant.source() + src.version(project.builddir, str(variant)) + + project.active_revision = revision + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + project = self.project + version_str = str(self.revision) + + return textwrap.indent( + f"* Add project version {version_str} for: {project.name}", + indent * " " + )
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/benchbuild/utils/settings/index.html b/_modules/benchbuild/utils/settings/index.html new file mode 100644 index 000000000..b386a1f9d --- /dev/null +++ b/_modules/benchbuild/utils/settings/index.html @@ -0,0 +1,993 @@ + + + + + + benchbuild.utils.settings + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.utils.settings

+"""
+Configuration utilities.
+
+Settings are stored in a dictionary-like configuration object.
+All settings are modifiable by environment variables that encode
+the path in the dictionary tree.
+
+Inner nodes in the dictionary tree can be any dictionary.
+A leaf node in the dictionary tree is represented by an inner node that
+contains a value key.
+"""
+import copy
+import logging
+import os
+import re
+import sys
+import typing as tp
+import uuid
+import warnings
+from importlib.metadata import version, PackageNotFoundError
+
+import attr
+import schema
+import six
+import yaml
+from plumbum import LocalPath, local
+
+import benchbuild.utils.user_interface as ui
+
+LOG = logging.getLogger(__name__)
+
+
+
+[docs] +class Indexable: + + def __getitem__(self: 'Indexable', key: str) -> 'Indexable': + pass
+ + + +try: + __version__ = version("benchbuild") +except PackageNotFoundError: + __version__ = "unknown" + LOG.error("could not find version information.") + + +
+[docs] +def available_cpu_count() -> int: + """ + Get the number of available CPUs. + + Number of available virtual or physical CPUs on this system, i.e. + user/real as output by time(1) when called with an optimally scaling + userspace-only program. + + Returns: + Number of avaialable CPUs. + """ + + # cpuset + # cpuset may restrict the number of *available* processors + try: + match = re.search( + r'(?m)^Cpus_allowed:\s*(.*)$', + open('/proc/self/status').read() + ) + if match: + res = bin(int(match.group(1).replace(',', ''), 16)).count('1') + if res > 0: + return res + except IOError: + LOG.debug("Could not get the number of allowed CPUs") + + # http://code.google.com/p/psutil/ + try: + import psutil + return int(psutil.cpu_count()) # psutil.NUM_CPUS on old versions + except (ImportError, AttributeError): + LOG.debug("Could not get the number of allowed CPUs") + + # POSIX + try: + res = int(os.sysconf('SC_NPROCESSORS_ONLN')) + + if res > 0: + return res + except (AttributeError, ValueError): + LOG.debug("Could not get the number of allowed CPUs") + + # Linux + try: + res = open('/proc/cpuinfo').read().count('processor\t:') + + if res > 0: + return res + except IOError: + LOG.debug("Could not get the number of allowed CPUs") + + raise Exception('Can not determine number of CPUs on this system')
+ + + +
+[docs] +def current_available_threads() -> int: + """Returns the number of currently available threads for BB.""" + return len(os.sched_getaffinity(0))
+ + + +
+[docs] +def get_number_of_jobs(config: 'Configuration') -> int: + """Returns the number of jobs set in the config.""" + jobs_configured = int(config["jobs"]) + if jobs_configured == 0: + return current_available_threads() + return jobs_configured
+ + + +
+[docs] +class InvalidConfigKey(RuntimeWarning): + """Warn, if you access a non-existing key benchbuild's configuration."""
+ + + +
+[docs] +def escape_yaml(raw_str: str) -> str: + """ + Shell-Escape a yaml input string. + + Args: + raw_str: The unescaped string. + """ + escape_list = [char for char in raw_str if char in ['!', '{', '[']] + if len(escape_list) == 0: + return raw_str + + str_quotes = '"' + i_str_quotes = "'" + if str_quotes in raw_str and str_quotes not in raw_str[1:-1]: + return raw_str + + if str_quotes in raw_str[1:-1]: + raw_str = i_str_quotes + raw_str + i_str_quotes + else: + raw_str = str_quotes + raw_str + str_quotes + return raw_str
+ + + +
+[docs] +def is_yaml(cfg_file: str) -> bool: + """Is the given cfg_file a YAML file.""" + return os.path.splitext(cfg_file)[1] in [".yml", ".yaml"]
+ + + +
+[docs] +class ConfigLoader(yaml.CSafeLoader): # type: ignore + """Avoid polluting yaml's namespace with our modifications."""
+ + + +
+[docs] +class ConfigDumper(yaml.SafeDumper): + """Avoid polluting yaml's namespace with our modifications."""
+ + + +
+[docs] +def to_yaml(value: tp.Any) -> tp.Optional[str]: + """Convert a given value to a YAML string.""" + stream = yaml.io.StringIO() + dumper = ConfigDumper(stream, default_flow_style=True, width=sys.maxsize) + val = None + try: + dumper.open() + dumper.represent(value) + val = str(stream.getvalue()).strip() + dumper.close() + finally: + dumper.dispose() + + return val
+ + + +
+[docs] +def to_env_var(env_var: str, value: tp.Any) -> str: + """ + Create an environment variable from a name and a value. + + This generates a shell-compatible representation of an + environment variable that is assigned a YAML representation of + a value. + + Args: + env_var (str): Name of the environment variable. + value (Any): A value we convert from. + """ + val = to_yaml(value) + ret_val = "%s=%s" % (env_var, escape_yaml(str(val))) + return ret_val
+ + + +InnerNode = tp.Dict[str, tp.Any] + +# This schema allows a configuration to be initialized/set from a standard +# dictionary. If you want to nest a new configuration node deeper than 1 level, +# you have to use dummy nodes to help benchbuild validate your nodes as +# Configuration nodes instead of plain dictionary values. +# +# Example: +# CFG['container'] = { +# 'strategy': { +# 'dummy': { 'default': True, 'desc': 'Update portage tree' } +# } +# } +# This opens the 'strategy' node up for deeper nesting in a second step: +# +# CFG['container']['strategy']['polyjit'] = { +# 'sync': { 'default': True', 'desc': '...' } +# } +_INNER_NODE_VALUE = schema.Schema({ + schema.Or('default', 'value'): object, + schema.Optional('desc'): str +}) +_INNER_NODE_SCHEMA = schema.Schema({ + schema.And(str, len): { + schema.Or('default', 'value'): object, + schema.Optional('desc'): str, + schema.Optional(str): dict + } +}) + + +
+[docs] +class Configuration(Indexable): + """ + Dictionary-like data structure to contain all configuration variables. + + This serves as a configuration dictionary throughout benchbuild. You can + use it to access all configuration options that are available. Whenever the + structure is updated with a new subtree, all variables defined in the new + subtree are updated from the environment. + + Environment variables are generated from the tree paths automatically. + CFG["build_dir"] becomes BB_BUILD_DIR + CFG["llvm"]["dir"] becomes BB_LLVM_DIR + + The configuration can be stored/loaded as YAML. + """ + + def __init__( + self, + parent_key: str, + node: tp.Optional[InnerNode] = None, + parent: tp.Optional['Configuration'] = None, + init: bool = True + ): + self.parent = parent + self.parent_key = parent_key + self.node = node if node is not None else {} + if init: + self.init_from_env() + +
+[docs] + def filter_exports(self) -> None: + if self.has_default(): + do_export = True + if "export" in self.node: + do_export = self.node["export"] + + if not do_export: + if self.parent: + self.parent.node.pop(self.parent_key) + else: + selfcopy = copy.deepcopy(self) + for k in self.node: + if selfcopy[k].is_leaf(): + selfcopy[k].filter_exports() + self.__dict__ = selfcopy.__dict__
+ + +
+[docs] + def store(self, config_file: LocalPath) -> None: + """ Store the configuration dictionary to a file.""" + + selfcopy = copy.deepcopy(self) + selfcopy.filter_exports() + + with open(config_file, 'w') as outf: + yaml.dump( + selfcopy.node, + outf, + width=80, + indent=4, + default_flow_style=False, + Dumper=ConfigDumper + )
+ + +
+[docs] + def load(self, _from: LocalPath) -> None: + """Load the configuration dictionary from file.""" + + def load_rec( + inode: tp.Dict[str, tp.Any], config: Configuration + ) -> None: + """Recursive part of loading.""" + for k in config: + if isinstance(config[k], dict) and \ + k not in ['value', 'default']: + if k in inode: + load_rec(inode[k], config[k]) + else: + LOG.debug("+ config element: '%s'", k) + else: + inode[k] = config[k] + + with open(str(_from), 'r') as infile: + obj: Configuration = yaml.load(infile, Loader=ConfigLoader) + upgrade(obj) + load_rec(self.node, obj) + self['config_file'] = os.path.abspath(_from)
+ + +
+[docs] + def has_value(self) -> bool: + """Check, if the node contains a 'value'.""" + return isinstance(self.node, dict) and 'value' in self.node
+ + +
+[docs] + def has_default(self) -> bool: + """Check, if the node contains a 'default' value.""" + return isinstance(self.node, dict) and 'default' in self.node
+ + +
+[docs] + def is_leaf(self) -> bool: + """Check, if the node is a 'leaf' node.""" + return self.has_value() or self.has_default()
+ + +
+[docs] + def init_from_env(self) -> None: + """ + Initialize this node from environment. + + If we're a leaf node, i.e., a node containing a dictionary that + consist of a 'default' key, compute our env variable and initialize + our value from the environment. + Otherwise, init our children. + """ + + if 'default' in self.node: + env_var = self.__to_env_var__().upper() + if not self.has_value(): + self.node['value'] = self.node['default'] + env_val = os.getenv(env_var, None) + if env_val is not None: + try: + self.node['value'] = yaml.load( + str(env_val), Loader=ConfigLoader + ) + except ValueError: + self.node['value'] = env_val + else: + if isinstance(self.node, dict): + for k in self.node: + self[k].init_from_env()
+ + + @property + def value(self) -> tp.Any: + """Return the node value, if we're a leaf node.""" + + def validate(node_value: tp.Any) -> tp.Any: + if hasattr(node_value, 'validate'): + node_value.validate() + return node_value + + if 'value' in self.node: + return validate(self.node['value']) + return self + + def __getitem__(self, key: str) -> 'Configuration': + if key not in self.node: + warnings.warn( + "Access to non-existing config element: {0}".format(key), + category=InvalidConfigKey, + stacklevel=2 + ) + return Configuration(key, init=False) + return Configuration(key, parent=self, node=self.node[key], init=False) + + def __setitem__(self, key: str, val: tp.Any) -> None: + if _INNER_NODE_SCHEMA.is_valid(val) or _INNER_NODE_VALUE.is_valid(val): + self.node[key] = val + elif key in self.node: + self.node[key]['value'] = val + else: + self.node[key] = {'value': val} + + def __iadd__(self, rhs: tp.Any) -> tp.Any: + """Append a value to a list value.""" + if not self.has_value(): + raise TypeError("Inner configuration node does not support +=.") + + value = self.node['value'] + if not hasattr(value, '__iadd__'): + raise TypeError("Configuration node value does not support +=.") + + value += rhs + return value + + def __int__(self) -> int: + """Convert the node's value to int, if available.""" + if not self.has_value(): + raise ValueError( + 'Inner configuration nodes cannot be converted to int.' + ) + return int(self.value) + + def __bool__(self) -> bool: + """Convert the node's value to bool, if available.""" + if not self.has_value(): + return True + return bool(self.value) + + def __contains__(self, key: str) -> bool: + return key in self.node + + def __str__(self) -> str: + if 'value' in self.node: + return str(self.node['value']) + return str(self.node) + + def __repr__(self) -> str: + """ + Represents the configuration as a list of environment variables. + """ + _repr = [] + + if self.has_value(): + return to_env_var(self.__to_env_var__(), self.node['value']) + if self.has_default(): + return to_env_var(self.__to_env_var__(), self.node['default']) + + for k in self.node: + _repr.append(repr(self[k])) + + return "\n".join(sorted(_repr)) + + def __to_env_var__(self) -> str: + parent_key = self.parent_key + if self.parent: + return str(self.parent.__to_env_var__() + "_" + parent_key).upper() + return parent_key.upper() + +
+[docs] + def to_env_dict(self) -> tp.Mapping[str, tp.Any]: + """Convert configuration object to a flat dictionary.""" + if self.has_value(): + return {self.__to_env_var__(): self.node['value']} + if self.has_default(): + return {self.__to_env_var__(): self.node['default']} + + entries: tp.Dict[str, str] = {} + for k in self.node: + entries.update(self[k].to_env_dict()) + + return entries
+
+ + + +
+[docs] +def convert_components(value: tp.Union[str, tp.List[str]]) -> tp.List[str]: + is_str = isinstance(value, six.string_types) + new_value = value + if is_str: + new_value = str(new_value) + if os.path.sep in new_value: + new_value = new_value.split(os.path.sep) + else: + new_value = [new_value] + new_value = [c for c in new_value if c != ''] + return new_value
+ + + +
+[docs] +@attr.s(str=False, frozen=True) +class ConfigPath: + """Wrapper around paths represented as list of strings.""" + components = attr.ib(converter=convert_components) + +
+[docs] + def validate(self) -> None: + """Make sure this configuration path exists.""" + path = local.path(ConfigPath.path_to_str(self.components)) + + if not path.exists(): + print("The path '%s' is required by your configuration." % path) + yes = ui.ask( + "Should I create '%s' for you?" % path, + default_answer=True, + default_answer_str="yes" + ) + if yes: + path.mkdir() + else: + LOG.error("User denied path creation of '%s'.", path) + if not path.exists(): + LOG.error("The path '%s' needs to exist.", path)
+ + +
+[docs] + @staticmethod + def path_to_str(components: tp.List[str]) -> str: + if components: + return os.path.sep + os.path.sep.join(components) + return os.path.sep
+ + + def __str__(self) -> str: + return ConfigPath.path_to_str(self.components)
+ + + +
+[docs] +def path_representer(dumper, data): + """ + Represent a ConfigPath object as a scalar YAML node. + """ + return dumper.represent_scalar('!create-if-needed', '%s' % data)
+ + + +
+[docs] +def path_constructor(loader, node): + """" + Construct a ConfigPath object form a scalar YAML node. + """ + value = loader.construct_scalar(node) + return ConfigPath(value)
+ + + +
+[docs] +def find_config( + test_file: tp.Optional[str] = None, + defaults: tp.Optional[tp.List[str]] = None, + root: str = os.curdir +) -> tp.Optional[LocalPath]: + """ + Find the path to the default config file. + + We look at :root: for the :default: config file. If we can't find it + there we start looking at the parent directory recursively until we + find a file named :default: and return the absolute path to it. + If we can't find anything, we return None. + + Args: + test_file: + default: The name of the config file we look for. + root: The directory to start looking for. + + Returns: + Path to the default config file, None if we can't find anything. + """ + if defaults is None: + defaults = [".benchbuild.yml", ".benchbuild.yaml"] + + def walk_rec(cfg_name: str, root: str) -> LocalPath: + cur_path = local.path(root) / cfg_name + if cur_path.exists(): + return cur_path + + new_root = local.path(root) / os.pardir + return walk_rec(cfg_name, new_root) if new_root != root else None + + if test_file is not None: + return walk_rec(test_file, root) + + for test_f in defaults: + ret = walk_rec(test_f, root) + if ret is not None: + return ret + + return None
+ + + +
+[docs] +def setup_config( + cfg: Configuration, + config_filenames: tp.Optional[tp.List[str]] = None, + env_var_name: tp.Optional[str] = None +) -> None: + """ + This will initialize the given configuration object. + + The following resources are available in the same order: + 1) Default settings. + 2) Config file. + 3) Environment variables. + + WARNING: Environment variables do _not_ take precedence over the config + file right now. (init_from_env will refuse to update the + value, if there is already one.) + + Args: + config_filenames: list of possible config filenames + env_var_name: name of the environment variable holding the config path + """ + if env_var_name is None: + env_var_name = "BB_CONFIG_FILE" + + config_path = os.getenv(env_var_name, None) + if not config_path: + config_path = find_config(defaults=config_filenames) + + if config_path: + cfg.load(config_path) + cfg["config_file"] = os.path.abspath(config_path) + cfg.init_from_env()
+ + + +
+[docs] +def update_env(cfg: Configuration) -> None: + env: tp.Dict[str, str] = dict(cfg["env"].value) + + path = env.get("PATH", "") + path = os.path.pathsep.join(path) + if "PATH" in os.environ: + path = os.path.pathsep.join([path, os.environ["PATH"]]) + os.environ["PATH"] = path + + lib_path = env.get("LD_LIBRARY_PATH", "") + lib_path = os.path.pathsep.join(lib_path) + if "LD_LIBRARY_PATH" in os.environ: + lib_path = os.path.pathsep.join([ + lib_path, os.environ["LD_LIBRARY_PATH"] + ]) + os.environ["LD_LIBRARY_PATH"] = lib_path + + home = env.get("HOME", None) + if home is not None and "HOME" in os.environ: + os.environ["HOME"] = home + + # Update local's env property because we changed the environment + # of the running python process. + local.env.update(PATH=os.environ["PATH"]) + local.env.update(LD_LIBRARY_PATH=os.environ["LD_LIBRARY_PATH"]) + if home is not None: + local.env.update(HOME=os.environ["HOME"])
+ + + +
+[docs] +def upgrade(cfg: Configuration) -> None: + """Provide forward migration for configuration files.""" + db_node = cfg["db"] + old_db_elems = ["host", "name", "port", "pass", "user", "dialect"] + has_old_db_elems = [x in db_node for x in old_db_elems] + + if any(has_old_db_elems): + print( + "Old database configuration found. " + "Converting to new connect_string. " + "This will *not* be stored in the configuration automatically." + ) + cfg["db"]["connect_string"] = \ + "{dialect}://{user}:{password}@{host}:{port}/{name}".format( + dialect=cfg["db"]["dialect"]["value"], + user=cfg["db"]["user"]["value"], + password=cfg["db"]["pass"]["value"], + host=cfg["db"]["host"]["value"], + port=cfg["db"]["port"]["value"], + name=cfg["db"]["name"]["value"])
+ + + +
+[docs] +def uuid_representer(dumper, data): + """Represent a uuid.UUID object as a scalar YAML node.""" + + return dumper.represent_scalar('!uuid', '%s' % data)
+ + + +
+[docs] +def uuid_constructor(loader, node): + """"Construct a uuid.UUID object form a scalar YAML node.""" + + value = loader.construct_scalar(node) + return uuid.UUID(value)
+ + + +
+[docs] +def uuid_add_implicit_resolver(loader=ConfigLoader, dumper=ConfigDumper): + """Attach an implicit pattern resolver for UUID objects.""" + uuid_regex = r'^\b[a-f0-9]{8}-\b[a-f0-9]{4}-\b[a-f0-9]{4}-\b[a-f0-9]{4}-\b[a-f0-9]{12}$' + pattern = re.compile(uuid_regex) + yaml.add_implicit_resolver('!uuid', pattern, Loader=loader, Dumper=dumper)
+ + + +def __init_module__() -> None: + yaml.add_representer(uuid.UUID, uuid_representer, Dumper=ConfigDumper) + yaml.add_representer(ConfigPath, path_representer, Dumper=ConfigDumper) + yaml.add_constructor('!uuid', uuid_constructor, Loader=ConfigLoader) + yaml.add_constructor( + '!create-if-needed', path_constructor, Loader=ConfigLoader + ) + uuid_add_implicit_resolver() + + +__init_module__() +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 000000000..b8571cc60 --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,242 @@ + + + + + + Overview: module code + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/_sources/CHANGELOG.md.txt b/_sources/CHANGELOG.md.txt new file mode 100644 index 000000000..6d83de0c8 --- /dev/null +++ b/_sources/CHANGELOG.md.txt @@ -0,0 +1,437 @@ + +## 6.8 (2023-10-09) + + +#### Features + +* **ci:** test with both db support and without ([af7bfd90](https://github.com/PolyJIT/benchbuild/commit/af7bfd90caf2c8fc56eb71de67384f15c6569838)) +* **coverage:** + * test with database support enabled ([0b8d6034](https://github.com/PolyJIT/benchbuild/commit/0b8d6034b3c8d58ab8034a3bdda6cc7509c25e9c)) + * add cli coverage report ([64ce9f87](https://github.com/PolyJIT/benchbuild/commit/64ce9f87cdcd32cda8665e17b84651abebead604)) + * add wrapped binaries to coverage ([d4c6841d](https://github.com/PolyJIT/benchbuild/commit/d4c6841d09fcb0c77564d5faaa29e69b4ff40822)) +* **db:** revert default setting for connect_string to sqlite:// ([806520d6](https://github.com/PolyJIT/benchbuild/commit/806520d6f34e85bdb3709e37465f7982b6d4db36)) + +#### Bug Fixes + +* use context vars instead of env vars ([e3ea47f0](https://github.com/PolyJIT/benchbuild/commit/e3ea47f01e4d85ddfedeb104ae6184d43e6957ef)) +* make github ci actually use its own env vars ([e0c7ab67](https://github.com/PolyJIT/benchbuild/commit/e0c7ab676aa3686a78bac97ed87d4c98f71e240d)) +* use BB_COVERAGE_PATH in .coveragerc ([141afafa](https://github.com/PolyJIT/benchbuild/commit/141afafa7859136bad5952c672448b92082f7551)) +* coveragerc requires curly braces for env variables ([3ae8b335](https://github.com/PolyJIT/benchbuild/commit/3ae8b3358e0d1e828f2d73f222a563bfcc01f8b6)) +* coveragerc requires curly braces for env variables ([5b9c9906](https://github.com/PolyJIT/benchbuild/commit/5b9c9906cbb5ff7f4e27a7018e1069ef24fe25bf)) +* **actions:** re-raise caught exception ([e4bff984](https://github.com/PolyJIT/benchbuild/commit/e4bff984e4f1e523ce9d685a5d3ec9a58c97a18a), closes [#561](https://github.com/PolyJIT/benchbuild/issues/561)) +* **environments:** buildah cannot find base images. ([eb03c363](https://github.com/PolyJIT/benchbuild/commit/eb03c363eac2a515e830ff3e9f0343c923348763)) + + + + +## 6.7 (2023-04-04) + + +#### Features + +* run auto-walrus over all of benchbuild's file ([79ac33d8](https://github.com/PolyJIT/benchbuild/commit/79ac33d8d69974fb6a1d049f75c5f013e444b2ce)) +* add support for auto-walrus as pre-commit hook ([d7a2165b](https://github.com/PolyJIT/benchbuild/commit/d7a2165bb22467754fd329fedc0c0f8330336e3f)) +* drop support for python 3.7 and 3.8 ([90308f2a](https://github.com/PolyJIT/benchbuild/commit/90308f2ae141fd4443f08ef55a4155e433fad929)) +* **ci:** + * update setup-python to v4 ([3e943df6](https://github.com/PolyJIT/benchbuild/commit/3e943df657cb06a4f2b47104a4e3dcb77f16793c)) + * update github setup actions to v3 ([dfa4cb81](https://github.com/PolyJIT/benchbuild/commit/dfa4cb8135d3c0256c6b99dbe40771d8ce1e5a5d)) +* **command:** use name as default value for a command's label ([07f74dd4](https://github.com/PolyJIT/benchbuild/commit/07f74dd4932eecdfbd902d231242a65984501007)) +* **environments:** force base image to alpine:3.17 ([fe5d6155](https://github.com/PolyJIT/benchbuild/commit/fe5d615574130260e1af1aaa49b1058600ed9668)) +* **setup:** + * widen allowed versions to major versions ([5d29079a](https://github.com/PolyJIT/benchbuild/commit/5d29079a973dc1d8650ee9083090eaa7bd99cbfc)) + * unlock latest versions of all packages ([7b5a704f](https://github.com/PolyJIT/benchbuild/commit/7b5a704f843872c90fa2a23eb738db4262883076)) +* **wrapping:** enforce global defaults for dill module ([489e3039](https://github.com/PolyJIT/benchbuild/commit/489e3039f8bb1ccee40219d1c27ca999cd8a3623)) + +#### Bug Fixes + +* python version for setup-python@v4 has to be string ([7a1db742](https://github.com/PolyJIT/benchbuild/commit/7a1db74237e6b35687213920bb534b5308773615)) +* remove python 3.7 and 3.8 from all workflows ([aaabc1b5](https://github.com/PolyJIT/benchbuild/commit/aaabc1b5e7a817304f9e948feb565f37916c68bb)) +* bump pathos & dill to unbreak gitlab ci ([bce45d8a](https://github.com/PolyJIT/benchbuild/commit/bce45d8a148e41914d6f56a18933f9faf26f58bf)) +* **ci:** + * disable mkdocs in github ci ([8540f880](https://github.com/PolyJIT/benchbuild/commit/8540f880607ddeae293fc6b9feb1f751fd9cc721)) + * reorder CI steps (test) ([74379d53](https://github.com/PolyJIT/benchbuild/commit/74379d5350c35cc2c76600ae7784b78aefd1a7db)) + * increase verbosity to max for all integation tasks ([b6625d31](https://github.com/PolyJIT/benchbuild/commit/b6625d31d444e2ea51dc923a80438f0eed4a962d)) +* **command:** use private label when fetching string representation ([d83aa666](https://github.com/PolyJIT/benchbuild/commit/d83aa6661d3e2e08a0849bd3b23f557bd086e5b6)) +* **commands:** preserve workload order when filtering ([3648dd5e](https://github.com/PolyJIT/benchbuild/commit/3648dd5e8d0c20a07141a05a94a4e1223f575399)) +* **setup:** unlock any major version of pygit2 ([b09d9248](https://github.com/PolyJIT/benchbuild/commit/b09d92489a57897d4e0ad39dcb8b99ce08133d36)) +* **wrapping:** remove unused code ([0d1c890d](https://github.com/PolyJIT/benchbuild/commit/0d1c890db0f674aab13b12432394699030114087)) + + + +# Changelog + + +## 6.6.4 (2023-03-16) + + + + + +## 6.6.3 (2023-03-06) + + + + + +## 6.6.2 (2023-03-06) + + +#### Bug Fixes + +* pin sqlalchemy version <2.0 ([86d45043](https://github.com/PolyJIT/benchbuild/commit/86d45043d269775d65c3b2844d9eee669824b46c)) + + + + +## 6.6.1 (2023-01-10) + + +#### Features + +* **environments:** + * do not overwrite config, if cli option is default ([b1a095c1](https://github.com/PolyJIT/benchbuild/commit/b1a095c1e5b6ceb32b7eb3a7eda61918eeb3f757)) + * improve error handling using result module ([fbb69502](https://github.com/PolyJIT/benchbuild/commit/fbb695027e83e99ab8dbbb58447bd3dc9d0073dd)) +* **slurm:** make container.runroot/container.root available for slurm customization ([616a4c69](https://github.com/PolyJIT/benchbuild/commit/616a4c69bea9ef17547cabfd2a8e076638b1e034), closes [#528](https://github.com/PolyJIT/benchbuild/issues/528)) +* **source:** make sure we manage the archive symlink properly. ([7687f0e3](https://github.com/PolyJIT/benchbuild/commit/7687f0e317b82b9e8a4b5e78a63827dd18255c06)) +* **source/http:** add auto-untar http source ([84f90e75](https://github.com/PolyJIT/benchbuild/commit/84f90e7568550a240a25c7cf06b139862f764ed0)) + +#### Bug Fixes + +* **environments:** + * add missing logging import ([aad1b287](https://github.com/PolyJIT/benchbuild/commit/aad1b2878721c466167f52c176683d97d25a9f86)) + * add missing Err import ([19c5983c](https://github.com/PolyJIT/benchbuild/commit/19c5983cd43e73d870212428bcc382d3e8255d9e)) + * notify user when commit of container image fails ([78b890af](https://github.com/PolyJIT/benchbuild/commit/78b890af5fd03093bc74631bc6ac63c19477ee70)) +* **project:** version filters should only consider expandable sources ([3d546314](https://github.com/PolyJIT/benchbuild/commit/3d5463146debb66b3448acbf3ee79c4ef17ce35f)) +* **source:** enforce sorted order of revisions ([ca973ff0](https://github.com/PolyJIT/benchbuild/commit/ca973ff0b7e01e3b79b6daafdc7848e1433f766a)) + + + +## 6.5 (2022-11-03) + +### Feat + +- **source**: re-enable project_cls in enumerate_revision interface +- **versions**: enable context-aware SingleVersionFilter +- **source**: only print context-free sources +- **source**: expand public source API +- **source**: introduce type skeleton and prototypes for context-aware version enumeration. +- **action**: replace StepClass metaclass with __init_subclass__ +- **actions**: mark StepTy covariant +- **actions**: use Stepable protocol as bound for StepTy. +- **actions**: accept any varargs in a Step's __call__ implementation + +### Fix + +- require dill version to be exactly 0.3.4 +- linter warning +- linter warnings +- **project**: remove debug print +- **utils**: variant -> revision +- **tests**: repair tests after VariantContext replacement. +- **source**: remove runtime_checkable decorator +- **source**: use project class instead of object for enumerate +- **source**: return sequence of variants instead of nestedvariant +- **source**: clean up protocol apis +- **actions**: rename StepTy -> StepTy_co +- **tests**: remove notify_step_begin_end +- **actions**: reduce mypy errors +- **actions**: use mutable generic container + +### Refactor + +- **versions**: remove BaseVersionGroup +- **source**: replace VariantContext with Revision +- **source**: remove ExpandableAndFetchableSource from API + +## 6.4 (2022-09-21) + +### Feat + +- **actions**: make MultiStep generic. +- **command**: make use of rendered and unrenderer PathToken explicit. +- **command**: safeguard pruning and backup +- **command**: add tests for enable_rollback +- **command**: add support for creates and consumes properties for commands +- **command**: add a label to commands +- **workload**: switch WorkloadSet to varargs instead of kwargs +- **command**: add example `OnlyIn` for WorkloadSet customization. + +### Fix + +- **command**: strictly less than python 3.9 +- **command**: use _is_relative_to where needed +- **command**: guard is_relative_to with else +- **command**: do not depend on Path.is_relative_to ( cleanup + +## 6.3.2 (2022-08-21) + +### Feat + +- **command**: rename NullRenderer to RootRenderer +- **command**: hook up token renderer logic with Commands +- **command**: add support for generic path tokens +- **workload**: convert scimark2 +- **command**: migrate git-based projects to workload sets +- **command**: add support for WorkloadSet. +- **command**: clear path tracker on fresh ProjectEnvironment +- **wrapping**: avoid wrapping the same command twice. +- **jobs**: add RunJob and RunJobs actions +- **command**: replace source root anywhere in command's parts +- **command**: pass environment to plumbum command +- **command**: pass args to plumbum command +- **command**: improve args and kwargs handling +- add env and __str__ to commands +- **command**: support declarative commands in projects (WIP) +- **source**: add 'fetch' support to FetchableSource derivatives +- **workloads**: add properties & tags accessors +- **workloads**: convert benchbuild.xz to support workloads + +### Fix + +- test must use render() +- **x264**: repair broken cli args +- **command**: actually run the workload +- **command**: check for existence, only after rendering +- **project**: target compile instead of run_tests, when accessing compile +- **command**: remove unused definitions +- **command**: context -> kwargs +- **typing**: python3.7 requires typing_extensions for runtime_checkable / Protocll +- **command**: missing rename job -> workload +- **command**: provide mapping type +- **workload**: strip previous workload draft +- workaround a mypy error +- correct mypy errors. +- **wrapping**: provide default arg for sprefix +- **actions**: provide default StepResult +- **command**: store args as tuple +- **bzip2**: clean draft marker +- **actions**: repair status print of actions +- **experiment**: initialize CleanExtra correctly +- **jobs**: allow jobs to run as wrapped binaries +- use oci_compliant name for image names +- **workloads**: wrong workload type +- **actions**: unbreak tests after list -> scalar conversion + +### Refactor + +- **command**: lower-case token str +- rename Job -> Workload +- **command**: remove debug prints +- **source**: remove unnecessary ellipsis + +## 6.3.1 (2022-03-01) + +### Feat + +- **actions**: clean interfaces of utils/actions +- **workloads**: make object instance accessible to workloads using descriptors +- **workloads**: hook up Compile and Run action to new workload impl +- **workloads**: add simple intersection filter to workloads +- **workloads**: change workload registration decorator style. +- **workloads**: migrate Compile/Run action to run workloads only +- **project**: remove run_tests and compile abstract methods +- **gzip**: convert gzip to workloads +- **workload**: Add prototype support for workloads. +- **environments**: strip container args when entering interactive mode + +### Fix + +- **workloads**: typo. +- **gzip**: undo wrong wrap command +- **actions**: project -> obj after rebase + +### Refactor + +- **workloads**: remove useless/unused parts + +## 6.3 (2022-02-03) + +### Feat + +- **actions**: throw error if RevisionStrings cannot match any Source. +- **source**: add FetchableSource.explore() method +- **source**: only filter context for expandable sources +- **actions**: support partial revisions in SetProjectVersion +- **source**: hook up context_from_revisions to SetProjectVersion +- **source**: provide an easy way to create a variant context +- **environments**: add container image removal to buildah adapter +- **environments**: support custom arguments in RunProjectContainer +- **actions**: track active_variant with SetProjectVersion +- **project**: add MultiVersioned Mixin to Projects +- **source**: symlink active version for http sources +- **source**: Link to active location after version() +- **actions**: Rename AddProjectVersion to SetProjectVersion +- **actions**: add AddProjectVersion action +- **actions**: remove obsolete parameters +- **actions**: remove attrs from utils/actions + +### Fix + +- **tests**: eye-breaking code alignment. +- **environments**: do not fail if no entrypoint is set. +- **environments**: supply args as dedicated subcommand args +- **environments**: use a default list factory, instead of a list class +- **source**: replace symlink to directory +- **actions**: obvious type errors in SetProjectVersion +- **actions**: assign active variant + +### Refactor + +- **pylint**: remove unused import +- **pylint**: make pylint happy. +- **pylint**: make pylint almost happy. + +## 6.2.7 (2021-09-21) + +## 6.2.6 (2021-09-16) + +### Fix + +- **sources**: do not use protocol class as ABC + +## 6.2.5 (2021-09-15) + +### Feat + +- **utils/run**: add unbuffered watch commands +- **source**: update git remote revisions. (#434) +- **log**: add force_tty switch to control RichHandler. (#435) + +## 6.2.4 (2021-09-03) + +## 6.2.3 (2021-08-26) + +### Fix + +- **schema**: silence SAWarning about caching (#428) +- **environments**: pass format string to logging call (#427) + +## 6.2.2 (2021-07-29) + +## 6.2.1 (2021-07-06) + +### Feat + +- **environments**: add an interactive mode for container runs. + +### Fix + +- **logging**: make rich log to stderr by default (#415) +- **settings**: BB_ENV is ignored when no config file is loaded" (#414) + +## 6.2 (2021-06-02) + +### Fix + +- **settings**: unbreak test cases. +- use correct schema version +- **settings**: consistent settings behavior. +- **environments**: notify the user, if image creation fails + +## 6.1.1 (2021-05-11) + +### Fix + +- **project**: do not track project classes twice + +## 6.1 (2021-05-11) + +### Feat + +- **environments**: just print env var name as error message +- **environments**: warn the user about too long paths for libpod +- **slurm**: support variable number of subcommand arguments +- tune down rich's custom log format +- **environments**: enable debugging of failed image builds +- **environments**: provide more consistent output through rich +- **environments**: add 'rmi' subcommand to delete images. +- **environments**: make an error message stand out more clearly +- **environments**: add g++ to base image +- **environments**: split image_exists into 2 implementations +- **environments**: split containers cli into 2 entitie +- **environments**: add basic error handling to environments +- **environments**: emit layer creation events +- **environments**: print layer construction progress +- **environments**: make layers hashable +- **environments**: step-wise image construction +- **environments**: split Repositories and Unit of Work into 2 entities each +- **utils/slurm**: add customizable SLURM templates +- **cli/project**: add details view for a single project +- **cli/project**: change project view to a condensed format +- **environments**: add option to replace container images +- add support for --export and --import flags in containers + +### Fix + +- **sources**: unshallow only when needed +- **environments**: unshallow git clones before dissociating +- **environments**: remove left-over parameters +- **ci**: typo. +- **environments**: do not overwrite exported images. +- **environments**: remove optional image name argument from podman load +- **slurm**: fix pylint/mypy +- **environments**: reuse same status bar structure for all other cli subcommands +- **environments**: mypy warnings +- **environments**: fix mypy/pylint annotations. +- **environments**: split return turple and baild out on error +- **environments**: mypy warnings +- **environments**: add missing type conversion +- **environments**: rework typing annotations for handlers +- **environments**: fix linter/mypy warnings +- **environments**: make Add & Copy layers hashable +- **environments**: add missing sys import +- **environments**: import Protocol from typing_extensions, if python <= 3.8 +- **environments**: handle 'None' for MaybeContainer return type +- **slurm**: do not modify slurm_node_dir +- **environments**: deal with multi-line container ids +- **environments**: do not spawn the FromLayer +- **cli/project**: annotate print_layers +- **cli/project**: add neutral element for multiplication with reduce +- **project**: project registration for groups +- **environments**: explicitly state remote registry location +- do not use global state to conffigure buildah/podman +- **x264**: use local name of source for lookup + +### Refactor + +- **environments**: fix possible unbound variable +- **slurm**: fix type error on cli_process +- **environments**: remove unused sys import +- **environments**: rmeove some linter warnings +- **environments**: replace functools.partial with custom closure function +- **environments**: unsplit image from layer creation +- **enviroments**: remove debug print +- **environments**: remove unused commands +- **cli/project**: remove version counting from project view +- **cli/project**: force use of str +- **cli/project**: add documentation to print_project +- **cli/project**: add type annotation for set_limit +- **cli/project**: add a default list limit for versions (10) +- **cli/project**: provide better layout of project information +- **cli/project**: use a multi-line string +- **cli/project**: use named fields +- **project**: provide correct type annotations + +## 6.0.1 (2020-12-29) + +### Fix + +- Avoid useless plugin spam when running with higher verbosity levels diff --git a/_sources/about.md.txt b/_sources/about.md.txt new file mode 100644 index 000000000..3570cdf33 --- /dev/null +++ b/_sources/about.md.txt @@ -0,0 +1,33 @@ +# BenchBuild Documentation + +BenchBuild is an open-source toolkit that helps with the management of case-studies used in software-driven empirical experiments. +BenchBuild was specifically designed to make defined experiments reusable between different +experiment setups. It mainly provides assistance with the following standard tasks found in empirical software experiments: + +- Add a new case-study to an existing experiment setup. +- Add a new experiment to an existing body of case-studies. + +## Design Philosophy + +BenchBuild is designed with the following main properties in mind. + +### A case-study doesn't know its experiment + +If you add a new case-study, you should never have to rely on background information about the experiment you are about to run on it. +A new case-study is only concerned with its own setup of dependencies and execution during its run-time. A case-study controls where and what can be +intercepted by an experiment. + +### An experiment doesn't know its case-studies + +Adding a new experiment never should have any knowledge about the case-studies +it runs on. +A new experiment takes care of intercepting the compilation process and/or the +execution procedure of a given case-study. This only defines what is being done at the defined extension points at compile-time or run-time. + +## Supported Python Versions + +BenchBuild supports Python 3.7 and 3.8. Main development is focused on Python 3.8, but an effort is made to support 3.7 as long as major distributions like Debian Linux only ship with 3.7 by default. + +## Getting started + +See the [Installation guide]() for help getting BenchBuild up and running quickly. diff --git a/_sources/advanced/cli.md.txt b/_sources/advanced/cli.md.txt new file mode 100644 index 000000000..97268ba55 --- /dev/null +++ b/_sources/advanced/cli.md.txt @@ -0,0 +1,4 @@ +## CLI + +* ``--force-watch-unbuffered``: This disables buffering from watched commands. + This can help with tools that call benchbuild and use their own output buffering. diff --git a/_sources/advanced/index.md.txt b/_sources/advanced/index.md.txt new file mode 100644 index 000000000..386708dd4 --- /dev/null +++ b/_sources/advanced/index.md.txt @@ -0,0 +1,28 @@ +# SLURM + +BenchBuild supports a high-level integration with the SLURM cluster resource +manager. An experiment setup can be exported as a SLURM bash script. Assuming +you have access to a configured benchbuid environment on the SLURM cluster, you +can provide the SLURM script to the ``sbatch`` command and have your experiment +run on the cluster environment. + +## Basics + +TODO + +## Template customization + +This customization is not recommended for the default use-case. However, you +might run in a situation where the existing cluster-environment requires a +more complicated setup than BenchBuild can provide. + +You can customize the template that is used for the SLURM script using a +modified copy of the base template BenchBuild uses +(see ``benchbuild/res/misc/slurm.sh.inc``). + +The customized template can be configured using the configuration option +``BB_SLURM_TEMPLATE``. If BenchBuild detects that the provided value points to +an existing file in your filesystem, it will load it. +If you change the setting and BenchBuild cannot find a file there, no script +will be generated. No validation of the template will be done, use at your own +risk. diff --git a/_sources/basics/actions.md.txt b/_sources/basics/actions.md.txt new file mode 100644 index 000000000..48b86fcfb --- /dev/null +++ b/_sources/basics/actions.md.txt @@ -0,0 +1,101 @@ +# Actions + +Actions are used to declare the workflow of an experiment. BenchBuild provides +a set of default actions that should suit most experiments. +A new experiment can define a new set of actions that should be used per project, +or use those defaults. + +## Customize actions + +Whenever you define a new expeirment, you have to provide an implementation +for ``def actions_for_project(self, project: 'Project')``. +This implementation usually configures extensions on the project and returns +a set of actions that should be run during execution. + +Example: +```{python} +def actions_for_project(self, project: 'Project'): + project.runtime_extension = time.RunWithTime( + run.RuntimeExtensions(project, self)) + project.runtime_extension = time.WithTimeout( + run.RunCompiler(project, self)) + + return self.default_runtime_actions(project) +``` + +This takes care of compiling, running and cleanup during experiment execution. + +## Available Actions + +The following actions are available out of the box. You can define your own +actions at any time + +### Step (Base) + +### Clean + +### MakeBuildDir + +### Compile + +### Run + +### Echo + +### Any (Group) + +### Experiment (Any, Group) + +### RequireAll (Group) + +### CleanExtra + +### ProjectEnvironment + +### SetProjectVersion + +This action provides you with a way to change the source version used inside the +build directory of this project. +During initialization, each project is assigned a variant that determines the +source versions that will be checked out into the build directory. + +Sometimes it can be useful to do comparisons of different source revisions +inside a single experiment run. This can be achieved using ``SetProjectVersion``. + +Usage: +```{python} +from benchbuild.source.base import RevisionStr +from benchbuild.utils import actions as a + +... +git_commit_hash = 'abcdefgh' + +actions = [ + a.Clean(project), + a.MakeBuildDir(project), + # This uses the default variant of the project (not necessarily 'abcdefgh') + a.ProjectEnvironment(project), + a.Compile(project), + a.Run(project), + + # From here we will work with git sources set to 'abcdefgh' + a.SetProjectVersion(project, RevisionStr(git_commit_hash)) + a.Compile(project), + a.Run(project) +] +``` + +The match is done on all(!) sources of the project. If you happen to find a +revision string twice in different souces, both will be checked out in the +build directory. + +The match is done exact and matches agains the ``source.versions()`` output of a +source. Only sources that are marked as expandable (``source.is_expandable``) +will be checked. + +```{eval-rst} +.. automodule:: benchbuild.utils.actions + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/_sources/basics/configuration.md.txt b/_sources/basics/configuration.md.txt new file mode 100644 index 000000000..213513f12 --- /dev/null +++ b/_sources/basics/configuration.md.txt @@ -0,0 +1,19 @@ +# Configure + +## Module: settings + +```{eval-rst} +.. automodule:: benchbuild.settings + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: utils.settings + +```{eval-rst} +.. automodule:: benchbuild.utils.settings + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/_sources/basics/containers.md.txt b/_sources/basics/containers.md.txt new file mode 100644 index 000000000..802b5a122 --- /dev/null +++ b/_sources/basics/containers.md.txt @@ -0,0 +1,143 @@ +# Containers + +Benchbuild allows the definition of container images to define the base system +all experiment runs run in for a given project. + +## Usage + +If you want to run an experiment inside the project's container, simply replace +the usual ``run`` subcommand with the ``container run`` subcommand. Project and +experiment selection are done in the same way. + +Example: +``` +benchbuild container run -E raw linpack +``` + +This will run the following stages: + + 1. Build all necessary base images. + All images are initiated from a base image. Benchbuild knows how to construct + a few base images. These will be prepared with all dependencies required to + run benchbuild inside the container. + 2. Build all project images. Each project has to define its' own image. + 3. Build the experiment images. Each experiment can add anything it needs to the + project images, if required. Use this to bring tools into the image that do + not require any knowledge about the environment to run properly. + For anything else, consider using a custom base image. + +### Replace Images + +Benchbuild will reuse any existing images it can find in your image registry. +The only relevant information is the image tag, e.g., ``benchbuild:alpine``. +If you want to avoid reuse and force to rebuild images unconditionally, you can +use the ``--replace`` flag when running the ``containers`` subcommand. + +Example: +``` +benchbuild container run --replace -E raw linpack +``` + +This will ignore **any** required image for the given experiments and projects. + +## Configuration + +You can configure the container environment using the following config variables. + +- ``BB_CONTAINER_EXPORT``: Path where benchbuild stores exported container + images. By default we store it in ``./containers/export``. Will be created + automatically, if needed. +- ``BB_CONTAINER_IMPORT``: Path where to input images from into the registry. + By default we load from ``./containers/export``. +- ``BB_CONTAINER_FROM_SOURCE``: Determine, if we should use benchbuild from the + current source checkout, or from pip. +- ``BB_CONTAINER_ROOT``: Where we store our image layers. This is the image + registry. Cannot be stored on filesystems that do not support subuid/-gid + mapping, e.g. NFS. + The default location is ``./containers/lib``. +- ``BB_CONTAINER_RUNROOT``: Where we store temporary image layers of running + containers. See ``BB_CONTAINER_ROOT`` for restrictions. + The default location is: ``./containers/run``. +- ``BB_CONTAINER_RUNTIME``: Podman can use any standard OCI-container runtime to + launch containers. We use [crun](https://github.com/containers/crun) by + default. Depending on your system, this one has already been installed with + ``podman``. + The default runtime is: ``/usr/bin/crun`` +- ``BB_CONTAINER_MOUNTS``: A list of mountpoint definitions that should be added + to all containers. With this you can add arbitrary tools into all containers. + Default: ``[]`` + +## Definition + +A project that wants to use a container image needs to define it in the +``CONTAINER`` attribute it using our declarative API provided by +``benchbuild.environments.domain.declarative``. + +``` +from benchbuild.environments.domain.declarative import ContainerImage + +class Testproject(Project): + CONTAINER = ContainerImage().from_('benchbuild:alpine') +``` + +The available set of commands follows the structure of a ``Dockerfile``. + +## Runtime requirements + +For containers to work properly, you need a few systems set up beforehand. + +### Buildah + +Image construction requires the [Buildah](https://buildah.io) tool. All image +construction tasks are formulated as buildah command calls in the backend. + +Buildah is supported up to version 1.19.8. + +### Podman + +Container construction and execution is handed off to [Podman](https://podman.io). +Podman provides rootless containers and does not requires the execution of a +daemon process. However, you need to setup your user namespace properly to allow +mapping of subordinate uids/gids. Otherwise, podman will not be able to map +users other than the root user to filesystem permissions inside the container. + +Please refer to podman's documentation on how to setup podman properly on your +system. + +Podman is supported up to version 2.2.1 + +## Module: benchbuild.container + +```{eval-rst} +.. automodule:: benchbuild.container + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: benchbuild.environments.domain.declarative + +```{eval-rst} +.. automodule:: benchbuild.environments.domain.declarative + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: benchbuild.environments.domain.model + +```{eval-rst} +.. automodule:: benchbuild.environments.domain.model + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: benchbuild.environments.domain.commands + +```{eval-rst} +.. automodule:: benchbuild.environments.domain.commands + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/_sources/basics/index.md.txt b/_sources/basics/index.md.txt new file mode 100644 index 000000000..23e728dba --- /dev/null +++ b/_sources/basics/index.md.txt @@ -0,0 +1,49 @@ +# Installation + +The installation instructions are tested against Ubuntu 20.04 for Python 3.7 and Python 3.8. The particular commands required for installation depend on your setup. +The dependencies below are not always mandatory, if they are not used. + +## Requirements + +Dependency | Minimum Version | Notes +-------------|-----------------|---------------------------- +Python | 3.7 | +libpq | 9.6 | Required by psycopg2. +libfuse | 2.9.9 | If uchroot is used. +unionfs-fuse | 1.0 | If unionfs support is used. +slurm-llnl | 18.08 | If slurm support is used. + + +### PostgreSQL + +The library dependency ``libpq`` is always need right now, because we make use of psycopg2 features internally. It is planned to get rid of this dependency in the future. +### FUSE + +BenchBuild can make use of ``unionfs`` and ``libfuse``. This is often used in conjunction with a tool named ``uchroot`` which provides legacy support for user-space containers. +This will be obsolete as soon as ``podman``/``buildah`` based OCI container support is considered stable. + +### SLURM + +The cluster management software ``slurm`` is only required by 'name', i.e., we have to be able to import the binaries as python objects in benchbuild. As an alternative to installing ``slurm`` on your machine, you can always provide symlinks to ``/bin/true`` to the commands ``sbatch`` and ``srun``. + +The minimum version should signal the minimum features set expected by BenchBuild when generating a ``slurm`` batch script. + +## Benchbuild + +BenchBuild is released via pip and can be installed on your system as follows: + +``` bash +pip install benchbuild +``` + +If you want to isolate BenchBuild from the rest of your system packages, you can install it in a dedicated virtual environment. + +``` bash +virtualenv -ppython3 +source /bin/activate +pip3 install benchbuild +``` + +### Bootstrapping + +BenchBuild provides a bootstrap procedure that checks a few key binaries on your system and tries to assist you in installation of any necessary binaries. diff --git a/_sources/concepts/command.md.txt b/_sources/concepts/command.md.txt new file mode 100644 index 000000000..87fa17a2a --- /dev/null +++ b/_sources/concepts/command.md.txt @@ -0,0 +1,59 @@ +# Commands + +BenchBuild provides an abstraction for binaries that are provided by a project, +after compilation. These ``Command`` objects carry the path to the binary, +customizable output paramters and support for dynamic tokens inside the path +generation. + +Besides these features, a command behaves identical to any other binary +command that you make use of inside BenchBuild, e.g., ``benchbuild.utils.cmd``. + +## Usage inside Projects + +For now, you make use of BenchBuild's commands inside a project's ``WORKLOADS`` +attribute. Let's have a look at the following example: + +``` +from benchbuild import Project +from benchbuild.command import Command, WorkloadSet, SourceRoot + +class MyProject(Project): + ... + SOURCE = [ + Git( + remote="https://github.com/myproject.git", + local="myproject.git", + limit=1, + refspec="HEAD" + ] + + WORKLOADS = { + WorkloadSet("compression"): [ + Command(SourceRoot("myproject.git") / "myprj") + ] + } +``` + +Here we have a ``Command`` that belongs to the ``WorkloadSet`` with the name +``compression`` that points to the binary ``myprj`` inside the project's +source directory of the git source ``myproject.git``. What concrete path +this will be is only known after this project has been instanced inside +an experiment and is not known before. + +This is done using tokens inside the commands' path representation. One +example of an available token is the above ``SourceRoot``. + +## Tokens + +BenchBuild offers project authors a way to tokenize path components for +commands. These can be used to refer to a project's root directory or +source directory in a generic way. + +## Module: command + +```{eval-rst} +.. automodule:: benchbuild.command + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/_sources/concepts/environments.md.txt b/_sources/concepts/environments.md.txt new file mode 100644 index 000000000..fa34659f8 --- /dev/null +++ b/_sources/concepts/environments.md.txt @@ -0,0 +1 @@ +# Environment diff --git a/_sources/concepts/experiments.md.txt b/_sources/concepts/experiments.md.txt new file mode 100644 index 000000000..9e6d63be1 --- /dev/null +++ b/_sources/concepts/experiments.md.txt @@ -0,0 +1,3 @@ +# Experiment + +TODO. diff --git a/_sources/concepts/projects.md.txt b/_sources/concepts/projects.md.txt new file mode 100644 index 000000000..de7b96884 --- /dev/null +++ b/_sources/concepts/projects.md.txt @@ -0,0 +1,3 @@ +# Project + +TODO. diff --git a/_sources/concepts/source.md.txt b/_sources/concepts/source.md.txt new file mode 100644 index 000000000..edf9a57e5 --- /dev/null +++ b/_sources/concepts/source.md.txt @@ -0,0 +1,46 @@ +# Source + +## Base + +```{eval-rst} +.. automodule:: benchbuild.source.base + :members: + :undoc-members: + :show-inheritance: +``` + +## Git + +```{eval-rst} +.. automodule:: benchbuild.source.git + :members: + :undoc-members: + :show-inheritance: +``` + +## HTTP + +```{eval-rst} +.. automodule:: benchbuild.source.http + :members: + :undoc-members: + :show-inheritance: +``` + +## RSync + +```{eval-rst} +.. automodule:: benchbuild.source.rsync + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: source + +```{eval-rst} +.. automodule:: benchbuild.source + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 000000000..9fcef7096 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,31 @@ +.. bencbuild documentation master file, created by + sphinx-quickstart on Tue Mar 28 01:42:59 2023. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to bencbuild's documentation! +===================================== + +.. toctree:: + :caption: Contents: + + about.md + basics/index.md + basics/configuration.md + basics/containers.md + basics/actions.md + concepts/command.md + concepts/source.md + concepts/environments.md + concepts/projects.md + concepts/experiments.md + advanced/index.md + advanced/cli.md + CHANGELOG.md + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 000000000..30fee9d0f --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 000000000..d06a71d75 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 000000000..f090a7485 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '6.8', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'dirhtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/_static/file.png differ diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 000000000..250f5665f --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 000000000..d96755fda Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 000000000..7107cec93 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 000000000..0e1cdf3f3 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,85 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #49483e } +.highlight { background: #272822; color: #f8f8f2 } +.highlight .c { color: #959077 } /* Comment */ +.highlight .err { color: #ed007e; background-color: #1e0010 } /* Error */ +.highlight .esc { color: #f8f8f2 } /* Escape */ +.highlight .g { color: #f8f8f2 } /* Generic */ +.highlight .k { color: #66d9ef } /* Keyword */ +.highlight .l { color: #ae81ff } /* Literal */ +.highlight .n { color: #f8f8f2 } /* Name */ +.highlight .o { color: #ff4689 } /* Operator */ +.highlight .x { color: #f8f8f2 } /* Other */ +.highlight .p { color: #f8f8f2 } /* Punctuation */ +.highlight .ch { color: #959077 } /* Comment.Hashbang */ +.highlight .cm { color: #959077 } /* Comment.Multiline */ +.highlight .cp { color: #959077 } /* Comment.Preproc */ +.highlight .cpf { color: #959077 } /* Comment.PreprocFile */ +.highlight .c1 { color: #959077 } /* Comment.Single */ +.highlight .cs { color: #959077 } /* Comment.Special */ +.highlight .gd { color: #ff4689 } /* Generic.Deleted */ +.highlight .ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #f8f8f2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #f8f8f2 } /* Generic.Error */ +.highlight .gh { color: #f8f8f2 } /* Generic.Heading */ +.highlight .gi { color: #a6e22e } /* Generic.Inserted */ +.highlight .go { color: #66d9ef } /* Generic.Output */ +.highlight .gp { color: #ff4689; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #959077 } /* Generic.Subheading */ +.highlight .gt { color: #f8f8f2 } /* Generic.Traceback */ +.highlight .kc { color: #66d9ef } /* Keyword.Constant */ +.highlight .kd { color: #66d9ef } /* Keyword.Declaration */ +.highlight .kn { color: #ff4689 } /* Keyword.Namespace */ +.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ +.highlight .kr { color: #66d9ef } /* Keyword.Reserved */ +.highlight .kt { color: #66d9ef } /* Keyword.Type */ +.highlight .ld { color: #e6db74 } /* Literal.Date */ +.highlight .m { color: #ae81ff } /* Literal.Number */ +.highlight .s { color: #e6db74 } /* Literal.String */ +.highlight .na { color: #a6e22e } /* Name.Attribute */ +.highlight .nb { color: #f8f8f2 } /* Name.Builtin */ +.highlight .nc { color: #a6e22e } /* Name.Class */ +.highlight .no { color: #66d9ef } /* Name.Constant */ +.highlight .nd { color: #a6e22e } /* Name.Decorator */ +.highlight .ni { color: #f8f8f2 } /* Name.Entity */ +.highlight .ne { color: #a6e22e } /* Name.Exception */ +.highlight .nf { color: #a6e22e } /* Name.Function */ +.highlight .nl { color: #f8f8f2 } /* Name.Label */ +.highlight .nn { color: #f8f8f2 } /* Name.Namespace */ +.highlight .nx { color: #a6e22e } /* Name.Other */ +.highlight .py { color: #f8f8f2 } /* Name.Property */ +.highlight .nt { color: #ff4689 } /* Name.Tag */ +.highlight .nv { color: #f8f8f2 } /* Name.Variable */ +.highlight .ow { color: #ff4689 } /* Operator.Word */ +.highlight .pm { color: #f8f8f2 } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f2 } /* Text.Whitespace */ +.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ +.highlight .mf { color: #ae81ff } /* Literal.Number.Float */ +.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ +.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ +.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ +.highlight .sa { color: #e6db74 } /* Literal.String.Affix */ +.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ +.highlight .sc { color: #e6db74 } /* Literal.String.Char */ +.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ +.highlight .sd { color: #e6db74 } /* Literal.String.Doc */ +.highlight .s2 { color: #e6db74 } /* Literal.String.Double */ +.highlight .se { color: #ae81ff } /* Literal.String.Escape */ +.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ +.highlight .si { color: #e6db74 } /* Literal.String.Interpol */ +.highlight .sx { color: #e6db74 } /* Literal.String.Other */ +.highlight .sr { color: #e6db74 } /* Literal.String.Regex */ +.highlight .s1 { color: #e6db74 } /* Literal.String.Single */ +.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ +.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #a6e22e } /* Name.Function.Magic */ +.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ +.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ +.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ +.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ +.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 000000000..7918c3fab --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 000000000..8a96c69a1 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/_static/sphinx_press_theme.css b/_static/sphinx_press_theme.css new file mode 100644 index 000000000..5c439cea7 --- /dev/null +++ b/_static/sphinx_press_theme.css @@ -0,0 +1,116 @@ +/* + * + * Defines default styles specific to Sphinx Press, + * on top of VuePress styles + * + */ + + /* FONTS FOR THE CODE - will fall back to monospace if unavailable */ + +@import url('https://fontlibrary.org/face/roboto-mono'); +@import url('https://fontlibrary.org/face/inconsolata'); + +/* MAKES MAIN TEXT SECTION LARGER */ +.content:not(.custom) { + max-width: 840px; +} + +/* THE SECTION BELOW DEFINES THE APPEARANCE OF AUTODOC-GENERATED DOCS */ + +.sig-name.descname { + font-size: 1.2em; + font-weight: bold; + padding: 0 0 3px; /* creates a perfect grey rectangle*/ +} + +.sig-param { + font-family: 'RobotoMonoRegular', 'Roboto Mono', 'Inconsolata', monospace; + margin-left: 0.3em; +} + +.sig-paren { + margin-left: 0.3em; +} + +dt { + line-height: 1.5em; + margin-bottom: 1em; +} + +dt.field-odd, dt.field-even, p.rubric { + font-size: 1.2em; + font-weight: bold; + color: #4d6a86 +} + +dd { + margin-inline-start: 10px; +} + +dd.field-odd p strong { + margin-left: 1em; +} + +dl.method, dl.function { + margin-top: 2em; + margin-bottom: 3em; +} + +.viewcode-link { + margin-left: 1em; + color: #9ad8bc; +} + +/* THE SECTION BELOW DEFINES THE APPEARANCE OF TABLE-OF-CONTENTS */ + +/* color fixes for table of contents */ +.toc-backref { + /* TOCS cause all your section titles to go green. Pouah! */ + color: inherit; +} + +.contents.topic p.topic-title { + /* Hide all TOC titles */ + display: none; +} + +.contents.topic { + margin-bottom: 3em; +} + + +/* THE SECTION BELOW CHANGES CODE FONTS FOR BETTER 80-CHARS READABILITY */ +/* Code will be displayed as Roboto, or Inconsolata if screen is small */ +code, pre { + font-family: 'RobotoMonoRegular', 'Roboto Mono', 'Inconsolata', monospace; +} + +@media (max-width: 1200px) { + code, pre { + font-family: 'InconsolataRegular', 'Inconsolata', 'RobotoMonoRegular', 'Roboto Mono', monospace; + } + pre { + font-size: 0.95em; + } +} + +blockquote { + font-size: inherit; +} + +blockquote h2 { + margin-left: 1em; +} + +/* THE SECTION BELOW FIXES A SPHINX-MERMAID OPACITY PROBLEM */ +.content .section { + opacity: 1.0 !important; +} +.section { + opacity: 1.0 !important; +} + +/* MAKES SPHINX SYNTAX figure:: :align:center WORK AGAIN */ +.figure.align-center { + text-align: center +} \ No newline at end of file diff --git a/_static/theme.css b/_static/theme.css new file mode 100644 index 000000000..409bbb9c1 --- /dev/null +++ b/_static/theme.css @@ -0,0 +1 @@ +.page{margin-left:10px;margin-right:10px}dd p,li p,table p{margin:0}.content{max-width:840px;margin:0 auto}.content pre{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.content .footnote-reference,.content .label,.content .reference{scroll-margin-top:3.6rem}.content a:focus{outline:0}.content:not(.custom){max-width:840px}.content section{scroll-margin-top:4.1rem;margin-bottom:0}.content section:hover .headerlink{opacity:1}h1:hover a.headerlink::after,h2:hover a.headerlink::after,h3:hover a.headerlink::after,h4:hover a.headerlink::after,h5:hover a.headerlink::after,h6:hover a.headerlink::after{visibility:visible;content:"#"}a.headerlink{font-size:.85em;visibility:hidden}a.headerlink:hover{text-decoration:none}ul.page-nav{list-style:none}ul.page-nav li{display:inline-block}.body-header{display:flex}.body-header ul.page-nav{flex-grow:1;list-style:none;list-style-position:inside;text-align:right;margin-right:30px}.body-header ul.page-nav li+li:before{content:"|";padding:0 1em}ul.breadcrumbs{list-style:none}ul.breadcrumbs li{display:inline-block;margin-right:5px}.toc-backref{color:inherit}.contents.topic p.topic-title{display:none}.contents.topic{margin-bottom:3em}aside.sidebar{margin:0 0 .5em 1em;border:1px solid #ddb;padding:7px;background-color:#ffe;width:40%;float:right;clear:right;overflow-x:auto}p.sidebar-title{font-weight:700}blockquote,div.admonition,div.topic{clear:left}div[class*=highlight-],pre{clear:both}.toctree-wrapper .caption{font-weight:600;line-height:1.25;font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}.footer{clear:both;min-height:2rem;padding-top:1rem;overflow:auto;color:grey;font-size:small;line-height:1.5rem}.content .highlight{border-radius:6px}.content .highlight pre{background-color:inherit}.content .highlighted{background-color:#fbe54e;font-weight:700;padding:0 4px}.admonition{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0;background-color:#e2e2e2;border-color:#787878}.admonition .admonition-title{font-weight:600;margin-bottom:-.4rem}.admonition.hint,.admonition.tip{background-color:#f3f5f7;border-color:#42b983}.admonition.important,.admonition.note{background-color:#e5f1fb;border-color:#5faaea}.admonition.caution,.admonition.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.admonition.caution .custom-block-title,.admonition.warning .custom-block-title{color:#b29400}.admonition.caution a,.admonition.warning a{color:#2c3e50}.admonition.danger,.admonition.error{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.admonition.danger .custom-block-title,.admonition.error .custom-block-title{color:#900}.admonition.danger a,.admonition.error a{color:#2c3e50}.line-block{display:block;margin-top:1em;margin-bottom:1em}.line-block .line-block{margin-top:0;margin-bottom:0;margin-left:1.5em}.guilabel,.menuselection{font-family:sans-serif}.accelerator{text-decoration:underline}.classifier{font-style:oblique}.classifier:before{font-style:normal;margin:.5em;content:":"}abbr,acronym{border-bottom:dotted 1px;cursor:help}div.topic{border:1px solid #ccc;padding:7px;margin:10px 0 10px 0;background-color:#f7f7f7}p.topic-title{font-size:1.1em;font-weight:700;margin-top:10px}a.brackets:before,span.brackets>a:before{content:"["}a.brackets:after,span.brackets>a:after{content:"]"}p.rubric{margin-top:30px;font-weight:700}.pre,code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace}@media (max-width:1200px){pre{font-size:.95em}}blockquote{font-size:inherit}blockquote h2{margin-left:1em}.sig .property{color:#4d6a86;padding-right:.25rem}.sig-name.descname{font-size:1.2em;font-weight:700;padding:0 0 3px}.sig-param{margin-left:.3em}.sig-paren{margin-left:.3em}dt{line-height:1.5em;margin-top:1em;font-weight:700}dt.field-even,dt.field-odd,p.rubric{font-size:1.2em;font-weight:700;color:#4d6a86}dd{margin-inline-start:10px}dd.field-odd p strong{margin-left:1em}dl.function,dl.method{margin-top:1em;margin-bottom:2em}.viewcode-link{margin-left:1em;color:#9ad8bc}dl.field-list{display:grid;grid-template-columns:fit-content(30%) auto}dl.field-list dt{margin-top:0}dl.field-list dd{margin-bottom:1em}dl.field-list>dt{font-weight:700;word-break:break-word;padding-left:.5em;padding-right:5px}dl.field-list>dt:after{content:":"}dl.field-list>dd{padding-left:.5em;margin-top:0;margin-left:0;margin-bottom:0}dl{margin-bottom:15px}.figure.align-left,figure.align-left,img.align-left,object.align-left{clear:left;float:left;margin-right:1em}.figure.align-right,figure.align-right,img.align-right,object.align-right{clear:right;float:right;margin-left:1em}.figure.align-center,figure.align-center,img.align-center,object.align-center{display:block;margin-left:auto;margin-right:auto}.figure.align-default,figure.align-default,img.align-default{display:block;margin-left:auto;margin-right:auto}.align-left{text-align:left}.align-center{text-align:center}.align-default{text-align:center}.align-right{text-align:right}.content .section{opacity:1!important}.section{opacity:1!important}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre code,.theme-default-content pre[class*=language-] code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:0 0;position:relative;z-index:1}div[class*=language-]::before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:rgba(255,255,255,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:' ';position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:rgba(255,255,255,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode::after{content:'';position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~="language-$codeLang"]:before{content:'$codeLang'}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:0;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:6px solid #ccc}.arrow.down{border-left:4px solid transparent;border-right:4px solid transparent;border-top:6px solid #ccc}.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:6px solid #ccc}.arrow.left{border-top:4px solid transparent;border-bottom:4px solid transparent;border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{position:fixed;z-index:20;top:0;left:0;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.sidebar-mask{position:fixed;z-index:9;top:0;left:0;width:100vw;height:100vh;display:none}.vp-sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;color:#3eaf7c;text-decoration:none}p a code{font-weight:400;color:#3eaf7c}kbd{background:#eee;border:solid .15rem #ddd;border-bottom:solid .25rem #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,"Courier New",monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .vp-sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .vp-sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.vp-sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.vp-sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .vp-sidebar{transform:translateX(0)}.theme-container.no-navbar .vp-sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}.page{margin-left:10px;margin-right:10px}dd p,li p,table p{margin:0}.content{max-width:840px;margin:0 auto}.content pre{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.content .footnote-reference,.content .label,.content .reference{scroll-margin-top:3.6rem}.content a:focus{outline:0}.content:not(.custom){max-width:840px}.content section{scroll-margin-top:4.1rem;margin-bottom:0}.content section:hover .headerlink{opacity:1}h1:hover a.headerlink::after,h2:hover a.headerlink::after,h3:hover a.headerlink::after,h4:hover a.headerlink::after,h5:hover a.headerlink::after,h6:hover a.headerlink::after{visibility:visible;content:"#"}a.headerlink{font-size:.85em;visibility:hidden}a.headerlink:hover{text-decoration:none}ul.page-nav{list-style:none}ul.page-nav li{display:inline-block}.body-header{display:flex}.body-header ul.page-nav{flex-grow:1;list-style:none;list-style-position:inside;text-align:right;margin-right:30px}.body-header ul.page-nav li+li:before{content:"|";padding:0 1em}ul.breadcrumbs{list-style:none}ul.breadcrumbs li{display:inline-block;margin-right:5px}.toc-backref{color:inherit}.contents.topic p.topic-title{display:none}.contents.topic{margin-bottom:3em}aside.sidebar{margin:0 0 .5em 1em;border:1px solid #ddb;padding:7px;background-color:#ffe;width:40%;float:right;clear:right;overflow-x:auto}p.sidebar-title{font-weight:700}blockquote,div.admonition,div.topic{clear:left}div[class*=highlight-],pre{clear:both}.toctree-wrapper .caption{font-weight:600;line-height:1.25;font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}.footer{clear:both;min-height:2rem;padding-top:1rem;overflow:auto;color:grey;font-size:small;line-height:1.5rem}.content .highlight{border-radius:6px}.content .highlight pre{background-color:inherit}.content .highlighted{background-color:#fbe54e;font-weight:700;padding:0 4px}.admonition{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0;background-color:#e2e2e2;border-color:#787878}.admonition .admonition-title{font-weight:600;margin-bottom:-.4rem}.admonition.hint,.admonition.tip{background-color:#f3f5f7;border-color:#42b983}.admonition.important,.admonition.note{background-color:#e5f1fb;border-color:#5faaea}.admonition.caution,.admonition.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.admonition.caution .custom-block-title,.admonition.warning .custom-block-title{color:#b29400}.admonition.caution a,.admonition.warning a{color:#2c3e50}.admonition.danger,.admonition.error{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.admonition.danger .custom-block-title,.admonition.error .custom-block-title{color:#900}.admonition.danger a,.admonition.error a{color:#2c3e50}.line-block{display:block;margin-top:1em;margin-bottom:1em}.line-block .line-block{margin-top:0;margin-bottom:0;margin-left:1.5em}.guilabel,.menuselection{font-family:sans-serif}.accelerator{text-decoration:underline}.classifier{font-style:oblique}.classifier:before{font-style:normal;margin:.5em;content:":"}abbr,acronym{border-bottom:dotted 1px;cursor:help}div.topic{border:1px solid #ccc;padding:7px;margin:10px 0 10px 0;background-color:#f7f7f7}p.topic-title{font-size:1.1em;font-weight:700;margin-top:10px}a.brackets:before,span.brackets>a:before{content:"["}a.brackets:after,span.brackets>a:after{content:"]"}p.rubric{margin-top:30px;font-weight:700}.pre,code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace}@media (max-width:1200px){pre{font-size:.95em}}blockquote{font-size:inherit}blockquote h2{margin-left:1em}.sig .property{color:#4d6a86;padding-right:.25rem}.sig-name.descname{font-size:1.2em;font-weight:700;padding:0 0 3px}.sig-param{margin-left:.3em}.sig-paren{margin-left:.3em}dt{line-height:1.5em;margin-top:1em;font-weight:700}dt.field-even,dt.field-odd,p.rubric{font-size:1.2em;font-weight:700;color:#4d6a86}dd{margin-inline-start:10px}dd.field-odd p strong{margin-left:1em}dl.function,dl.method{margin-top:1em;margin-bottom:2em}.viewcode-link{margin-left:1em;color:#9ad8bc}dl.field-list{display:grid;grid-template-columns:fit-content(30%) auto}dl.field-list dt{margin-top:0}dl.field-list dd{margin-bottom:1em}dl.field-list>dt{font-weight:700;word-break:break-word;padding-left:.5em;padding-right:5px}dl.field-list>dt:after{content:":"}dl.field-list>dd{padding-left:.5em;margin-top:0;margin-left:0;margin-bottom:0}dl{margin-bottom:15px}.figure.align-left,figure.align-left,img.align-left,object.align-left{clear:left;float:left;margin-right:1em}.figure.align-right,figure.align-right,img.align-right,object.align-right{clear:right;float:right;margin-left:1em}.figure.align-center,figure.align-center,img.align-center,object.align-center{display:block;margin-left:auto;margin-right:auto}.figure.align-default,figure.align-default,img.align-default{display:block;margin-left:auto;margin-right:auto}.align-left{text-align:left}.align-center{text-align:center}.align-default{text-align:center}.align-right{text-align:right}.content .section{opacity:1!important}.section{opacity:1!important}.page{margin-left:10px;margin-right:10px}dd p,li p,table p{margin:0}.content{max-width:840px;margin:0 auto}.content pre{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.content .footnote-reference,.content .label,.content .reference{scroll-margin-top:3.6rem}.content a:focus{outline:0}.content:not(.custom){max-width:840px}.content section{scroll-margin-top:4.1rem;margin-bottom:0}.content section:hover .headerlink{opacity:1}h1:hover a.headerlink::after,h2:hover a.headerlink::after,h3:hover a.headerlink::after,h4:hover a.headerlink::after,h5:hover a.headerlink::after,h6:hover a.headerlink::after{visibility:visible;content:"#"}a.headerlink{font-size:.85em;visibility:hidden}a.headerlink:hover{text-decoration:none}ul.page-nav{list-style:none}ul.page-nav li{display:inline-block}.body-header{display:flex}.body-header ul.page-nav{flex-grow:1;list-style:none;list-style-position:inside;text-align:right;margin-right:30px}.body-header ul.page-nav li+li:before{content:"|";padding:0 1em}ul.breadcrumbs{list-style:none}ul.breadcrumbs li{display:inline-block;margin-right:5px}.toc-backref{color:inherit}.contents.topic p.topic-title{display:none}.contents.topic{margin-bottom:3em}aside.sidebar{margin:0 0 .5em 1em;border:1px solid #ddb;padding:7px;background-color:#ffe;width:40%;float:right;clear:right;overflow-x:auto}p.sidebar-title{font-weight:700}blockquote,div.admonition,div.topic{clear:left}div[class*=highlight-],pre{clear:both}.toctree-wrapper .caption{font-weight:600;line-height:1.25;font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}.footer{clear:both;min-height:2rem;padding-top:1rem;overflow:auto;color:grey;font-size:small;line-height:1.5rem}.content .highlight{border-radius:6px}.content .highlight pre{background-color:inherit}.content .highlighted{background-color:#fbe54e;font-weight:700;padding:0 4px}.admonition{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0;background-color:#e2e2e2;border-color:#787878}.admonition .admonition-title{font-weight:600;margin-bottom:-.4rem}.admonition.hint,.admonition.tip{background-color:#f3f5f7;border-color:#42b983}.admonition.important,.admonition.note{background-color:#e5f1fb;border-color:#5faaea}.admonition.caution,.admonition.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.admonition.caution .custom-block-title,.admonition.warning .custom-block-title{color:#b29400}.admonition.caution a,.admonition.warning a{color:#2c3e50}.admonition.danger,.admonition.error{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.admonition.danger .custom-block-title,.admonition.error .custom-block-title{color:#900}.admonition.danger a,.admonition.error a{color:#2c3e50}.line-block{display:block;margin-top:1em;margin-bottom:1em}.line-block .line-block{margin-top:0;margin-bottom:0;margin-left:1.5em}.guilabel,.menuselection{font-family:sans-serif}.accelerator{text-decoration:underline}.classifier{font-style:oblique}.classifier:before{font-style:normal;margin:.5em;content:":"}abbr,acronym{border-bottom:dotted 1px;cursor:help}div.topic{border:1px solid #ccc;padding:7px;margin:10px 0 10px 0;background-color:#f7f7f7}p.topic-title{font-size:1.1em;font-weight:700;margin-top:10px}a.brackets:before,span.brackets>a:before{content:"["}a.brackets:after,span.brackets>a:after{content:"]"}p.rubric{margin-top:30px;font-weight:700}.pre,code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace}@media (max-width:1200px){pre{font-size:.95em}}blockquote{font-size:inherit}blockquote h2{margin-left:1em}.sig .property{color:#4d6a86;padding-right:.25rem}.sig-name.descname{font-size:1.2em;font-weight:700;padding:0 0 3px}.sig-param{margin-left:.3em}.sig-paren{margin-left:.3em}dt{line-height:1.5em;margin-top:1em;font-weight:700}dt.field-even,dt.field-odd,p.rubric{font-size:1.2em;font-weight:700;color:#4d6a86}dd{margin-inline-start:10px}dd.field-odd p strong{margin-left:1em}dl.function,dl.method{margin-top:1em;margin-bottom:2em}.viewcode-link{margin-left:1em;color:#9ad8bc}dl.field-list{display:grid;grid-template-columns:fit-content(30%) auto}dl.field-list dt{margin-top:0}dl.field-list dd{margin-bottom:1em}dl.field-list>dt{font-weight:700;word-break:break-word;padding-left:.5em;padding-right:5px}dl.field-list>dt:after{content:":"}dl.field-list>dd{padding-left:.5em;margin-top:0;margin-left:0;margin-bottom:0}dl{margin-bottom:15px}.figure.align-left,figure.align-left,img.align-left,object.align-left{clear:left;float:left;margin-right:1em}.figure.align-right,figure.align-right,img.align-right,object.align-right{clear:right;float:right;margin-left:1em}.figure.align-center,figure.align-center,img.align-center,object.align-center{display:block;margin-left:auto;margin-right:auto}.figure.align-default,figure.align-default,img.align-default{display:block;margin-left:auto;margin-right:auto}.align-left{text-align:left}.align-center{text-align:center}.align-default{text-align:center}.align-right{text-align:right}.content .section{opacity:1!important}.section{opacity:1!important}.icon.outbound{color:#aaa;display:inline-block}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:$MQMobile){.sidebar-button{display:block}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem;position:fixed}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{font-size:.9rem;position:absolute;right:1.5rem;top:.7rem}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.sidebar-button{display:block}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#3eaf7c}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #46bd87}}.vp-sidebar ul{padding:0;margin:0;list-style-type:none}.vp-sidebar a{display:inline-block}.vp-sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem 0}.vp-sidebar .nav-links a{font-weight:600}.vp-sidebar .nav-links .nav-item,.vp-sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.vp-sidebar .searchbox{font-weight:600;font-size:1.1em;line-height:1.5rem;padding:1rem 0 1.5rem .75rem;border-bottom:1px solid #eaecef}.vp-sidebar .sidebar-links{padding:1.5rem 0}@media (max-width:719px){.vp-sidebar .nav-links{display:block}.vp-sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after{top:calc(1rem - 2px)}.vp-sidebar .sidebar-links{padding:1rem 0}}.sidebar-group:not(.first){margin-top:1em}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .caption{cursor:auto;color:inherit}.sidebar-group .caption{color:#999;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:0 1.5rem;margin-top:0;margin-bottom:.5rem}.sidebar-group .caption.open,.sidebar-group .caption:hover{color:inherit}.sidebar-group .caption .arrow{position:relative;top:-.12em;left:.5em}.sidebar-group .caption:.open .arrow{top:-.18em}.sidebar-group-items{transition:height .1s ease-out;overflow:hidden}.vp-sidebar .toctree-l1 ul{font-size:.95em}.vp-sidebar .toctree-l1 a,.vp-sidebar .toctree-l2 a{font-weight:400;display:inline-block;color:#2c3e50;line-height:1.4;width:100%;box-sizing:border-box;border-left:.5rem solid transparent}.vp-sidebar .toctree-l1 a.current,.vp-sidebar .toctree-l2 a.current{color:#3eaf7c;font-weight:600}.vp-sidebar .toctree-l1 a:hover,.vp-sidebar .toctree-l2 a:hover{color:#3eaf7c}.vp-sidebar .toctree-l1.current a{border-left:.5rem solid #86d4b1}.vp-sidebar .toctree-l1 a{padding:.35rem 1rem .35rem 1.25rem}.vp-sidebar .toctree-l1 a.current{border-left-color:#3eaf7c}.vp-sidebar .toctree-l2 a{padding:.25rem 1rem .25rem 1.75rem}.page-edit,.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit,.page-nav{padding:2rem}}@media (max-width:419px){.page-edit,.page-nav{padding:1.5rem}}.page{padding-top:3.6rem;padding-bottom:2rem}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#aaa}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}} \ No newline at end of file diff --git a/_static/theme.js b/_static/theme.js new file mode 100644 index 000000000..37bbfe687 --- /dev/null +++ b/_static/theme.js @@ -0,0 +1 @@ +!function(){"use strict";function e(e,t){const n=Object.create(null),o=e.split(",");for(let r=0;r!!n[e.toLowerCase()]:e=>!!n[e]}const t=e("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt"),n=e("itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly");function o(e){if(w(e)){const t={};for(let n=0;n{if(e){const n=e.split(s);n.length>1&&(t[n[0].trim()]=n[1].trim())}})),t}function l(e){let t="";if(F(e))t=e;else if(w(e))for(let n=0;np(e,t)))}const d=(e,t)=>T(t)?{[`Map(${t.size})`]:[...t.entries()].reduce(((e,[t,n])=>(e[`${t} =>`]=n,e)),{})}:E(t)?{[`Set(${t.size})`]:[...t.values()]}:!A(t)||w(t)||R(t)?t:String(t),h={},m=[],g=()=>{},v=()=>!1,y=/^on[^a-z]/,b=e=>y.test(e),_=e=>e.startsWith("onUpdate:"),x=Object.assign,S=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},C=Object.prototype.hasOwnProperty,k=(e,t)=>C.call(e,t),w=Array.isArray,T=e=>"[object Map]"===B(e),E=e=>"[object Set]"===B(e),N=e=>e instanceof Date,$=e=>"function"==typeof e,F=e=>"string"==typeof e,M=e=>"symbol"==typeof e,A=e=>null!==e&&"object"==typeof e,I=e=>A(e)&&$(e.then)&&$(e.catch),O=Object.prototype.toString,B=e=>O.call(e),R=e=>"[object Object]"===B(e),V=e=>F(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,P=e(",key,ref,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),L=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},j=/-(\w)/g,U=L((e=>e.replace(j,((e,t)=>t?t.toUpperCase():"")))),H=/\B([A-Z])/g,D=L((e=>e.replace(H,"-$1").toLowerCase())),z=L((e=>e.charAt(0).toUpperCase()+e.slice(1))),W=L((e=>e?`on${z(e)}`:"")),K=(e,t)=>e!==t&&(e==e||t==t),G=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},J=e=>{const t=parseFloat(e);return isNaN(t)?e:t},Z=new WeakMap,Q=[];let X;const Y=Symbol(""),ee=Symbol("");function te(e,t=h){(function(e){return e&&!0===e._isEffect})(e)&&(e=e.raw);const n=function(e,t){const n=function(){if(!n.active)return t.scheduler?void 0:e();if(!Q.includes(n)){re(n);try{return ie.push(se),se=!0,Q.push(n),X=n,e()}finally{Q.pop(),ce(),X=Q[Q.length-1]}}};return n.id=oe++,n.allowRecurse=!!t.allowRecurse,n._isEffect=!0,n.active=!0,n.raw=e,n.deps=[],n.options=t,n}(e,t);return t.lazy||n(),n}function ne(e){e.active&&(re(e),e.options.onStop&&e.options.onStop(),e.active=!1)}let oe=0;function re(e){const{deps:t}=e;if(t.length){for(let n=0;n{e&&e.forEach((e=>{(e!==X||e.allowRecurse)&&l.add(e)}))};if("clear"===t)i.forEach(c);else if("length"===n&&w(e))i.forEach(((e,t)=>{("length"===t||t>=o)&&c(e)}));else switch(void 0!==n&&c(i.get(n)),t){case"add":w(e)?V(n)&&c(i.get("length")):(c(i.get(Y)),T(e)&&c(i.get(ee)));break;case"delete":w(e)||(c(i.get(Y)),T(e)&&c(i.get(ee)));break;case"set":T(e)&&c(i.get(Y))}l.forEach((e=>{e.options.scheduler?e.options.scheduler(e):e()}))}const pe=e("__proto__,__v_isRef,__isVue"),fe=new Set(Object.getOwnPropertyNames(Symbol).map((e=>Symbol[e])).filter(M)),de=ye(),he=ye(!1,!0),me=ye(!0),ge=ye(!0,!0),ve={};function ye(e=!1,t=!1){return function(n,o,r){if("__v_isReactive"===o)return!e;if("__v_isReadonly"===o)return e;if("__v_raw"===o&&r===(e?t?Ze:Je:t?qe:Ge).get(n))return n;const s=w(n);if(!e&&s&&k(ve,o))return Reflect.get(ve,o,r);const i=Reflect.get(n,o,r);if(M(o)?fe.has(o):pe(o))return i;if(e||ae(n,0,o),t)return i;if(lt(i)){return!s||!V(o)?i.value:i}return A(i)?e?et(i):Xe(i):i}}["includes","indexOf","lastIndexOf"].forEach((e=>{const t=Array.prototype[e];ve[e]=function(...e){const n=st(this);for(let t=0,r=this.length;t{const t=Array.prototype[e];ve[e]=function(...e){le();const n=t.apply(this,e);return ce(),n}}));function be(e=!1){return function(t,n,o,r){let s=t[n];if(!e&&(o=st(o),s=st(s),!w(t)&<(s)&&!lt(o)))return s.value=o,!0;const i=w(t)&&V(n)?Number(n)!0,deleteProperty:(e,t)=>!0},Se=x({},_e,{get:he,set:be(!0)}),Ce=x({},xe,{get:ge}),ke=e=>A(e)?Xe(e):e,we=e=>A(e)?et(e):e,Te=e=>e,Ee=e=>Reflect.getPrototypeOf(e);function Ne(e,t,n=!1,o=!1){const r=st(e=e.__v_raw),s=st(t);t!==s&&!n&&ae(r,0,t),!n&&ae(r,0,s);const{has:i}=Ee(r),l=o?Te:n?we:ke;return i.call(r,t)?l(e.get(t)):i.call(r,s)?l(e.get(s)):void 0}function $e(e,t=!1){const n=this.__v_raw,o=st(n),r=st(e);return e!==r&&!t&&ae(o,0,e),!t&&ae(o,0,r),e===r?n.has(e):n.has(e)||n.has(r)}function Fe(e,t=!1){return e=e.__v_raw,!t&&ae(st(e),0,Y),Reflect.get(e,"size",e)}function Me(e){e=st(e);const t=st(this);return Ee(t).has.call(t,e)||(t.add(e),ue(t,"add",e,e)),this}function Ae(e,t){t=st(t);const n=st(this),{has:o,get:r}=Ee(n);let s=o.call(n,e);s||(e=st(e),s=o.call(n,e));const i=r.call(n,e);return n.set(e,t),s?K(t,i)&&ue(n,"set",e,t):ue(n,"add",e,t),this}function Ie(e){const t=st(this),{has:n,get:o}=Ee(t);let r=n.call(t,e);r||(e=st(e),r=n.call(t,e)),o&&o.call(t,e);const s=t.delete(e);return r&&ue(t,"delete",e,void 0),s}function Oe(){const e=st(this),t=0!==e.size,n=e.clear();return t&&ue(e,"clear",void 0,void 0),n}function Be(e,t){return function(n,o){const r=this,s=r.__v_raw,i=st(s),l=t?Te:e?we:ke;return!e&&ae(i,0,Y),s.forEach(((e,t)=>n.call(o,l(e),l(t),r)))}}function Re(e,t,n){return function(...o){const r=this.__v_raw,s=st(r),i=T(s),l="entries"===e||e===Symbol.iterator&&i,c="keys"===e&&i,a=r[e](...o),u=n?Te:t?we:ke;return!t&&ae(s,0,c?ee:Y),{next(){const{value:e,done:t}=a.next();return t?{value:e,done:t}:{value:l?[u(e[0]),u(e[1])]:u(e),done:t}},[Symbol.iterator](){return this}}}}function Ve(e){return function(...t){return"delete"!==e&&this}}const Pe={get(e){return Ne(this,e)},get size(){return Fe(this)},has:$e,add:Me,set:Ae,delete:Ie,clear:Oe,forEach:Be(!1,!1)},Le={get(e){return Ne(this,e,!1,!0)},get size(){return Fe(this)},has:$e,add:Me,set:Ae,delete:Ie,clear:Oe,forEach:Be(!1,!0)},je={get(e){return Ne(this,e,!0)},get size(){return Fe(this,!0)},has(e){return $e.call(this,e,!0)},add:Ve("add"),set:Ve("set"),delete:Ve("delete"),clear:Ve("clear"),forEach:Be(!0,!1)},Ue={get(e){return Ne(this,e,!0,!0)},get size(){return Fe(this,!0)},has(e){return $e.call(this,e,!0)},add:Ve("add"),set:Ve("set"),delete:Ve("delete"),clear:Ve("clear"),forEach:Be(!0,!0)};function He(e,t){const n=t?e?Ue:Le:e?je:Pe;return(t,o,r)=>"__v_isReactive"===o?!e:"__v_isReadonly"===o?e:"__v_raw"===o?t:Reflect.get(k(n,o)&&o in t?n:t,o,r)}["keys","values","entries",Symbol.iterator].forEach((e=>{Pe[e]=Re(e,!1,!1),je[e]=Re(e,!0,!1),Le[e]=Re(e,!1,!0),Ue[e]=Re(e,!0,!0)}));const De={get:He(!1,!1)},ze={get:He(!1,!0)},We={get:He(!0,!1)},Ke={get:He(!0,!0)},Ge=new WeakMap,qe=new WeakMap,Je=new WeakMap,Ze=new WeakMap;function Qe(e){return e.__v_skip||!Object.isExtensible(e)?0:function(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}((e=>B(e).slice(8,-1))(e))}function Xe(e){return e&&e.__v_isReadonly?e:tt(e,!1,_e,De,Ge)}function Ye(e){return tt(e,!1,Se,ze,qe)}function et(e){return tt(e,!0,xe,We,Je)}function tt(e,t,n,o,r){if(!A(e))return e;if(e.__v_raw&&(!t||!e.__v_isReactive))return e;const s=r.get(e);if(s)return s;const i=Qe(e);if(0===i)return e;const l=new Proxy(e,2===i?o:n);return r.set(e,l),l}function nt(e){return ot(e)?nt(e.__v_raw):!(!e||!e.__v_isReactive)}function ot(e){return!(!e||!e.__v_isReadonly)}function rt(e){return nt(e)||ot(e)}function st(e){return e&&st(e.__v_raw)||e}const it=e=>A(e)?Xe(e):e;function lt(e){return Boolean(e&&!0===e.__v_isRef)}function ct(e){return ut(e)}class at{constructor(e,t=!1){this._rawValue=e,this._shallow=t,this.__v_isRef=!0,this._value=t?e:it(e)}get value(){return ae(st(this),0,"value"),this._value}set value(e){K(st(e),this._rawValue)&&(this._rawValue=e,this._value=this._shallow?e:it(e),ue(st(this),"set","value",e))}}function ut(e,t=!1){return lt(e)?e:new at(e,t)}function pt(e){return lt(e)?e.value:e}const ft={get:(e,t,n)=>pt(Reflect.get(e,t,n)),set:(e,t,n,o)=>{const r=e[t];return lt(r)&&!lt(n)?(r.value=n,!0):Reflect.set(e,t,n,o)}};function dt(e){return nt(e)?e:new Proxy(e,ft)}class ht{constructor(e){this.__v_isRef=!0;const{get:t,set:n}=e((()=>ae(this,0,"value")),(()=>ue(this,"set","value")));this._get=t,this._set=n}get value(){return this._get()}set value(e){this._set(e)}}class mt{constructor(e,t){this._object=e,this._key=t,this.__v_isRef=!0}get value(){return this._object[this._key]}set value(e){this._object[this._key]=e}}function gt(e,t){return lt(e[t])?e[t]:new mt(e,t)}class vt{constructor(e,t,n){this._setter=t,this._dirty=!0,this.__v_isRef=!0,this.effect=te(e,{lazy:!0,scheduler:()=>{this._dirty||(this._dirty=!0,ue(st(this),"set","value"))}}),this.__v_isReadonly=n}get value(){const e=st(this);return e._dirty&&(e._value=this.effect(),e._dirty=!1),ae(e,0,"value"),e._value}set value(e){this._setter(e)}}const yt=[];function bt(e,...t){le();const n=yt.length?yt[yt.length-1].component:null,o=n&&n.appContext.config.warnHandler,r=function(){let e=yt[yt.length-1];if(!e)return[];const t=[];for(;e;){const n=t[0];n&&n.vnode===e?n.recurseCount++:t.push({vnode:e,recurseCount:0});const o=e.component&&e.component.parent;e=o&&o.vnode}return t}();if(o)St(o,n,11,[e+t.join(""),n&&n.proxy,r.map((({vnode:e})=>`at <${Rr(n,e.type)}>`)).join("\n"),r]);else{const n=[`[Vue warn]: ${e}`,...t];r.length&&n.push("\n",...function(e){const t=[];return e.forEach(((e,n)=>{t.push(...0===n?[]:["\n"],...function({vnode:e,recurseCount:t}){const n=t>0?`... (${t} recursive calls)`:"",o=!!e.component&&null==e.component.parent,r=` at <${Rr(e.component,e.type,o)}`,s=">"+n;return e.props?[r,..._t(e.props),s]:[r+s]}(e))})),t}(r)),console.warn(...n)}ce()}function _t(e){const t=[],n=Object.keys(e);return n.slice(0,3).forEach((n=>{t.push(...xt(n,e[n]))})),n.length>3&&t.push(" ..."),t}function xt(e,t,n){return F(t)?(t=JSON.stringify(t),n?t:[`${e}=${t}`]):"number"==typeof t||"boolean"==typeof t||null==t?n?t:[`${e}=${t}`]:lt(t)?(t=xt(e,st(t.value),!0),n?t:[`${e}=Ref<`,t,">"]):$(t)?[`${e}=fn${t.name?`<${t.name}>`:""}`]:(t=st(t),n?t:[`${e}=`,t])}function St(e,t,n,o){let r;try{r=o?e(...o):e()}catch(s){kt(s,t,n)}return r}function Ct(e,t,n,o){if($(e)){const r=St(e,t,n,o);return r&&I(r)&&r.catch((e=>{kt(e,t,n)})),r}const r=[];for(let s=0;s>>1;Wt(Et[e])-1?Et.splice(t,0,e):Et.push(e),jt()}}function jt(){wt||Tt||(Tt=!0,Rt=Bt.then(Kt))}function Ut(e,t,n,o){w(e)?n.push(...e):t&&t.includes(e,e.allowRecurse?o+1:o)||n.push(e),jt()}function Ht(e){Ut(e,It,At,Ot)}function Dt(e,t=null){if($t.length){for(Vt=t,Ft=[...new Set($t)],$t.length=0,Mt=0;MtWt(e)-Wt(t))),Ot=0;Otnull==e.id?1/0:e.id;function Kt(e){Tt=!1,wt=!0,Dt(e),Et.sort(((e,t)=>Wt(e)-Wt(t)));try{for(Nt=0;Nte.trim())):t&&(r=n.map(J))}let l,c=o[l=W(t)]||o[l=W(U(t))];!c&&s&&(c=o[l=W(D(t))]),c&&Ct(c,e,6,r);const a=o[l+"Once"];if(a){if(e.emitted){if(e.emitted[l])return}else(e.emitted={})[l]=!0;Ct(a,e,6,r)}}function Jt(e,t,n=!1){if(!t.deopt&&void 0!==e.__emits)return e.__emits;const o=e.emits;let r={},s=!1;if(!$(e)){const o=e=>{const n=Jt(e,t,!0);n&&(s=!0,x(r,n))};!n&&t.mixins.length&&t.mixins.forEach(o),e.extends&&o(e.extends),e.mixins&&e.mixins.forEach(o)}return o||s?(w(o)?o.forEach((e=>r[e]=null)):x(r,o),e.__emits=r):e.__emits=null}function Zt(e,t){return!(!e||!b(t))&&(t=t.slice(2).replace(/Once$/,""),k(e,t[0].toLowerCase()+t.slice(1))||k(e,D(t))||k(e,t))}let Qt=0;const Xt=e=>Qt+=e;function Yt(e,t,n={},o,r){let s=e[t];Qt++,Wo();const i=s&&en(s(n)),l=qo(Lo,{key:n.key||`_${t}`},i||(o?o():[]),i&&1===e._?64:-2);return!r&&l.scopeId&&(l.slotScopeIds=[l.scopeId+"-s"]),Qt--,l}function en(e){return e.some((e=>!Jo(e)||e.type!==Uo&&!(e.type===Lo&&!en(e.children))))?e:null}let tn=null,nn=null;function on(e){const t=tn;return tn=e,nn=e&&e.type.__scopeId||null,t}function rn(e,t=tn){if(!t)return e;const n=(...n)=>{Qt||Wo(!0);const o=on(t),r=e(...n);return on(o),Qt||Ko(),r};return n._c=!0,n}function sn(e){const{type:t,vnode:n,proxy:o,withProxy:r,props:s,propsOptions:[i],slots:l,attrs:c,emit:a,render:u,renderCache:p,data:f,setupState:d,ctx:h}=e;let m;const g=on(e);try{let e;if(4&n.shapeFlag){const t=r||o;m=or(u.call(t,t,p,s,d,f,h)),e=c}else{const n=t;0,m=or(n.length>1?n(s,{attrs:c,slots:l,emit:a}):n(s,null)),e=t.props?c:cn(c)}let g=m;if(!1!==t.inheritAttrs&&e){const t=Object.keys(e),{shapeFlag:n}=g;t.length&&(1&n||6&n)&&(i&&t.some(_)&&(e=an(e,i)),g=tr(g,e))}n.dirs&&(g.dirs=g.dirs?g.dirs.concat(n.dirs):n.dirs),n.transition&&(g.transition=n.transition),m=g}catch(v){Do.length=0,kt(v,e,1),m=er(Uo)}return on(g),m}function ln(e){let t;for(let n=0;n{let t;for(const n in e)("class"===n||"style"===n||b(n))&&((t||(t={}))[n]=e[n]);return t},an=(e,t)=>{const n={};for(const o in e)_(o)&&o.slice(9)in t||(n[o]=e[o]);return n};function un(e,t,n){const o=Object.keys(t);if(o.length!==Object.keys(e).length)return!0;for(let r=0;r0?(a(null,e.ssFallback,t,n,o,null,s,i),gn(f,e.ssFallback)):f.resolve()}(t,n,o,r,s,i,l,c,a):function(e,t,n,o,r,s,i,l,{p:c,um:a,o:{createElement:u}}){const p=t.suspense=e.suspense;p.vnode=t,t.el=e.el;const f=t.ssContent,d=t.ssFallback,{activeBranch:h,pendingBranch:m,isInFallback:g,isHydrating:v}=p;if(m)p.pendingBranch=f,Zo(f,m)?(c(m,f,p.hiddenContainer,null,r,p,s,i,l),p.deps<=0?p.resolve():g&&(c(h,d,n,o,r,null,s,i,l),gn(p,d))):(p.pendingId++,v?(p.isHydrating=!1,p.activeBranch=m):a(m,r,p),p.deps=0,p.effects.length=0,p.hiddenContainer=u("div"),g?(c(null,f,p.hiddenContainer,null,r,p,s,i,l),p.deps<=0?p.resolve():(c(h,d,n,o,r,null,s,i,l),gn(p,d))):h&&Zo(f,h)?(c(h,f,n,o,r,p,s,i,l),p.resolve(!0)):(c(null,f,p.hiddenContainer,null,r,p,s,i,l),p.deps<=0&&p.resolve()));else if(h&&Zo(f,h))c(h,f,n,o,r,p,s,i,l),gn(p,f);else{const e=t.props&&t.props.onPending;if($(e)&&e(),p.pendingBranch=f,p.pendingId++,c(null,f,p.hiddenContainer,null,r,p,s,i,l),p.deps<=0)p.resolve();else{const{timeout:e,pendingId:t}=p;e>0?setTimeout((()=>{p.pendingId===t&&p.fallback(d)}),e):0===e&&p.fallback(d)}}}(e,t,n,o,r,i,l,c,a)},hydrate:function(e,t,n,o,r,s,i,l,c){const a=t.suspense=dn(t,o,n,e.parentNode,document.createElement("div"),null,r,s,i,l,!0),u=c(e,a.pendingBranch=t.ssContent,n,a,s,i);0===a.deps&&a.resolve();return u},create:dn};function dn(e,t,n,o,r,s,i,l,c,a,u=!1){const{p:p,m:f,um:d,n:h,o:{parentNode:m,remove:g}}=a,v=J(e.props&&e.props.timeout),y={vnode:e,parent:t,parentComponent:n,isSVG:i,container:o,hiddenContainer:r,anchor:s,deps:0,pendingId:0,timeout:"number"==typeof v?v:-1,activeBranch:null,pendingBranch:null,isInFallback:!0,isHydrating:u,isUnmounted:!1,effects:[],resolve(e=!1){const{vnode:t,activeBranch:n,pendingBranch:o,pendingId:r,effects:s,parentComponent:i,container:l}=y;if(y.isHydrating)y.isHydrating=!1;else if(!e){const e=n&&o.transition&&"out-in"===o.transition.mode;e&&(n.transition.afterLeave=()=>{r===y.pendingId&&f(o,l,t,0)});let{anchor:t}=y;n&&(t=h(n),d(n,i,y,!0)),e||f(o,l,t,0)}gn(y,o),y.pendingBranch=null,y.isInFallback=!1;let c=y.parent,a=!1;for(;c;){if(c.pendingBranch){c.effects.push(...s),a=!0;break}c=c.parent}a||Ht(s),y.effects=[];const u=t.props&&t.props.onResolve;$(u)&&u()},fallback(e){if(!y.pendingBranch)return;const{vnode:t,activeBranch:n,parentComponent:o,container:r,isSVG:s}=y,i=t.props&&t.props.onFallback;$(i)&&i();const a=h(n),u=()=>{y.isInFallback&&(p(null,e,r,a,o,null,s,l,c),gn(y,e))},f=e.transition&&"out-in"===e.transition.mode;f&&(n.transition.afterLeave=u),d(n,o,null,!0),y.isInFallback=!0,f||u()},move(e,t,n){y.activeBranch&&f(y.activeBranch,e,t,n),y.container=e},next:()=>y.activeBranch&&h(y.activeBranch),registerDep(e,t){const n=!!y.pendingBranch;n&&y.deps++;const o=e.vnode.el;e.asyncDep.catch((t=>{kt(t,e,0)})).then((r=>{if(e.isUnmounted||y.isUnmounted||y.pendingId!==e.suspenseId)return;e.asyncResolved=!0;const{vnode:s}=e;$r(e,r),o&&(s.el=o);const l=!o&&e.subTree.el;t(e,s,m(o||e.subTree.el),o?null:h(e.subTree),y,i,c),l&&g(l),pn(e,s.el),n&&0==--y.deps&&y.resolve()}))},unmount(e,t){y.isUnmounted=!0,y.activeBranch&&d(y.activeBranch,n,e,t),y.pendingBranch&&d(y.pendingBranch,n,e,t)}};return y}function hn(e){if($(e)&&(e=e()),w(e)){e=ln(e)}return or(e)}function mn(e,t){t&&t.pendingBranch?w(e)?t.effects.push(...e):t.effects.push(e):Ht(e)}function gn(e,t){e.activeBranch=t;const{vnode:n,parentComponent:o}=e,r=n.el=t.el;o&&o.subTree===n&&(o.vnode.el=r,pn(o,r))}function vn(e,t,n,o){const[r,s]=e.propsOptions;if(t)for(const i in t){const s=t[i];if(P(i))continue;let l;r&&k(r,l=U(i))?n[l]=s:Zt(e.emitsOptions,i)||(o[i]=s)}if(s){const t=st(n);for(let o=0;o{i=!0;const[n,o]=bn(e,t,!0);x(r,n),o&&s.push(...o)};!n&&t.mixins.length&&t.mixins.forEach(o),e.extends&&o(e.extends),e.mixins&&e.mixins.forEach(o)}if(!o&&!i)return e.__props=m;if(w(o))for(let l=0;l-1,n[1]=o<0||t-1||k(n,"default"))&&s.push(e)}}}return e.__props=[r,s]}function _n(e){return"$"!==e[0]}function xn(e){const t=e&&e.toString().match(/^\s*function (\w+)/);return t?t[1]:""}function Sn(e,t){return xn(e)===xn(t)}function Cn(e,t){return w(t)?t.findIndex((t=>Sn(t,e))):$(t)&&Sn(t,e)?0:-1}function kn(e,t,n=Cr,o=!1){if(n){const r=n[e]||(n[e]=[]),s=t.__weh||(t.__weh=(...o)=>{if(n.isUnmounted)return;le(),wr(n);const r=Ct(t,n,e,o);return wr(null),ce(),r});return o?r.unshift(s):r.push(s),s}}const wn=e=>(t,n=Cr)=>!Nr&&kn(e,t,n),Tn=wn("bm"),En=wn("m"),Nn=wn("bu"),$n=wn("u"),Fn=wn("bum"),Mn=wn("um"),An=wn("rtg"),In=wn("rtc"),On=(e,t=Cr)=>{kn("ec",e,t)};function Bn(e,t){return Pn(e,null,t)}const Rn={};function Vn(e,t,n){return Pn(e,t,n)}function Pn(e,t,{immediate:n,deep:o,flush:r,onTrack:s,onTrigger:i}=h,l=Cr){let c,a,u=!1;if(lt(e)?(c=()=>e.value,u=!!e._shallow):nt(e)?(c=()=>e,o=!0):c=w(e)?()=>e.map((e=>lt(e)?e.value:nt(e)?jn(e):$(e)?St(e,l,2,[l&&l.proxy]):void 0)):$(e)?t?()=>St(e,l,2,[l&&l.proxy]):()=>{if(!l||!l.isUnmounted)return a&&a(),Ct(e,l,3,[p])}:g,t&&o){const e=c;c=()=>jn(e())}let p=e=>{a=v.options.onStop=()=>{St(e,l,4)}},f=w(e)?[]:Rn;const d=()=>{if(v.active)if(t){const e=v();(o||u||K(e,f))&&(a&&a(),Ct(t,l,3,[e,f===Rn?void 0:f,p]),f=e)}else v()};let m;d.allowRecurse=!!t,m="sync"===r?d:"post"===r?()=>So(d,l&&l.suspense):()=>{!l||l.isMounted?function(e){Ut(e,Ft,$t,Mt)}(d):d()};const v=te(c,{lazy:!0,onTrack:s,onTrigger:i,scheduler:m});return Ir(v,l),t?n?d():f=v():"post"===r?So(v,l&&l.suspense):v(),()=>{ne(v),l&&S(l.effects,v)}}function Ln(e,t,n){const o=this.proxy;return Pn(F(e)?()=>o[e]:e.bind(o),t.bind(o),n,this)}function jn(e,t=new Set){if(!A(e)||t.has(e))return e;if(t.add(e),lt(e))jn(e.value,t);else if(w(e))for(let n=0;n{jn(e,t)}));else for(const n in e)jn(e[n],t);return e}function Un(){const e={isMounted:!1,isLeaving:!1,isUnmounting:!1,leavingVNodes:new Map};return En((()=>{e.isMounted=!0})),Fn((()=>{e.isUnmounting=!0})),e}const Hn=[Function,Array],Dn={name:"BaseTransition",props:{mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Hn,onEnter:Hn,onAfterEnter:Hn,onEnterCancelled:Hn,onBeforeLeave:Hn,onLeave:Hn,onAfterLeave:Hn,onLeaveCancelled:Hn,onBeforeAppear:Hn,onAppear:Hn,onAfterAppear:Hn,onAppearCancelled:Hn},setup(e,{slots:t}){const n=kr(),o=Un();let r;return()=>{const s=t.default&&Jn(t.default(),!0);if(!s||!s.length)return;const i=st(e),{mode:l}=i,c=s[0];if(o.isLeaving)return Kn(c);const a=Gn(c);if(!a)return Kn(c);const u=Wn(a,i,o,n);qn(a,u);const p=n.subTree,f=p&&Gn(p);let d=!1;const{getTransitionKey:h}=a.type;if(h){const e=h();void 0===r?r=e:e!==r&&(r=e,d=!0)}if(f&&f.type!==Uo&&(!Zo(a,f)||d)){const e=Wn(f,i,o,n);if(qn(f,e),"out-in"===l)return o.isLeaving=!0,e.afterLeave=()=>{o.isLeaving=!1,n.update()},Kn(c);"in-out"===l&&a.type!==Uo&&(e.delayLeave=(e,t,n)=>{zn(o,f)[String(f.key)]=f,e._leaveCb=()=>{t(),e._leaveCb=void 0,delete u.delayedLeave},u.delayedLeave=n})}return c}}};function zn(e,t){const{leavingVNodes:n}=e;let o=n.get(t.type);return o||(o=Object.create(null),n.set(t.type,o)),o}function Wn(e,t,n,o){const{appear:r,mode:s,persisted:i=!1,onBeforeEnter:l,onEnter:c,onAfterEnter:a,onEnterCancelled:u,onBeforeLeave:p,onLeave:f,onAfterLeave:d,onLeaveCancelled:h,onBeforeAppear:m,onAppear:g,onAfterAppear:v,onAppearCancelled:y}=t,b=String(e.key),_=zn(n,e),x=(e,t)=>{e&&Ct(e,o,9,t)},S={mode:s,persisted:i,beforeEnter(t){let o=l;if(!n.isMounted){if(!r)return;o=m||l}t._leaveCb&&t._leaveCb(!0);const s=_[b];s&&Zo(e,s)&&s.el._leaveCb&&s.el._leaveCb(),x(o,[t])},enter(e){let t=c,o=a,s=u;if(!n.isMounted){if(!r)return;t=g||c,o=v||a,s=y||u}let i=!1;const l=e._enterCb=t=>{i||(i=!0,x(t?s:o,[e]),S.delayedLeave&&S.delayedLeave(),e._enterCb=void 0)};t?(t(e,l),t.length<=1&&l()):l()},leave(t,o){const r=String(e.key);if(t._enterCb&&t._enterCb(!0),n.isUnmounting)return o();x(p,[t]);let s=!1;const i=t._leaveCb=n=>{s||(s=!0,o(),x(n?h:d,[t]),t._leaveCb=void 0,_[r]===e&&delete _[r])};_[r]=e,f?(f(t,i),f.length<=1&&i()):i()},clone:e=>Wn(e,t,n,o)};return S}function Kn(e){if(Zn(e))return(e=tr(e)).children=null,e}function Gn(e){return Zn(e)?e.children?e.children[0]:void 0:e}function qn(e,t){6&e.shapeFlag&&e.component?qn(e.component.subTree,t):128&e.shapeFlag?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Jn(e,t=!1){let n=[],o=0;for(let r=0;r1)for(let r=0;re.type.__isKeepAlive,Qn={name:"KeepAlive",__isKeepAlive:!0,props:{include:[String,RegExp,Array],exclude:[String,RegExp,Array],max:[String,Number]},setup(e,{slots:t}){const n=kr(),o=n.ctx;if(!o.renderer)return t.default;const r=new Map,s=new Set;let i=null;const l=n.suspense,{renderer:{p:c,m:a,um:u,o:{createElement:p}}}=o,f=p("div");function d(e){oo(e),u(e,n,l)}function h(e){r.forEach(((t,n)=>{const o=Br(t.type);!o||e&&e(o)||m(n)}))}function m(e){const t=r.get(e);i&&t.type===i.type?i&&oo(i):d(t),r.delete(e),s.delete(e)}o.activate=(e,t,n,o,r)=>{const s=e.component;a(e,t,n,0,l),c(s.vnode,e,t,n,s,l,o,e.slotScopeIds,r),So((()=>{s.isDeactivated=!1,s.a&&G(s.a);const t=e.props&&e.props.onVnodeMounted;t&&Eo(t,s.parent,e)}),l)},o.deactivate=e=>{const t=e.component;a(e,f,null,1,l),So((()=>{t.da&&G(t.da);const n=e.props&&e.props.onVnodeUnmounted;n&&Eo(n,t.parent,e),t.isDeactivated=!0}),l)},Vn((()=>[e.include,e.exclude]),(([e,t])=>{e&&h((t=>Xn(e,t))),t&&h((e=>!Xn(t,e)))}),{flush:"post",deep:!0});let g=null;const v=()=>{null!=g&&r.set(g,ro(n.subTree))};return En(v),$n(v),Fn((()=>{r.forEach((e=>{const{subTree:t,suspense:o}=n,r=ro(t);if(e.type!==r.type)d(e);else{oo(r);const e=r.component.da;e&&So(e,o)}}))})),()=>{if(g=null,!t.default)return null;const n=t.default(),o=n[0];if(n.length>1)return i=null,n;if(!(Jo(o)&&(4&o.shapeFlag||128&o.shapeFlag)))return i=null,o;let l=ro(o);const c=l.type,a=Br(c),{include:u,exclude:p,max:f}=e;if(u&&(!a||!Xn(u,a))||p&&a&&Xn(p,a))return i=l,o;const d=null==l.key?c:l.key,h=r.get(d);return l.el&&(l=tr(l),128&o.shapeFlag&&(o.ssContent=l)),g=d,h?(l.el=h.el,l.component=h.component,l.transition&&qn(l,l.transition),l.shapeFlag|=512,s.delete(d),s.add(d)):(s.add(d),f&&s.size>parseInt(f,10)&&m(s.values().next().value)),l.shapeFlag|=256,i=l,o}}};function Xn(e,t){return w(e)?e.some((e=>Xn(e,t))):F(e)?e.split(",").indexOf(t)>-1:!!e.test&&e.test(t)}function Yn(e,t){to(e,"a",t)}function eo(e,t){to(e,"da",t)}function to(e,t,n=Cr){const o=e.__wdc||(e.__wdc=()=>{let t=n;for(;t;){if(t.isDeactivated)return;t=t.parent}e()});if(kn(t,o,n),n){let e=n.parent;for(;e&&e.parent;)Zn(e.parent.vnode)&&no(o,t,n,e),e=e.parent}}function no(e,t,n,o){const r=kn(t,e,o,!0);Mn((()=>{S(o[t],r)}),n)}function oo(e){let t=e.shapeFlag;256&t&&(t-=256),512&t&&(t-=512),e.shapeFlag=t}function ro(e){return 128&e.shapeFlag?e.ssContent:e}const so=e=>"_"===e[0]||"$stable"===e,io=e=>w(e)?e.map(or):[or(e)],lo=(e,t,n)=>rn((e=>io(t(e))),n),co=(e,t)=>{const n=e._ctx;for(const o in e){if(so(o))continue;const r=e[o];if($(r))t[o]=lo(0,r,n);else if(null!=r){const e=io(r);t[o]=()=>e}}},ao=(e,t)=>{const n=io(t);e.slots.default=()=>n};function uo(e,t,n,o){const r=e.dirs,s=t&&t.dirs;for(let i=0;i(s.has(e)||(e&&$(e.install)?(s.add(e),e.install(l,...t)):$(e)&&(s.add(e),e(l,...t))),l),mixin:e=>(r.mixins.includes(e)||(r.mixins.push(e),(e.props||e.emits)&&(r.deopt=!0)),l),component:(e,t)=>t?(r.components[e]=t,l):r.components[e],directive:(e,t)=>t?(r.directives[e]=t,l):r.directives[e],mount(s,c,a){if(!i){const u=er(n,o);return u.appContext=r,c&&t?t(u,s):e(u,s,a),i=!0,l._container=s,s.__vue_app__=l,u.component.proxy}},unmount(){i&&(e(null,l._container),delete l._container.__vue_app__)},provide:(e,t)=>(r.provides[e]=t,l)};return l}}let mo=!1;const go=e=>/svg/.test(e.namespaceURI)&&"foreignObject"!==e.tagName,vo=e=>8===e.nodeType;function yo(e){const{mt:t,p:n,o:{patchProp:o,nextSibling:r,parentNode:s,remove:i,insert:l,createComment:c}}=e,a=(n,o,i,l,c,m=!1)=>{const g=vo(n)&&"["===n.data,v=()=>d(n,o,i,l,c,g),{type:y,ref:b,shapeFlag:_}=o,x=n.nodeType;o.el=n;let S=null;switch(y){case jo:3!==x?S=v():(n.data!==o.children&&(mo=!0,n.data=o.children),S=r(n));break;case Uo:S=8!==x||g?v():r(n);break;case Ho:if(1===x){S=n;const e=!o.children.length;for(let t=0;t{t(o,e,null,i,l,go(e),m)},u=o.type.__asyncLoader;u?u().then(a):a(),S=g?h(n):r(n)}else 64&_?S=8!==x?v():o.type.hydrate(n,o,i,l,c,m,e,p):128&_&&(S=o.type.hydrate(n,o,i,l,go(s(n)),c,m,e,a))}return null!=b&&Co(b,null,l,o),S},u=(e,t,n,r,s,l)=>{l=l||!!t.dynamicChildren;const{props:c,patchFlag:a,shapeFlag:u,dirs:f}=t;if(-1!==a){if(f&&uo(t,null,n,"created"),c)if(!l||16&a||32&a)for(const t in c)!P(t)&&b(t)&&o(e,t,null,c[t]);else c.onClick&&o(e,"onClick",null,c.onClick);let d;if((d=c&&c.onVnodeBeforeMount)&&Eo(d,n,t),f&&uo(t,null,n,"beforeMount"),((d=c&&c.onVnodeMounted)||f)&&mn((()=>{d&&Eo(d,n,t),f&&uo(t,null,n,"mounted")}),r),16&u&&(!c||!c.innerHTML&&!c.textContent)){let o=p(e.firstChild,t,e,n,r,s,l);for(;o;){mo=!0;const e=o;o=o.nextSibling,i(e)}}else 8&u&&e.textContent!==t.children&&(mo=!0,e.textContent=t.children)}return e.nextSibling},p=(e,t,o,r,s,i,l)=>{l=l||!!t.dynamicChildren;const c=t.children,u=c.length;for(let p=0;p{const{slotScopeIds:u}=t;u&&(i=i?i.concat(u):u);const f=s(e),d=p(r(e),t,f,n,o,i,a);return d&&vo(d)&&"]"===d.data?r(t.anchor=d):(mo=!0,l(t.anchor=c("]"),f,d),d)},d=(e,t,o,l,c,a)=>{if(mo=!0,t.el=null,a){const t=h(e);for(;;){const n=r(e);if(!n||n===t)break;i(n)}}const u=r(e),p=s(e);return i(e),n(null,t,p,u,o,l,go(p),c),u},h=e=>{let t=0;for(;e;)if((e=r(e))&&vo(e)&&("["===e.data&&t++,"]"===e.data)){if(0===t)return r(e);t--}return e};return[(e,t)=>{mo=!1,a(t.firstChild,e,null,null,null),zt(),mo&&console.error("Hydration completed but contains mismatches.")},a]}function bo(e){return $(e)?{setup:e,name:e.name}:e}function _o(e,{vnode:{ref:t,props:n,children:o}}){const r=er(e,n,o);return r.ref=t,r}const xo={scheduler:Lt,allowRecurse:!0},So=mn,Co=(e,t,n,o)=>{if(w(e))return void e.forEach(((e,r)=>Co(e,t&&(w(t)?t[r]:t),n,o)));let r;if(o){if(o.type.__asyncLoader)return;r=4&o.shapeFlag?o.component.exposed||o.component.proxy:o.el}else r=null;const{i:s,r:i}=e,l=t&&t.r,c=s.refs===h?s.refs={}:s.refs,a=s.setupState;if(null!=l&&l!==i&&(F(l)?(c[l]=null,k(a,l)&&(a[l]=null)):lt(l)&&(l.value=null)),F(i)){const e=()=>{c[i]=r,k(a,i)&&(a[i]=r)};r?(e.id=-1,So(e,n)):e()}else if(lt(i)){const e=()=>{i.value=r};r?(e.id=-1,So(e,n)):e()}else $(i)&&St(i,s,12,[r,c])};function ko(e){return To(e)}function wo(e){return To(e,yo)}function To(e,t){const{insert:n,remove:o,patchProp:r,forcePatchProp:s,createElement:i,createText:l,createComment:c,setText:a,setElementText:u,parentNode:p,nextSibling:f,setScopeId:d=g,cloneNode:v,insertStaticContent:y}=e,b=(e,t,n,o=null,r=null,s=null,i=!1,l=null,c=!1)=>{e&&!Zo(e,t)&&(o=Y(e),K(e,r,s,!0),e=null),-2===t.patchFlag&&(c=!1,t.dynamicChildren=null);const{type:a,ref:u,shapeFlag:p}=t;switch(a){case jo:_(e,t,n,o);break;case Uo:S(e,t,n,o);break;case Ho:null==e&&C(t,n,o,i);break;case Lo:A(e,t,n,o,r,s,i,l,c);break;default:1&p?w(e,t,n,o,r,s,i,l,c):6&p?O(e,t,n,o,r,s,i,l,c):(64&p||128&p)&&a.process(e,t,n,o,r,s,i,l,c,oe)}null!=u&&r&&Co(u,e&&e.ref,s,t)},_=(e,t,o,r)=>{if(null==e)n(t.el=l(t.children),o,r);else{const n=t.el=e.el;t.children!==e.children&&a(n,t.children)}},S=(e,t,o,r)=>{null==e?n(t.el=c(t.children||""),o,r):t.el=e.el},C=(e,t,n,o)=>{[e.el,e.anchor]=y(e.children,t,n,o)},w=(e,t,n,o,r,s,i,l,c)=>{i=i||"svg"===t.type,null==e?T(t,n,o,r,s,i,l,c):$(e,t,r,s,i,l,c)},T=(e,t,o,s,l,c,a,p)=>{let f,d;const{type:h,props:m,shapeFlag:g,transition:y,patchFlag:b,dirs:_}=e;if(e.el&&void 0!==v&&-1===b)f=e.el=v(e.el);else{if(f=e.el=i(e.type,c,m&&m.is,m),8&g?u(f,e.children):16&g&&N(e.children,f,null,s,l,c&&"foreignObject"!==h,a,p||!!e.dynamicChildren),_&&uo(e,null,s,"created"),m){for(const t in m)P(t)||r(f,t,null,m[t],c,e.children,s,l,X);(d=m.onVnodeBeforeMount)&&Eo(d,s,e)}E(f,e,e.scopeId,a,s)}_&&uo(e,null,s,"beforeMount");const x=(!l||l&&!l.pendingBranch)&&y&&!y.persisted;x&&y.beforeEnter(f),n(f,t,o),((d=m&&m.onVnodeMounted)||x||_)&&So((()=>{d&&Eo(d,s,e),x&&y.enter(f),_&&uo(e,null,s,"mounted")}),l)},E=(e,t,n,o,r)=>{if(n&&d(e,n),o)for(let s=0;s{for(let a=c;a{const a=t.el=e.el;let{patchFlag:p,dynamicChildren:f,dirs:d}=t;p|=16&e.patchFlag;const m=e.props||h,g=t.props||h;let v;if((v=g.onVnodeBeforeUpdate)&&Eo(v,n,t,e),d&&uo(t,e,n,"beforeUpdate"),p>0){if(16&p)M(a,t,m,g,n,o,i);else if(2&p&&m.class!==g.class&&r(a,"class",null,g.class,i),4&p&&r(a,"style",m.style,g.style,i),8&p){const l=t.dynamicProps;for(let t=0;t{v&&Eo(v,n,t,e),d&&uo(t,e,n,"updated")}),o)},F=(e,t,n,o,r,s,i)=>{for(let l=0;l{if(n!==o){for(const a in o){if(P(a))continue;const u=o[a],p=n[a];(u!==p||s&&s(e,a))&&r(e,a,p,u,c,t.children,i,l,X)}if(n!==h)for(const s in n)P(s)||s in o||r(e,s,n[s],null,c,t.children,i,l,X)}},A=(e,t,o,r,s,i,c,a,u)=>{const p=t.el=e?e.el:l(""),f=t.anchor=e?e.anchor:l("");let{patchFlag:d,dynamicChildren:h,slotScopeIds:m}=t;d>0&&(u=!0),m&&(a=a?a.concat(m):m),null==e?(n(p,o,r),n(f,o,r),N(t.children,o,f,s,i,c,a,u)):d>0&&64&d&&h&&e.dynamicChildren?(F(e.dynamicChildren,h,o,s,i,c,a),(null!=t.key||s&&t===s.subTree)&&No(e,t,!0)):j(e,t,o,f,s,i,c,a,u)},O=(e,t,n,o,r,s,i,l,c)=>{t.slotScopeIds=l,null==e?512&t.shapeFlag?r.ctx.activate(t,n,o,i,c):B(t,n,o,r,s,i,c):R(e,t,c)},B=(e,t,n,o,r,s,i)=>{const l=e.component=function(e,t,n){const o=e.type,r=(t?t.appContext:e.appContext)||xr,s={uid:Sr++,vnode:e,type:o,parent:t,appContext:r,root:null,next:null,subTree:null,update:null,render:null,proxy:null,exposed:null,withProxy:null,effects:null,provides:t?t.provides:Object.create(r.provides),accessCache:null,renderCache:[],components:null,directives:null,propsOptions:bn(o,r),emitsOptions:Jt(o,r),emit:null,emitted:null,propsDefaults:h,ctx:h,data:h,props:h,attrs:h,slots:h,refs:h,setupState:h,setupContext:null,suspense:n,suspenseId:n?n.pendingId:0,asyncDep:null,asyncResolved:!1,isMounted:!1,isUnmounted:!1,isDeactivated:!1,bc:null,c:null,bm:null,m:null,bu:null,u:null,um:null,bum:null,da:null,a:null,rtg:null,rtc:null,ec:null};return s.ctx={_:s},s.root=t?t.root:s,s.emit=qt.bind(null,s),s}(e,o,r);if(Zn(e)&&(l.ctx.renderer=oe),function(e,t=!1){Nr=t;const{props:n,children:o}=e.vnode,r=Tr(e);(function(e,t,n,o=!1){const r={},s={};q(s,Qo,1),e.propsDefaults=Object.create(null),vn(e,t,r,s),n?e.props=o?r:Ye(r):e.type.props?e.props=r:e.props=s,e.attrs=s})(e,n,r,t),((e,t)=>{if(32&e.vnode.shapeFlag){const n=t._;n?(e.slots=t,q(t,"_",n)):co(t,e.slots={})}else e.slots={},t&&ao(e,t);q(e.slots,Qo,1)})(e,o);const s=r?function(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,br);const{setup:o}=n;if(o){const n=e.setupContext=o.length>1?Ar(e):null;Cr=e,le();const r=St(o,e,0,[e.props,n]);if(ce(),Cr=null,I(r)){if(t)return r.then((t=>{$r(e,t)})).catch((t=>{kt(t,e,0)}));e.asyncDep=r}else $r(e,r)}else Mr(e)}(e,t):void 0;Nr=!1}(l),l.asyncDep){if(r&&r.registerDep(l,V),!e.el){const e=l.subTree=er(Uo);S(null,e,t,n)}}else V(l,e,t,n,r,s,i)},R=(e,t,n)=>{const o=t.component=e.component;if(function(e,t,n){const{props:o,children:r,component:s}=e,{props:i,children:l,patchFlag:c}=t,a=s.emitsOptions;if(t.dirs||t.transition)return!0;if(!(n&&c>=0))return!(!r&&!l||l&&l.$stable)||o!==i&&(o?!i||un(o,i,a):!!i);if(1024&c)return!0;if(16&c)return o?un(o,i,a):!!i;if(8&c){const e=t.dynamicProps;for(let t=0;tNt&&Et.splice(t,1)}(o.update),o.update()}else t.component=e.component,t.el=e.el,o.vnode=t},V=(e,t,n,o,r,s,i)=>{e.update=te((function(){if(e.isMounted){let t,{next:n,bu:o,u:l,parent:c,vnode:a}=e,u=n;n?(n.el=a.el,L(e,n,i)):n=a,o&&G(o),(t=n.props&&n.props.onVnodeBeforeUpdate)&&Eo(t,c,n,a);const f=sn(e),d=e.subTree;e.subTree=f,b(d,f,p(d.el),Y(d),e,r,s),n.el=f.el,null===u&&pn(e,f.el),l&&So(l,r),(t=n.props&&n.props.onVnodeUpdated)&&So((()=>{Eo(t,c,n,a)}),r)}else{let i;const{el:l,props:c}=t,{bm:a,m:u,parent:p}=e;a&&G(a),(i=c&&c.onVnodeBeforeMount)&&Eo(i,p,t);const f=e.subTree=sn(e);if(l&&se?se(t.el,f,e,r,null):(b(null,f,n,o,e,r,s),t.el=f.el),u&&So(u,r),i=c&&c.onVnodeMounted){const e=t;So((()=>{Eo(i,p,e)}),r)}const{a:d}=e;d&&256&t.shapeFlag&&So(d,r),e.isMounted=!0,t=n=o=null}}),xo)},L=(e,t,n)=>{t.component=e;const o=e.vnode.props;e.vnode=t,e.next=null,function(e,t,n,o){const{props:r,attrs:s,vnode:{patchFlag:i}}=e,l=st(r),[c]=e.propsOptions;if(!(o||i>0)||16&i){let o;vn(e,t,r,s);for(const s in l)t&&(k(t,s)||(o=D(s))!==s&&k(t,o))||(c?!n||void 0===n[s]&&void 0===n[o]||(r[s]=yn(c,t||h,s,void 0,e)):delete r[s]);if(s!==l)for(const e in s)t&&k(t,e)||delete s[e]}else if(8&i){const n=e.vnode.dynamicProps;for(let o=0;o{const{vnode:o,slots:r}=e;let s=!0,i=h;if(32&o.shapeFlag){const e=t._;e?n&&1===e?s=!1:(x(r,t),n||1!==e||delete r._):(s=!t.$stable,co(t,r)),i=t}else t&&(ao(e,t),i={default:1});if(s)for(const l in r)so(l)||l in i||delete r[l]})(e,t.children,n),le(),Dt(void 0,e.update),ce()},j=(e,t,n,o,r,s,i,l,c=!1)=>{const a=e&&e.children,p=e?e.shapeFlag:0,f=t.children,{patchFlag:d,shapeFlag:h}=t;if(d>0){if(128&d)return void z(a,f,n,o,r,s,i,l,c);if(256&d)return void H(a,f,n,o,r,s,i,l,c)}8&h?(16&p&&X(a,r,s),f!==a&&u(n,f)):16&p?16&h?z(a,f,n,o,r,s,i,l,c):X(a,r,s,!0):(8&p&&u(n,""),16&h&&N(f,n,o,r,s,i,l,c))},H=(e,t,n,o,r,s,i,l,c)=>{t=t||m;const a=(e=e||m).length,u=t.length,p=Math.min(a,u);let f;for(f=0;fu?X(e,r,s,!0,!1,p):N(t,n,o,r,s,i,l,c,p)},z=(e,t,n,o,r,s,i,l,c)=>{let a=0;const u=t.length;let p=e.length-1,f=u-1;for(;a<=p&&a<=f;){const o=e[a],u=t[a]=c?rr(t[a]):or(t[a]);if(!Zo(o,u))break;b(o,u,n,null,r,s,i,l,c),a++}for(;a<=p&&a<=f;){const o=e[p],a=t[f]=c?rr(t[f]):or(t[f]);if(!Zo(o,a))break;b(o,a,n,null,r,s,i,l,c),p--,f--}if(a>p){if(a<=f){const e=f+1,p=ef)for(;a<=p;)K(e[a],r,s,!0),a++;else{const d=a,h=a,g=new Map;for(a=h;a<=f;a++){const e=t[a]=c?rr(t[a]):or(t[a]);null!=e.key&&g.set(e.key,a)}let v,y=0;const _=f-h+1;let x=!1,S=0;const C=new Array(_);for(a=0;a<_;a++)C[a]=0;for(a=d;a<=p;a++){const o=e[a];if(y>=_){K(o,r,s,!0);continue}let u;if(null!=o.key)u=g.get(o.key);else for(v=h;v<=f;v++)if(0===C[v-h]&&Zo(o,t[v])){u=v;break}void 0===u?K(o,r,s,!0):(C[u-h]=a+1,u>=S?S=u:x=!0,b(o,t[u],n,null,r,s,i,l,c),y++)}const k=x?function(e){const t=e.slice(),n=[0];let o,r,s,i,l;const c=e.length;for(o=0;o0&&(t[o]=n[s-1]),n[s]=o)}}s=n.length,i=n[s-1];for(;s-- >0;)n[s]=i,i=t[i];return n}(C):m;for(v=k.length-1,a=_-1;a>=0;a--){const e=h+a,p=t[e],f=e+1{const{el:i,type:l,transition:c,children:a,shapeFlag:u}=e;if(6&u)return void W(e.component.subTree,t,o,r);if(128&u)return void e.suspense.move(t,o,r);if(64&u)return void l.move(e,t,o,oe);if(l===Lo){n(i,t,o);for(let e=0;e{let s;for(;e&&e!==t;)s=f(e),n(e,o,r),e=s;n(t,o,r)})(e,t,o);if(2!==r&&1&u&&c)if(0===r)c.beforeEnter(i),n(i,t,o),So((()=>c.enter(i)),s);else{const{leave:e,delayLeave:r,afterLeave:s}=c,l=()=>n(i,t,o),a=()=>{e(i,(()=>{l(),s&&s()}))};r?r(i,l,a):a()}else n(i,t,o)},K=(e,t,n,o=!1,r=!1)=>{const{type:s,props:i,ref:l,children:c,dynamicChildren:a,shapeFlag:u,patchFlag:p,dirs:f}=e;if(null!=l&&Co(l,null,n,null),256&u)return void t.ctx.deactivate(e);const d=1&u&&f;let h;if((h=i&&i.onVnodeBeforeUnmount)&&Eo(h,t,e),6&u)Q(e.component,n,o);else{if(128&u)return void e.suspense.unmount(n,o);d&&uo(e,null,t,"beforeUnmount"),64&u?e.type.remove(e,t,n,r,oe,o):a&&(s!==Lo||p>0&&64&p)?X(a,t,n,!1,!0):(s===Lo&&(128&p||256&p)||!r&&16&u)&&X(c,t,n),o&&J(e)}((h=i&&i.onVnodeUnmounted)||d)&&So((()=>{h&&Eo(h,t,e),d&&uo(e,null,t,"unmounted")}),n)},J=e=>{const{type:t,el:n,anchor:r,transition:s}=e;if(t===Lo)return void Z(n,r);if(t===Ho)return void(({el:e,anchor:t})=>{let n;for(;e&&e!==t;)n=f(e),o(e),e=n;o(t)})(e);const i=()=>{o(n),s&&!s.persisted&&s.afterLeave&&s.afterLeave()};if(1&e.shapeFlag&&s&&!s.persisted){const{leave:t,delayLeave:o}=s,r=()=>t(n,i);o?o(e.el,i,r):r()}else i()},Z=(e,t)=>{let n;for(;e!==t;)n=f(e),o(e),e=n;o(t)},Q=(e,t,n)=>{const{bum:o,effects:r,update:s,subTree:i,um:l}=e;if(o&&G(o),r)for(let c=0;c{e.isUnmounted=!0}),t),t&&t.pendingBranch&&!t.isUnmounted&&e.asyncDep&&!e.asyncResolved&&e.suspenseId===t.pendingId&&(t.deps--,0===t.deps&&t.resolve())},X=(e,t,n,o=!1,r=!1,s=0)=>{for(let i=s;i6&e.shapeFlag?Y(e.component.subTree):128&e.shapeFlag?e.suspense.next():f(e.anchor||e.el),ee=(e,t,n)=>{null==e?t._vnode&&K(t._vnode,null,null,!0):b(t._vnode||null,e,t,null,null,null,n),zt(),t._vnode=e},oe={p:b,um:K,m:W,r:J,mt:B,mc:N,pc:j,pbc:F,n:Y,o:e};let re,se;return t&&([re,se]=t(oe)),{render:ee,hydrate:re,createApp:ho(ee,re)}}function Eo(e,t,n,o=null){Ct(e,t,7,[n,o])}function No(e,t,n=!1){const o=e.children,r=t.children;if(w(o)&&w(r))for(let s=0;se&&(e.disabled||""===e.disabled),Fo=e=>"undefined"!=typeof SVGElement&&e instanceof SVGElement,Mo=(e,t)=>{const n=e&&e.to;if(F(n)){if(t){return t(n)}return null}return n};function Ao(e,t,n,{o:{insert:o},m:r},s=2){0===s&&o(e.targetAnchor,t,n);const{el:i,anchor:l,shapeFlag:c,children:a,props:u}=e,p=2===s;if(p&&o(i,t,n),(!p||$o(u))&&16&c)for(let f=0;f{16&y&&u(b,e,t,r,s,i,l,c)};v?g(n,a):p&&g(p,f)}else{t.el=e.el;const o=t.anchor=e.anchor,u=t.target=e.target,d=t.targetAnchor=e.targetAnchor,m=$o(e.props),g=m?n:u,y=m?o:d;if(i=i||Fo(u),t.dynamicChildren?(f(e.dynamicChildren,t.dynamicChildren,g,r,s,i,l),No(e,t,!0)):c||p(e,t,g,y,r,s,i,l,!1),v)m||Ao(t,n,o,a,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const e=t.target=Mo(t.props,h);e&&Ao(t,e,null,a,0)}else m&&Ao(t,u,d,a,1)}},remove(e,t,n,o,{um:r,o:{remove:s}},i){const{shapeFlag:l,children:c,anchor:a,targetAnchor:u,target:p,props:f}=e;if(p&&s(u),(i||!$o(f))&&(s(a),16&l))for(let d=0;d0&&zo&&zo.push(s),s}function Jo(e){return!!e&&!0===e.__v_isVNode}function Zo(e,t){return e.type===t.type&&e.key===t.key}const Qo="__vInternal",Xo=({key:e})=>null!=e?e:null,Yo=({ref:e})=>null!=e?F(e)||lt(e)||$(e)?{i:tn,r:e}:e:null,er=function(e,t=null,n=null,r=0,s=null,i=!1){e&&e!==Ro||(e=Uo);if(Jo(e)){const o=tr(e,t,!0);return n&&sr(o,n),o}c=e,$(c)&&"__vccOpts"in c&&(e=e.__vccOpts);var c;if(t){(rt(t)||Qo in t)&&(t=x({},t));let{class:e,style:n}=t;e&&!F(e)&&(t.class=l(e)),A(n)&&(rt(n)&&!w(n)&&(n=x({},n)),t.style=o(n))}const a=F(e)?1:(e=>e.__isSuspense)(e)?128:(e=>e.__isTeleport)(e)?64:A(e)?4:$(e)?2:0,u={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Xo(t),ref:t&&Yo(t),scopeId:nn,slotScopeIds:null,children:null,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:a,patchFlag:r,dynamicProps:s,dynamicChildren:null,appContext:null};if(sr(u,n),128&a){const{content:e,fallback:t}=function(e){const{shapeFlag:t,children:n}=e;let o,r;return 32&t?(o=hn(n.default),r=hn(n.fallback)):(o=hn(n),r=or(null)),{content:o,fallback:r}}(u);u.ssContent=e,u.ssFallback=t}Go>0&&!i&&zo&&(r>0||6&a)&&32!==r&&zo.push(u);return u};function tr(e,t,n=!1){const{props:o,ref:r,patchFlag:s,children:i}=e,l=t?ir(o||{},t):o;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&Xo(l),ref:t&&t.ref?n&&r?w(r)?r.concat(Yo(t)):[r,Yo(t)]:Yo(t):r,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:i,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==Lo?-1===s?16:16|s:s,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&tr(e.ssContent),ssFallback:e.ssFallback&&tr(e.ssFallback),el:e.el,anchor:e.anchor}}function nr(e=" ",t=0){return er(jo,null,e,t)}function or(e){return null==e||"boolean"==typeof e?er(Uo):w(e)?er(Lo,null,e):"object"==typeof e?null===e.el?e:tr(e):er(jo,null,String(e))}function rr(e){return null===e.el?e:tr(e)}function sr(e,t){let n=0;const{shapeFlag:o}=e;if(null==t)t=null;else if(w(t))n=16;else if("object"==typeof t){if(1&o||64&o){const n=t.default;return void(n&&(n._c&&Xt(1),sr(e,n()),n._c&&Xt(-1)))}{n=32;const o=t._;o||Qo in t?3===o&&tn&&(1024&tn.vnode.patchFlag?(t._=2,e.patchFlag|=1024):t._=1):t._ctx=tn}}else $(t)?(t={default:t,_ctx:tn},n=32):(t=String(t),64&o?(n=16,t=[nr(t)]):n=8);e.children=t,e.shapeFlag|=n}function ir(...e){const t=x({},e[0]);for(let n=1;n1)return n&&$(t)?t():t}}let ar=!0;function ur(e,t,n=[],o=[],r=[],s=!1){const{mixins:i,extends:l,data:c,computed:a,methods:u,watch:p,provide:f,inject:d,components:m,directives:v,beforeMount:y,mounted:b,beforeUpdate:_,updated:S,activated:C,deactivated:k,beforeDestroy:T,beforeUnmount:E,destroyed:N,unmounted:F,render:M,renderTracked:I,renderTriggered:O,errorCaptured:B,expose:R}=t,V=e.proxy,P=e.ctx,L=e.appContext.mixins;if(s&&M&&e.render===g&&(e.render=M),s||(ar=!1,pr("beforeCreate","bc",t,e,L),ar=!0,dr(e,L,n,o,r)),l&&ur(e,l,n,o,r,!0),i&&dr(e,i,n,o,r),d)if(w(d))for(let h=0;hhr(e,t,V))),c&&hr(e,c,V)),a)for(const h in a){const e=a[h],t=Vr({get:$(e)?e.bind(V,V):$(e.get)?e.get.bind(V,V):g,set:!$(e)&&$(e.set)?e.set.bind(V):g});Object.defineProperty(P,h,{enumerable:!0,configurable:!0,get:()=>t.value,set:e=>t.value=e})}if(p&&o.push(p),!s&&o.length&&o.forEach((e=>{for(const t in e)mr(e[t],P,V,t)})),f&&r.push(f),!s&&r.length&&r.forEach((e=>{const t=$(e)?e.call(V):e;Reflect.ownKeys(t).forEach((e=>{lr(e,t[e])}))})),s&&(m&&x(e.components||(e.components=x({},e.type.components)),m),v&&x(e.directives||(e.directives=x({},e.type.directives)),v)),s||pr("created","c",t,e,L),y&&Tn(y.bind(V)),b&&En(b.bind(V)),_&&Nn(_.bind(V)),S&&$n(S.bind(V)),C&&Yn(C.bind(V)),k&&eo(k.bind(V)),B&&On(B.bind(V)),I&&In(I.bind(V)),O&&An(O.bind(V)),E&&Fn(E.bind(V)),F&&Mn(F.bind(V)),w(R)&&!s)if(R.length){const t=e.exposed||(e.exposed=dt({}));R.forEach((e=>{t[e]=gt(V,e)}))}else e.exposed||(e.exposed=h)}function pr(e,t,n,o,r){for(let s=0;s{let t=e;for(let e=0;en[o];if(F(e)){const n=t[e];$(n)&&Vn(r,n)}else if($(e))Vn(r,e.bind(n));else if(A(e))if(w(e))e.forEach((e=>mr(e,t,n,o)));else{const o=$(e.handler)?e.handler.bind(n):t[e.handler];$(o)&&Vn(r,o,e)}}function gr(e,t,n){const o=n.appContext.config.optionMergeStrategies,{mixins:r,extends:s}=t;s&&gr(e,s,n),r&&r.forEach((t=>gr(e,t,n)));for(const i in t)o&&k(o,i)?e[i]=o[i](e[i],t[i],n.proxy,i):e[i]=t[i]}const vr=e=>e?Tr(e)?e.exposed?e.exposed:e.proxy:vr(e.parent):null,yr=x(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>vr(e.parent),$root:e=>vr(e.root),$emit:e=>e.emit,$options:e=>function(e){const t=e.type,{__merged:n,mixins:o,extends:r}=t;if(n)return n;const s=e.appContext.mixins;if(!s.length&&!o&&!r)return t;const i={};return s.forEach((t=>gr(i,t,e))),gr(i,t,e),t.__merged=i}(e),$forceUpdate:e=>()=>Lt(e.update),$nextTick:e=>Pt.bind(e.proxy),$watch:e=>Ln.bind(e)}),br={get({_:e},t){const{ctx:n,setupState:o,data:r,props:s,accessCache:i,type:l,appContext:c}=e;if("__v_skip"===t)return!0;let a;if("$"!==t[0]){const l=i[t];if(void 0!==l)switch(l){case 0:return o[t];case 1:return r[t];case 3:return n[t];case 2:return s[t]}else{if(o!==h&&k(o,t))return i[t]=0,o[t];if(r!==h&&k(r,t))return i[t]=1,r[t];if((a=e.propsOptions[0])&&k(a,t))return i[t]=2,s[t];if(n!==h&&k(n,t))return i[t]=3,n[t];ar&&(i[t]=4)}}const u=yr[t];let p,f;return u?("$attrs"===t&&ae(e,0,t),u(e)):(p=l.__cssModules)&&(p=p[t])?p:n!==h&&k(n,t)?(i[t]=3,n[t]):(f=c.config.globalProperties,k(f,t)?f[t]:void 0)},set({_:e},t,n){const{data:o,setupState:r,ctx:s}=e;if(r!==h&&k(r,t))r[t]=n;else if(o!==h&&k(o,t))o[t]=n;else if(k(e.props,t))return!1;return("$"!==t[0]||!(t.slice(1)in e))&&(s[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:o,appContext:r,propsOptions:s}},i){let l;return void 0!==n[i]||e!==h&&k(e,i)||t!==h&&k(t,i)||(l=s[0])&&k(l,i)||k(o,i)||k(yr,i)||k(r.config.globalProperties,i)}},_r=x({},br,{get(e,t){if(t!==Symbol.unscopables)return br.get(e,t,e)},has:(e,n)=>"_"!==n[0]&&!t(n)}),xr=po();let Sr=0;let Cr=null;const kr=()=>Cr||tn,wr=e=>{Cr=e};function Tr(e){return 4&e.vnode.shapeFlag}let Er,Nr=!1;function $r(e,t,n){$(t)?e.render=t:A(t)&&(e.setupState=dt(t)),Mr(e)}function Fr(e){Er=e}function Mr(e,t){const n=e.type;e.render||(Er&&n.template&&!n.render&&(n.render=Er(n.template,{isCustomElement:e.appContext.config.isCustomElement,delimiters:n.delimiters})),e.render=n.render||g,e.render._rc&&(e.withProxy=new Proxy(e.ctx,_r))),Cr=e,le(),ur(e,n),ce(),Cr=null}function Ar(e){const t=t=>{e.exposed=dt(t)};return{attrs:e.attrs,slots:e.slots,emit:e.emit,expose:t}}function Ir(e,t=Cr){t&&(t.effects||(t.effects=[])).push(e)}const Or=/(?:^|[-_])(\w)/g;function Br(e){return $(e)&&e.displayName||e.name}function Rr(e,t,n=!1){let o=Br(t);if(!o&&t.__file){const e=t.__file.match(/([^/\\]+)\.\w+$/);e&&(o=e[1])}if(!o&&e&&e.parent){const n=e=>{for(const n in e)if(e[n]===t)return n};o=n(e.components||e.parent.type.components)||n(e.appContext.components)}return o?o.replace(Or,(e=>e.toUpperCase())).replace(/[-_]/g,""):n?"App":"Anonymous"}function Vr(e){const t=function(e){let t,n;return $(e)?(t=e,n=g):(t=e.get,n=e.set),new vt(t,n,$(e)||!e.set)}(e);return Ir(t.effect),t}function Pr(e,t,n){const o=arguments.length;return 2===o?A(t)&&!w(t)?Jo(t)?er(e,null,[t]):er(e,t):er(e,null,t):(o>3?n=Array.prototype.slice.call(arguments,2):3===o&&Jo(n)&&(n=[n]),er(e,t,n))}const Lr=Symbol("");const jr="3.0.11",Ur="http://www.w3.org/2000/svg",Hr="undefined"!=typeof document?document:null;let Dr,zr;const Wr={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,o)=>{const r=t?Hr.createElementNS(Ur,e):Hr.createElement(e,n?{is:n}:void 0);return"select"===e&&o&&null!=o.multiple&&r.setAttribute("multiple",o.multiple),r},createText:e=>Hr.createTextNode(e),createComment:e=>Hr.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Hr.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},cloneNode(e){const t=e.cloneNode(!0);return"_value"in e&&(t._value=e._value),t},insertStaticContent(e,t,n,o){const r=o?zr||(zr=Hr.createElementNS(Ur,"svg")):Dr||(Dr=Hr.createElement("div"));r.innerHTML=e;const s=r.firstChild;let i=s,l=i;for(;i;)l=i,Wr.insert(i,t,n),i=r.firstChild;return[s,l]}};const Kr=/\s*!important$/;function Gr(e,t,n){if(w(n))n.forEach((n=>Gr(e,t,n)));else if(t.startsWith("--"))e.setProperty(t,n);else{const o=function(e,t){const n=Jr[t];if(n)return n;let o=U(t);if("filter"!==o&&o in e)return Jr[t]=o;o=z(o);for(let r=0;rdocument.createEvent("Event").timeStamp&&(Qr=()=>performance.now());const e=navigator.userAgent.match(/firefox\/(\d+)/i);Xr=!!(e&&Number(e[1])<=53)}let Yr=0;const es=Promise.resolve(),ts=()=>{Yr=0};function ns(e,t,n,o){e.addEventListener(t,n,o)}function os(e,t,n,o,r=null){const s=e._vei||(e._vei={}),i=s[t];if(o&&i)i.value=o;else{const[n,l]=function(e){let t;if(rs.test(e)){let n;for(t={};n=e.match(rs);)e=e.slice(0,e.length-n[0].length),t[n[0].toLowerCase()]=!0}return[D(e.slice(2)),t]}(t);if(o){ns(e,n,s[t]=function(e,t){const n=e=>{const o=e.timeStamp||Qr();(Xr||o>=n.attached-1)&&Ct(function(e,t){if(w(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map((e=>t=>!t._stopped&&e(t)))}return t}(e,n.value),t,5,[e])};return n.value=e,n.attached=(()=>Yr||(es.then(ts),Yr=Qr()))(),n}(o,r),l)}else i&&(!function(e,t,n,o){e.removeEventListener(t,n,o)}(e,n,i,l),s[t]=void 0)}}const rs=/(?:Once|Passive|Capture)$/;const ss=/^on[a-z]/;function is(e,t){if(128&e.shapeFlag){const n=e.suspense;e=n.activeBranch,n.pendingBranch&&!n.isHydrating&&n.effects.push((()=>{is(n.activeBranch,t)}))}for(;e.component;)e=e.component.subTree;if(1&e.shapeFlag&&e.el){const n=e.el.style;for(const e in t)n.setProperty(`--${e}`,t[e])}else e.type===Lo&&e.children.forEach((e=>is(e,t)))}const ls="transition",cs="animation",as=(e,{slots:t})=>Pr(Dn,fs(e),t);as.displayName="Transition";const us={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},ps=as.props=x({},Dn.props,us);function fs(e){let{name:t="v",type:n,css:o=!0,duration:r,enterFromClass:s=`${t}-enter-from`,enterActiveClass:i=`${t}-enter-active`,enterToClass:l=`${t}-enter-to`,appearFromClass:c=s,appearActiveClass:a=i,appearToClass:u=l,leaveFromClass:p=`${t}-leave-from`,leaveActiveClass:f=`${t}-leave-active`,leaveToClass:d=`${t}-leave-to`}=e;const h={};for(const x in e)x in us||(h[x]=e[x]);if(!o)return h;const m=function(e){if(null==e)return null;if(A(e))return[ds(e.enter),ds(e.leave)];{const t=ds(e);return[t,t]}}(r),g=m&&m[0],v=m&&m[1],{onBeforeEnter:y,onEnter:b,onEnterCancelled:_,onLeave:S,onLeaveCancelled:C,onBeforeAppear:k=y,onAppear:w=b,onAppearCancelled:T=_}=h,E=(e,t,n)=>{ms(e,t?u:l),ms(e,t?a:i),n&&n()},N=(e,t)=>{ms(e,d),ms(e,f),t&&t()},$=e=>(t,o)=>{const r=e?w:b,i=()=>E(t,e,o);r&&r(t,i),gs((()=>{ms(t,e?c:s),hs(t,e?u:l),r&&r.length>1||ys(t,n,g,i)}))};return x(h,{onBeforeEnter(e){y&&y(e),hs(e,s),hs(e,i)},onBeforeAppear(e){k&&k(e),hs(e,c),hs(e,a)},onEnter:$(!1),onAppear:$(!0),onLeave(e,t){const o=()=>N(e,t);hs(e,p),Ss(),hs(e,f),gs((()=>{ms(e,p),hs(e,d),S&&S.length>1||ys(e,n,v,o)})),S&&S(e,o)},onEnterCancelled(e){E(e,!1),_&&_(e)},onAppearCancelled(e){E(e,!0),T&&T(e)},onLeaveCancelled(e){N(e),C&&C(e)}})}function ds(e){return J(e)}function hs(e,t){t.split(/\s+/).forEach((t=>t&&e.classList.add(t))),(e._vtc||(e._vtc=new Set)).add(t)}function ms(e,t){t.split(/\s+/).forEach((t=>t&&e.classList.remove(t)));const{_vtc:n}=e;n&&(n.delete(t),n.size||(e._vtc=void 0))}function gs(e){requestAnimationFrame((()=>{requestAnimationFrame(e)}))}let vs=0;function ys(e,t,n,o){const r=e._endId=++vs,s=()=>{r===e._endId&&o()};if(n)return setTimeout(s,n);const{type:i,timeout:l,propCount:c}=bs(e,t);if(!i)return o();const a=i+"end";let u=0;const p=()=>{e.removeEventListener(a,f),s()},f=t=>{t.target===e&&++u>=c&&p()};setTimeout((()=>{u(n[e]||"").split(", "),r=o("transitionDelay"),s=o("transitionDuration"),i=_s(r,s),l=o("animationDelay"),c=o("animationDuration"),a=_s(l,c);let u=null,p=0,f=0;t===ls?i>0&&(u=ls,p=i,f=s.length):t===cs?a>0&&(u=cs,p=a,f=c.length):(p=Math.max(i,a),u=p>0?i>a?ls:cs:null,f=u?u===ls?s.length:c.length:0);return{type:u,timeout:p,propCount:f,hasTransform:u===ls&&/\b(transform|all)(,|$)/.test(n.transitionProperty)}}function _s(e,t){for(;e.lengthxs(t)+xs(e[n]))))}function xs(e){return 1e3*Number(e.slice(0,-1).replace(",","."))}function Ss(){return document.body.offsetHeight}const Cs=new WeakMap,ks=new WeakMap,ws={name:"TransitionGroup",props:x({},ps,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=kr(),o=Un();let r,s;return $n((()=>{if(!r.length)return;const t=e.moveClass||`${e.name||"v"}-move`;if(!function(e,t,n){const o=e.cloneNode();e._vtc&&e._vtc.forEach((e=>{e.split(/\s+/).forEach((e=>e&&o.classList.remove(e)))}));n.split(/\s+/).forEach((e=>e&&o.classList.add(e))),o.style.display="none";const r=1===t.nodeType?t:t.parentNode;r.appendChild(o);const{hasTransform:s}=bs(o);return r.removeChild(o),s}(r[0].el,n.vnode.el,t))return;r.forEach(Ts),r.forEach(Es);const o=r.filter(Ns);Ss(),o.forEach((e=>{const n=e.el,o=n.style;hs(n,t),o.transform=o.webkitTransform=o.transitionDuration="";const r=n._moveCb=e=>{e&&e.target!==n||e&&!/transform$/.test(e.propertyName)||(n.removeEventListener("transitionend",r),n._moveCb=null,ms(n,t))};n.addEventListener("transitionend",r)}))})),()=>{const i=st(e),l=fs(i),c=i.tag||Lo;r=s,s=t.default?Jn(t.default()):[];for(let e=0;e{const t=e.props["onUpdate:modelValue"];return w(t)?e=>G(t,e):t};function Fs(e){e.target.composing=!0}function Ms(e){const t=e.target;t.composing&&(t.composing=!1,function(e,t){const n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}(t,"input"))}const As={created(e,{modifiers:{lazy:t,trim:n,number:o}},r){e._assign=$s(r);const s=o||"number"===e.type;ns(e,t?"change":"input",(t=>{if(t.target.composing)return;let o=e.value;n?o=o.trim():s&&(o=J(o)),e._assign(o)})),n&&ns(e,"change",(()=>{e.value=e.value.trim()})),t||(ns(e,"compositionstart",Fs),ns(e,"compositionend",Ms),ns(e,"change",Ms))},mounted(e,{value:t}){e.value=null==t?"":t},beforeUpdate(e,{value:t,modifiers:{trim:n,number:o}},r){if(e._assign=$s(r),e.composing)return;if(document.activeElement===e){if(n&&e.value.trim()===t)return;if((o||"number"===e.type)&&J(e.value)===t)return}const s=null==t?"":t;e.value!==s&&(e.value=s)}},Is={created(e,t,n){e._assign=$s(n),ns(e,"change",(()=>{const t=e._modelValue,n=Ps(e),o=e.checked,r=e._assign;if(w(t)){const e=f(t,n),s=-1!==e;if(o&&!s)r(t.concat(n));else if(!o&&s){const n=[...t];n.splice(e,1),r(n)}}else if(E(t)){const e=new Set(t);o?e.add(n):e.delete(n),r(e)}else r(Ls(e,o))}))},mounted:Os,beforeUpdate(e,t,n){e._assign=$s(n),Os(e,t,n)}};function Os(e,{value:t,oldValue:n},o){e._modelValue=t,w(t)?e.checked=f(t,o.props.value)>-1:E(t)?e.checked=t.has(o.props.value):t!==n&&(e.checked=p(t,Ls(e,!0)))}const Bs={created(e,{value:t},n){e.checked=p(t,n.props.value),e._assign=$s(n),ns(e,"change",(()=>{e._assign(Ps(e))}))},beforeUpdate(e,{value:t,oldValue:n},o){e._assign=$s(o),t!==n&&(e.checked=p(t,o.props.value))}},Rs={created(e,{value:t,modifiers:{number:n}},o){const r=E(t);ns(e,"change",(()=>{const t=Array.prototype.filter.call(e.options,(e=>e.selected)).map((e=>n?J(Ps(e)):Ps(e)));e._assign(e.multiple?r?new Set(t):t:t[0])})),e._assign=$s(o)},mounted(e,{value:t}){Vs(e,t)},beforeUpdate(e,t,n){e._assign=$s(n)},updated(e,{value:t}){Vs(e,t)}};function Vs(e,t){const n=e.multiple;if(!n||w(t)||E(t)){for(let o=0,r=e.options.length;o-1:r.selected=t.has(s);else if(p(Ps(r),t))return void(e.selectedIndex=o)}n||(e.selectedIndex=-1)}}function Ps(e){return"_value"in e?e._value:e.value}function Ls(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}const js={created(e,t,n){Us(e,t,n,null,"created")},mounted(e,t,n){Us(e,t,n,null,"mounted")},beforeUpdate(e,t,n,o){Us(e,t,n,o,"beforeUpdate")},updated(e,t,n,o){Us(e,t,n,o,"updated")}};function Us(e,t,n,o,r){let s;switch(e.tagName){case"SELECT":s=Rs;break;case"TEXTAREA":s=As;break;default:switch(n.props&&n.props.type){case"checkbox":s=Is;break;case"radio":s=Bs;break;default:s=As}}const i=s[r];i&&i(e,t,n,o)}const Hs=["ctrl","shift","alt","meta"],Ds={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&0!==e.button,middle:e=>"button"in e&&1!==e.button,right:e=>"button"in e&&2!==e.button,exact:(e,t)=>Hs.some((n=>e[`${n}Key`]&&!t.includes(n)))},zs={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Ws={beforeMount(e,{value:t},{transition:n}){e._vod="none"===e.style.display?"":e.style.display,n&&t?n.beforeEnter(e):Ks(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:o}){!t!=!n&&(o?t?(o.beforeEnter(e),Ks(e,!0),o.enter(e)):o.leave(e,(()=>{Ks(e,!1)})):Ks(e,t))},beforeUnmount(e,{value:t}){Ks(e,t)}};function Ks(e,t){e.style.display=t?e._vod:"none"}const Gs=x({patchProp:(e,t,o,r,s=!1,i,l,c,a)=>{switch(t){case"class":!function(e,t,n){if(null==t&&(t=""),n)e.setAttribute("class",t);else{const n=e._vtc;n&&(t=(t?[t,...n]:[...n]).join(" ")),e.className=t}}(e,r,s);break;case"style":!function(e,t,n){const o=e.style;if(n)if(F(n)){if(t!==n){const t=o.display;o.cssText=n,"_vod"in e&&(o.display=t)}}else{for(const e in n)Gr(o,e,n[e]);if(t&&!F(t))for(const e in t)null==n[e]&&Gr(o,e,"")}else e.removeAttribute("style")}(e,o,r);break;default:b(t)?_(t)||os(e,t,0,r,l):function(e,t,n,o){if(o)return"innerHTML"===t||!!(t in e&&ss.test(t)&&$(n));if("spellcheck"===t||"draggable"===t)return!1;if("form"===t)return!1;if("list"===t&&"INPUT"===e.tagName)return!1;if("type"===t&&"TEXTAREA"===e.tagName)return!1;if(ss.test(t)&&F(n))return!1;return t in e}(e,t,r,s)?function(e,t,n,o,r,s,i){if("innerHTML"===t||"textContent"===t)return o&&i(o,r,s),void(e[t]=null==n?"":n);if("value"!==t||"PROGRESS"===e.tagName){if(""===n||null==n){const o=typeof e[t];if(""===n&&"boolean"===o)return void(e[t]=!0);if(null==n&&"string"===o)return e[t]="",void e.removeAttribute(t);if("number"===o)return e[t]=0,void e.removeAttribute(t)}try{e[t]=n}catch(l){}}else{e._value=n;const t=null==n?"":n;e.value!==t&&(e.value=t)}}(e,t,r,i,l,c,a):("true-value"===t?e._trueValue=r:"false-value"===t&&(e._falseValue=r),function(e,t,o,r){if(r&&t.startsWith("xlink:"))null==o?e.removeAttributeNS(Zr,t.slice(6,t.length)):e.setAttributeNS(Zr,t,o);else{const r=n(t);null==o||r&&!1===o?e.removeAttribute(t):e.setAttribute(t,r?"":o)}}(e,t,r,s))}},forcePatchProp:(e,t)=>"value"===t},Wr);let qs,Js=!1;function Zs(){return qs||(qs=ko(Gs))}function Qs(){return qs=Js?qs:wo(Gs),Js=!0,qs}const Xs=(...e)=>{const t=Zs().createApp(...e),{mount:n}=t;return t.mount=e=>{const o=Ys(e);if(!o)return;const r=t._component;$(r)||r.render||r.template||(r.template=o.innerHTML),o.innerHTML="";const s=n(o,!1,o instanceof SVGElement);return o instanceof Element&&(o.removeAttribute("v-cloak"),o.setAttribute("data-v-app","")),s},t};function Ys(e){if(F(e)){return document.querySelector(e)}return e}var ei=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",Transition:as,TransitionGroup:ws,createApp:Xs,createSSRApp:(...e)=>{const t=Qs().createApp(...e),{mount:n}=t;return t.mount=e=>{const t=Ys(e);if(t)return n(t,!0,t instanceof SVGElement)},t},hydrate:(...e)=>{Qs().hydrate(...e)},render:(...e)=>{Zs().render(...e)},useCssModule:function(e="$style"){{const t=kr();if(!t)return h;const n=t.type.__cssModules;if(!n)return h;const o=n[e];return o||h}},useCssVars:function(e){const t=kr();if(!t)return;const n=()=>is(t.subTree,e(t.proxy));En((()=>Bn(n,{flush:"post"}))),$n(n)},vModelCheckbox:Is,vModelDynamic:js,vModelRadio:Bs,vModelSelect:Rs,vModelText:As,vShow:Ws,withKeys:(e,t)=>n=>{if(!("key"in n))return;const o=D(n.key);return t.some((e=>e===o||zs[e]===o))?e(n):void 0},withModifiers:(e,t)=>(n,...o)=>{for(let e=0;enull==e?"":A(e)?JSON.stringify(e,d,2):String(e),toHandlerKey:W,BaseTransition:Dn,Comment:Uo,Fragment:Lo,KeepAlive:Qn,Static:Ho,Suspense:fn,Teleport:Io,Text:jo,callWithAsyncErrorHandling:Ct,callWithErrorHandling:St,cloneVNode:tr,computed:Vr,createBlock:qo,createCommentVNode:function(e="",t=!1){return t?(Wo(),qo(Uo,null,e)):er(Uo,null,e)},createHydrationRenderer:wo,createRenderer:ko,createSlots:function(e,t){for(let n=0;n{let e;return a||(e=a=t().catch((e=>{if(e=e instanceof Error?e:new Error(String(e)),l)return new Promise(((t,n)=>{l(e,(()=>t((u++,a=null,p()))),(()=>n(e)),u+1)}));throw e})).then((t=>e!==a&&a?a:(t&&(t.__esModule||"Module"===t[Symbol.toStringTag])&&(t=t.default),c=t,t))))};return bo({__asyncLoader:p,name:"AsyncComponentWrapper",setup(){const e=Cr;if(c)return()=>_o(c,e);const t=t=>{a=null,kt(t,e,13,!o)};if(i&&e.suspense)return p().then((t=>()=>_o(t,e))).catch((e=>(t(e),()=>o?er(o,{error:e}):null)));const l=ct(!1),u=ct(),f=ct(!!r);return r&&setTimeout((()=>{f.value=!1}),r),null!=s&&setTimeout((()=>{if(!l.value&&!u.value){const e=new Error(`Async component timed out after ${s}ms.`);t(e),u.value=e}}),s),p().then((()=>{l.value=!0})).catch((e=>{t(e),u.value=e})),()=>l.value&&c?_o(c,e):u.value&&o?er(o,{error:u.value}):n&&!f.value?er(n):void 0}})},defineComponent:bo,defineEmit:function(){return null},defineProps:function(){return null},get devtools(){return Gt},getCurrentInstance:kr,getTransitionRawChildren:Jn,h:Pr,handleError:kt,initCustomFormatter:function(){},inject:cr,isRuntimeOnly:()=>!Er,isVNode:Jo,mergeProps:ir,nextTick:Pt,onActivated:Yn,onBeforeMount:Tn,onBeforeUnmount:Fn,onBeforeUpdate:Nn,onDeactivated:eo,onErrorCaptured:On,onMounted:En,onRenderTracked:In,onRenderTriggered:An,onUnmounted:Mn,onUpdated:$n,openBlock:Wo,popScopeId:function(){nn=null},provide:lr,pushScopeId:function(e){nn=e},queuePostFlushCb:Ht,registerRuntimeCompiler:Fr,renderList:function(e,t){let n;if(w(e)||F(e)){n=new Array(e.length);for(let o=0,r=e.length;o{{const e=cr(Lr);return e||bt("Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build."),e}},useTransitionState:Un,version:jr,warn:bt,watch:Vn,watchEffect:Bn,withCtx:rn,withDirectives:function(e,t){if(null===tn)return e;const n=tn.proxy,o=e.dirs||(e.dirs=[]);for(let r=0;rrn});function ti(e){throw e}function ni(e,t,n,o){const r=new SyntaxError(String(e));return r.code=e,r.loc=t,r}const oi=Symbol(""),ri=Symbol(""),si=Symbol(""),ii=Symbol(""),li=Symbol(""),ci=Symbol(""),ai=Symbol(""),ui=Symbol(""),pi=Symbol(""),fi=Symbol(""),di=Symbol(""),hi=Symbol(""),mi=Symbol(""),gi=Symbol(""),vi=Symbol(""),yi=Symbol(""),bi=Symbol(""),_i=Symbol(""),xi=Symbol(""),Si=Symbol(""),Ci=Symbol(""),ki=Symbol(""),wi=Symbol(""),Ti=Symbol(""),Ei=Symbol(""),Ni=Symbol(""),$i=Symbol(""),Fi=Symbol(""),Mi=Symbol(""),Ai=Symbol(""),Ii=Symbol(""),Oi={[oi]:"Fragment",[ri]:"Teleport",[si]:"Suspense",[ii]:"KeepAlive",[li]:"BaseTransition",[ci]:"openBlock",[ai]:"createBlock",[ui]:"createVNode",[pi]:"createCommentVNode",[fi]:"createTextVNode",[di]:"createStaticVNode",[hi]:"resolveComponent",[mi]:"resolveDynamicComponent",[gi]:"resolveDirective",[vi]:"withDirectives",[yi]:"renderList",[bi]:"renderSlot",[_i]:"createSlots",[xi]:"toDisplayString",[Si]:"mergeProps",[Ci]:"toHandlers",[ki]:"camelize",[wi]:"capitalize",[Ti]:"toHandlerKey",[Ei]:"setBlockTracking",[Ni]:"pushScopeId",[$i]:"popScopeId",[Fi]:"withScopeId",[Mi]:"withCtx",[Ai]:"unref",[Ii]:"isRef"};const Bi={source:"",start:{line:1,column:1,offset:0},end:{line:1,column:1,offset:0}};function Ri(e,t,n,o,r,s,i,l=!1,c=!1,a=Bi){return e&&(l?(e.helper(ci),e.helper(ai)):e.helper(ui),i&&e.helper(vi)),{type:13,tag:t,props:n,children:o,patchFlag:r,dynamicProps:s,directives:i,isBlock:l,disableTracking:c,loc:a}}function Vi(e,t=Bi){return{type:17,loc:t,elements:e}}function Pi(e,t=Bi){return{type:15,loc:t,properties:e}}function Li(e,t){return{type:16,loc:Bi,key:F(e)?ji(e,!0):e,value:t}}function ji(e,t,n=Bi,o=0){return{type:4,loc:n,content:e,isStatic:t,constType:t?3:o}}function Ui(e,t=Bi){return{type:8,loc:t,children:e}}function Hi(e,t=[],n=Bi){return{type:14,loc:n,callee:e,arguments:t}}function Di(e,t,n=!1,o=!1,r=Bi){return{type:18,params:e,returns:t,newline:n,isSlot:o,loc:r}}function zi(e,t,n,o=!0){return{type:19,test:e,consequent:t,alternate:n,newline:o,loc:Bi}}const Wi=e=>4===e.type&&e.isStatic,Ki=(e,t)=>e===t||e===D(t);function Gi(e){return Ki(e,"Teleport")?ri:Ki(e,"Suspense")?si:Ki(e,"KeepAlive")?ii:Ki(e,"BaseTransition")?li:void 0}const qi=/^\d|[^\$\w]/,Ji=e=>!qi.test(e),Zi=/^[A-Za-z_$\xA0-\uFFFF][\w$\xA0-\uFFFF]*(?:\s*\.\s*[A-Za-z_$\xA0-\uFFFF][\w$\xA0-\uFFFF]*|\[[^\]]+\])*$/,Qi=e=>!!e&&Zi.test(e.trim());function Xi(e,t,n){const o={source:e.source.substr(t,n),start:Yi(e.start,e.source,t),end:e.end};return null!=n&&(o.end=Yi(e.start,e.source,t+n)),o}function Yi(e,t,n=t.length){return el(x({},e),t,n)}function el(e,t,n=t.length){let o=0,r=-1;for(let s=0;s4===e.key.type&&e.key.content===n))}e||r.properties.unshift(t),o=r}else o=Hi(n.helper(Si),[Pi([t]),r]);13===e.type?e.props=o:e.arguments[2]=o}function al(e,t){return`_${t}_${e.replace(/[^\w]/g,"_")}`}const ul=/&(gt|lt|amp|apos|quot);/g,pl={gt:">",lt:"<",amp:"&",apos:"'",quot:'"'},fl={delimiters:["{{","}}"],getNamespace:()=>0,getTextMode:()=>0,isVoidTag:v,isPreTag:v,isCustomElement:v,decodeEntities:e=>e.replace(ul,((e,t)=>pl[t])),onError:ti,comments:!1};function dl(e,t={}){const n=function(e,t){const n=x({},fl);for(const o in t)n[o]=t[o]||fl[o];return{options:n,column:1,line:1,offset:0,originalSource:e,source:e,inPre:!1,inVPre:!1}}(e,t),o=El(n);return function(e,t=Bi){return{type:0,children:e,helpers:[],components:[],directives:[],hoists:[],imports:[],cached:0,temps:0,codegenNode:void 0,loc:t}}(hl(n,0,[]),Nl(n,o))}function hl(e,t,n){const o=$l(n),r=o?o.ns:0,s=[];for(;!Bl(e,t,n);){const i=e.source;let l;if(0===t||1===t)if(!e.inVPre&&Fl(i,e.options.delimiters[0]))l=kl(e,t);else if(0===t&&"<"===i[0])if(1===i.length)Ol(e,5,1);else if("!"===i[1])Fl(i,"\x3c!--")?l=vl(e):Fl(i,""===i[2]){Ol(e,14,2),Ml(e,3);continue}if(/[a-z]/i.test(i[2])){Ol(e,23),xl(e,1,o);continue}Ol(e,12,2),l=yl(e)}else/[a-z]/i.test(i[1])?l=bl(e,n):"?"===i[1]?(Ol(e,21,1),l=yl(e)):Ol(e,12,1);if(l||(l=wl(e,t)),w(l))for(let e=0;e/.exec(e.source);if(o){o.index<=3&&Ol(e,0),o[1]&&Ol(e,10),n=e.source.slice(4,o.index);const t=e.source.slice(0,o.index);let r=1,s=0;for(;-1!==(s=t.indexOf("\x3c!--",r));)Ml(e,s-r+1),s+4");return-1===r?(o=e.source.slice(n),Ml(e,e.source.length)):(o=e.source.slice(n,r),Ml(e,r+1)),{type:3,content:o,loc:Nl(e,t)}}function bl(e,t){const n=e.inPre,o=e.inVPre,r=$l(t),s=xl(e,0,r),i=e.inPre&&!n,l=e.inVPre&&!o;if(s.isSelfClosing||e.options.isVoidTag(s.tag))return s;t.push(s);const c=e.options.getTextMode(s,r),a=hl(e,c,t);if(t.pop(),s.children=a,Rl(e.source,s.tag))xl(e,1,r);else if(Ol(e,24,0,s.loc.start),0===e.source.length&&"script"===s.tag.toLowerCase()){const t=a[0];t&&Fl(t.loc.source,"\x3c!--")&&Ol(e,8)}return s.loc=Nl(e,s.loc.start),i&&(e.inPre=!1),l&&(e.inVPre=!1),s}const _l=e("if,else,else-if,for,slot");function xl(e,t,n){const o=El(e),r=/^<\/?([a-z][^\t\r\n\f />]*)/i.exec(e.source),s=r[1],i=e.options.getNamespace(s,n);Ml(e,r[0].length),Al(e);const l=El(e),c=e.source;let a=Sl(e,t);e.options.isPreTag(s)&&(e.inPre=!0),!e.inVPre&&a.some((e=>7===e.type&&"pre"===e.name))&&(e.inVPre=!0,x(e,l),e.source=c,a=Sl(e,t).filter((e=>"v-pre"!==e.name)));let u=!1;0===e.source.length?Ol(e,9):(u=Fl(e.source,"/>"),1===t&&u&&Ol(e,4),Ml(e,u?2:1));let p=0;const f=e.options;if(!e.inVPre&&!f.isCustomElement(s)){const e=a.some((e=>7===e.type&&"is"===e.name));f.isNativeTag&&!e?f.isNativeTag(s)||(p=1):(e||Gi(s)||f.isBuiltInComponent&&f.isBuiltInComponent(s)||/^[A-Z]/.test(s)||"component"===s)&&(p=1),"slot"===s?p=2:"template"===s&&a.some((e=>7===e.type&&_l(e.name)))&&(p=3)}return{type:1,ns:i,tag:s,tagType:p,props:a,isSelfClosing:u,children:[],loc:Nl(e,o),codegenNode:void 0}}function Sl(e,t){const n=[],o=new Set;for(;e.source.length>0&&!Fl(e.source,">")&&!Fl(e.source,"/>");){if(Fl(e.source,"/")){Ol(e,22),Ml(e,1),Al(e);continue}1===t&&Ol(e,3);const r=Cl(e,o);0===t&&n.push(r),/^[^\t\r\n\f />]/.test(e.source)&&Ol(e,15),Al(e)}return n}function Cl(e,t){const n=El(e),o=/^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(e.source)[0];t.has(o)&&Ol(e,2),t.add(o),"="===o[0]&&Ol(e,19);{const t=/["'<]/g;let n;for(;n=t.exec(o);)Ol(e,17,n.index)}let r;Ml(e,o.length),/^[\t\r\n\f ]*=/.test(e.source)&&(Al(e),Ml(e,1),Al(e),r=function(e){const t=El(e);let n;const o=e.source[0],r='"'===o||"'"===o;if(r){Ml(e,1);const t=e.source.indexOf(o);-1===t?n=Tl(e,e.source.length,4):(n=Tl(e,t,4),Ml(e,1))}else{const t=/^[^\t\r\n\f >]+/.exec(e.source);if(!t)return;const o=/["'<=`]/g;let r;for(;r=o.exec(t[0]);)Ol(e,18,r.index);n=Tl(e,t[0].length,4)}return{content:n,isQuoted:r,loc:Nl(e,t)}}(e),r||Ol(e,13));const s=Nl(e,n);if(!e.inVPre&&/^(v-|:|@|#)/.test(o)){const t=/(?:^v-([a-z0-9-]+))?(?:(?::|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(o),i=t[1]||(Fl(o,":")?"bind":Fl(o,"@")?"on":"slot");let l;if(t[2]){const r="slot"===i,s=o.lastIndexOf(t[2]),c=Nl(e,Il(e,n,s),Il(e,n,s+t[2].length+(r&&t[3]||"").length));let a=t[2],u=!0;a.startsWith("[")?(u=!1,a.endsWith("]")||Ol(e,26),a=a.substr(1,a.length-2)):r&&(a+=t[3]||""),l={type:4,content:a,isStatic:u,constType:u?3:0,loc:c}}if(r&&r.isQuoted){const e=r.loc;e.start.offset++,e.start.column++,e.end=Yi(e.start,r.content),e.source=e.source.slice(1,-1)}return{type:7,name:i,exp:r&&{type:4,content:r.content,isStatic:!1,constType:0,loc:r.loc},arg:l,modifiers:t[3]?t[3].substr(1).split("."):[],loc:s}}return{type:6,name:o,value:r&&{type:2,content:r.content,loc:r.loc},loc:s}}function kl(e,t){const[n,o]=e.options.delimiters,r=e.source.indexOf(o,n.length);if(-1===r)return void Ol(e,25);const s=El(e);Ml(e,n.length);const i=El(e),l=El(e),c=r-n.length,a=e.source.slice(0,c),u=Tl(e,c,t),p=u.trim(),f=u.indexOf(p);f>0&&el(i,a,f);return el(l,a,c-(u.length-p.length-f)),Ml(e,o.length),{type:5,content:{type:4,isStatic:!1,constType:0,content:p,loc:Nl(e,i,l)},loc:Nl(e,s)}}function wl(e,t){const n=["<",e.options.delimiters[0]];3===t&&n.push("]]>");let o=e.source.length;for(let s=0;st&&(o=t)}const r=El(e);return{type:2,content:Tl(e,o,t),loc:Nl(e,r)}}function Tl(e,t,n){const o=e.source.slice(0,t);return Ml(e,t),2===n||3===n||-1===o.indexOf("&")?o:e.options.decodeEntities(o,4===n)}function El(e){const{column:t,line:n,offset:o}=e;return{column:t,line:n,offset:o}}function Nl(e,t,n){return{start:t,end:n=n||El(e),source:e.originalSource.slice(t.offset,n.offset)}}function $l(e){return e[e.length-1]}function Fl(e,t){return e.startsWith(t)}function Ml(e,t){const{source:n}=e;el(e,n,t),e.source=n.slice(t)}function Al(e){const t=/^[\t\r\n\f ]+/.exec(e.source);t&&Ml(e,t[0].length)}function Il(e,t,n){return Yi(t,e.originalSource.slice(t.offset,n),n)}function Ol(e,t,n,o=El(e)){n&&(o.offset+=n,o.column+=n),e.options.onError(ni(t,{start:o,end:o,source:""}))}function Bl(e,t,n){const o=e.source;switch(t){case 0:if(Fl(o,"=0;--e)if(Rl(o,n[e].tag))return!0;break;case 1:case 2:{const e=$l(n);if(e&&Rl(o,e.tag))return!0;break}case 3:if(Fl(o,"]]>"))return!0}return!o}function Rl(e,t){return Fl(e,"]/.test(e[2+t.length]||">")}function Vl(e,t){Ll(e,t,Pl(e,e.children[0]))}function Pl(e,t){const{children:n}=e;return 1===n.length&&1===t.type&&!ll(t)}function Ll(e,t,n=!1){let o=!1,r=!0;const{children:s}=e;for(let i=0;i0){if(s<3&&(r=!1),s>=2){e.codegenNode.patchFlag="-1",e.codegenNode=t.hoist(e.codegenNode),o=!0;continue}}else{const n=e.codegenNode;if(13===n.type){const o=Dl(n);if((!o||512===o||1===o)&&Ul(e,t)>=2){const o=Hl(e);o&&(n.props=t.hoist(o))}}}}else if(12===e.type){const n=jl(e.content,t);n>0&&(n<3&&(r=!1),n>=2&&(e.codegenNode=t.hoist(e.codegenNode),o=!0))}if(1===e.type){const n=1===e.tagType;n&&t.scopes.vSlot++,Ll(e,t),n&&t.scopes.vSlot--}else if(11===e.type)Ll(e,t,1===e.children.length);else if(9===e.type)for(let n=0;n1)for(let r=0;r`_${Oi[S.helper(e)]}`,replaceNode(e){S.parent.children[S.childIndex]=S.currentNode=e},removeNode(e){const t=S.parent.children,n=e?t.indexOf(e):S.currentNode?S.childIndex:-1;e&&e!==S.currentNode?S.childIndex>n&&(S.childIndex--,S.onNodeRemoved()):(S.currentNode=null,S.onNodeRemoved()),S.parent.children.splice(n,1)},onNodeRemoved:()=>{},addIdentifiers(e){},removeIdentifiers(e){},hoist(e){S.hoists.push(e);const t=ji(`_hoisted_${S.hoists.length}`,!1,e.loc,2);return t.hoisted=e,t},cache:(e,t=!1)=>function(e,t,n=!1){return{type:20,index:e,value:t,isVNode:n,loc:Bi}}(++S.cached,e,t)};return S}function Wl(e,t){const n=zl(e,t);Kl(e,n),t.hoistStatic&&Vl(e,n),t.ssr||function(e,t){const{helper:n,removeHelper:o}=t,{children:r}=e;if(1===r.length){const t=r[0];if(Pl(e,t)&&t.codegenNode){const r=t.codegenNode;13===r.type&&(r.isBlock||(o(ui),r.isBlock=!0,n(ci),n(ai))),e.codegenNode=r}else e.codegenNode=t}else if(r.length>1){let o=64;e.codegenNode=Ri(t,n(oi),void 0,e.children,o+"",void 0,void 0,!0)}}(e,n),e.helpers=[...n.helpers.keys()],e.components=[...n.components],e.directives=[...n.directives],e.imports=n.imports,e.hoists=n.hoists,e.temps=n.temps,e.cached=n.cached}function Kl(e,t){t.currentNode=e;const{nodeTransforms:n}=t,o=[];for(let s=0;s{n--};for(;nt===e:t=>e.test(t);return(e,o)=>{if(1===e.type){const{props:r}=e;if(3===e.tagType&&r.some(sl))return;const s=[];for(let i=0;i`_${Oi[e]}`,push(e,t){u.code+=e},indent(){p(++u.indentLevel)},deindent(e=!1){e?--u.indentLevel:p(--u.indentLevel)},newline(){p(u.indentLevel)}};function p(e){u.push("\n"+" ".repeat(e))}return u}(e,t);t.onContextCreated&&t.onContextCreated(n);const{mode:o,push:r,prefixIdentifiers:s,indent:i,deindent:l,newline:c,scopeId:a,ssr:u}=n,p=e.helpers.length>0,f=!s&&"module"!==o;!function(e,t){const{ssr:n,prefixIdentifiers:o,push:r,newline:s,runtimeModuleName:i,runtimeGlobalName:l}=t,c=l,a=e=>`${Oi[e]}: _${Oi[e]}`;if(e.helpers.length>0&&(r(`const _Vue = ${c}\n`),e.hoists.length)){r(`const { ${[ui,pi,fi,di].filter((t=>e.helpers.includes(t))).map(a).join(", ")} } = _Vue\n`)}(function(e,t){if(!e.length)return;t.pure=!0;const{push:n,newline:o,helper:r,scopeId:s,mode:i}=t;o(),e.forEach(((e,r)=>{e&&(n(`const _hoisted_${r+1} = `),Yl(e,t),o())})),t.pure=!1})(e.hoists,t),s(),r("return ")}(e,n);if(r(`function ${u?"ssrRender":"render"}(${(u?["_ctx","_push","_parent","_attrs"]:["_ctx","_cache"]).join(", ")}) {`),i(),f&&(r("with (_ctx) {"),i(),p&&(r(`const { ${e.helpers.map((e=>`${Oi[e]}: _${Oi[e]}`)).join(", ")} } = _Vue`),r("\n"),c())),e.components.length&&(Zl(e.components,"component",n),(e.directives.length||e.temps>0)&&c()),e.directives.length&&(Zl(e.directives,"directive",n),e.temps>0&&c()),e.temps>0){r("let ");for(let t=0;t0?", ":""}_temp${t}`)}return(e.components.length||e.directives.length||e.temps)&&(r("\n"),c()),u||r("return "),e.codegenNode?Yl(e.codegenNode,n):r("null"),f&&(l(),r("}")),l(),r("}"),{ast:e,code:n.code,preamble:"",map:n.map?n.map.toJSON():void 0}}function Zl(e,t,{helper:n,push:o,newline:r}){const s=n("component"===t?hi:gi);for(let i=0;i3||!1;t.push("["),n&&t.indent(),Xl(e,t,n),n&&t.deindent(),t.push("]")}function Xl(e,t,n=!1,o=!0){const{push:r,newline:s}=t;for(let i=0;ie||"null"))}([s,i,l,c,a]),t),n(")"),p&&n(")");u&&(n(", "),Yl(u,t),n(")"))}(e,t);break;case 14:!function(e,t){const{push:n,helper:o,pure:r}=t,s=F(e.callee)?e.callee:o(e.callee);r&&n(ql);n(s+"(",e),Xl(e.arguments,t),n(")")}(e,t);break;case 15:!function(e,t){const{push:n,indent:o,deindent:r,newline:s}=t,{properties:i}=e;if(!i.length)return void n("{}",e);const l=i.length>1||!1;n(l?"{":"{ "),l&&o();for(let c=0;c "),(u||a)&&(n("{"),o());c?(u&&n("return "),w(c)?Ql(c,t):Yl(c,t)):a&&Yl(a,t);(u||a)&&(r(),n("}"));p&&n(")")}(e,t);break;case 19:!function(e,t){const{test:n,consequent:o,alternate:r,newline:s}=e,{push:i,indent:l,deindent:c,newline:a}=t;if(4===n.type){const e=!Ji(n.content);e&&i("("),ec(n,t),e&&i(")")}else i("("),Yl(n,t),i(")");s&&l(),t.indentLevel++,s||i(" "),i("? "),Yl(o,t),t.indentLevel--,s&&a(),s||i(" "),i(": ");const u=19===r.type;u||t.indentLevel++;Yl(r,t),u||t.indentLevel--;s&&c(!0)}(e,t);break;case 20:!function(e,t){const{push:n,helper:o,indent:r,deindent:s,newline:i}=t;n(`_cache[${e.index}] || (`),e.isVNode&&(r(),n(`${o(Ei)}(-1),`),i());n(`_cache[${e.index}] = `),Yl(e.value,t),e.isVNode&&(n(","),i(),n(`${o(Ei)}(1),`),i(),n(`_cache[${e.index}]`),s());n(")")}(e,t)}}function ec(e,t){const{content:n,isStatic:o}=e;t.push(o?JSON.stringify(n):n,e)}function tc(e,t){for(let n=0;nfunction(e,t,n,o){if(!("else"===t.name||t.exp&&t.exp.content.trim())){const o=t.exp?t.exp.loc:e.loc;n.onError(ni(27,t.loc)),t.exp=ji("true",!1,o)}if("if"===t.name){const r=rc(e,t),s={type:9,loc:e.loc,branches:[r]};if(n.replaceNode(s),o)return o(s,r,!0)}else{const r=n.parent.children;let s=r.indexOf(e);for(;s-- >=-1;){const i=r[s];if(!i||2!==i.type||i.content.trim().length){if(i&&9===i.type){n.removeNode();const r=rc(e,t);i.branches.push(r);const s=o&&o(i,r,!1);Kl(r,n),s&&s(),n.currentNode=null}else n.onError(ni(29,e.loc));break}n.removeNode(i)}}}(e,t,n,((e,t,o)=>{const r=n.parent.children;let s=r.indexOf(e),i=0;for(;s-- >=0;){const e=r[s];e&&9===e.type&&(i+=e.branches.length)}return()=>{if(o)e.codegenNode=sc(t,i,n);else{(function(e){for(;;)if(19===e.type){if(19!==e.alternate.type)return e;e=e.alternate}else 20===e.type&&(e=e.value)}(e.codegenNode)).alternate=sc(t,i+e.branches.length-1,n)}}}))));function rc(e,t){return{type:10,loc:e.loc,condition:"else"===t.name?void 0:t.exp,children:3!==e.tagType||tl(e,"for")?[e]:e.children,userKey:nl(e,"key")}}function sc(e,t,n){return e.condition?zi(e.condition,ic(e,t,n),Hi(n.helper(pi),['""',"true"])):ic(e,t,n)}function ic(e,t,n){const{helper:o,removeHelper:r}=n,s=Li("key",ji(`${t}`,!1,Bi,2)),{children:i}=e,l=i[0];if(1!==i.length||1!==l.type){if(1===i.length&&11===l.type){const e=l.codegenNode;return cl(e,s,n),e}{let t=64;return Ri(n,o(oi),Pi([s]),i,t+"",void 0,void 0,!0,!1,e.loc)}}{const e=l.codegenNode;return 13!==e.type||e.isBlock||(r(ui),e.isBlock=!0,o(ci),o(ai)),cl(e,s,n),e}}const lc=Gl("for",((e,t,n)=>{const{helper:o,removeHelper:r}=n;return function(e,t,n,o){if(!t.exp)return void n.onError(ni(30,t.loc));const r=pc(t.exp);if(!r)return void n.onError(ni(31,t.loc));const{addIdentifiers:s,removeIdentifiers:i,scopes:l}=n,{source:c,value:a,key:u,index:p}=r,f={type:11,loc:t.loc,source:c,valueAlias:a,keyAlias:u,objectIndexAlias:p,parseResult:r,children:il(e)?e.children:[e]};n.replaceNode(f),l.vFor++;const d=o&&o(f);return()=>{l.vFor--,d&&d()}}(e,t,n,(t=>{const s=Hi(o(yi),[t.source]),i=nl(e,"key"),l=i?Li("key",6===i.type?ji(i.value.content,!0):i.exp):null,c=4===t.source.type&&t.source.constType>0,a=c?64:i?128:256;return t.codegenNode=Ri(n,o(oi),void 0,s,a+"",void 0,void 0,!0,!c,e.loc),()=>{let i;const a=il(e),{children:u}=t,p=1!==u.length||1!==u[0].type,f=ll(e)?e:a&&1===e.children.length&&ll(e.children[0])?e.children[0]:null;f?(i=f.codegenNode,a&&l&&cl(i,l,n)):p?i=Ri(n,o(oi),l?Pi([l]):void 0,e.children,"64",void 0,void 0,!0):(i=u[0].codegenNode,a&&l&&cl(i,l,n),i.isBlock!==!c&&(i.isBlock?(r(ci),r(ai)):r(ui)),i.isBlock=!c,i.isBlock?(o(ci),o(ai)):o(ui)),s.arguments.push(Di(dc(t.parseResult),i,!0))}}))}));const cc=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,ac=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,uc=/^\(|\)$/g;function pc(e,t){const n=e.loc,o=e.content,r=o.match(cc);if(!r)return;const[,s,i]=r,l={source:fc(n,i.trim(),o.indexOf(i,s.length)),value:void 0,key:void 0,index:void 0};let c=s.trim().replace(uc,"").trim();const a=s.indexOf(c),u=c.match(ac);if(u){c=c.replace(ac,"").trim();const e=u[1].trim();let t;if(e&&(t=o.indexOf(e,a+c.length),l.key=fc(n,e,t)),u[2]){const r=u[2].trim();r&&(l.index=fc(n,r,o.indexOf(r,l.key?t+e.length:a+c.length)))}}return c&&(l.value=fc(n,c,a)),l}function fc(e,t,n){return ji(t,!1,Xi(e,n,t.length))}function dc({value:e,key:t,index:n}){const o=[];return e&&o.push(e),t&&(e||o.push(ji("_",!1)),o.push(t)),n&&(t||(e||o.push(ji("_",!1)),o.push(ji("__",!1))),o.push(n)),o}const hc=ji("undefined",!1),mc=(e,t)=>{if(1===e.type&&(1===e.tagType||3===e.tagType)){const n=tl(e,"slot");if(n)return n.exp,t.scopes.vSlot++,()=>{t.scopes.vSlot--}}},gc=(e,t,n)=>Di(e,t,!1,!0,t.length?t[0].loc:n);function vc(e,t,n=gc){t.helper(Mi);const{children:o,loc:r}=e,s=[],i=[],l=(e,t)=>Li("default",n(e,t,r));let c=t.scopes.vSlot>0||t.scopes.vFor>0;const a=tl(e,"slot",!0);if(a){const{arg:e,exp:t}=a;e&&!Wi(e)&&(c=!0),s.push(Li(e||ji("default",!0),n(t,o,r)))}let u=!1,p=!1;const f=[],d=new Set;for(let g=0;gfunction(){if(1!==(e=t.currentNode).type||0!==e.tagType&&1!==e.tagType)return;const{tag:n,props:o}=e,r=1===e.tagType,s=r?function(e,t,n=!1){const{tag:o}=e,r=wc(o)?nl(e,"is"):tl(e,"is");if(r){const e=6===r.type?r.value&&ji(r.value.content,!0):r.exp;if(e)return Hi(t.helper(mi),[e])}const s=Gi(o)||t.isBuiltInComponent(o);if(s)return n||t.helper(s),s;return t.helper(hi),t.components.add(o),al(o,"component")}(e,t):`"${n}"`;let i,l,c,a,u,p,f=0,d=A(s)&&s.callee===mi||s===ri||s===si||!r&&("svg"===n||"foreignObject"===n||nl(e,"key",!0));if(o.length>0){const n=Sc(e,t);i=n.props,f=n.patchFlag,u=n.dynamicPropNames;const o=n.directives;p=o&&o.length?Vi(o.map((e=>function(e,t){const n=[],o=_c.get(e);o?n.push(t.helperString(o)):(t.helper(gi),t.directives.add(e.name),n.push(al(e.name,"directive")));const{loc:r}=e;e.exp&&n.push(e.exp);e.arg&&(e.exp||n.push("void 0"),n.push(e.arg));if(Object.keys(e.modifiers).length){e.arg||(e.exp||n.push("void 0"),n.push("void 0"));const t=ji("true",!1,r);n.push(Pi(e.modifiers.map((e=>Li(e,t))),r))}return Vi(n,e.loc)}(e,t)))):void 0}if(e.children.length>0){s===ii&&(d=!0,f|=1024);if(r&&s!==ri&&s!==ii){const{slots:n,hasDynamicSlots:o}=vc(e,t);l=n,o&&(f|=1024)}else if(1===e.children.length&&s!==ri){const n=e.children[0],o=n.type,r=5===o||8===o;r&&0===jl(n,t)&&(f|=1),l=r||2===o?n:e.children}else l=e.children}0!==f&&(c=String(f),u&&u.length&&(a=function(e){let t="[";for(let n=0,o=e.length;n{if(Wi(e)){const o=e.content,r=b(o);if(i||!r||"onclick"===o.toLowerCase()||"onUpdate:modelValue"===o||P(o)||(h=!0),r&&P(o)&&(g=!0),20===n.type||(4===n.type||8===n.type)&&jl(n,t)>0)return;"ref"===o?p=!0:"class"!==o||i?"style"!==o||i?"key"===o||v.includes(o)||v.push(o):d=!0:f=!0}else m=!0};for(let b=0;b1?Hi(t.helper(Si),c,s):c[0]):l.length&&(_=Pi(Cc(l),s)),m?u|=16:(f&&(u|=2),d&&(u|=4),v.length&&(u|=8),h&&(u|=32)),0!==u&&32!==u||!(p||g||a.length>0)||(u|=512),{props:_,directives:a,patchFlag:u,dynamicPropNames:v}}function Cc(e){const t=new Map,n=[];for(let o=0;o{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))})((e=>e.replace(Tc,((e,t)=>t?t.toUpperCase():"")))),Nc=(e,t)=>{if(ll(e)){const{children:n,loc:o}=e,{slotName:r,slotProps:s}=function(e,t){let n,o='"default"';const r=[];for(let s=0;s0){const{props:o,directives:s}=Sc(e,t,r);n=o,s.length&&t.onError(ni(35,s[0].loc))}return{slotName:o,slotProps:n}}(e,t),i=[t.prefixIdentifiers?"_ctx.$slots":"$slots",r];s&&i.push(s),n.length&&(s||i.push("{}"),i.push(Di([],n,!1,!1,o))),t.scopeId&&!t.slotted&&(s||i.push("{}"),n.length||i.push("undefined"),i.push("true")),e.codegenNode=Hi(t.helper(bi),i,o)}};const $c=/^\s*([\w$_]+|\([^)]*?\))\s*=>|^\s*function(?:\s+[\w$]+)?\s*\(/,Fc=(e,t,n,o)=>{const{loc:r,modifiers:s,arg:i}=e;let l;if(e.exp||s.length||n.onError(ni(34,r)),4===i.type)if(i.isStatic){const e=i.content;l=ji(W(U(e)),!0,i.loc)}else l=Ui([`${n.helperString(Ti)}(`,i,")"]);else l=i,l.children.unshift(`${n.helperString(Ti)}(`),l.children.push(")");let c=e.exp;c&&!c.content.trim()&&(c=void 0);let a=n.cacheHandlers&&!c;if(c){const e=Qi(c.content),t=!(e||$c.test(c.content)),n=c.content.includes(";");(t||a&&e)&&(c=Ui([`${t?"$event":"(...args)"} => ${n?"{":"("}`,c,n?"}":")"]))}let u={props:[Li(l,c||ji("() => {}",!1,r))]};return o&&(u=o(u)),a&&(u.props[0].value=n.cache(u.props[0].value)),u},Mc=(e,t,n)=>{const{exp:o,modifiers:r,loc:s}=e,i=e.arg;return 4!==i.type?(i.children.unshift("("),i.children.push(') || ""')):i.isStatic||(i.content=`${i.content} || ""`),r.includes("camel")&&(4===i.type?i.isStatic?i.content=U(i.content):i.content=`${n.helperString(ki)}(${i.content})`:(i.children.unshift(`${n.helperString(ki)}(`),i.children.push(")"))),!o||4===o.type&&!o.content.trim()?(n.onError(ni(33,s)),{props:[Li(i,ji("",!0,s))]}):{props:[Li(i,o)]}},Ac=(e,t)=>{if(0===e.type||1===e.type||11===e.type||10===e.type)return()=>{const n=e.children;let o,r=!1;for(let e=0;e{if(1===e.type&&tl(e,"once",!0)){if(Ic.has(e))return;return Ic.add(e),t.helper(Ei),()=>{const e=t.currentNode;e.codegenNode&&(e.codegenNode=t.cache(e.codegenNode,!0))}}},Bc=(e,t,n)=>{const{exp:o,arg:r}=e;if(!o)return n.onError(ni(40,e.loc)),Rc();const s=o.loc.source,i=4===o.type?o.content:s;n.bindingMetadata[s];if(!Qi(i))return n.onError(ni(41,o.loc)),Rc();const l=r||ji("modelValue",!0),c=r?Wi(r)?`onUpdate:${r.content}`:Ui(['"onUpdate:" + ',r]):"onUpdate:modelValue";let a;a=Ui([`${n.isTS?"($event: any)":"$event"} => (`,o," = $event)"]);const u=[Li(l,e.exp),Li(c,a)];if(e.modifiers.length&&1===t.tagType){const t=e.modifiers.map((e=>(Ji(e)?e:JSON.stringify(e))+": true")).join(", "),n=r?Wi(r)?`${r.content}Modifiers`:Ui([r,' + "Modifiers"']):"modelModifiers";u.push(Li(n,ji(`{ ${t} }`,!1,e.loc,2)))}return Rc(u)};function Rc(e=[]){return{props:e}}function Vc(e,t={}){const n=t.onError||ti,o="module"===t.mode;!0===t.prefixIdentifiers?n(ni(45)):o&&n(ni(46));t.cacheHandlers&&n(ni(47)),t.scopeId&&!o&&n(ni(48));const r=F(e)?dl(e,t):e,[s,i]=[[Oc,oc,lc,Nc,xc,mc,Ac],{on:Fc,bind:Mc,model:Bc}];return Wl(r,x({},t,{prefixIdentifiers:false,nodeTransforms:[...s,...t.nodeTransforms||[]],directiveTransforms:x({},i,t.directiveTransforms||{})})),Jl(r,x({},t,{prefixIdentifiers:false}))}const Pc=Symbol(""),Lc=Symbol(""),jc=Symbol(""),Uc=Symbol(""),Hc=Symbol(""),Dc=Symbol(""),zc=Symbol(""),Wc=Symbol(""),Kc=Symbol(""),Gc=Symbol("");var qc;let Jc;qc={[Pc]:"vModelRadio",[Lc]:"vModelCheckbox",[jc]:"vModelText",[Uc]:"vModelSelect",[Hc]:"vModelDynamic",[Dc]:"withModifiers",[zc]:"withKeys",[Wc]:"vShow",[Kc]:"Transition",[Gc]:"TransitionGroup"},Object.getOwnPropertySymbols(qc).forEach((e=>{Oi[e]=qc[e]}));const Zc=e("style,iframe,script,noscript",!0),Qc={isVoidTag:u,isNativeTag:e=>c(e)||a(e),isPreTag:e=>"pre"===e,decodeEntities:function(e){return(Jc||(Jc=document.createElement("div"))).innerHTML=e,Jc.textContent},isBuiltInComponent:e=>Ki(e,"Transition")?Kc:Ki(e,"TransitionGroup")?Gc:void 0,getNamespace(e,t){let n=t?t.ns:0;if(t&&2===n)if("annotation-xml"===t.tag){if("svg"===e)return 1;t.props.some((e=>6===e.type&&"encoding"===e.name&&null!=e.value&&("text/html"===e.value.content||"application/xhtml+xml"===e.value.content)))&&(n=0)}else/^m(?:[ions]|text)$/.test(t.tag)&&"mglyph"!==e&&"malignmark"!==e&&(n=0);else t&&1===n&&("foreignObject"!==t.tag&&"desc"!==t.tag&&"title"!==t.tag||(n=0));if(0===n){if("svg"===e)return 1;if("math"===e)return 2}return n},getTextMode({tag:e,ns:t}){if(0===t){if("textarea"===e||"title"===e)return 1;if(Zc(e))return 2}return 0}},Xc=(e,t)=>{const n=i(e);return ji(JSON.stringify(n),!1,t,3)};function Yc(e,t){return ni(e,t)}const ea=e("passive,once,capture"),ta=e("stop,prevent,self,ctrl,shift,alt,meta,exact,middle"),na=e("left,right"),oa=e("onkeyup,onkeydown,onkeypress",!0),ra=(e,t)=>Wi(e)&&"onclick"===e.content.toLowerCase()?ji(t,!0):4!==e.type?Ui(["(",e,`) === "onClick" ? "${t}" : (`,e,")"]):e,sa=(e,t)=>{1!==e.type||0!==e.tagType||"script"!==e.tag&&"style"!==e.tag||(t.onError(Yc(59,e.loc)),t.removeNode())},ia=[e=>{1===e.type&&e.props.forEach(((t,n)=>{6===t.type&&"style"===t.name&&t.value&&(e.props[n]={type:7,name:"bind",arg:ji("style",!0,t.loc),exp:Xc(t.value.content,t.loc),modifiers:[],loc:t.loc})}))}],la={cloak:()=>({props:[]}),html:(e,t,n)=>{const{exp:o,loc:r}=e;return o||n.onError(Yc(49,r)),t.children.length&&(n.onError(Yc(50,r)),t.children.length=0),{props:[Li(ji("innerHTML",!0,r),o||ji("",!0))]}},text:(e,t,n)=>{const{exp:o,loc:r}=e;return o||n.onError(Yc(51,r)),t.children.length&&(n.onError(Yc(52,r)),t.children.length=0),{props:[Li(ji("textContent",!0),o?Hi(n.helperString(xi),[o],r):ji("",!0))]}},model:(e,t,n)=>{const o=Bc(e,t,n);if(!o.props.length||1===t.tagType)return o;e.arg&&n.onError(Yc(54,e.arg.loc));const{tag:r}=t,s=n.isCustomElement(r);if("input"===r||"textarea"===r||"select"===r||s){let i=jc,l=!1;if("input"===r||s){const o=nl(t,"type");if(o){if(7===o.type)i=Hc;else if(o.value)switch(o.value.content){case"radio":i=Pc;break;case"checkbox":i=Lc;break;case"file":l=!0,n.onError(Yc(55,e.loc))}}else(function(e){return e.props.some((e=>!(7!==e.type||"bind"!==e.name||e.arg&&4===e.arg.type&&e.arg.isStatic)))})(t)&&(i=Hc)}else"select"===r&&(i=Uc);l||(o.needRuntime=n.helper(i))}else n.onError(Yc(53,e.loc));return o.props=o.props.filter((e=>!(4===e.key.type&&"modelValue"===e.key.content))),o},on:(e,t,n)=>Fc(e,0,n,(t=>{const{modifiers:o}=e;if(!o.length)return t;let{key:r,value:s}=t.props[0];const{keyModifiers:i,nonKeyModifiers:l,eventOptionModifiers:c}=((e,t)=>{const n=[],o=[],r=[];for(let s=0;s{const{exp:o,loc:r}=e;return o||n.onError(Yc(57,r)),{props:[],needRuntime:n.helper(Wc)}}};const ca=Object.create(null);Fr((function(e,t){if(!F(e)){if(!e.nodeType)return g;e=e.innerHTML}const n=e,o=ca[n];if(o)return o;if("#"===e[0]){const t=document.querySelector(e);e=t?t.innerHTML:""}const{code:r}=function(e,t={}){return Vc(e,x({},Qc,t,{nodeTransforms:[sa,...ia,...t.nodeTransforms||[]],directiveTransforms:x({},la,t.directiveTransforms||{}),transformHoist:null}))}(e,x({hoistStatic:!0,onError(e){throw e}},t)),s=new Function("Vue",r)(ei);return s._rc=!0,ca[n]=s}));const aa={name:"App",data:()=>({isSidebarOpen:!1,swUpdateEvent:null}),computed:{pageClasses(){return[{"sidebar-open":this.isSidebarOpen}]}},methods:{toggleSidebar(e){this.isSidebarOpen="boolean"==typeof e?e:!this.isSidebarOpen}}};const ua={},pa={class:"icon outbound",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",x:"0px",y:"0px",viewBox:"0 0 100 100",width:"15",height:"15"},fa=er("path",{fill:"currentColor",d:"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"},null,-1),da=er("polygon",{fill:"currentColor",points:"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"},null,-1);ua.render=function(e,t){return Wo(),qo("svg",pa,[fa,da])};const ha={},ma=er("svg",{class:"icon",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"},[er("path",{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z",class:""})],-1);ha.render=function(e,t){return Wo(),qo("div",{class:"sidebar-button",onClick:t[1]||(t[1]=t=>e.$emit("toggle-sidebar"))},[ma])};const ga={components:{SidebarButton:ha}},va={class:"navbar"};ga.render=function(e,t,n,o,r,s){const i=Bo("SidebarButton");return Wo(),qo("header",va,[er(i,{onToggleSidebar:t[1]||(t[1]=t=>e.$emit("toggle-sidebar"))}),Yt(e.$slots,"default")])};const ya={},ba={class:"nav-links"};ya.render=function(e,t,n,o,r,s){return Wo(),qo("nav",ba,[Yt(e.$slots,"default")])};const _a={},xa={class:"vp-sidebar"};_a.render=function(e,t,n,o,r,s){return Wo(),qo("div",xa,[Yt(e.$slots,"default")])};const Sa={},Ca={class:"page"};Sa.render=function(e,t,n,o,r,s){return Wo(),qo("div",Ca,[Yt(e.$slots,"default"),Yt(e.$slots,"bottom")])};const ka=Xs(aa);ka.component("outboundlink",ua),ka.component("navbar",ga),ka.component("navlinks",ya),ka.component("sidebar",_a),ka.component("page",Sa),ka.component("router-link",{props:["to"],template:''}),ka.mount("#app",!0)}(); diff --git a/about/index.html b/about/index.html new file mode 100644 index 000000000..ce561f440 --- /dev/null +++ b/about/index.html @@ -0,0 +1,295 @@ + + + + + + + BenchBuild Documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

BenchBuild Documentation

+

BenchBuild is an open-source toolkit that helps with the management of case-studies used in software-driven empirical experiments. +BenchBuild was specifically designed to make defined experiments reusable between different +experiment setups. It mainly provides assistance with the following standard tasks found in empirical software experiments:

+
    +
  • Add a new case-study to an existing experiment setup.

  • +
  • Add a new experiment to an existing body of case-studies.

  • +
+
+

Design Philosophy

+

BenchBuild is designed with the following main properties in mind.

+
+

A case-study doesn’t know its experiment

+

If you add a new case-study, you should never have to rely on background information about the experiment you are about to run on it. +A new case-study is only concerned with its own setup of dependencies and execution during its run-time. A case-study controls where and what can be +intercepted by an experiment.

+
+
+

An experiment doesn’t know its case-studies

+

Adding a new experiment never should have any knowledge about the case-studies +it runs on. +A new experiment takes care of intercepting the compilation process and/or the +execution procedure of a given case-study. This only defines what is being done at the defined extension points at compile-time or run-time.

+
+
+
+

Supported Python Versions

+

BenchBuild supports Python 3.7 and 3.8. Main development is focused on Python 3.8, but an effort is made to support 3.7 as long as major distributions like Debian Linux only ship with 3.7 by default.

+
+
+

Getting started

+

See the Installation guide for help getting BenchBuild up and running quickly.

+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/advanced/cli/index.html b/advanced/cli/index.html new file mode 100644 index 000000000..1c0c04581 --- /dev/null +++ b/advanced/cli/index.html @@ -0,0 +1,263 @@ + + + + + + + CLI + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

CLI

+
    +
  • --force-watch-unbuffered: This disables buffering from watched commands. +This can help with tools that call benchbuild and use their own output buffering.

  • +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/advanced/index.html b/advanced/index.html new file mode 100644 index 000000000..1431661ca --- /dev/null +++ b/advanced/index.html @@ -0,0 +1,285 @@ + + + + + + + SLURM + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

SLURM

+

BenchBuild supports a high-level integration with the SLURM cluster resource +manager. An experiment setup can be exported as a SLURM bash script. Assuming +you have access to a configured benchbuid environment on the SLURM cluster, you +can provide the SLURM script to the sbatch command and have your experiment +run on the cluster environment.

+
+

Basics

+

TODO

+
+
+

Template customization

+

This customization is not recommended for the default use-case. However, you +might run in a situation where the existing cluster-environment requires a +more complicated setup than BenchBuild can provide.

+

You can customize the template that is used for the SLURM script using a +modified copy of the base template BenchBuild uses +(see benchbuild/res/misc/slurm.sh.inc).

+

The customized template can be configured using the configuration option +BB_SLURM_TEMPLATE. If BenchBuild detects that the provided value points to +an existing file in your filesystem, it will load it. +If you change the setting and BenchBuild cannot find a file there, no script +will be generated. No validation of the template will be done, use at your own +risk.

+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/basics/actions/index.html b/basics/actions/index.html new file mode 100644 index 000000000..65d8fd857 --- /dev/null +++ b/basics/actions/index.html @@ -0,0 +1,799 @@ + + + + + + + Actions + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Actions

+

Actions are used to declare the workflow of an experiment. BenchBuild provides +a set of default actions that should suit most experiments. +A new experiment can define a new set of actions that should be used per project, +or use those defaults.

+
+

Customize actions

+

Whenever you define a new expeirment, you have to provide an implementation +for def actions_for_project(self, project: 'Project'). +This implementation usually configures extensions on the project and returns +a set of actions that should be run during execution.

+

Example:

+

This takes care of compiling, running and cleanup during experiment execution.

+
+
+

Available Actions

+

The following actions are available out of the box. You can define your own +actions at any time

+
+

Step (Base)

+
+
+

Clean

+
+
+

MakeBuildDir

+
+
+

Compile

+
+
+

Run

+
+
+

Echo

+
+
+

Any (Group)

+
+
+

Experiment (Any, Group)

+
+
+

RequireAll (Group)

+
+
+

CleanExtra

+
+
+

ProjectEnvironment

+
+
+

SetProjectVersion

+

This action provides you with a way to change the source version used inside the +build directory of this project. +During initialization, each project is assigned a variant that determines the +source versions that will be checked out into the build directory.

+

Sometimes it can be useful to do comparisons of different source revisions +inside a single experiment run. This can be achieved using SetProjectVersion.

+

Usage:

+

The match is done on all(!) sources of the project. If you happen to find a +revision string twice in different souces, both will be checked out in the +build directory.

+

The match is done exact and matches agains the source.versions() output of a +source. Only sources that are marked as expandable (source.is_expandable) +will be checked.

+

# Actions

+

Actions are enhanced callables that are used by Experiments to define +the order of operations a project is put through when the experiment +executes.

+

## Example

+

TODO +`python +`

+
+
+class benchbuild.utils.actions.Any(actions=None)[source]
+

Bases: MultiStep

+
+
+DESCRIPTION: ClassVar[str] = 'Just run all actions, no questions asked.'
+
+ +
+
+NAME: ClassVar[str] = 'ANY'
+
+ +
+ +
+
+class benchbuild.utils.actions.Clean(project, check_empty=False)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Cleans the build directory'
+
+ +
+
+NAME: tp.ClassVar[str] = 'CLEAN'
+
+ +
+
+static clean_mountpoints(root)[source]
+

Unmount any remaining mountpoints under :root.

+
+
Parameters:
+

root (str) – All UnionFS-mountpoints under this directory will be +unmounted.

+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class benchbuild.utils.actions.CleanExtra[source]
+

Bases: Step

+
+
+DESCRIPTION: ClassVar[str] = 'Cleans the extra directories.'
+
+ +
+
+NAME: ClassVar[str] = 'CLEAN EXTRA'
+
+ +
+ +
+
+class benchbuild.utils.actions.Compile(project)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Compile the project'
+
+ +
+
+NAME: tp.ClassVar[str] = 'COMPILE'
+
+ +
+ +
+
+class benchbuild.utils.actions.Echo(message='')[source]
+

Bases: Step

+
+
+DESCRIPTION: ClassVar[str] = 'Print a message.'
+
+ +
+
+NAME: ClassVar[str] = 'ECHO'
+
+ +
+
+message: str
+
+ +
+ +
+
+class benchbuild.utils.actions.Experiment(experiment, actions)[source]
+

Bases: Any

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Run a experiment, wrapped in a db transaction'
+
+ +
+
+NAME: tp.ClassVar[str] = 'EXPERIMENT'
+
+ +
+
+begin_transaction()[source]
+
+
Return type:
+

tp.Tuple[‘benchbuild.utils.schema.Experiment’, tp.Any]

+
+
+
+ +
+
+static end_transaction(experiment, session)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+experiment: benchbuild.experiment.Experiment
+
+ +
+ +
+
+class benchbuild.utils.actions.MakeBuildDir(project)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Create the build directory'
+
+ +
+
+NAME: tp.ClassVar[str] = 'MKDIR'
+
+ +
+ +
+
+class benchbuild.utils.actions.MultiStep(actions=None)[source]
+

Bases: Step, Generic[StepTy_co]

+

Group multiple actions into one step.

+

Usually used to define behavior on error, e.g., execute everything +regardless of any errors, or fail everything upon first error.

+
+
+DESCRIPTION: ClassVar[str] = ''
+
+ +
+
+NAME: ClassVar[str] = ''
+
+ +
+
+actions: MutableSequence[TypeVar(StepTy_co, bound= Step, covariant=True)]
+
+ +
+
+onerror()[source]
+

Default implementation does nothing.

+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class benchbuild.utils.actions.ProjectEnvironment(project)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Prepare the project environment.'
+
+ +
+
+NAME: tp.ClassVar[str] = 'ENV'
+
+ +
+ +
+
+class benchbuild.utils.actions.ProjectStep(project)[source]
+

Bases: Step

+

Base class of a project step.

+

Adds a project attribute to the Step base class and some defaults.

+
+
Raises:
+

StopIteration – If we do not encapsulate more substeps.

+
+
+
+
+DESCRIPTION: tp.ClassVar[str] = ''
+
+ +
+
+NAME: tp.ClassVar[str] = ''
+
+ +
+
+onerror()[source]
+

Default implementation does nothing.

+
+
Return type:
+

None

+
+
+
+ +
+
+project: benchbuild.project.Project
+
+ +
+ +
+
+class benchbuild.utils.actions.RequireAll(actions=None)[source]
+

Bases: MultiStep

+
+
+DESCRIPTION: ClassVar[str] = 'All child steps need to succeed'
+
+ +
+
+NAME: ClassVar[str] = 'REQUIRE ALL'
+
+ +
+ +
+
+class benchbuild.utils.actions.Run(project, experiment)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Execute the run action'
+
+ +
+
+NAME: tp.ClassVar[str] = 'RUN'
+
+ +
+
+experiment: benchbuild.experiment.Experiment
+
+ +
+ +
+
+class benchbuild.utils.actions.RunWorkload(project, workload=None)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = "Run a project's workload"
+
+ +
+
+NAME: tp.ClassVar[str] = 'RUN WORKLOAD'
+
+ +
+
+property workload_ref: Callable[[], Any]
+
+ +
+ +
+
+class benchbuild.utils.actions.RunWorkloads(project, experiment, run_only=None)[source]
+

Bases: MultiStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Generic run all project workloads'
+
+ +
+
+NAME: tp.ClassVar[str] = 'RUN WORKLOADS'
+
+ +
+
+experiment: benchbuild.experiment.Experiment
+
+ +
+
+project: benchbuild.project.Project
+
+ +
+ +
+
+class benchbuild.utils.actions.SetProjectVersion(project, *revision_strings)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Checkout a project version'
+
+ +
+
+NAME: tp.ClassVar[str] = 'SET PROJECT VERSION'
+
+ +
+
+revision: source.Revision
+
+ +
+ +
+
+class benchbuild.utils.actions.Step(status)[source]
+

Bases: object

+

Base class of a step.

+
+
Raises:
+

StopIteration – If we do not encapsulate more substeps.

+
+
+
+
+DESCRIPTION: ClassVar[str] = ''
+
+ +
+
+NAME: ClassVar[str] = ''
+
+ +
+
+onerror()[source]
+

Default implementation does nothing.

+
+
Return type:
+

None

+
+
+
+ +
+
+status: StepResult
+
+ +
+ +
+
+class benchbuild.utils.actions.StepResult(value)[source]
+

Bases: IntEnum

+

Result type for action results.

+
+
+CAN_CONTINUE = 2
+
+ +
+
+ERROR = 3
+
+ +
+
+OK = 1
+
+ +
+
+UNSET = 0
+
+ +
+ +
+
+benchbuild.utils.actions.log_before_after(name, desc)[source]
+

Log customized string before & after running func.

+
+
Return type:
+

Callable[[Callable[..., StepResult]], Callable[..., StepResult]]

+
+
+
+ +
+
+benchbuild.utils.actions.prepend_status(func)[source]
+

Prepends the output of func with the status.

+
+
Return type:
+

Callable[..., str]

+
+
+
+ +
+
+benchbuild.utils.actions.run_any_child(child)[source]
+

Execute child step.

+
+
Parameters:
+

child (Step) – The child step.

+
+
Return type:
+

StepResult

+
+
+
+ +
+
+benchbuild.utils.actions.step_has_failed(result, error_status=None)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/basics/configuration/index.html b/basics/configuration/index.html new file mode 100644 index 000000000..0927b57d9 --- /dev/null +++ b/basics/configuration/index.html @@ -0,0 +1,676 @@ + + + + + + + Configure + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Configure

+
+

Module: settings

+

Settings module for benchbuild.

+

All settings are stored in a simple dictionary. Each +setting should be modifiable via environment variable.

+
+
+

Module: utils.settings

+

Configuration utilities.

+

Settings are stored in a dictionary-like configuration object. +All settings are modifiable by environment variables that encode +the path in the dictionary tree.

+

Inner nodes in the dictionary tree can be any dictionary. +A leaf node in the dictionary tree is represented by an inner node that +contains a value key.

+
+
+class benchbuild.utils.settings.ConfigDumper(stream, default_style=None, default_flow_style=False, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, version=None, tags=None, sort_keys=True)[source]
+

Bases: SafeDumper

+

Avoid polluting yaml’s namespace with our modifications.

+
+
+yaml_implicit_resolvers = {'!': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '&': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '': [('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], '*': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '+': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE))], '-': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE))], '.': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE))], '0': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '1': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '2': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '3': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '4': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '5': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '6': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '7': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '8': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '9': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '<': [('tag:yaml.org,2002:merge', re.compile('^(?:<<)$'))], '=': [('tag:yaml.org,2002:value', re.compile('^(?:=)$'))], 'F': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'N': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE)), ('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], 'O': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'T': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'Y': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'f': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'n': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE)), ('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], 'o': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 't': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'y': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], '~': [('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], None: [('!uuid', re.compile('^\\b[a-f0-9]{8}-\\b[a-f0-9]{4}-\\b[a-f0-9]{4}-\\b[a-f0-9]{4}-\\b[a-f0-9]{12}$'))]}
+
+ +
+
+yaml_representers = {<class 'NoneType'>: <function SafeRepresenter.represent_none>, <class 'benchbuild.utils.settings.ConfigPath'>: <function path_representer>, <class 'bool'>: <function SafeRepresenter.represent_bool>, <class 'bytes'>: <function SafeRepresenter.represent_binary>, <class 'datetime.date'>: <function SafeRepresenter.represent_date>, <class 'datetime.datetime'>: <function SafeRepresenter.represent_datetime>, <class 'dict'>: <function SafeRepresenter.represent_dict>, <class 'float'>: <function SafeRepresenter.represent_float>, <class 'int'>: <function SafeRepresenter.represent_int>, <class 'list'>: <function SafeRepresenter.represent_list>, <class 'set'>: <function SafeRepresenter.represent_set>, <class 'str'>: <function SafeRepresenter.represent_str>, <class 'tuple'>: <function SafeRepresenter.represent_list>, <class 'uuid.UUID'>: <function uuid_representer>, None: <function SafeRepresenter.represent_undefined>}
+
+ +
+ +
+
+class benchbuild.utils.settings.ConfigLoader(stream)[source]
+

Bases: CSafeLoader

+

Avoid polluting yaml’s namespace with our modifications.

+
+
+yaml_constructors = {'!create-if-needed': <function path_constructor>, '!uuid': <function uuid_constructor>, 'tag:yaml.org,2002:binary': <function SafeConstructor.construct_yaml_binary>, 'tag:yaml.org,2002:bool': <function SafeConstructor.construct_yaml_bool>, 'tag:yaml.org,2002:float': <function SafeConstructor.construct_yaml_float>, 'tag:yaml.org,2002:int': <function SafeConstructor.construct_yaml_int>, 'tag:yaml.org,2002:map': <function SafeConstructor.construct_yaml_map>, 'tag:yaml.org,2002:null': <function SafeConstructor.construct_yaml_null>, 'tag:yaml.org,2002:omap': <function SafeConstructor.construct_yaml_omap>, 'tag:yaml.org,2002:pairs': <function SafeConstructor.construct_yaml_pairs>, 'tag:yaml.org,2002:seq': <function SafeConstructor.construct_yaml_seq>, 'tag:yaml.org,2002:set': <function SafeConstructor.construct_yaml_set>, 'tag:yaml.org,2002:str': <function SafeConstructor.construct_yaml_str>, 'tag:yaml.org,2002:timestamp': <function SafeConstructor.construct_yaml_timestamp>, None: <function SafeConstructor.construct_undefined>}
+
+ +
+
+yaml_implicit_resolvers = {'!': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '&': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '': [('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], '*': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '+': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE))], '-': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE))], '.': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE))], '0': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '1': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '2': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '3': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '4': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '5': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '6': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '7': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '8': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '9': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '<': [('tag:yaml.org,2002:merge', re.compile('^(?:<<)$'))], '=': [('tag:yaml.org,2002:value', re.compile('^(?:=)$'))], 'F': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'N': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE)), ('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], 'O': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'T': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'Y': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'f': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'n': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE)), ('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], 'o': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 't': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'y': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], '~': [('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], None: [('!uuid', re.compile('^\\b[a-f0-9]{8}-\\b[a-f0-9]{4}-\\b[a-f0-9]{4}-\\b[a-f0-9]{4}-\\b[a-f0-9]{12}$'))]}
+
+ +
+ +
+
+class benchbuild.utils.settings.ConfigPath(components)[source]
+

Bases: object

+

Wrapper around paths represented as list of strings.

+
+
+static path_to_str(components)[source]
+
+
Return type:
+

str

+
+
+
+ +
+
+validate()[source]
+

Make sure this configuration path exists.

+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class benchbuild.utils.settings.Configuration(parent_key, node=None, parent=None, init=True)[source]
+

Bases: Indexable

+

Dictionary-like data structure to contain all configuration variables.

+

This serves as a configuration dictionary throughout benchbuild. You can +use it to access all configuration options that are available. Whenever the +structure is updated with a new subtree, all variables defined in the new +subtree are updated from the environment.

+
+
Environment variables are generated from the tree paths automatically.

CFG[“build_dir”] becomes BB_BUILD_DIR +CFG[“llvm”][“dir”] becomes BB_LLVM_DIR

+
+
+

The configuration can be stored/loaded as YAML.

+
+
+filter_exports()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+has_default()[source]
+

Check, if the node contains a ‘default’ value.

+
+
Return type:
+

bool

+
+
+
+ +
+
+has_value()[source]
+

Check, if the node contains a ‘value’.

+
+
Return type:
+

bool

+
+
+
+ +
+
+init_from_env()[source]
+

Initialize this node from environment.

+

If we’re a leaf node, i.e., a node containing a dictionary that +consist of a ‘default’ key, compute our env variable and initialize +our value from the environment. +Otherwise, init our children.

+
+
Return type:
+

None

+
+
+
+ +
+
+is_leaf()[source]
+

Check, if the node is a ‘leaf’ node.

+
+
Return type:
+

bool

+
+
+
+ +
+
+load(_from)[source]
+

Load the configuration dictionary from file.

+
+
Return type:
+

None

+
+
+
+ +
+
+store(config_file)[source]
+

Store the configuration dictionary to a file.

+
+
Return type:
+

None

+
+
+
+ +
+
+to_env_dict()[source]
+

Convert configuration object to a flat dictionary.

+
+
Return type:
+

Mapping[str, Any]

+
+
+
+ +
+
+property value: Any
+

Return the node value, if we’re a leaf node.

+
+ +
+ +
+
+class benchbuild.utils.settings.Indexable[source]
+

Bases: object

+
+ +
+
+exception benchbuild.utils.settings.InvalidConfigKey[source]
+

Bases: RuntimeWarning

+

Warn, if you access a non-existing key benchbuild’s configuration.

+
+ +
+
+benchbuild.utils.settings.available_cpu_count()[source]
+

Get the number of available CPUs.

+

Number of available virtual or physical CPUs on this system, i.e. +user/real as output by time(1) when called with an optimally scaling +userspace-only program.

+
+
Return type:
+

int

+
+
Returns:
+

Number of avaialable CPUs.

+
+
+
+ +
+
+benchbuild.utils.settings.convert_components(value)[source]
+
+
Return type:
+

List[str]

+
+
+
+ +
+
+benchbuild.utils.settings.current_available_threads()[source]
+

Returns the number of currently available threads for BB.

+
+
Return type:
+

int

+
+
+
+ +
+
+benchbuild.utils.settings.escape_yaml(raw_str)[source]
+

Shell-Escape a yaml input string.

+
+
Parameters:
+

raw_str (str) – The unescaped string.

+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.utils.settings.find_config(test_file=None, defaults=None, root='.')[source]
+

Find the path to the default config file.

+

We look at :root: for the :default: config file. If we can’t find it +there we start looking at the parent directory recursively until we +find a file named :default: and return the absolute path to it. +If we can’t find anything, we return None.

+
+
Parameters:
+
    +
  • test_file (Optional[str]) –

  • +
  • default – The name of the config file we look for.

  • +
  • root (str) – The directory to start looking for.

  • +
+
+
Return type:
+

Optional[LocalPath]

+
+
Returns:
+

Path to the default config file, None if we can’t find anything.

+
+
+
+ +
+
+benchbuild.utils.settings.get_number_of_jobs(config)[source]
+

Returns the number of jobs set in the config.

+
+
Return type:
+

int

+
+
+
+ +
+
+benchbuild.utils.settings.is_yaml(cfg_file)[source]
+

Is the given cfg_file a YAML file.

+
+
Return type:
+

bool

+
+
+
+ +
+
+benchbuild.utils.settings.path_constructor(loader, node)[source]
+

” +Construct a ConfigPath object form a scalar YAML node.

+
+ +
+
+benchbuild.utils.settings.path_representer(dumper, data)[source]
+

Represent a ConfigPath object as a scalar YAML node.

+
+ +
+
+benchbuild.utils.settings.setup_config(cfg, config_filenames=None, env_var_name=None)[source]
+

This will initialize the given configuration object.

+
+
The following resources are available in the same order:
    +
  1. Default settings.

  2. +
  3. Config file.

  4. +
  5. Environment variables.

  6. +
+
+
WARNING: Environment variables do _not_ take precedence over the config

file right now. (init_from_env will refuse to update the +value, if there is already one.)

+
+
+
+
Parameters:
+
    +
  • config_filenames (Optional[List[str]]) – list of possible config filenames

  • +
  • env_var_name (Optional[str]) – name of the environment variable holding the config path

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+benchbuild.utils.settings.to_env_var(env_var, value)[source]
+

Create an environment variable from a name and a value.

+

This generates a shell-compatible representation of an +environment variable that is assigned a YAML representation of +a value.

+
+
Parameters:
+
    +
  • env_var (str) – Name of the environment variable.

  • +
  • value (Any) – A value we convert from.

  • +
+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.utils.settings.to_yaml(value)[source]
+

Convert a given value to a YAML string.

+
+
Return type:
+

Optional[str]

+
+
+
+ +
+
+benchbuild.utils.settings.update_env(cfg)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+benchbuild.utils.settings.upgrade(cfg)[source]
+

Provide forward migration for configuration files.

+
+
Return type:
+

None

+
+
+
+ +
+
+benchbuild.utils.settings.uuid_add_implicit_resolver(loader=<class 'benchbuild.utils.settings.ConfigLoader'>, dumper=<class 'benchbuild.utils.settings.ConfigDumper'>)[source]
+

Attach an implicit pattern resolver for UUID objects.

+
+ +
+
+benchbuild.utils.settings.uuid_constructor(loader, node)[source]
+

“Construct a uuid.UUID object form a scalar YAML node.

+
+ +
+
+benchbuild.utils.settings.uuid_representer(dumper, data)[source]
+

Represent a uuid.UUID object as a scalar YAML node.

+
+ +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/basics/containers/index.html b/basics/containers/index.html new file mode 100644 index 000000000..014a56645 --- /dev/null +++ b/basics/containers/index.html @@ -0,0 +1,1308 @@ + + + + + + + Containers + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Containers

+

Benchbuild allows the definition of container images to define the base system +all experiment runs run in for a given project.

+
+

Usage

+

If you want to run an experiment inside the project’s container, simply replace +the usual run subcommand with the container run subcommand. Project and +experiment selection are done in the same way.

+

Example:

+
benchbuild container run -E raw linpack
+
+
+

This will run the following stages:

+
    +
  1. Build all necessary base images. +All images are initiated from a base image. Benchbuild knows how to construct +a few base images. These will be prepared with all dependencies required to +run benchbuild inside the container.

  2. +
  3. Build all project images. Each project has to define its’ own image.

  4. +
  5. Build the experiment images. Each experiment can add anything it needs to the +project images, if required. Use this to bring tools into the image that do +not require any knowledge about the environment to run properly. +For anything else, consider using a custom base image.

  6. +
+
+

Replace Images

+

Benchbuild will reuse any existing images it can find in your image registry. +The only relevant information is the image tag, e.g., benchbuild:alpine. +If you want to avoid reuse and force to rebuild images unconditionally, you can +use the --replace flag when running the containers subcommand.

+

Example:

+
benchbuild container run --replace -E raw linpack
+
+
+

This will ignore any required image for the given experiments and projects.

+
+
+
+

Configuration

+

You can configure the container environment using the following config variables.

+
    +
  • BB_CONTAINER_EXPORT: Path where benchbuild stores exported container +images. By default we store it in ./containers/export. Will be created +automatically, if needed.

  • +
  • BB_CONTAINER_IMPORT: Path where to input images from into the registry. +By default we load from ./containers/export.

  • +
  • BB_CONTAINER_FROM_SOURCE: Determine, if we should use benchbuild from the +current source checkout, or from pip.

  • +
  • BB_CONTAINER_ROOT: Where we store our image layers. This is the image +registry. Cannot be stored on filesystems that do not support subuid/-gid +mapping, e.g. NFS. +The default location is ./containers/lib.

  • +
  • BB_CONTAINER_RUNROOT: Where we store temporary image layers of running +containers. See BB_CONTAINER_ROOT for restrictions. +The default location is: ./containers/run.

  • +
  • BB_CONTAINER_RUNTIME: Podman can use any standard OCI-container runtime to +launch containers. We use crun by +default. Depending on your system, this one has already been installed with +podman. +The default runtime is: /usr/bin/crun

  • +
  • BB_CONTAINER_MOUNTS: A list of mountpoint definitions that should be added +to all containers. With this you can add arbitrary tools into all containers. +Default: []

  • +
+
+
+

Definition

+

A project that wants to use a container image needs to define it in the +CONTAINER attribute it using our declarative API provided by +benchbuild.environments.domain.declarative.

+
from benchbuild.environments.domain.declarative import ContainerImage
+
+class Testproject(Project):
+  CONTAINER = ContainerImage().from_('benchbuild:alpine')
+
+
+

The available set of commands follows the structure of a Dockerfile.

+
+
+

Runtime requirements

+

For containers to work properly, you need a few systems set up beforehand.

+
+

Buildah

+

Image construction requires the Buildah tool. All image +construction tasks are formulated as buildah command calls in the backend.

+

Buildah is supported up to version 1.19.8.

+
+
+

Podman

+

Container construction and execution is handed off to Podman. +Podman provides rootless containers and does not requires the execution of a +daemon process. However, you need to setup your user namespace properly to allow +mapping of subordinate uids/gids. Otherwise, podman will not be able to map +users other than the root user to filesystem permissions inside the container.

+

Please refer to podman’s documentation on how to setup podman properly on your +system.

+

Podman is supported up to version 2.2.1

+
+
+
+

Module: benchbuild.container

+

Container construction tool.

+

This tool assists in the creation of customized uchroot containers. +You can define strategies and apply them on a given container base-image +to have a fixed way of creating a user-space environment.

+
+
+class benchbuild.container.BashStrategy[source]
+

Bases: ContainerStrategy

+

The user interface for setting up a bash inside the container.

+
+
+run(context)[source]
+

Execute a container strategy.

+
+
Parameters:
+

context – A context object with attributes used for the strategy.

+
+
+
+ +
+ +
+
+class benchbuild.container.Container(executable=None)[source]
+

Bases: Application

+

Manage uchroot containers.

+
+
+VERSION = '6.8'
+
+ +
+
+builddir(tmpdir)[source]
+

Set the current builddir of the container.

+
+ +
+
+input_file(_container)[source]
+

Find the input path of a uchroot container.

+
+ +
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+
+mounts(user_mount)[source]
+

Save the current mount of the container into the settings.

+
+ +
+
+output_file(_container)[source]
+

Find and writes the output path of a chroot container.

+
+ +
+
+shell(custom_shell)[source]
+

The command to run inside the container.

+
+ +
+
+verbosity
+

Sets an attribute

+
+ +
+ +
+
+class benchbuild.container.ContainerBootstrap(executable=None)[source]
+

Bases: Application

+

Check for the needed files.

+
+
+install_cmake_and_exit()[source]
+

Tell the user to install cmake and aborts the current process.

+
+ +
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+ +
+
+class benchbuild.container.ContainerCreate(executable=None)[source]
+

Bases: Application

+

Create a new container with a predefined strategy.

+

We offer a variety of creation policies for a new container. By default a +basic ‘spawn a bash’ policy is used. This just leaves you inside a bash +that is started in the extracted container. After customization you can +exit the bash and pack up the result.

+
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+
+strategy(strategy)[source]
+

Select strategy based on key.

+
+
Parameters:
+

strategy (str) – The strategy to select.

+
+
Returns:
+

A strategy object.

+
+
+
+ +
+ +
+
+class benchbuild.container.ContainerList(executable=None)[source]
+

Bases: Application

+

Prints a list of the known containers.

+
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+ +
+
+class benchbuild.container.ContainerRun(executable=None)[source]
+

Bases: Application

+

Execute commannds inside a prebuilt container.

+
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+ +
+
+class benchbuild.container.ContainerStrategy[source]
+

Bases: object

+

Interfaces for the different containers chosen by the experiment.

+
+
+abstract run(context)[source]
+

Execute a container strategy.

+
+
Parameters:
+

context – A context object with attributes used for the strategy.

+
+
+
+ +
+ +
+
+class benchbuild.container.MockObj(**kwargs)[source]
+

Bases: object

+

Context object to be used in strategies.

+

This object’s attributes are initialized on construction.

+
+ +
+
+class benchbuild.container.SetupPolyJITGentooStrategy[source]
+

Bases: ContainerStrategy

+

Interface of using gentoo as a container for an experiment.

+
+
+run(context)[source]
+

Setup a gentoo container suitable for PolyJIT.

+
+ +
+ +
+
+benchbuild.container.clean_directories(builddir, in_dir=True, out_dir=True)[source]
+

Remove the in and out of the container if confirmed by the user.

+
+ +
+
+benchbuild.container.find_hash(container_db, key)[source]
+

Find the first container in the database with the given key.

+
+ +
+
+benchbuild.container.main(*args)[source]
+

Main entry point for the container tool.

+
+ +
+
+benchbuild.container.pack_container(in_container, out_file)[source]
+

Pack a container image into a .tar.bz2 archive.

+
+
Parameters:
+
    +
  • in_container (str) – Path string to the container image.

  • +
  • out_file (str) – Output file name.

  • +
+
+
+
+ +
+
+benchbuild.container.run_in_container(command, container_dir)[source]
+

Run a given command inside a container.

+

Mounts a directory as a container at the given mountpoint and tries to run +the given command inside the new container.

+
+ +
+
+benchbuild.container.set_input_container(_container, cfg)[source]
+

Save the input for the container in the configurations.

+
+ +
+
+benchbuild.container.setup_bash_in_container(builddir, _container, outfile, shell)[source]
+

Setup a bash environment inside a container.

+

Creates a new chroot, which the user can use as a bash to run the wanted +projects inside the mounted container, that also gets returned afterwards.

+
+ +
+
+benchbuild.container.setup_container(builddir, _container)[source]
+

Prepare the container and returns the path where it can be found.

+
+ +
+
+benchbuild.container.setup_directories(builddir)[source]
+

Create the in and out directories of the container.

+
+ +
+
+

Module: benchbuild.environments.domain.declarative

+

BenchBuild supports containerized execution of all experiments. This gives you +full control about the environment your [projects](/concepts/projects/) and +[experiments](/concepts/experiments/) may run in.

+

The following example uses the latest alpine:latest:

+
ContainerImage().from_('alpine:latest')
+    .run('apk', 'update')
+    .run('apk', 'add', 'python3')
+
+
+
+
+class benchbuild.environments.domain.declarative.ContainerImage(iterable=(), /)[source]
+

Bases: list

+

Define a container image declaratively.

+

Start a new image using the .from_ method and provide a base image. +Each method creates a new layer in the container image.

+
+
+add(sources, tgt)[source]
+

Add given files from the source to the container image.

+

Dockerfile syntax: ADD <source> [<source>…] <target>

+
+
Parameters:
+
    +
  • sources (tp.Iterable[str]) – Source path to add to the target

  • +
  • tgt (str) – Absolute target path.

  • +
+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+property base: str
+
+ +
+
+command(*args)[source]
+

Set the default command the container runs.

+

Dockerfile syntax: CMD <command>

+
+
Parameters:
+

*args (str) – A list of command components.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+context(func)[source]
+

Interact with the build context of the container.

+

Sometimes you have to interact with the build context of a container +image. For example, you need to add artifacts to the build context +before you can add the to the container image. +BenchBuild uses this to add the sources to the container image +automatically.

+
+
Parameters:
+

func (tp.Callable[[], None]) – A callable that is executed in the +build-context directory.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+copy_(sources, tgt)[source]
+

Copy given files from the source to the container image.

+

Dockerfile syntax: COPY <source> [<source>…] <target>

+
+
Parameters:
+
    +
  • sources (tp.Iterable[str]) – Source path to add to the target

  • +
  • tgt (str) – Absolute target path.

  • +
+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+entrypoint(*args)[source]
+

Set the entrypoint of the container.

+

Dockerfile syntax: ENTRYPOINT <command>

+

This sets the default binary to run to the given command.

+
+
Parameters:
+

*args (str) – A list of command components.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+env(**kwargs)[source]
+

Create an environment layer in this image.

+

Dockerfile syntax: ENV

+
+
Parameters:
+

kwargs (str) – a dictionary containing name/value pairings to be +set as environment variables.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+from_(base_image)[source]
+

Specify a new base layer for this image.

+

Dockerfile syntax: FROM <image>

+
+
Parameters:
+

base_image (str) – The base image for our new container image.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+run(command, *args, **kwargs)[source]
+

Run a command in the container image.

+

Dockerfile syntax: RUN <command>

+
+
Parameters:
+
    +
  • command (str) – The binary to execute in the container.

  • +
  • *args (str) – Arguments that will be passed to the container.

  • +
  • **kwargs (str) – Additional options that will be passed to the +backend run command.

  • +
+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+workingdir(directory)[source]
+

Change the working directory in the container.

+

Dockerfile syntax: WORKINGDIR <absolute-path>

+

All layers that follow this layer will be run with their working +directory set to directory.

+
+
Parameters:
+

directory (str) – The target directory to set our cwd to.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+ +
+
+benchbuild.environments.domain.declarative.add_benchbuild_layers(layers)[source]
+

Add benchbuild into the given container image.

+

This assumes all necessary depenencies are available in the image already. +The installation is done, either using pip from a remote mirror, or using +the source checkout of benchbuild.

+

A source installation requires your buildah/podman installation to be +able to complete a bind-mount as the user that runs benchbuild.

+
+
Parameters:
+

layers (ContainerImage) – a container image we will add our install layers to.

+
+
Return type:
+

ContainerImage

+
+
Returns:
+

the modified container image.

+
+
+
+ +
+
+

Module: benchbuild.environments.domain.model

+
+
+class benchbuild.environments.domain.model.AddLayer(sources, destination)[source]
+

Bases: Layer

+
+
+destination: str
+
+ +
+
+sources: Tuple[str, ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Command[source]
+

Bases: Message

+
+ +
+
+class benchbuild.environments.domain.model.Container(container_id, image, context, name, events=_Nothing.NOTHING)[source]
+

Bases: object

+
+
+container_id: str
+
+ +
+
+context: str
+
+ +
+
+events: List[Message]
+
+ +
+
+image: Image
+
+ +
+
+name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.model.ContextLayer(func)[source]
+

Bases: Layer

+
+
+func: Callable[[], None]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.CopyLayer(sources, destination)[source]
+

Bases: Layer

+
+
+destination: str
+
+ +
+
+sources: Tuple[str, ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.EntryPoint(command)[source]
+

Bases: Layer

+
+
+command: Tuple[str, ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Event[source]
+

Bases: Message

+
+ +
+
+class benchbuild.environments.domain.model.FromLayer(base)[source]
+

Bases: Layer

+
+
+base: str
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Image(name, from_, layers, events=_Nothing.NOTHING, env=_Nothing.NOTHING, mounts=_Nothing.NOTHING, layer_index=_Nothing.NOTHING)[source]
+

Bases: object

+
+
+append(*layers)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+env: Dict[str, str]
+
+ +
+
+events: List[Message]
+
+ +
+
+from_: FromLayer
+
+ +
+
+is_complete()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+is_present(layer)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+layer_index: Dict[Layer, LayerState]
+
+ +
+
+layers: List[Layer]
+
+ +
+
+mounts: List[Mount]
+
+ +
+
+name: str
+
+ +
+
+prepend(layer)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+present(layer)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+update_env(**kwargs)[source]
+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Layer[source]
+

Bases: ABC

+

A layer represents a filesystem layer in a container image.

+

Layers can be ‘virtual’ in the sense that they do not lead to changes +in the container image filesystem, e.g. setting up the build context.

+

This more or less represents commands/statements available in buildah +or Dockerfiles.

+
+

Examples

+

buildah add -> AddLayer +buildah copy -> CopyLayer +buildah from -> FromLayer

+
+
+ +
+
+class benchbuild.environments.domain.model.LayerState(value)[source]
+

Bases: Enum

+

An enumeration.

+
+
+ABSENT = 2
+
+ +
+
+PRESENT = 1
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Message[source]
+

Bases: object

+
+ +
+
+class benchbuild.environments.domain.model.Mount(source, target)[source]
+

Bases: object

+
+
+source: str
+
+ +
+
+target: str
+
+ +
+ +
+
+class benchbuild.environments.domain.model.RunLayer(command, args, kwargs)[source]
+

Bases: Layer

+
+
+args: Tuple[str, ...]
+
+ +
+
+command: str
+
+ +
+
+kwargs: Tuple[Tuple[str, str], ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.SetCommand(command)[source]
+

Bases: Layer

+
+
+command: Tuple[str, ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.UpdateEnv(env)[source]
+

Bases: Layer

+
+
+env: Tuple[Tuple[str, str], ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.WorkingDirectory(directory)[source]
+

Bases: Layer

+
+
+directory: str
+
+ +
+ +
+
+benchbuild.environments.domain.model.immutable_kwargs(kwargs)[source]
+

Convert str-typed kwargs into a hashable tuple.

+
+
Return type:
+

Tuple[Tuple[str, str], ...]

+
+
+
+ +
+
+

Module: benchbuild.environments.domain.commands

+
+
+class benchbuild.environments.domain.commands.CreateBenchbuildBase(name, layers)[source]
+

Bases: Command

+
+
+layers: ContainerImage
+
+ +
+
+name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.CreateImage(name, layers)[source]
+

Bases: Command

+
+
+layers: ContainerImage
+
+ +
+
+name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.DeleteImage(name)[source]
+

Bases: Command

+
+
+name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.ExportImage(image, out_name)[source]
+

Bases: Command

+
+
+image: str
+
+ +
+
+out_name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.ImportImage(image, in_path)[source]
+

Bases: Command

+
+
+image: str
+
+ +
+
+in_path: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.RunProjectContainer(image, name, build_dir, args=_Nothing.NOTHING)[source]
+

Bases: Command

+
+
+args: Sequence[str]
+
+ +
+
+build_dir: str
+
+ +
+
+image: str
+
+ +
+
+name: str
+
+ +
+ +
+
+benchbuild.environments.domain.commands.fs_compliant_name(name)[source]
+

Convert a name to a valid filename.

+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.environments.domain.commands.oci_compliant_name(name)[source]
+

Convert a name to an OCI compliant name.

+

For now, we just make sure it is lower-case. This is depending on +the implementation of your container registry. podman/buildah require +lower-case repository names for now.

+
+
Parameters:
+

name (str) – the name to convert

+
+
Return type:
+

str

+
+
+
+

Examples

+
>>> oci_compliant_name("foo")
+'foo'
+>>> oci_compliant_name("FoO")
+'foo'
+
+
+
+
+ +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/basics/index.html b/basics/index.html new file mode 100644 index 000000000..0608088f6 --- /dev/null +++ b/basics/index.html @@ -0,0 +1,327 @@ + + + + + + + Installation + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Installation

+

The installation instructions are tested against Ubuntu 20.04 for Python 3.7 and Python 3.8. The particular commands required for installation depend on your setup. +The dependencies below are not always mandatory, if they are not used.

+
+

Requirements

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Dependency

Minimum Version

Notes

Python

3.7

libpq

9.6

Required by psycopg2.

libfuse

2.9.9

If uchroot is used.

unionfs-fuse

1.0

If unionfs support is used.

slurm-llnl

18.08

If slurm support is used.

+
+

PostgreSQL

+

The library dependency libpq is always need right now, because we make use of psycopg2 features internally. It is planned to get rid of this dependency in the future.

+
+
+

FUSE

+

BenchBuild can make use of unionfs and libfuse. This is often used in conjunction with a tool named uchroot which provides legacy support for user-space containers. +This will be obsolete as soon as podman/buildah based OCI container support is considered stable.

+
+
+

SLURM

+

The cluster management software slurm is only required by ‘name’, i.e., we have to be able to import the binaries as python objects in benchbuild. As an alternative to installing slurm on your machine, you can always provide symlinks to /bin/true to the commands sbatch and srun.

+

The minimum version should signal the minimum features set expected by BenchBuild when generating a slurm batch script.

+
+
+
+

Benchbuild

+

BenchBuild is released via pip and can be installed on your system as follows:

+
pip install benchbuild
+
+
+

If you want to isolate BenchBuild from the rest of your system packages, you can install it in a dedicated virtual environment.

+
virtualenv -ppython3 <venv_path>
+source <venv_path>/bin/activate
+pip3 install benchbuild
+
+
+
+

Bootstrapping

+

BenchBuild provides a bootstrap procedure that checks a few key binaries on your system and tries to assist you in installation of any necessary binaries.

+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/.buildinfo b/branch/f-QoLImprovements/.buildinfo new file mode 100644 index 000000000..38cbf8b7c --- /dev/null +++ b/branch/f-QoLImprovements/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: ba3c244f56741a760a4c5373c3254226 +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/branch/f-QoLImprovements/.nojekyll b/branch/f-QoLImprovements/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/branch/f-QoLImprovements/CHANGELOG/index.html b/branch/f-QoLImprovements/CHANGELOG/index.html new file mode 100644 index 000000000..ae9685f1b --- /dev/null +++ b/branch/f-QoLImprovements/CHANGELOG/index.html @@ -0,0 +1,778 @@ + + + + + + + 6.8 (2023-10-09) + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

+
+

6.8 (2023-10-09)

+
+

Features

+
    +
  • ci: test with both db support and without (af7bfd90)

  • +
  • coverage:

    +
      +
    • test with database support enabled (0b8d6034)

    • +
    • add cli coverage report (64ce9f87)

    • +
    • add wrapped binaries to coverage (d4c6841d)

    • +
    +
  • +
  • db: revert default setting for connect_string to sqlite:// (806520d6)

  • +
+
+
+

Bug Fixes

+
    +
  • use context vars instead of env vars (e3ea47f0)

  • +
  • make github ci actually use its own env vars (e0c7ab67)

  • +
  • use BB_COVERAGE_PATH in .coveragerc (141afafa)

  • +
  • coveragerc requires curly braces for env variables (3ae8b335)

  • +
  • coveragerc requires curly braces for env variables (5b9c9906)

  • +
  • actions: re-raise caught exception (e4bff984, closes #561)

  • +
  • environments: buildah cannot find base images. (eb03c363)

  • +
+

+
+
+
+

6.7 (2023-04-04)

+
+

Features

+
    +
  • run auto-walrus over all of benchbuild’s file (79ac33d8)

  • +
  • add support for auto-walrus as pre-commit hook (d7a2165b)

  • +
  • drop support for python 3.7 and 3.8 (90308f2a)

  • +
  • ci:

    +
      +
    • update setup-python to v4 (3e943df6)

    • +
    • update github setup actions to v3 (dfa4cb81)

    • +
    +
  • +
  • command: use name as default value for a command’s label (07f74dd4)

  • +
  • environments: force base image to alpine:3.17 (fe5d6155)

  • +
  • setup:

    +
      +
    • widen allowed versions to major versions (5d29079a)

    • +
    • unlock latest versions of all packages (7b5a704f)

    • +
    +
  • +
  • wrapping: enforce global defaults for dill module (489e3039)

  • +
+
+
+

Bug Fixes

+
    +
  • python version for setup-python@v4 has to be string (7a1db742)

  • +
  • remove python 3.7 and 3.8 from all workflows (aaabc1b5)

  • +
  • bump pathos & dill to unbreak gitlab ci (bce45d8a)

  • +
  • ci:

    +
      +
    • disable mkdocs in github ci (8540f880)

    • +
    • reorder CI steps (test) (74379d53)

    • +
    • increase verbosity to max for all integation tasks (b6625d31)

    • +
    +
  • +
  • command: use private label when fetching string representation (d83aa666)

  • +
  • commands: preserve workload order when filtering (3648dd5e)

  • +
  • setup: unlock any major version of pygit2 (b09d9248)

  • +
  • wrapping: remove unused code (0d1c890d)

  • +
+
+
+
+

Changelog

+

+
+

6.6.4 (2023-03-16)

+

+
+
+

6.6.3 (2023-03-06)

+

+
+
+

6.6.2 (2023-03-06)

+
+

Bug Fixes

+
    +
  • pin sqlalchemy version <2.0 (86d45043)

  • +
+

+
+
+
+

6.6.1 (2023-01-10)

+
+

Features

+
    +
  • environments:

    +
      +
    • do not overwrite config, if cli option is default (b1a095c1)

    • +
    • improve error handling using result module (fbb69502)

    • +
    +
  • +
  • slurm: make container.runroot/container.root available for slurm customization (616a4c69, closes #528)

  • +
  • source: make sure we manage the archive symlink properly. (7687f0e3)

  • +
  • source/http: add auto-untar http source (84f90e75)

  • +
+
+
+

Bug Fixes

+
    +
  • environments:

    +
      +
    • add missing logging import (aad1b287)

    • +
    • add missing Err import (19c5983c)

    • +
    • notify user when commit of container image fails (78b890af)

    • +
    +
  • +
  • project: version filters should only consider expandable sources (3d546314)

  • +
  • source: enforce sorted order of revisions (ca973ff0)

  • +
+
+
+
+

6.5 (2022-11-03)

+
+

Feat

+
    +
  • source: re-enable project_cls in enumerate_revision interface

  • +
  • versions: enable context-aware SingleVersionFilter

  • +
  • source: only print context-free sources

  • +
  • source: expand public source API

  • +
  • source: introduce type skeleton and prototypes for context-aware version enumeration.

  • +
  • action: replace StepClass metaclass with init_subclass

  • +
  • actions: mark StepTy covariant

  • +
  • actions: use Stepable protocol as bound for StepTy.

  • +
  • actions: accept any varargs in a Step’s call implementation

  • +
+
+
+

Fix

+
    +
  • require dill version to be exactly 0.3.4

  • +
  • linter warning

  • +
  • linter warnings

  • +
  • project: remove debug print

  • +
  • utils: variant -> revision

  • +
  • tests: repair tests after VariantContext replacement.

  • +
  • source: remove runtime_checkable decorator

  • +
  • source: use project class instead of object for enumerate

  • +
  • source: return sequence of variants instead of nestedvariant

  • +
  • source: clean up protocol apis

  • +
  • actions: rename StepTy -> StepTy_co

  • +
  • tests: remove notify_step_begin_end

  • +
  • actions: reduce mypy errors

  • +
  • actions: use mutable generic container

  • +
+
+
+

Refactor

+
    +
  • versions: remove BaseVersionGroup

  • +
  • source: replace VariantContext with Revision

  • +
  • source: remove ExpandableAndFetchableSource from API

  • +
+
+
+
+

6.4 (2022-09-21)

+
+

Feat

+
    +
  • actions: make MultiStep generic.

  • +
  • command: make use of rendered and unrenderer PathToken explicit.

  • +
  • command: safeguard pruning and backup

  • +
  • command: add tests for enable_rollback

  • +
  • command: add support for creates and consumes properties for commands

  • +
  • command: add a label to commands

  • +
  • workload: switch WorkloadSet to varargs instead of kwargs

  • +
  • command: add example OnlyIn for WorkloadSet customization.

  • +
+
+
+

Fix

+
    +
  • command: strictly less than python 3.9

  • +
  • command: use _is_relative_to where needed

  • +
  • command: guard is_relative_to with else

  • +
  • command: do not depend on Path.is_relative_to (<python3.9)

  • +
  • command: make mypy happy.

  • +
  • command: Command.label is Optional

  • +
  • command: use protocols instead of typing.Callable for callback functions

  • +
  • command: Command.getitem used constructor wrong

  • +
  • command: return self._label instead of self.label

  • +
  • command: return Path instead of str or PathToken

  • +
  • command: assign consumed files to consumes attribute

  • +
  • tests: remove missing_ok from unlink (python3.7)

  • +
  • tests: repair test_command tests

  • +
  • tests: make test project pickle’able

  • +
  • tests: add missing pytest-git dependency

  • +
  • command: only might be None

  • +
  • command: access cache path instead of builddir path

  • +
  • command: make sure SupportsUnwrap returns a WorkloadSet

  • +
+
+
+

Refactor

+
    +
  • command: rename enable_rollback -> cleanup

  • +
+
+
+
+

6.3.2 (2022-08-21)

+
+

Feat

+
    +
  • command: rename NullRenderer to RootRenderer

  • +
  • command: hook up token renderer logic with Commands

  • +
  • command: add support for generic path tokens

  • +
  • workload: convert scimark2

  • +
  • command: migrate git-based projects to workload sets

  • +
  • command: add support for WorkloadSet.

  • +
  • command: clear path tracker on fresh ProjectEnvironment

  • +
  • wrapping: avoid wrapping the same command twice.

  • +
  • jobs: add RunJob and RunJobs actions

  • +
  • command: replace source root anywhere in command’s parts

  • +
  • command: pass environment to plumbum command

  • +
  • command: pass args to plumbum command

  • +
  • command: improve args and kwargs handling

  • +
  • add env and str to commands

  • +
  • command: support declarative commands in projects (WIP)

  • +
  • source: add ‘fetch’ support to FetchableSource derivatives

  • +
  • workloads: add properties & tags accessors

  • +
  • workloads: convert benchbuild.xz to support workloads

  • +
+
+
+

Fix

+
    +
  • test must use render()

  • +
  • x264: repair broken cli args

  • +
  • command: actually run the workload

  • +
  • command: check for existence, only after rendering

  • +
  • project: target compile instead of run_tests, when accessing compile

  • +
  • command: remove unused definitions

  • +
  • command: context -> kwargs

  • +
  • typing: python3.7 requires typing_extensions for runtime_checkable / Protocll

  • +
  • command: missing rename job -> workload

  • +
  • command: provide mapping type

  • +
  • workload: strip previous workload draft

  • +
  • workaround a mypy error

  • +
  • correct mypy errors.

  • +
  • wrapping: provide default arg for sprefix

  • +
  • actions: provide default StepResult

  • +
  • command: store args as tuple

  • +
  • bzip2: clean draft marker

  • +
  • actions: repair status print of actions

  • +
  • experiment: initialize CleanExtra correctly

  • +
  • jobs: allow jobs to run as wrapped binaries

  • +
  • use oci_compliant name for image names

  • +
  • workloads: wrong workload type

  • +
  • actions: unbreak tests after list -> scalar conversion

  • +
+
+
+

Refactor

+
    +
  • command: lower-case token str

  • +
  • rename Job -> Workload

  • +
  • command: remove debug prints

  • +
  • source: remove unnecessary ellipsis

  • +
+
+
+
+

6.3.1 (2022-03-01)

+
+

Feat

+
    +
  • actions: clean interfaces of utils/actions

  • +
  • workloads: make object instance accessible to workloads using descriptors

  • +
  • workloads: hook up Compile and Run action to new workload impl

  • +
  • workloads: add simple intersection filter to workloads

  • +
  • workloads: change workload registration decorator style.

  • +
  • workloads: migrate Compile/Run action to run workloads only

  • +
  • project: remove run_tests and compile abstract methods

  • +
  • gzip: convert gzip to workloads

  • +
  • workload: Add prototype support for workloads.

  • +
  • environments: strip container args when entering interactive mode

  • +
+
+
+

Fix

+
    +
  • workloads: typo.

  • +
  • gzip: undo wrong wrap command

  • +
  • actions: project -> obj after rebase

  • +
+
+
+

Refactor

+
    +
  • workloads: remove useless/unused parts

  • +
+
+
+
+

6.3 (2022-02-03)

+
+

Feat

+
    +
  • actions: throw error if RevisionStrings cannot match any Source.

  • +
  • source: add FetchableSource.explore() method

  • +
  • source: only filter context for expandable sources

  • +
  • actions: support partial revisions in SetProjectVersion

  • +
  • source: hook up context_from_revisions to SetProjectVersion

  • +
  • source: provide an easy way to create a variant context

  • +
  • environments: add container image removal to buildah adapter

  • +
  • environments: support custom arguments in RunProjectContainer

  • +
  • actions: track active_variant with SetProjectVersion

  • +
  • project: add MultiVersioned Mixin to Projects

  • +
  • source: symlink active version for http sources

  • +
  • source: Link to active location after version()

  • +
  • actions: Rename AddProjectVersion to SetProjectVersion

  • +
  • actions: add AddProjectVersion action

  • +
  • actions: remove obsolete parameters

  • +
  • actions: remove attrs from utils/actions

  • +
+
+
+

Fix

+
    +
  • tests: eye-breaking code alignment.

  • +
  • environments: do not fail if no entrypoint is set.

  • +
  • environments: supply args as dedicated subcommand args

  • +
  • environments: use a default list factory, instead of a list class

  • +
  • source: replace symlink to directory

  • +
  • actions: obvious type errors in SetProjectVersion

  • +
  • actions: assign active variant

  • +
+
+
+

Refactor

+
    +
  • pylint: remove unused import

  • +
  • pylint: make pylint happy.

  • +
  • pylint: make pylint almost happy.

  • +
+
+
+
+

6.2.7 (2021-09-21)

+
+
+

6.2.6 (2021-09-16)

+
+

Fix

+
    +
  • sources: do not use protocol class as ABC

  • +
+
+
+
+

6.2.5 (2021-09-15)

+
+

Feat

+
    +
  • utils/run: add unbuffered watch commands

  • +
  • source: update git remote revisions. (#434)

  • +
  • log: add force_tty switch to control RichHandler. (#435)

  • +
+
+
+
+

6.2.4 (2021-09-03)

+
+
+

6.2.3 (2021-08-26)

+
+

Fix

+
    +
  • schema: silence SAWarning about caching (#428)

  • +
  • environments: pass format string to logging call (#427)

  • +
+
+
+
+

6.2.2 (2021-07-29)

+
+
+

6.2.1 (2021-07-06)

+
+

Feat

+
    +
  • environments: add an interactive mode for container runs.

  • +
+
+
+

Fix

+
    +
  • logging: make rich log to stderr by default (#415)

  • +
  • settings: BB_ENV is ignored when no config file is loaded” (#414)

  • +
+
+
+
+

6.2 (2021-06-02)

+
+

Fix

+
    +
  • settings: unbreak test cases.

  • +
  • use correct schema version

  • +
  • settings: consistent settings behavior.

  • +
  • environments: notify the user, if image creation fails

  • +
+
+
+
+

6.1.1 (2021-05-11)

+
+

Fix

+
    +
  • project: do not track project classes twice

  • +
+
+
+
+

6.1 (2021-05-11)

+
+

Feat

+
    +
  • environments: just print env var name as error message

  • +
  • environments: warn the user about too long paths for libpod

  • +
  • slurm: support variable number of subcommand arguments

  • +
  • tune down rich’s custom log format

  • +
  • environments: enable debugging of failed image builds

  • +
  • environments: provide more consistent output through rich

  • +
  • environments: add ‘rmi’ subcommand to delete images.

  • +
  • environments: make an error message stand out more clearly

  • +
  • environments: add g++ to base image

  • +
  • environments: split image_exists into 2 implementations

  • +
  • environments: split containers cli into 2 entitie

  • +
  • environments: add basic error handling to environments

  • +
  • environments: emit layer creation events

  • +
  • environments: print layer construction progress

  • +
  • environments: make layers hashable

  • +
  • environments: step-wise image construction

  • +
  • environments: split Repositories and Unit of Work into 2 entities each

  • +
  • utils/slurm: add customizable SLURM templates

  • +
  • cli/project: add details view for a single project

  • +
  • cli/project: change project view to a condensed format

  • +
  • environments: add option to replace container images

  • +
  • add support for –export and –import flags in containers

  • +
+
+
+

Fix

+
    +
  • sources: unshallow only when needed

  • +
  • environments: unshallow git clones before dissociating

  • +
  • environments: remove left-over parameters

  • +
  • ci: typo.

  • +
  • environments: do not overwrite exported images.

  • +
  • environments: remove optional image name argument from podman load

  • +
  • slurm: fix pylint/mypy

  • +
  • environments: reuse same status bar structure for all other cli subcommands

  • +
  • environments: mypy warnings

  • +
  • environments: fix mypy/pylint annotations.

  • +
  • environments: split return turple and baild out on error

  • +
  • environments: mypy warnings

  • +
  • environments: add missing type conversion

  • +
  • environments: rework typing annotations for handlers

  • +
  • environments: fix linter/mypy warnings

  • +
  • environments: make Add & Copy layers hashable

  • +
  • environments: add missing sys import

  • +
  • environments: import Protocol from typing_extensions, if python <= 3.8

  • +
  • environments: handle ‘None’ for MaybeContainer return type

  • +
  • slurm: do not modify slurm_node_dir

  • +
  • environments: deal with multi-line container ids

  • +
  • environments: do not spawn the FromLayer

  • +
  • cli/project: annotate print_layers

  • +
  • cli/project: add neutral element for multiplication with reduce

  • +
  • project: project registration for groups

  • +
  • environments: explicitly state remote registry location

  • +
  • do not use global state to conffigure buildah/podman

  • +
  • x264: use local name of source for lookup

  • +
+
+
+

Refactor

+
    +
  • environments: fix possible unbound variable

  • +
  • slurm: fix type error on cli_process

  • +
  • environments: remove unused sys import

  • +
  • environments: rmeove some linter warnings

  • +
  • environments: replace functools.partial with custom closure function

  • +
  • environments: unsplit image from layer creation

  • +
  • enviroments: remove debug print

  • +
  • environments: remove unused commands

  • +
  • cli/project: remove version counting from project view

  • +
  • cli/project: force use of str

  • +
  • cli/project: add documentation to print_project

  • +
  • cli/project: add type annotation for set_limit

  • +
  • cli/project: add a default list limit for versions (10)

  • +
  • cli/project: provide better layout of project information

  • +
  • cli/project: use a multi-line string

  • +
  • cli/project: use named fields

  • +
  • project: provide correct type annotations

  • +
+
+
+
+

6.0.1 (2020-12-29)

+
+

Fix

+
    +
  • Avoid useless plugin spam when running with higher verbosity levels

  • +
+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/command/index.html b/branch/f-QoLImprovements/_modules/benchbuild/command/index.html new file mode 100644 index 000000000..1f897d08b --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/command/index.html @@ -0,0 +1,1173 @@ + + + + + + benchbuild.command + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.command

+import logging
+import shutil
+import sys
+import typing as tp
+from contextlib import contextmanager
+from pathlib import Path
+from typing import Protocol, runtime_checkable
+
+from plumbum import local
+from plumbum.commands.base import BoundEnvCommand
+
+from benchbuild.settings import CFG
+from benchbuild.source.base import primary
+from benchbuild.utils.revision_ranges import RevisionRange
+from benchbuild.utils.run import watch
+from benchbuild.utils.wrapping import wrap
+
+if tp.TYPE_CHECKING:
+    import benchbuild.project.Project  # pylint: disable=unused-import
+
+LOG = logging.getLogger(__name__)
+
+
+
+[docs] +@runtime_checkable +class ArgsRenderStrategy(Protocol): + """ + Rendering strategy protocol for command line argument tokens. + """ + + @property + def unrendered(self) -> str: + """ + Returns an unrendered representation of this strategy. + """ + +
+[docs] + def rendered(self, **kwargs: tp.Any) -> tp.Tuple[str, ...]: + """Renders this strategy."""
+
+ + + +
+[docs] +@runtime_checkable +class PathRenderStrategy(Protocol): + """ + Rendering strategy protocol for path components. + """ + + @property + def unrendered(self) -> str: + """ + Returns an unrendered representation of this strategy. + """ + +
+[docs] + def rendered(self, **kwargs: tp.Any) -> Path: + """Renders this strategy."""
+
+ + + +
+[docs] +class RootRenderer: + """ + Renders the root directory. + """ + + @property + def unrendered(self) -> str: + return "/" + +
+[docs] + def rendered(self, **kwargs: tp.Any) -> Path: + del kwargs + return Path("/")
+ + + def __str__(self) -> str: + return self.unrendered + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +class ConstStrRenderer: + """ + Renders a constant string defined by the user. + """ + value: str + + def __init__(self, value: str) -> None: + self.value = value + + @property + def unrendered(self) -> str: + return self.value + +
+[docs] + def rendered(self, **kwargs: tp.Any) -> Path: + del kwargs + return Path(self.value)
+ + + def __str__(self) -> str: + return self.value + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +class BuilddirRenderer: + """ + Renders the build directory of the assigned project. + """ + + @property + def unrendered(self) -> str: + return "<builddir>" + +
+[docs] + def rendered( + self, + project: tp.Optional['benchbuild.project.Project'] = None, + **kwargs: tp.Any + ) -> Path: + """ + Render the project's build directory. + + If rendering is not possible, the unrendered representation is + provided and an error will be loggged. + + Args: + project: the project to render the build directory from. + """ + del kwargs + + if project is None: + LOG.error("Cannot render a build directory without a project.") + return Path(self.unrendered) + + return Path(project.builddir)
+ + + def __str__(self) -> str: + return self.unrendered
+ + + +
+[docs] +class SourceRootRenderer: + """ + Renders the source root of the given local source name. + + The attribute 'local' refers to the local attribute in a project's + source definition. + If the local name cannot be found inside the project's source definition, + it will concatenate the project's builddir with the given name. + """ + local: str + + def __init__(self, local_name: str) -> None: + self.local = local_name + + @property + def unrendered(self) -> str: + return f"<source_of({self.local})>" + +
+[docs] + def rendered( + self, + project: tp.Optional['benchbuild.project.Project'] = None, + **kwargs: tp.Any + ) -> Path: + """ + Render the project's source directory. + + If rendering is not possible, the unrendered representation is + provided and an error will be loggged. + + Args: + project: the project to render the build directory from. + """ + del kwargs + + if project is None: + LOG.error("Cannot render a source directory without a project.") + return Path(self.unrendered) + + if (src_path := project.source_of(self.local)): + return Path(src_path) + return Path(project.builddir) / self.local
+ + + def __str__(self) -> str: + return self.unrendered
+ + + +
+[docs] +class ArgsToken: + """ + Base class for tokens that can be rendered into command-line arguments. + """ + renderer: ArgsRenderStrategy + +
+[docs] + @classmethod + def make_token( + cls, renderer: ArgsRenderStrategy + ) -> 'ArgsToken': + return ArgsToken(renderer)
+ + + def __init__(self, renderer: ArgsRenderStrategy) -> None: + self.renderer = renderer + +
+[docs] + def render(self, **kwargs: tp.Any) -> tp.Tuple[str, ...]: + """ + Renders the PathToken as a standard pathlib Path. + + Any kwargs will be forwarded to the PathRenderStrategy. + """ + return self.renderer.rendered(**kwargs)
+ + + def __str__(self) -> str: + return self.renderer.unrendered + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +class PathToken: + """ + Base class used for command token substitution. + + A path token can use similar to pathlib's Path components. However, each + token can render dynamically based on the given render context. + """ + renderer: PathRenderStrategy + + left: tp.Optional['PathToken'] + right: tp.Optional['PathToken'] + +
+[docs] + @classmethod + def make_token( + cls, renderer: tp.Optional[PathRenderStrategy] = None + ) -> 'PathToken': + if renderer: + return PathToken(renderer) + return PathToken(RootRenderer())
+ + + def __init__( + self, + renderer: PathRenderStrategy, + left: tp.Optional['PathToken'] = None, + right: tp.Optional['PathToken'] = None + ) -> None: + + self.renderer = renderer + self.left = left + self.right = right + + @property + def name(self) -> str: + return Path(str(self)).name + + @property + def dirname(self) -> Path: + return Path(str(self)).parent + +
+[docs] + def exists(self) -> bool: + return Path(str(self)).exists()
+ + +
+[docs] + def render(self, **kwargs: tp.Any) -> Path: + """ + Renders the PathToken as a standard pathlib Path. + + Any kwargs will be forwarded to the PathRenderStrategy. + """ + token = self.renderer.rendered(**kwargs) + p = Path() + + if self.left: + p = self.left.render(**kwargs) + + p = p / token + + if self.right: + p = p / self.right.render(**kwargs) + + return p
+ + + def __truediv__(self, rhs: tp.Union[str, 'PathToken']) -> 'PathToken': + if isinstance(rhs, str): + render_str = ConstStrRenderer(rhs) + rhs_token = PathToken(render_str) + else: + rhs_token = rhs + + if self.right is None: + return PathToken(self.renderer, self.left, rhs_token) + return PathToken(self.renderer, self.left, self.right / rhs_token) + + def __str__(self) -> str: + parts = [self.left, self.renderer.unrendered, self.right] + return str(Path(*[str(part) for part in parts if part is not None])) + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +def source_root(local_name: str) -> PathToken: + """ + Create a SourceRoot token for the given name. + + Args: + local_name (str): The source's local name to access. + """ + return PathToken.make_token(SourceRootRenderer(local_name))
+ + + +SourceRoot = source_root + + +
+[docs] +def project_root() -> PathToken: + return PathToken.make_token(BuilddirRenderer())
+ + + +ProjectRoot = project_root + + +
+[docs] +@runtime_checkable +class SupportsUnwrap(Protocol): + """ + Support unwrapping a WorkloadSet. + + Unwrapping ensures access to a WorkloadSet from any wrapper object. + """ + +
+[docs] + def unwrap(self, project: "benchbuild.project.Project") -> "WorkloadSet": + ...
+
+ + + +
+[docs] +class WorkloadSet: + """An immutable set of workload descriptors. + + A WorkloadSet is immutable and usable as a key in a job mapping. + WorkloadSets support composition through intersection and union. + + Example: + >>> WorkloadSet(1, 0) & WorkloadSet(1) + WorkloadSet({1}) + >>> WorkloadSet(1, 0) & WorkloadSet(2) + WorkloadSet({}) + >>> WorkloadSet(1, 0) | WorkloadSet(2) + WorkloadSet({0, 1, 2}) + >>> WorkloadSet(1, 0) | WorkloadSet("1") + WorkloadSet({0, 1, 1}) + + A workload set is not sorted, therefore, requires no comparability between + inserted values. + """ + + _tags: tp.FrozenSet[tp.Any] + + def __init__(self, *args: tp.Any) -> None: + self._tags = frozenset(args) + + def __iter__(self) -> tp.Iterator[str]: + return [k for k, _ in self._tags].__iter__() + + def __contains__(self, v: tp.Any) -> bool: + return self._tags.__contains__(v) + + def __len__(self) -> int: + return len(self._tags) + + def __and__(self, rhs: "WorkloadSet") -> "WorkloadSet": + lhs_t = self._tags + rhs_t = rhs._tags + + ret = WorkloadSet() + ret._tags = lhs_t & rhs_t + return ret + + def __or__(self, rhs: "WorkloadSet") -> "WorkloadSet": + lhs_t = self._tags + rhs_t = rhs._tags + + ret = WorkloadSet() + ret._tags = lhs_t | rhs_t + return ret + + def __hash__(self) -> int: + return hash(self._tags) + + def __repr__(self) -> str: + repr_str = ", ".join([f"{k}" for k in self._tags]) + + return f"WorkloadSet({{{repr_str}}})" + +
+[docs] + def unwrap(self, project: "benchbuild.project.Project") -> "WorkloadSet": + """ + Implement the `SupportsUnwrap` protocol. + + WorkloadSets only implement identity. + """ + del project + return self
+
+ + + +
+[docs] +class OnlyIn: + """ + Provide a filled `WorkloadSet` only if, given revision is inside the range. + + This makes use of the unwrap protocol and returns the given WorkloadSet, + iff, the Project's revision is included in the range specified by the + RevisionRange. + """ + rev_range: RevisionRange + workload_set: WorkloadSet + + def __init__( + self, rev_range: RevisionRange, workload_set: WorkloadSet + ) -> None: + self.rev_range = rev_range + self.workload_set = workload_set + +
+[docs] + def unwrap(self, project: "benchbuild.project.Project") -> WorkloadSet: + """ + Provide the store WorkloadSet only if our revision is in the range. + """ + source = primary(*project.source) + self.rev_range.init_cache(source.fetch()) + + revision = project.version_of_primary + if revision in set(self.rev_range): + return self.workload_set + return WorkloadSet()
+
+ + + +ArtefactPath = tp.Union[PathToken, str] + + +
+[docs] +class Command: + """ + A command wrapper for benchbuild's commands. + + Commands are defined by a path to an executable binary and it's arguments. + Optional, commands can provide output and output_param parameters to + declare the Command's output behavior. + + Attributes: + path: The binary path of the command + *args: Command arguments. + output_param: A format string that encodes the output parameter argument + using the `output` attribute. + + Example: output_param = f"--out {output}". + BenchBuild will construct the output argument from this. + output: An optional PathToken to declare an output file of the command. + label: An optional Label that can be used to name a command. + creates: A list of PathToken that encodes any artifacts that are + created by this command. + This will include the output PathToken automatically. Any + additional PathTokens provided will be provided for cleanup. + consumes: A list of PathToken that holds any artifacts that will be + consumed by this command. + **kwargs: Any remaining kwargs will be added as environment variables + to the command. + + Base command path: + >>> ROOT = PathToken.make_token() + >>> base_c = Command(ROOT / "bin" / "true") + >>> base_c + Command(path=/bin/true) + >>> str(base_c) + '/bin/true' + + Test environment representations: + >>> env_c = Command(ROOT / "bin"/ "true", BB_ENV_TEST=1) + >>> env_c + Command(path=/bin/true env={'BB_ENV_TEST': 1}) + >>> str(env_c) + 'BB_ENV_TEST=1 /bin/true' + + Argument representations: + >>> args_c = Command(ROOT / "bin" / "true", "--arg1", "--arg2") + >>> args_c + Command(path=/bin/true args=('--arg1', '--arg2')) + >>> str(args_c) + '/bin/true --arg1 --arg2' + + Use str for creates: + >>> cmd = Command(ROOT / "bin" / "true", creates=["tmp/foo"]) + >>> cmd.creates + [<builddir>/tmp/foo] + + Use absolute path-str for creates: + >>> cmd = Command(ROOT / "bin" / "true", creates=["/tmp/foo"]) + >>> cmd.creates + [/tmp/foo] + """ + + _args: tp.Tuple[tp.Any, ...] + _env: tp.Dict[str, str] + _label: tp.Optional[str] + _output: tp.Optional[PathToken] + _output_param: tp.Sequence[str] + _path: PathToken + _creates: tp.Sequence[PathToken] + _consumes: tp.Sequence[PathToken] + + def __init__( + self, + path: PathToken, + *args: tp.Any, + output: tp.Optional[PathToken] = None, + output_param: tp.Optional[tp.Sequence[str]] = None, + label: tp.Optional[str] = None, + creates: tp.Optional[tp.Sequence[ArtefactPath]] = None, + consumes: tp.Optional[tp.Sequence[ArtefactPath]] = None, + **kwargs: str, + ) -> None: + + def _to_pathtoken(token: ArtefactPath) -> PathToken: + if isinstance(token, str): + return ProjectRoot() / token + return token + + self._path = path + self._args = tuple(args) + self._output = output + + self._output_param = output_param if output_param is not None else [] + self._label = label + self._env = kwargs + + _creates = creates if creates is not None else [] + _consumes = consumes if consumes is not None else [] + + self._creates = [_to_pathtoken(token) for token in _creates] + self._consumes = [_to_pathtoken(token) for token in _consumes] + + if output: + self._creates.append(output) + + @property + def name(self) -> str: + return self._path.name + + @property + def path(self) -> PathToken: + return self._path + + @path.setter + def path(self, new_path: PathToken) -> None: + self._path = new_path + + @property + def dirname(self) -> Path: + return self._path.dirname + + @property + def output(self) -> tp.Optional[PathToken]: + return self._output + + @property + def creates(self) -> tp.Sequence[PathToken]: + return self._creates + + @property + def consumes(self) -> tp.Sequence[PathToken]: + return self._consumes + +
+[docs] + def env(self, **kwargs: str) -> None: + self._env.update(kwargs)
+ + + @property + def label(self) -> str: + return self._label if self._label else self.name + + @label.setter + def label(self, new_label: str) -> None: + self._label = new_label + + def __getitem__(self, args: tp.Tuple[tp.Any, ...]) -> "Command": + return Command( + self._path, + *self._args, + *args, + output=self._output, + output_param=self._output_param, + creates=self._creates, + consumes=self._consumes, + **self._env + ) + + def __call__(self, *args: tp.Any, **kwargs: tp.Any) -> tp.Any: + """Run the command in foreground.""" + cmd_w_output = self.as_plumbum(**kwargs) + return watch(cmd_w_output)(*args) + +
+[docs] + def rendered_args(self, **kwargs: tp.Any) -> tp.Tuple[str, ...]: + args: tp.List[str] = [] + + for arg in self._args: + if isinstance(arg, ArgsToken): + args.extend(arg.render(**kwargs)) + else: + args.append(str(arg)) + + return tuple(args)
+ + +
+[docs] + def as_plumbum(self, **kwargs: tp.Any) -> BoundEnvCommand: + """ + Convert this command into a plumbum compatible command. + + This renders all tokens in the command's path and creates a new + plumbum command with the given parameters and environment. + + Args: + **kwargs: parameters passed to the path renderers. + + Returns: + An executable plumbum command. + """ + cmd_path = self.path.render(**kwargs) + assert cmd_path.exists(), f"{str(cmd_path)} doesn't exist!" + + cmd = local[str(cmd_path)] + cmd_w_args = cmd[self.rendered_args(**kwargs)] + cmd_w_output = cmd_w_args + if self.output: + output_path = self.output.render(**kwargs) + output_params = [ + arg.format(output=output_path) for arg in self._output_param + ] + cmd_w_output = cmd_w_args[output_params] + cmd_w_env = cmd_w_output.with_env(**self._env) + + return cmd_w_env
+ + + def __repr__(self) -> str: + repr_str = f"path={self._path}" + + if self._label: + repr_str = f"{self._label} {repr_str}" + if self._args: + repr_str += f" args={tuple(str(arg) for arg in self._args)}" + if self._env: + repr_str += f" env={self._env}" + if self._output: + repr_str += f" output={self._output}" + if self._output_param: + repr_str += f" output_param={self._output_param}" + + return f"Command({repr_str})" + + def __str__(self) -> str: + env_str = " ".join([f"{k}={str(v)}" for k, v in self._env.items()]) + args_str = " ".join(tuple(str(arg) for arg in self._args)) + + command_str = f"{self._path}" + if env_str: + command_str = f"{env_str} {command_str}" + if args_str: + command_str = f"{command_str} {args_str}" + if self._label: + command_str = f"{self._label} {command_str}" + return command_str
+ + + +
+[docs] +class ProjectCommand: + """ProjectCommands associate a command to a benchbuild project. + + A project command can wrap the given command with the assigned + runtime extension. + If the binary is located inside a subdirectory relative to one of the + project's sources, you can provide a path relative to it's local + directory. + A project command will always try to resolve any reference to a local + source directory in a command's path. + + A call to a project command will drop the current configuration inside + the project's build directory and confine the run into the project's + build directory. The binary will be replaced with a wrapper that + calls the project's runtime_extension. + """ + + project: "benchbuild.project.Project" + command: Command + + def __init__( + self, project: "benchbuild.project.Project", command: Command + ) -> None: + self.project = project + self.command = command + + @property + def path(self) -> Path: + return self.command.path.render(project=self.project) + + def __call__(self, *args: tp.Any): + build_dir = self.project.builddir + + CFG.store(Path(build_dir) / ".benchbuild.yml") + with local.cwd(build_dir): + cmd_path = self.path + + wrap(str(cmd_path), self.project) + return self.command.__call__(*args, project=self.project) + + def __repr__(self) -> str: + return f"ProjectCommand({self.project.name}, {self.path})" + + def __str__(self) -> str: + return str(self.command)
+ + + +def _is_relative_to(p: Path, other: Path) -> bool: + return p.is_relative_to(other) + + +def _default_prune(project_command: ProjectCommand) -> None: + command = project_command.command + project = project_command.project + builddir = Path(str(project.builddir)) + + for created in command.creates: + created_path = created.render(project=project) + if created_path.exists() and created_path.is_file(): + if not _is_relative_to(created_path, builddir): + LOG.error("Pruning outside project builddir was rejected!") + else: + created_path.unlink() + + +def _default_backup( + project_command: ProjectCommand, + _suffix: str = ".benchbuild_backup" +) -> tp.List[Path]: + command = project_command.command + project = project_command.project + builddir = Path(str(project.builddir)) + + backup_destinations: tp.List[Path] = [] + for backup in command.consumes: + backup_path = backup.render(project=project) + backup_destination = backup_path.with_suffix(_suffix) + if backup_path.exists(): + if not _is_relative_to(backup_path, builddir): + LOG.error("Backup outside project builddir was rejected!") + else: + shutil.copy(backup_path, backup_destination) + backup_destinations.append(backup_destination) + + return backup_destinations + + +def _default_restore(backup_paths: tp.List[Path]) -> None: + for backup_path in backup_paths: + original_path = backup_path.with_suffix("") + if not original_path.exists() and backup_path.exists(): + backup_path.rename(original_path) + + if not original_path.exists() and not backup_path.exists(): + LOG.error("No backup to restore from. %s missing", str(backup_path)) + + if original_path.exists() and backup_path.exists(): + LOG.error("%s not consumed, ignoring backup", str(original_path)) + + +
+[docs] +class PruneFn(Protocol): + """Prune function protocol.""" + + def __call__(self, project_command: ProjectCommand) -> None: + ...
+ + + +
+[docs] +class BackupFn(Protocol): + """Backup callback function protocol.""" + + def __call__(self, + project_command: ProjectCommand, + _suffix: str = ...) -> tp.List[Path]: + ...
+ + + +
+[docs] +class RestoreFn(Protocol): + """Restore function protocol.""" + + def __call__(self, backup_paths: tp.List[Path]) -> None: + ...
+ + + +
+[docs] +@contextmanager +def cleanup( + project_command: ProjectCommand, + backup: BackupFn = _default_backup, + restore: RestoreFn = _default_restore, + prune: PruneFn = _default_prune +): + """ + Encapsulate a command in automatic backup, restore and prune. + + This will wrap a ProjectCommand inside a contextmanager. All consumed + files inside the project's build directory will be backed up by benchbuild. + You can then run your command as usual. + When you leave the context, all created paths are deleted and all consumed + paths restored. + """ + + backup_paths = backup(project_command) + yield project_command + prune(project_command) + restore(backup_paths)
+ + + +WorkloadIndex = tp.MutableMapping[WorkloadSet, tp.List[Command]] + + +
+[docs] +def unwrap( + index: WorkloadIndex, project: 'benchbuild.project.Project' +) -> WorkloadIndex: + """ + Unwrap all keys in a workload index. + + 'Empty' WorkloadSets will be removed. A WorkloadSet is empty, if it's + boolean representation evaluates to `False`. + """ + return {k: v for k, v in index.items() if bool(k.unwrap(project))}
+ + + +
+[docs] +def filter_workload_index( + only: tp.Optional[WorkloadSet], index: WorkloadIndex +) -> tp.Generator[tp.List[Command], None, None]: + """ + Yield only commands from the index that match the filter. + + This removes all command lists from the index not matching `only`. + """ + + keys = [k for k in index if k and ((only and (k & only)) or (not only))] + for k in keys: + yield index[k]
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/container/index.html b/branch/f-QoLImprovements/_modules/benchbuild/container/index.html new file mode 100644 index 000000000..bc13e74f0 --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/container/index.html @@ -0,0 +1,794 @@ + + + + + + benchbuild.container + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.container

+"""
+Container construction tool.
+
+This tool assists in the creation of customized uchroot containers.
+You can define strategies and apply them on a given container base-image
+to have a fixed way of creating a user-space environment.
+"""
+import logging
+import os
+import sys
+from abc import abstractmethod
+
+from plumbum import FG, TF, ProcessExecutionError, cli, local
+
+from benchbuild.settings import CFG
+from benchbuild.utils import bootstrap, container, download, log, run, uchroot
+from benchbuild.utils import user_interface as ui
+from benchbuild.utils.cmd import bash, mkdir, mv, rm, tar
+from benchbuild.utils.settings import get_number_of_jobs
+
+LOG = logging.getLogger(__name__)
+
+
+
+[docs] +def clean_directories(builddir, in_dir=True, out_dir=True): + """Remove the in and out of the container if confirmed by the user.""" + container_in = local.path(builddir) / "container-in" + container_out = local.path(builddir) / "container-out" + + if in_dir and container_in.exists(): + if ui.ask("Should I delete '{0}'?".format(container_in)): + container_in.delete() + if out_dir and container_out.exists(): + if ui.ask("Should I delete '{0}'?".format(container_out)): + container_out.delete()
+ + + +
+[docs] +def setup_directories(builddir): + """Create the in and out directories of the container.""" + build_dir = local.path(builddir) + in_dir = build_dir / "container-in" + out_dir = build_dir / "container-out" + + if not in_dir.exists(): + in_dir.mkdir() + if not out_dir.exists(): + out_dir.mkdir()
+ + + +
+[docs] +def setup_container(builddir, _container): + """Prepare the container and returns the path where it can be found.""" + build_dir = local.path(builddir) + in_dir = build_dir / "container-in" + container_path = local.path(_container) + with local.cwd(builddir): + container_bin = container_path.basename + container_in = in_dir / container_bin + download.Copy(_container, container_in) + uchrt = uchroot.no_args() + + with local.cwd("container-in"): + uchrt = uchrt["-E", "-A", "-u", "0", "-g", "0", "-C", "-r", "/", + "-w", + os.path.abspath("."), "--"] + + # Check, if we need erlent support for this archive. + has_erlent = bash["-c", + "tar --list -f './{0}' | grep --silent '.erlent'". + format(container_in)] + has_erlent = (has_erlent & TF) + + # Unpack input container to: container-in + if not has_erlent: + cmd = local["/bin/tar"]["xf"] + cmd = uchrt[cmd[container_bin]] + else: + cmd = tar["xf"] + cmd = cmd[container_in] + + with local.cwd("container-in"): + cmd("--exclude=dev/*") + rm(container_in) + return in_dir
+ + + +
+[docs] +def run_in_container(command, container_dir): + """ + Run a given command inside a container. + + Mounts a directory as a container at the given mountpoint and tries to run + the given command inside the new container. + """ + container_p = local.path(container_dir) + with local.cwd(container_p): + uchrt = uchroot.with_mounts() + uchrt = uchrt["-E", "-A", "-u", "0", "-g", "0", "-C", "-w", "/", "-r", + container_p] + uchrt = uchrt["--"] + + cmd_path = container_p / command[0].lstrip('/') + if not cmd_path.exists(): + LOG.error( + "The command does not exist inside the container! %s", cmd_path + ) + raise ValueError('The command does not exist inside the container!') + + cmd = uchrt[command] + return cmd & FG
+ + + +
+[docs] +def pack_container(in_container, out_file): + """ + Pack a container image into a .tar.bz2 archive. + + Args: + in_container (str): Path string to the container image. + out_file (str): Output file name. + """ + container_filename = local.path(out_file).basename + out_container = local.cwd / "container-out" / container_filename + out_dir = out_container.dirname + + # Pack the results to: container-out + with local.cwd(in_container): + tar("cjf", out_container, ".") + c_hash = download.update_hash(out_container) + if out_dir.exists(): + mkdir("-p", out_dir) + mv(out_container, out_file) + mv(out_container + ".hash", out_file + ".hash") + + new_container = {"path": out_file, "hash": str(c_hash)} + CFG["container"]["known"] += new_container
+ + + +
+[docs] +def setup_bash_in_container(builddir, _container, outfile, shell): + """ + Setup a bash environment inside a container. + + Creates a new chroot, which the user can use as a bash to run the wanted + projects inside the mounted container, that also gets returned afterwards. + """ + with local.cwd(builddir): + # Switch to bash inside uchroot + print( + "Entering bash inside User-Chroot. Prepare your image and " + "type 'exit' when you are done. If bash exits with a non-zero" + "exit code, no new container will be stored." + ) + store_new_container = True + try: + run_in_container(shell, _container) + except ProcessExecutionError: + store_new_container = False + + if store_new_container: + print("Packing new container image.") + pack_container(_container, outfile) + config_path = str(CFG["config_file"]) + CFG.store(config_path) + print("Storing config in {0}".format(os.path.abspath(config_path)))
+ + + +
+[docs] +def find_hash(container_db, key): + """Find the first container in the database with the given key.""" + for keyvalue in container_db: + if keyvalue["hash"].startswith(key): + return keyvalue["path"] + return None
+ + + +
+[docs] +def set_input_container(_container, cfg): + """Save the input for the container in the configurations.""" + if not _container: + return False + if _container.exists(): + cfg["container"]["input"] = str(_container) + return True + return False
+ + + +
+[docs] +class MockObj: + """Context object to be used in strategies. + + This object's attributes are initialized on construction. + """ + + def __init__(self, **kwargs): + self.__dict__.update(kwargs)
+ + + +
+[docs] +class ContainerStrategy: + """Interfaces for the different containers chosen by the experiment.""" + +
+[docs] + @abstractmethod + def run(self, context): + """Execute a container strategy. + + Args: + context: A context object with attributes used for the strategy. + """
+
+ + + +
+[docs] +class BashStrategy(ContainerStrategy): + """The user interface for setting up a bash inside the container.""" + +
+[docs] + def run(self, context): + print( + "Entering a shell in the container.\nUse the exit " + "command to leave the container." + ) + setup_bash_in_container( + context.builddir, context.in_container, context.out_container, + context.shell + )
+
+ + + +
+[docs] +class SetupPolyJITGentooStrategy(ContainerStrategy): + """Interface of using gentoo as a container for an experiment.""" + +
+[docs] + def run(self, context): + """Setup a gentoo container suitable for PolyJIT.""" + # Don't do something when running non-interactive. + if not sys.stdout.isatty(): + return + + with local.cwd(context.in_container): + from benchbuild.projects.gentoo import gentoo + gentoo.setup_networking() + gentoo.configure_portage() + + sed_in_chroot = uchroot.uchroot()["/bin/sed"] + sed_in_chroot = run.watch(sed_in_chroot) + emerge_in_chroot = uchroot.uchroot()["/usr/bin/emerge"] + emerge_in_chroot = run.watch(emerge_in_chroot) + has_pkg = uchroot.uchroot()["/usr/bin/qlist", "-I"] + + sed_in_chroot("-i", '/CC=/d', "/etc/portage/make.conf") + sed_in_chroot("-i", '/CXX=/d', "/etc/portage/make.conf") + + want_sync = bool(CFG["container"]["strategy"]["polyjit"]["sync"]) + want_upgrade = bool( + CFG["container"]["strategy"]["polyjit"]["upgrade"] + ) + + packages = \ + CFG["container"]["strategy"]["polyjit"]["packages"].value + with local.env(MAKEOPTS="-j{0}".format(get_number_of_jobs(CFG))): + if want_sync: + LOG.debug("Synchronizing portage.") + emerge_in_chroot("--sync") + if want_upgrade: + LOG.debug("Upgrading world.") + emerge_in_chroot( + "--autounmask-only=y", "-uUDN", "--with-bdeps=y", + "@world" + ) + for pkg in packages: + if has_pkg[pkg["name"]] & TF: + continue + env = pkg["env"] + with local.env(**env): + emerge_in_chroot(pkg["name"]) + + gentoo.setup_benchbuild() + + print("Packing new container image.") + with local.cwd(context.builddir): + pack_container(context.in_container, context.out_container)
+
+ + + +
+[docs] +class Container(cli.Application): + """Manage uchroot containers.""" + + VERSION = str(CFG["version"]) + +
+[docs] + @cli.switch(["-i", "--input-file"], str, help="Input container path") + def input_file(self, _container): + """Find the input path of a uchroot container.""" + p = local.path(_container) + if set_input_container(p, CFG): + return + + p = find_hash(CFG["container"]["known"].value, container) + if set_input_container(p, CFG): + return + + raise ValueError("The path '{0}' does not exist.".format(p))
+ + +
+[docs] + @cli.switch(["-o", "--output-file"], str, help="Output container path") + def output_file(self, _container): + """Find and writes the output path of a chroot container.""" + p = local.path(_container) + if p.exists(): + if not ui.ask("Path '{0}' already exists." " Overwrite?".format(p)): + sys.exit(0) + CFG["container"]["output"] = str(p)
+ + +
+[docs] + @cli.switch(["-s", "--shell"], + str, + help="The shell command we invoke inside the container.") + def shell(self, custom_shell): + """The command to run inside the container.""" + CFG["container"]["shell"] = custom_shell
+ + +
+[docs] + @cli.switch(["-t", "-tmp-dir"], + cli.ExistingDirectory, + help="Temporary directory") + def builddir(self, tmpdir): + """Set the current builddir of the container.""" + CFG["build_dir"] = tmpdir
+ + +
+[docs] + @cli.switch( + ["m", "--mount"], + cli.ExistingDirectory, + list=True, + help="Mount the given directory under / inside the uchroot container" + ) + def mounts(self, user_mount): + """Save the current mount of the container into the settings.""" + CFG["container"]["mounts"] = user_mount
+ + + verbosity = cli.CountOf('-v', help="Enable verbose output") + +
+[docs] + def main(self, *args): + log.configure() + builddir = local.path(str(CFG["build_dir"])) + if not builddir.exists(): + response = ui.ask( + "The build directory {dirname} does not exist yet. " + "Should I create it?".format(dirname=builddir) + ) + + if response: + mkdir("-p", builddir) + print("Created directory {0}.".format(builddir)) + + setup_directories(builddir)
+
+ + + +
+[docs] +@Container.subcommand("run") +class ContainerRun(cli.Application): + """Execute commannds inside a prebuilt container.""" + +
+[docs] + def main(self, *args): + builddir = str(CFG["build_dir"]) + in_container = str(CFG["container"]["input"]) + + if (in_container is None) or not os.path.exists(in_container): + in_is_file = False + in_container = container.Gentoo().local + else: + in_is_file = os.path.isfile(in_container) + if in_is_file: + clean_directories(builddir) + setup_directories(builddir) + in_container = setup_container(builddir, in_container) + + run_in_container(args, in_container) + clean_directories(builddir, in_is_file, False)
+
+ + + +
+[docs] +@Container.subcommand("create") +class ContainerCreate(cli.Application): + """ + Create a new container with a predefined strategy. + + We offer a variety of creation policies for a new container. By default a + basic 'spawn a bash' policy is used. This just leaves you inside a bash + that is started in the extracted container. After customization you can + exit the bash and pack up the result. + """ + + _strategy = BashStrategy() + +
+[docs] + @cli.switch(["-S", "--strategy"], + cli.Set("bash", "polyjit", case_sensitive=False), + help="Defines the strategy used to create a new container.", + mandatory=False) + def strategy(self, strategy): + """Select strategy based on key. + + Args: + strategy (str): The strategy to select. + + Returns: + A strategy object. + """ + self._strategy = { + "bash": BashStrategy(), + "polyjit": SetupPolyJITGentooStrategy() + }[strategy]
+ + +
+[docs] + def main(self, *args): + builddir = str(CFG["build_dir"]) + in_container = str(CFG["container"]["input"]) + out_container = str(CFG["container"]["output"]) + mounts = CFG["container"]["mounts"].value + shell = str(CFG["container"]["shell"]) + + if (in_container is None) or not os.path.exists(in_container): + in_container = container.Gentoo().local + + in_is_file = os.path.isfile(in_container) + if in_is_file: + in_container = setup_container(builddir, in_container) + + self._strategy.run( + MockObj( + builddir=builddir, + in_container=in_container, + out_container=out_container, + mounts=mounts, + shell=shell + ) + ) + clean_directories(builddir, in_is_file, True)
+
+ + + +
+[docs] +@Container.subcommand("bootstrap") +class ContainerBootstrap(cli.Application): + """Check for the needed files.""" + +
+[docs] + def install_cmake_and_exit(self): + """Tell the user to install cmake and aborts the current process.""" + print( + "You need to install cmake via your package manager manually." + " Exiting." + ) + sys.exit(-1)
+ + +
+[docs] + def main(self, *args): + print("Checking container binary dependencies...") + if not bootstrap.find_package("uchroot"): + if not bootstrap.find_package("cmake"): + self.install_cmake_and_exit() + bootstrap.install_uchroot(None) + print("...OK") + config_file = str(CFG["config_file"]) + if not (config_file and os.path.exists(config_file)): + config_file = ".benchbuild.json" + CFG.store(config_file) + print("Storing config in {0}".format(os.path.abspath(config_file))) + print( + "Future container commands from this directory will automatically" + " source the config file." + )
+
+ + + +
+[docs] +@Container.subcommand("list") +class ContainerList(cli.Application): + """Prints a list of the known containers.""" + +
+[docs] + def main(self, *args): + containers = CFG["container"]["known"].value + for c in containers: + print("[{1:.8s}] {0}".format(c["path"], str(c["hash"])))
+
+ + + +
+[docs] +def main(*args): + """Main entry point for the container tool.""" + return Container.run(*args)
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/environments/domain/commands/index.html b/branch/f-QoLImprovements/_modules/benchbuild/environments/domain/commands/index.html new file mode 100644 index 000000000..de8496bdf --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/environments/domain/commands/index.html @@ -0,0 +1,354 @@ + + + + + + benchbuild.environments.domain.commands + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.environments.domain.commands

+import re
+import typing as tp
+import unicodedata
+
+import attr
+
+from . import declarative, model
+
+
+
+[docs] +def fs_compliant_name(name: str) -> str: + """ + Convert a name to a valid filename. + """ + value = str(name) + value = unicodedata.normalize('NFKD', + value).encode('ascii', + 'ignore').decode('ascii') + value = re.sub(r'[^\w\s-]', '', value.lower()) + return re.sub(r'[-\s]+', '-', value).strip('-_')
+ + + +
+[docs] +def oci_compliant_name(name: str) -> str: + """ + Convert a name to an OCI compliant name. + + For now, we just make sure it is lower-case. This is depending on + the implementation of your container registry. podman/buildah require + lower-case repository names for now. + + Args: + name: the name to convert + + Examples: + >>> oci_compliant_name("foo") + 'foo' + >>> oci_compliant_name("FoO") + 'foo' + """ + # OCI Spec requires image names to be lowercase + return name.lower()
+ + + +# +# Dataclasses are perfectly valid without public methods +# + + +# pylint: disable=too-few-public-methods +
+[docs] +@attr.s(frozen=True, hash=False) +class CreateImage(model.Command): + name: str = attr.ib(converter=oci_compliant_name) + layers: declarative.ContainerImage = attr.ib() + + def __hash__(self) -> int: + return hash(self.name)
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class DeleteImage(model.Command): + name: str = attr.ib(converter=oci_compliant_name)
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class CreateBenchbuildBase(model.Command): + name: str = attr.ib(converter=oci_compliant_name, eq=True) + layers: declarative.ContainerImage = attr.ib() + + def __hash__(self) -> int: + return hash(self.name)
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class RunProjectContainer(model.Command): + image: str = attr.ib(converter=oci_compliant_name) + name: str = attr.ib(converter=oci_compliant_name) + + build_dir: str = attr.ib() + tmp_dir: str = attr.ib() + mount_build_dir: bool = attr.ib() + mount_tmp_dir: bool = attr.ib() + args: tp.Sequence[str] = attr.ib(default=attr.Factory(list))
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class ExportImage(model.Command): + image: str = attr.ib(converter=oci_compliant_name) + out_name: str = attr.ib()
+ + + +
+[docs] +@attr.s(frozen=True, hash=False) +class ImportImage(model.Command): + image: str = attr.ib(converter=oci_compliant_name) + in_path: str = attr.ib()
+ + + +# pylint: enable=too-few-public-methods +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/environments/domain/declarative/index.html b/branch/f-QoLImprovements/_modules/benchbuild/environments/domain/declarative/index.html new file mode 100644 index 000000000..10499d77f --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/environments/domain/declarative/index.html @@ -0,0 +1,495 @@ + + + + + + benchbuild.environments.domain.declarative + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.environments.domain.declarative

+"""
+BenchBuild supports containerized execution of all experiments. This gives you
+full control about the environment your [projects](/concepts/projects/) and
+[experiments](/concepts/experiments/) may run in.
+
+The following example uses the latest ``alpine:latest``:
+
+.. code-block:: python
+
+    ContainerImage().from_('alpine:latest')
+        .run('apk', 'update')
+        .run('apk', 'add', 'python3')
+
+"""
+
+import logging
+import typing as tp
+
+from benchbuild.environments.adapters.common import buildah_version
+from benchbuild.settings import CFG
+
+from . import model
+
+LOG = logging.getLogger(__name__)
+
+
+
+[docs] +class ContainerImage(list): + """ + Define a container image declaratively. + + Start a new image using the ``.from_`` method and provide a base image. + Each method creates a new layer in the container image. + """ + + def __str__(self) -> str: + return "\n".join([str(elt) for elt in self]) + + @property + def base(self) -> str: + layers = [l for l in self if isinstance(l, model.FromLayer)] + if layers: + return layers.pop(0).base + return '' + +
+[docs] + def env(self, **kwargs: str) -> 'ContainerImage': + """ + Create an environment layer in this image. + + Dockerfile syntax: ENV + + Args: + kwargs (str): a dictionary containing name/value pairings to be + set as environment variables. + """ + self.append(model.UpdateEnv(kwargs)) + return self
+ + +
+[docs] + def from_(self, base_image: str) -> 'ContainerImage': + """ + Specify a new base layer for this image. + + Dockerfile syntax: FROM <image> + + Args: + base_image (str): The base image for our new container image. + """ + self.append(model.FromLayer(base_image)) + return self
+ + +
+[docs] + def context(self, func: tp.Callable[[], None]) -> 'ContainerImage': + """ + Interact with the build context of the container. + + Sometimes you have to interact with the build context of a container + image. For example, you need to add artifacts to the build context + before you can add the to the container image. + BenchBuild uses this to add the sources to the container image + automatically. + + Args: + func (tp.Callable[[], None]): A callable that is executed in the + build-context directory. + """ + self.append(model.ContextLayer(func)) + return self
+ + +
+[docs] + def add(self, sources: tp.Iterable[str], tgt: str) -> 'ContainerImage': + """ + Add given files from the source to the container image. + + Dockerfile syntax: ADD <source> [<source>...] <target> + + Args: + sources (tp.Iterable[str]): Source path to add to the target + tgt (str): Absolute target path. + """ + self.append(model.AddLayer(tuple(sources), tgt)) + return self
+ + +
+[docs] + def copy_(self, sources: tp.Iterable[str], tgt: str) -> 'ContainerImage': + """ + Copy given files from the source to the container image. + + Dockerfile syntax: COPY <source> [<source>...] <target> + + Args: + sources (tp.Iterable[str]): Source path to add to the target + tgt (str): Absolute target path. + """ + self.append(model.CopyLayer(tuple(sources), tgt)) + return self
+ + +
+[docs] + def run(self, command: str, *args: str, **kwargs: str) -> 'ContainerImage': + """ + Run a command in the container image. + + Dockerfile syntax: RUN <command> + + Args: + command (str): The binary to execute in the container. + *args (str): Arguments that will be passed to the container. + **kwargs (str): Additional options that will be passed to the + backend run command. + """ + self.append(model.RunLayer(command, args, kwargs)) + return self
+ + +
+[docs] + def workingdir(self, directory: str) -> 'ContainerImage': + """ + Change the working directory in the container. + + Dockerfile syntax: WORKINGDIR <absolute-path> + + All layers that follow this layer will be run with their working + directory set to ``directory``. + + Args: + directory (str): The target directory to set our cwd to. + """ + self.append(model.WorkingDirectory(directory)) + return self
+ + +
+[docs] + def entrypoint(self, *args: str) -> 'ContainerImage': + """ + Set the entrypoint of the container. + + Dockerfile syntax: ENTRYPOINT <command> + + This sets the default binary to run to the given command. + + Args: + *args (str): A list of command components. + """ + self.append(model.EntryPoint(args)) + return self
+ + +
+[docs] + def command(self, *args: str) -> 'ContainerImage': + """ + Set the default command the container runs. + + Dockerfile syntax: CMD <command> + + Args: + *args (str): A list of command components. + """ + self.append(model.SetCommand(args)) + return self
+
+ + + +DEFAULT_BASES: tp.Dict[str, ContainerImage] = { + 'benchbuild:alpine': ContainerImage() \ + .from_("docker.io/alpine:3.17") \ + .run('apk', 'update') \ + .run('apk', 'add', 'python3', 'python3-dev', 'postgresql-dev', + 'linux-headers', 'musl-dev', 'git', 'gcc', 'g++', + 'sqlite-libs', 'libgit2-dev', 'libffi-dev', 'py3-pip') +} + + +
+[docs] +def add_benchbuild_layers(layers: ContainerImage) -> ContainerImage: + """ + Add benchbuild into the given container image. + + This assumes all necessary depenencies are available in the image already. + The installation is done, either using pip from a remote mirror, or using + the source checkout of benchbuild. + + A source installation requires your buildah/podman installation to be + able to complete a bind-mount as the user that runs benchbuild. + + Args: + layers: a container image we will add our install layers to. + + Returns: + the modified container image. + """ + crun = str(CFG['container']['runtime']) + src_dir = str(CFG['container']['source']) + tgt_dir = '/benchbuild' + + def from_source(image: ContainerImage) -> None: + LOG.debug('BenchBuild will be installed from source.') + + mount = f'type=bind,src={src_dir},target={tgt_dir}' + if buildah_version() >= (1, 24, 0): + mount += ',rw' + + # The image requires git, pip and a working python3.7 or better. + image.run('mkdir', f'{tgt_dir}', runtime=crun) + image.run('pip3', 'install', 'setuptools', runtime=crun) + image.run( + 'pip3', + 'install', + '--ignore-installed', + tgt_dir, + mount=mount, + runtime=crun + ) + + def from_pip(image: ContainerImage) -> None: + LOG.debug('installing benchbuild from pip release.') + image.run('pip3', 'install', 'benchbuild', runtime=crun) + + if bool(CFG['container']['from_source']): + from_source(layers) + else: + from_pip(layers) + return layers
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/environments/domain/model/index.html b/branch/f-QoLImprovements/_modules/benchbuild/environments/domain/model/index.html new file mode 100644 index 000000000..372d6c6c4 --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/environments/domain/model/index.html @@ -0,0 +1,508 @@ + + + + + + benchbuild.environments.domain.model + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.environments.domain.model

+import abc
+import enum
+import typing as tp
+
+import attr
+
+
+# pylint: disable=too-few-public-methods
+
+[docs] +@attr.s(frozen=True) +class Message: + pass
+ + + +MessageT = tp.Type[Message] + + +
+[docs] +@attr.s(frozen=True) +class Event(Message): + pass
+ + + +
+[docs] +@attr.s(frozen=True) +class Command(Message): + pass
+ + + +
+[docs] +class LayerState(enum.Enum): + PRESENT = 1 + ABSENT = 2
+ + + +
+[docs] +@attr.s(frozen=True) +class Layer(abc.ABC): + """ + A layer represents a filesystem layer in a container image. + + Layers can be 'virtual' in the sense that they do not lead to changes + in the container image filesystem, e.g. setting up the build context. + + This more or less represents commands/statements available in buildah + or Dockerfiles. + + Examples: + buildah add -> AddLayer + buildah copy -> CopyLayer + buildah from -> FromLayer + """
+ + + +# pylint: enable=too-few-public-methods +
+[docs] +@attr.s(frozen=True) +class FromLayer(Layer): + base: str = attr.ib() + + def __str__(self) -> str: + return f'FROM {self.base}'
+ + + +
+[docs] +@attr.s(frozen=True) +class AddLayer(Layer): + sources: tp.Tuple[str, ...] = attr.ib() + destination: str = attr.ib() + + def __str__(self) -> str: + sources = ' '.join(self.sources) + return f'ADD {sources} self.destination'
+ + + +
+[docs] +@attr.s(frozen=True) +class CopyLayer(Layer): + sources: tp.Tuple[str, ...] = attr.ib() + destination: str = attr.ib() + + def __str__(self) -> str: + sources = ' '.join(self.sources) + return f'COPY {sources} {self.destination}'
+ + + +
+[docs] +def immutable_kwargs( + kwargs: tp.Dict[str, str] +) -> tp.Tuple[tp.Tuple[str, str], ...]: + """ + Convert str-typed kwargs into a hashable tuple. + """ + return tuple((k, v) for k, v in kwargs.items())
+ + + +
+[docs] +@attr.s(frozen=True) +class RunLayer(Layer): + command: str = attr.ib() + args: tp.Tuple[str, ...] = attr.ib() + kwargs: tp.Tuple[tp.Tuple[str, str], + ...] = attr.ib(converter=immutable_kwargs) + + def __str__(self) -> str: + args = ' '.join(self.args) + return f'RUN {self.command} {args}'
+ + + +
+[docs] +@attr.s(frozen=True) +class ContextLayer(Layer): + func: tp.Callable[[], None] = attr.ib() + + def __str__(self) -> str: + return 'CONTEXT custom build context modification'
+ + + +
+[docs] +@attr.s(frozen=True) +class UpdateEnv(Layer): + env: tp.Tuple[tp.Tuple[str, str], ...] = attr.ib(converter=immutable_kwargs) + + def __str__(self) -> str: + return f'ENV {len(self.env)} entries'
+ + + +
+[docs] +@attr.s(frozen=True) +class WorkingDirectory(Layer): + directory: str = attr.ib() + + def __str__(self) -> str: + return f'CWD {self.directory}'
+ + + +
+[docs] +@attr.s(frozen=True) +class EntryPoint(Layer): + command: tp.Tuple[str, ...] = attr.ib() + + def __str__(self) -> str: + command = ' '.join(self.command) + return f'ENTRYPOINT {command}'
+ + + +
+[docs] +@attr.s(frozen=True) +class SetCommand(Layer): + command: tp.Tuple[str, ...] = attr.ib() + + def __str__(self) -> str: + command = ' '.join(self.command) + return f'CMD {command}'
+ + + +
+[docs] +@attr.s(frozen=True) +class Mount: + source: str = attr.ib() + target: str = attr.ib() + + def __str__(self) -> str: + return f'{self.source}:{self.target}'
+ + + +
+[docs] +@attr.s(eq=False) +class Image: + name: str = attr.ib() + from_: FromLayer = attr.ib() + layers: tp.List[Layer] = attr.ib() + events: tp.List[Message] = attr.ib(attr.Factory(list)) + env: tp.Dict[str, str] = attr.ib(attr.Factory(dict)) + mounts: tp.List[Mount] = attr.ib(attr.Factory(list)) + layer_index: tp.Dict[Layer, LayerState] = attr.ib(attr.Factory(dict)) + +
+[docs] + def update_env(self, **kwargs: str) -> None: + self.env.update(kwargs)
+ + +
+[docs] + def append(self, *layers: Layer) -> None: + for layer in layers: + self.layers.append(layer) + self.layer_index[layer] = LayerState.ABSENT
+ + +
+[docs] + def present(self, layer: Layer) -> None: + if layer in self.layer_index: + self.layer_index[layer] = LayerState.PRESENT
+ + +
+[docs] + def is_present(self, layer: Layer) -> bool: + return layer in self.layer_index and self.layer_index[ + layer] == LayerState.PRESENT
+ + +
+[docs] + def is_complete(self) -> bool: + return all([ + state == LayerState.PRESENT for state in self.layer_index.values() + ])
+ + +
+[docs] + def prepend(self, layer: Layer) -> None: + old_layers = self.layers + self.layers = [layer] + self.layers.extend(old_layers) + self.layer_index[layer] = LayerState.ABSENT
+
+ + + +MaybeImage = tp.Optional[Image] + + +
+[docs] +@attr.s(eq=False) +class Container: + container_id: str = attr.ib() + image: Image = attr.ib() + context: str = attr.ib() + name: str = attr.ib() + + events: tp.List[Message] = attr.ib(attr.Factory(list))
+ + + +MaybeContainer = tp.Optional[Container] +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/source/base/index.html b/branch/f-QoLImprovements/_modules/benchbuild/source/base/index.html new file mode 100644 index 000000000..63248985b --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/source/base/index.html @@ -0,0 +1,982 @@ + + + + + + benchbuild.source.base + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.source.base

+"""
+Provide a base interface for downloadable sources.
+"""
+import abc
+import itertools
+import sys
+import typing as tp
+from typing import Protocol
+
+import attr
+import plumbum as pb
+
+from benchbuild.settings import CFG
+
+if tp.TYPE_CHECKING:
+    from benchbuild.project import Project
+
+
+
+[docs] +@attr.s(frozen=True, eq=True) +class RevisionStr: # pylint: disable=too-few-public-methods + value: str = attr.ib()
+ + + +
+[docs] +@attr.s(frozen=True, eq=True) +class Variant: + """ + Provide a 'string'-like wrapper around source version information. + + Use this, whenever you need a 'version' string somewhere in benchbuild. + In terms of output/logging or use as program arguments, this should not + carry more semantics than a simple version string. + + However, this wrapper is linked to its 'owner'. The owner serves as + the back-reference to the source code where it originated from. + + This can serve as a 'hook' to deal with version information the + same way as a program variant like a specific configuraiton. + """ + + owner: 'FetchableSource' = attr.ib(eq=False, repr=False) + version: str = attr.ib() + +
+[docs] + def name(self) -> str: + return self.owner.local
+ + +
+[docs] + def source(self) -> 'FetchableSource': + return self.owner
+ + + def __str__(self) -> str: + return str(self.version)
+ + + +NestedVariants = tp.Iterable[tp.Tuple[Variant, ...]] + + +
+[docs] +class Revision: + """ + A revision captures all variants that form a single project revision. + + A project may have an arbitrary number of input sources that are + required for it's defined workloads, e.g., test input files, optional + dependencies, or submodules. + + BenchBuild considers each source to have different version numbers, + encoded as "Variants". The complete set of "Variants" for a project + then forms a project revision. + """ + + project_cls: tp.Type["Project"] + variants: tp.Sequence[Variant] + + def __init__( + self, project_cls: tp.Type["Project"], _primary: Variant, + *variants: Variant + ) -> None: + self.project_cls = project_cls + self.variants = [_primary] + list(variants) + +
+[docs] + def extend(self, *variants: Variant) -> None: + self.variants = list(self.variants) + list(variants)
+ + + def __update_variant(self, variant: Variant) -> None: + + def __replace(elem: Variant): + if elem.name() == variant.name(): + return variant + return elem + + self.variants = list(map(__replace, self.variants)) + +
+[docs] + def update(self, revision: "Revision") -> None: + for variant in revision.variants: + self.__update_variant(variant)
+ + +
+[docs] + def variant_by_name(self, name: str) -> Variant: + """ + Return the variant for the given source name. + + Args: + name: The local name of the source. + + Returns: + then version of the found source. + """ + found_variants = [ + variant for variant in self.variants if variant.owner.key == name + ] + if len(found_variants) > 0: + return found_variants[0] + + raise KeyError(f"Source with name {name} not found.")
+ + +
+[docs] + def has_variant(self, name: str) -> bool: + """ + Check if a variant with the given source name exists. + + Args: + name: The local name of the source. + + Returns: + True, should a variant with the given name exists + """ + return any(variant.owner.key == name for variant in self.variants)
+ + +
+[docs] + def source_by_name(self, name: str) -> 'FetchableSource': + """ + Return the source object that matches the key. + + Args: + name: The local name of the source. + + Returns: + the found source object + + Raises: + KeyError, if we cannot find the source with this name. + """ + found_variants = [ + variant for variant in self.variants if variant.owner.key == name + ] + if len(found_variants) > 0: + return found_variants[0].owner + + raise KeyError(f"Source with name {name} not found.")
+ + + @property + def primary(self) -> Variant: + variants = self.sorted() + return variants[0] + +
+[docs] + def sorted(self) -> tp.Sequence[Variant]: + """ + Return an ordered list of Variants from this revision. + + The order is defined by the order in the SOURCE attribute of the + associated project class. + """ + sources = self.project_cls.SOURCE + sources = [src for src in sources if self.has_variant(src.key)] + + return [self.variant_by_name(src.key) for src in sources]
+ + + def __str__(self) -> str: + variants = self.sorted() + return to_str(*variants) + + def __repr__(self) -> str: + return str(self)
+ + + +
+[docs] +def to_str(*variants: Variant) -> str: + """ + Convert an arbitrary number of variants into their string representation. + + Returns: + string representation of all input variants joined by ','. + """ + return ",".join([str(i) for i in variants])
+ + + +
+[docs] +class Fetchable(Protocol): + + @property + def key(self) -> str: + """ + Return the source's key property. + + This provides you with a key component that identifes a single source. + It should (no guarantee) be unique among all sources for this project. + + While this make no further assumption, but a good candidate is a + file-system name/path. + """ + + @property + def local(self) -> str: + """ + The source location (path-like) after fetching it from its remote. + """ + + @property + def remote(self) -> tp.Union[str, tp.Dict[str, str]]: + """ + The source location in the remote location. + """ + +
+[docs] + def fetch(self) -> pb.LocalPath: + """ + Fetch the necessary source files into benchbuild's cache. + """
+
+ + + +
+[docs] +class Expandable(Protocol): + + @property + def is_expandable(self) -> bool: + """ + Returns true, if this source should take part in version expansion. + + Some sources may only be treated as virtual and would not take part + in the version expansion of an associated project. + """ + +
+[docs] + def versions(self) -> tp.Sequence[Variant]: + """ + List all available versions of this source. + + Returns: + List[str]: The list of all available versions. + """
+
+ + + +
+[docs] +class ContextAwareSource(Protocol): + +
+[docs] + def is_context_free(self) -> bool: + """ + Return, if this source needs context to evaluate it's own + list of available versions. + """
+ + +
+[docs] + def versions_with_context(self, ctx: Revision) -> tp.Sequence[Variant]: + """ + Augment the given revision with new variants associated with this source. + + Args: + ctx: the project revision, containing information about every + context-free variant. + + Returns: + a sequence of project revisions. + """
+
+ + + +
+[docs] +class ContextFreeMixin: + """ + Make a context-free source context-aware. + + This will setup default implementations that avoids interaction with any context. + """ + +
+[docs] + def is_context_free(self) -> bool: + return True
+ + +
+[docs] + def versions_with_context(self, ctx: Revision) -> tp.Sequence[Variant]: + raise AttributeError("Invalid use of versions with context")
+
+ + + +
+[docs] +class Versioned(Protocol): + + @property + def default(self) -> Variant: + """ + The default version for this source. + """ + +
+[docs] + def version(self, target_dir: str, version: str) -> pb.LocalPath: + """ + Fetch the requested version and place it in the target_dir + + Args: + target_dir (str): + The filesystem path where the version should be placed in. + version (str): + The version that should be fetched from the local cache. + + Returns: + str: [description] + """
+ + +
+[docs] + def versions(self) -> tp.Sequence[Variant]: + """ + List all available versions of this source. + + Returns: + List[str]: The list of all available versions. + """
+
+ + + +
+[docs] +class FetchableSource(ContextFreeMixin): + """ + Base class for fetchable sources. + + Subclasses have to provide the following protocols: + - Expandable + - Fetchable + - Versioned + """ + + _local: str + _remote: tp.Union[str, tp.Dict[str, str]] + + def __init__(self, local: str, remote: tp.Union[str, tp.Dict[str, str]]): + super().__init__() + + self._local = local + self._remote = remote + + @property + def local(self) -> str: + return self._local + + @property + def remote(self) -> tp.Union[str, tp.Dict[str, str]]: + return self._remote + + @property + def key(self) -> str: + return self.local + + @property + @abc.abstractmethod + def default(self) -> Variant: + """ + The default version for this source. + """ + raise NotImplementedError() + +
+[docs] + @abc.abstractmethod + def version(self, target_dir: str, version: str) -> pb.LocalPath: + """ + Fetch the requested version and place it in the target_dir + + Args: + target_dir (str): + The filesystem path where the version should be placed in. + version (str): + The version that should be fetched from the local cache. + + Returns: + str: [description] + """ + raise NotImplementedError()
+ + +
+[docs] + @abc.abstractmethod + def versions(self) -> tp.Sequence[Variant]: + """ + List all available versions of this source. + + Returns: + List[str]: The list of all available versions. + """ + raise NotImplementedError()
+ + +
+[docs] + def explore(self) -> tp.Sequence[Variant]: + """ + Explore revisions of this source. + + This provides access to all revisions this source can offer. + BenchBuild own filters will not block any revision here. + + Custom sources or source filters can opt in to block revisions + anyways. + + Returns: + List[str]: The list of versions to explore. + """ + if self.is_context_free(): + return self.versions() + return []
+ + + @property + def is_expandable(self) -> bool: + return True + +
+[docs] + @abc.abstractmethod + def fetch(self) -> pb.LocalPath: + """ + Fetch the necessary source files into benchbuild's cache. + """ + raise NotImplementedError()
+
+ + + +Sources = tp.List['FetchableSource'] + + +
+[docs] +class NoSource(FetchableSource): + + @property + def default(self) -> Variant: + return Variant(owner=self, version='None') + +
+[docs] + def version(self, target_dir: str, version: str) -> pb.LocalPath: + return 'None'
+ + +
+[docs] + def versions(self) -> tp.List[Variant]: + return [Variant(owner=self, version='None')]
+ + +
+[docs] + def fetch(self) -> pb.LocalPath: + return 'None'
+
+ + + +
+[docs] +def nosource() -> NoSource: + return NoSource('NoSource', 'NoSource')
+ + + +
+[docs] +def target_prefix() -> str: + """ + Return the prefix directory for all downloads. + + Returns: + str: the prefix where we download everything to. + """ + return str(CFG['tmp_dir'])
+ + + +SourceT = tp.TypeVar('SourceT') + + +
+[docs] +def primary(*sources: SourceT) -> SourceT: + """ + Return the implicit 'main' source of a project. + + We define the main source as the first source listed in a project. + + If you define a new project and rely on the existence of a 'main' + source code repository, make sure to define it as the first one. + """ + (head, *_) = sources + return head
+ + + +
+[docs] +def secondaries(*sources: SourceT) -> tp.Sequence[SourceT]: + """ + Return the complement to the primary source of a project. + + Returns: + A list of all sources not considered primary. + """ + (_, *tail) = sources + return list(tail)
+ + + +
+[docs] +def product(*sources: Expandable) -> NestedVariants: + """ + Return the cross product of the given sources. + + Returns: + An iterable containing the cross product of all source variants. + """ + + siblings = [source.versions() for source in sources if source.is_expandable] + return itertools.product(*siblings)
+ + + +
+[docs] +class BaseSource(Expandable, Versioned, ContextAwareSource, Protocol): + """ + Composition of source protocols. + """
+ + + +
+[docs] +class EnumeratorFn(Protocol): + + def __call__(self, *source: Expandable) -> NestedVariants: + """ + Return an enumeration of all variants for each source. + + Returns: + a list of version tuples, containing each possible variant. + """
+ + + +def _default_enumerator(*sources: Expandable) -> NestedVariants: + return product(*sources) + + +
+[docs] +class ContextEnumeratorFn(Protocol): + + def __call__( + self, project_cls: tp.Type["Project"], context: Revision, + *sources: ContextAwareSource + ) -> tp.Sequence[Revision]: + """ + Enumerate all revisions that are valid under the given context. + """
+ + + +def _default_caw_enumerator( + project_cls: tp.Type["Project"], context: Revision, + *sources: ContextAwareSource +) -> tp.Sequence[Revision]: + """ + Transform given variant into a list of variants to check. + + This only considers the given context of all context-free sources + per context-sensitive source. + + Args: + context: + *sources: + """ + + variants = [source.versions_with_context(context) for source in sources] + variants = [var for var in variants if var] + + ret = [ + Revision(project_cls, *(list(context.variants) + list(caw_variants))) + for caw_variants in itertools.product(*variants) + ] + return ret + + +
+[docs] +def enumerate_revisions( + project_cls: tp.Type["Project"], + context_free_enumerator: EnumeratorFn = _default_enumerator, + context_aware_enumerator: ContextEnumeratorFn = _default_caw_enumerator +) -> tp.Sequence[Revision]: + """ + Enumerates the given sources. + + The enumeration requires two phases. + 1. A phase for all sources that do not require a context to evaluate. + 2. A phase for all sources that require a static context. + """ + sources = project_cls.SOURCE + + context_free_sources = [ + source for source in sources if source.is_context_free() + ] + context_aware_sources = [ + source for source in sources if not source.is_context_free() + ] + + revisions = context_free_enumerator(*context_free_sources) + project_revisions = [ + Revision(project_cls, *variants) for variants in revisions + ] + + if len(context_aware_sources) > 0: + revs = list( + itertools.chain( + *( + context_aware_enumerator( + project_cls, rev, *context_aware_sources + ) for rev in project_revisions + ) + ) + ) + return revs + + return project_revisions
+ + + +SourceContext = tp.Dict[str, Fetchable] + + +
+[docs] +def sources_as_dict(*sources: Fetchable) -> SourceContext: + """ + Convert fetchables to a dictionary. + + The dictionary will be indexed by the Fetchable's local attribute. + + Args: + *sources: Fetchables stored in the dictionary. + """ + return {src.local: src for src in sources}
+ + + +
+[docs] +def revision_from_str( + revs: tp.Sequence[RevisionStr], project_cls: tp.Type["Project"] +) -> Revision: + """ + Create a Revision from a sequence of revision strings. + + A valid Revision can only be created, if the number of valid revision + strings is equivalent to the number of sources. + A valid revision string is one that has been found in the a source's + version. + It is required that each revision string is found in a different source + version. + + We assume that the first source is the primary source of the revision. + + Args: + revs: sequence of revision strings, e.g. a commit-hash. + *sources: sources of a project. + + Returns: + A variant context. + """ + found: tp.List[Variant] = [] + sources = project_cls.SOURCE + + for source in sources: + if source.is_expandable: + found.extend([ + variant for variant in source.explore() for rev in revs + if variant.version == rev.value + ]) + + if len(found) == 0: + raise ValueError(f'Revisions {revs} not found in any available source.') + + return Revision(project_cls, primary(*found), *secondaries(*found))
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/source/git/index.html b/branch/f-QoLImprovements/_modules/benchbuild/source/git/index.html new file mode 100644 index 000000000..f0406764b --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/source/git/index.html @@ -0,0 +1,434 @@ + + + + + + benchbuild.source.git + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.source.git

+"""
+Declare a git source.
+"""
+import logging
+import os
+import typing as tp
+from pathlib import Path
+
+import plumbum as pb
+from plumbum.commands.base import BoundCommand
+
+from benchbuild.utils.cmd import git, ln, mkdir
+
+from . import base
+
+LOG = logging.getLogger(__name__)
+
+VarRemotes = tp.Union[str, tp.Dict[str, str]]
+Remotes = tp.Dict[str, str]
+
+_fetched_cache: tp.Set['Git'] = set()
+
+
+
+[docs] +class Git(base.FetchableSource): + """ + Fetch the downloadable source via git. + """ + + def __init__( + self, + remote: str, + local: str, + clone: bool = True, + limit: tp.Optional[int] = 10, + refspec: str = 'HEAD', + shallow: bool = True, + version_filter: tp.Callable[[str], bool] = lambda version: True + ): + super().__init__(local, remote) + + self.clone = clone + self.limit = limit + self.refspec = refspec + self.shallow = shallow + self.version_filter = version_filter + + @property + def default(self) -> base.Variant: + """ + Return current HEAD as default version for this Git project. + """ + return self.versions()[0] + +
+[docs] + def fetch(self) -> pb.LocalPath: + """ + Clone the repository, if needed. + + This will create a git clone inside the global cache directory. + + Args: + version (Optional[str], optional): [description]. Defaults to None. + + Returns: + str: [description] + """ + prefix = base.target_prefix() + clone = maybe_shallow( + git['clone', '--recurse-submodules'], self.shallow + ) + fetch = git['fetch', '--update-shallow', '--all'] + flat_local = self.local.replace(os.sep, '-') + cache_path = pb.local.path(prefix) / flat_local + + if clone_needed(self.remote, cache_path): + clone(self.remote, cache_path) + else: + if self in _fetched_cache: + LOG.debug('Already fetched %s, skipping.', self.local) + else: + LOG.debug('Fetching %s.', self.local) + _fetched_cache.add(self) + with pb.local.cwd(cache_path): + fetch() + + return cache_path
+ + +
+[docs] + def version(self, target_dir: str, version: str = 'HEAD') -> pb.LocalPath: + """ + Create a new git worktree pointing to the requested version. + + Args: + target_dir (str): + The filesystem path where the new worktree should live. + version (str): + The desired version the new worktree needs to point to. + Defaults to 'HEAD'. + + Returns: + str: [description] + """ + src_loc = self.fetch() + active_loc = pb.local.path(target_dir) / self.local + tgt_subdir = f'{self.local}-{version}' + tgt_loc = pb.local.path(target_dir) / tgt_subdir + + clone = git['clone'] + pull = git['pull'] + rev_parse = git['rev-parse'] + checkout = git['checkout'] + + with pb.local.cwd(src_loc): + is_shallow = rev_parse('--is-shallow-repository').strip() + if is_shallow == 'true': + pull('--unshallow') + + if Path(tgt_loc).exists(): + LOG.info( + 'Found target location %s. Going to skip creation and ' + 'repository cloning.', str(tgt_loc) + ) + else: + mkdir('-p', tgt_loc) + with pb.local.cwd(tgt_loc): + clone( + '--dissociate', '--recurse-submodules', '--reference', + src_loc, self.remote, '.' + ) + checkout('--detach', version) + + ln('-nsf', tgt_subdir, active_loc) + return tgt_loc
+ + +
+[docs] + def versions(self) -> tp.List[base.Variant]: + cache_path = self.fetch() + git_rev_list = git['rev-list', '--abbrev-commit', '--abbrev=10'] + + rev_list: tp.List[str] = [] + with pb.local.cwd(cache_path): + rev_list = list(git_rev_list(self.refspec).strip().split('\n')) + + rev_list = list(filter(self.version_filter, rev_list)) + rev_list = rev_list[:self.limit] if self.limit else rev_list + revs = [base.Variant(version=rev, owner=self) for rev in rev_list] + return revs
+
+ + + +
+[docs] +class GitSubmodule(Git): + + @property + def is_expandable(self) -> bool: + """Submodules will not participate in version expansion.""" + return False
+ + + +
+[docs] +def maybe_shallow(cmd: BoundCommand, enable: bool) -> BoundCommand: + """ + Conditionally add the shallow clone to the given git command. + + Args: + cmd (Any): + A git clone command (shallow doesn't make sense anywhere else. + shallow (bool): + Should we add the shallow options? + + Returns: + Any: A new git clone command, with shallow clone enabled, if selected. + """ + if enable: + return cmd['--depth', '1'] + return cmd
+ + + +
+[docs] +def clone_needed(repository: VarRemotes, repo_loc: str) -> bool: + from benchbuild.utils.download import __clone_needed__ + + if not isinstance(repository, str): + raise TypeError('\'remote\' needs to be a git repo string') + + return __clone_needed__(repository, repo_loc)
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/source/http/index.html b/branch/f-QoLImprovements/_modules/benchbuild/source/http/index.html new file mode 100644 index 000000000..8f91ee80e --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/source/http/index.html @@ -0,0 +1,459 @@ + + + + + + benchbuild.source.http + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.source.http

+"""
+Declare a http source.
+"""
+import typing as tp
+
+import plumbum as pb
+
+from benchbuild.source import base
+from benchbuild.utils.cmd import cp, ln, wget, tar, mkdir, mv
+
+VarRemotes = tp.Union[str, tp.Dict[str, str]]
+Remotes = tp.Dict[str, str]
+
+
+
+[docs] +class HTTP(base.FetchableSource): + """ + Fetch the downloadable source via http. + """ + + def __init__( + self, + local: str, + remote: tp.Union[str, tp.Dict[str, str]], + check_certificate: bool = True + ): + super().__init__(local, remote) + self._check_certificate = check_certificate + + @property + def default(self) -> base.Variant: + return self.versions()[0] + +
+[docs] + def fetch(self) -> pb.LocalPath: + """ + Fetch via http using default version string. + """ + return self.fetch_version(self.default.version)
+ + +
+[docs] + def fetch_version(self, version: str) -> pb.LocalPath: + """ + Fetch via http using given version string. + + Args: + version: the version string to pull via http. + + Returns: + local path to fetched version. + """ + prefix = base.target_prefix() + remotes = normalize_remotes(self.remote) + + url = remotes[version] + target_name = versioned_target_name(self.local, version) + cache_path = pb.local.path(prefix) / target_name + download_single_version(url, cache_path, self._check_certificate) + + return cache_path
+ + +
+[docs] + def version(self, target_dir: str, version: str) -> pb.LocalPath: + target_name = versioned_target_name(self.local, version) + cache_path = self.fetch_version(version) + + target_path = pb.local.path(target_dir) / target_name + active_loc = pb.local.path(target_dir) / self.local + + cp('-ar', cache_path, target_path) + ln('-sf', target_name, active_loc) + + return target_path
+ + +
+[docs] + def versions(self) -> tp.List[base.Variant]: + remotes = normalize_remotes(self.remote) + return [base.Variant(version=rev, owner=self) for rev in remotes]
+
+ + + +
+[docs] +class HTTPUntar(HTTP): + """ + Fetch and download source via http and auto-unpack using GNU tar + """ + +
+[docs] + def version(self, target_dir: str, version: str) -> pb.LocalPath: + """ + Setup the given version of this HTTPUntar source. + + This will fetch the given version from the remote source and unpack the + archive into the build directory using tar. + + The location matches the behavior of other sources. However, you need + to consider that benchbuild will return a directory instead of a file path. + + When using workloads, you can refer to a directory with the SourceRootRenderer using + ``benchbuild.command.source_root``. + + Example: + You specify a remote version 1.0 of an archive compression.tar.gz and + a local name of "compression.tar.gz". + The build directory will look as follows: + + <builddir>/1.0-compression.dir/ + <builddir>/1.0-compression.tar.gz + <builddir>/compression.tar.gz -> ./1.0-compression.tar.dir + + The content of the archive is found in the directory compression.tar.gz. + Your workloads need to make sure to reference this directory (e.g. using tokens), + e.g., ``source_root("compression.tar.gz")`` + """ + archive_path = super().version(target_dir, version) + + target_name = str(pb.local.path(archive_path).with_suffix(".dir")) + target_path = pb.local.path(target_dir) / target_name + active_loc = pb.local.path(target_dir) / self.local + + mkdir(target_path) + tar("-x", "--no-same-owner", "-C", target_path, "-f", archive_path) + + ln('-sf', target_path, active_loc) + + return target_path
+
+ + + +
+[docs] +class HTTPMultiple(HTTP): + """ + Fetch and download multiple files via HTTP. + """ + + def __init__( + self, + local: str, + remote: tp.Union[str, tp.Dict[str, str]], + files: tp.List[str], + check_certificate: bool = True + ): + super().__init__(local, remote, check_certificate) + self._files = files + +
+[docs] + def fetch_version(self, version: str) -> pb.LocalPath: + prefix = base.target_prefix() + remotes = normalize_remotes(self.remote) + + url = remotes[version] + target_name = versioned_target_name(self.local, version) + + cache_path = pb.local.path(prefix) / target_name + mkdir('-p', cache_path) + + for file in self._files: + download_single_version( + f'{url}/{file}', cache_path / file, self._check_certificate + ) + + return cache_path
+
+ + + +
+[docs] +def normalize_remotes(remote: VarRemotes) -> Remotes: + if isinstance(remote, str): + raise TypeError('\'remote\' needs to be a mapping type') + + # FIXME: What the hell? + _remotes: Remotes = {} + _remotes.update(remote) + return _remotes
+ + + +
+[docs] +def versioned_target_name(target_name: str, version: str) -> str: + return "{}-{}".format(version, target_name)
+ + + +
+[docs] +def download_single_version( + url: str, target_path: str, check_certificate: bool +) -> str: + if not download_required(target_path): + return target_path + + if check_certificate: + wget(url, '-O', target_path) + else: + wget(url, '--no-check-certificate', '-O', target_path) + + from benchbuild.utils.download import update_hash + update_hash(target_path) + return target_path
+ + + +
+[docs] +def download_required(target_path: str) -> bool: + from benchbuild.utils.download import source_required + return source_required(target_path)
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/utils/actions/index.html b/branch/f-QoLImprovements/_modules/benchbuild/utils/actions/index.html new file mode 100644 index 000000000..40d7671a3 --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/utils/actions/index.html @@ -0,0 +1,1094 @@ + + + + + + benchbuild.utils.actions + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.utils.actions

+"""# Actions
+
+Actions are enhanced callables that are used by `Experiments` to define
+the order of operations a project is put through when the experiment
+executes.
+
+
+## Example
+
+TODO
+```python
+```
+"""
+from __future__ import annotations
+
+import abc
+import enum
+import functools as ft
+import itertools
+import logging
+import os
+import sys
+import textwrap
+import traceback
+import typing as tp
+from datetime import datetime
+
+from plumbum import ProcessExecutionError
+
+from benchbuild import command, signals, source
+from benchbuild.settings import CFG
+from benchbuild.utils import db, run
+from benchbuild.utils.cmd import mkdir, rm, rmdir
+
+LOG = logging.getLogger(__name__)
+
+ReturnType = tp.TypeVar("ReturnType")
+ReturnTypeA = tp.TypeVar("ReturnTypeA")
+ReturnTypeB = tp.TypeVar("ReturnTypeB")
+DecoratedFunction = tp.Callable[..., ReturnType]
+FunctionDecorator = tp.Callable[[DecoratedFunction[ReturnTypeA]],
+                                DecoratedFunction[ReturnTypeB]]
+
+if tp.TYPE_CHECKING:
+    import benchbuild.experiment.Experiment  # pylint: disable=unused-import
+    import benchbuild.project.Project  # pylint: disable=unused-import
+    import benchbuild.utils.schema.Experiment  # pylint: disable=unused-import
+
+
+
+[docs] +@enum.unique +class StepResult(enum.IntEnum): + """Result type for action results.""" + + UNSET = 0 + OK = 1 + CAN_CONTINUE = 2 + ERROR = 3
+ + + +StepResultList = tp.List[StepResult] + + +
+[docs] +def step_has_failed( + result: StepResult, + error_status: tp.Optional[tp.List[StepResult]] = None +) -> bool: + if not error_status: + error_status = [StepResult.ERROR, StepResult.CAN_CONTINUE] + + return result in error_status
+ + + +
+[docs] +def prepend_status(func: DecoratedFunction[str]) -> DecoratedFunction[str]: + """Prepends the output of `func` with the status.""" + + @tp.overload + def wrapper(self: "Step", indent: int) -> str: + ... + + @tp.overload + def wrapper(self: "Step") -> str: + ... + + @ft.wraps(func) + def wrapper(self: "Step", *args: tp.Any, **kwargs: tp.Any) -> str: + """Wrapper stub.""" + res = func(self, *args, **kwargs) + if self.status is not StepResult.UNSET: + res = f"[{self.status.name}]{res}" + return res + + return wrapper
+ + + +
+[docs] +def log_before_after(name: str, + desc: str) -> FunctionDecorator[StepResult, StepResult]: + """Log customized string before & after running func.""" + + def func_decorator( + func: DecoratedFunction[StepResult], + ) -> DecoratedFunction[StepResult]: + """Wrapper stub.""" + + @ft.wraps(func) + def wrapper(*args: tp.Any, **kwargs: tp.Any) -> StepResult: + """Wrapper stub.""" + LOG.info("\n%s - %s", name, desc) + res = func(*args, **kwargs) + msg = f"{name} - {res.name}" + if res != StepResult.ERROR: + LOG.info(msg) + else: + LOG.error(msg) + return res + + return wrapper + + return func_decorator
+ + + +
+[docs] +class Step: + """ + Base class of a step. + + Raises: + StopIteration: If we do not encapsulate more substeps. + """ + + NAME: tp.ClassVar[str] = "" + DESCRIPTION: tp.ClassVar[str] = "" + + status: StepResult + + def __init_subclass__(cls, **kwargs: tp.Any): + super().__init_subclass__(**kwargs) + + setattr( + cls, "__call__", + log_before_after(cls.NAME, cls.DESCRIPTION)(cls.__call__) + ) + setattr(cls, "__str__", prepend_status(cls.__str__)) + + def __init__(self, status: StepResult) -> None: + self.status = status + + def __len__(self) -> int: + return 1 + + def __str__(self, indent: int = 0) -> str: + return f"* Running action {self.NAME} - {self.DESCRIPTION}" + +
+[docs] + def onerror(self) -> None: + """ + Default implementation does nothing. + """
+ + + @abc.abstractmethod + def __call__(self) -> StepResult: + raise NotImplementedError
+ + + +
+[docs] +class ProjectStep(Step): + """Base class of a project step. + + Adds a project attribute to the Step base class and some defaults. + + Raises: + StopIteration: If we do not encapsulate more substeps. + """ + + NAME: tp.ClassVar[str] = "" + DESCRIPTION: tp.ClassVar[str] = "" + + project: "benchbuild.project.Project" + + def __init__(self, project: "benchbuild.project.Project") -> None: + super().__init__(StepResult.UNSET) + self.project = project + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent("* Execute configured action.", indent * " ") + +
+[docs] + def onerror(self) -> None: + Clean(self.project)()
+ + + @abc.abstractmethod + def __call__(self) -> StepResult: + raise NotImplementedError
+ + + +StepTy_co = tp.TypeVar("StepTy_co", bound=Step, covariant=True) + + +
+[docs] +class MultiStep(Step, tp.Generic[StepTy_co]): + """Group multiple actions into one step. + + Usually used to define behavior on error, e.g., execute everything + regardless of any errors, or fail everything upon first error. + """ + + NAME: tp.ClassVar[str] = "" + DESCRIPTION: tp.ClassVar[str] = "" + + actions: tp.MutableSequence[StepTy_co] + + def __init__( + self, + actions: tp.Optional[tp.MutableSequence[StepTy_co]] = None + ) -> None: + super().__init__(StepResult.UNSET) + + self.actions = list(actions) if actions else [] + + def __len__(self) -> int: + return sum([len(x) for x in self.actions]) + 1 + + def __iter__(self) -> tp.Iterator[StepTy_co]: + return self.actions.__iter__() + + @abc.abstractmethod + def __call__(self) -> StepResult: + raise NotImplementedError + + def __str__(self, indent: int = 0) -> str: + raise NotImplementedError + +
+[docs] + def onerror(self) -> None: + pass
+
+ + + +
+[docs] +class Clean(ProjectStep): + NAME = "CLEAN" + DESCRIPTION = "Cleans the build directory" + + def __init__( + self, + project: "benchbuild.project.Project", + check_empty: bool = False + ) -> None: + super().__init__(project) + self.check_empty = check_empty + +
+[docs] + @staticmethod + def clean_mountpoints(root: str) -> None: + """Unmount any remaining mountpoints under :root. + + Args: + root: All UnionFS-mountpoints under this directory will be + unmounted. + """ + import psutil # pylint: disable=import-outside-toplevel + + umount_paths = [] + real_root = os.path.realpath(root) + for part in psutil.disk_partitions(all=True): + if os.path.commonpath([part.mountpoint, real_root]) == real_root: + if not part.fstype == "fuse.unionfs": + LOG.error("NON-UnionFS mountpoint found under %s", root) + else: + umount_paths.append(part.mountpoint)
+ + + def __call__(self) -> StepResult: + if not CFG["clean"]: + LOG.warning("Clean disabled by config.") + return StepResult.OK + if not self.project: + LOG.warning("No object assigned to this action.") + return StepResult.ERROR + obj_builddir = os.path.abspath(self.project.builddir) + if os.path.exists(obj_builddir): + LOG.debug("Path %s exists", obj_builddir) + Clean.clean_mountpoints(obj_builddir) + if self.check_empty: + rmdir(obj_builddir, retcode=None) + else: + rm("-rf", obj_builddir) + else: + LOG.debug("Path %s did not exist anymore", obj_builddir) + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + project = self.project + return textwrap.indent( + f"* {project.name}: Clean the directory: {project.builddir}", + indent * " " + )
+ + + +
+[docs] +class MakeBuildDir(ProjectStep): + NAME = "MKDIR" + DESCRIPTION = "Create the build directory" + + def __call__(self) -> StepResult: + if not self.project: + return StepResult.ERROR + if not os.path.exists(self.project.builddir): + mkdir("-p", self.project.builddir) + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent( + f"* {self.project.name}: Create the build directory", indent * " " + )
+ + + +
+[docs] +class Compile(ProjectStep): + NAME = "COMPILE" + DESCRIPTION = "Compile the project" + + def __call__(self) -> StepResult: + try: + self.project.compile() + + except ProcessExecutionError: + self.status = StepResult.ERROR + raise + self.status = StepResult.OK + + return self.status + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent(f"* {self.project.name}: Compile", indent * " ")
+ + + +
+[docs] +class Run(ProjectStep): + NAME = "RUN" + DESCRIPTION = "Execute the run action" + + experiment: "benchbuild.experiment.Experiment" + + def __init__( + self, + project: "benchbuild.project.Project", + experiment: "benchbuild.experiment.Experiment", + ) -> None: + super().__init__(project) + + self.experiment = experiment + + def __call__(self) -> StepResult: + if CFG["db"]["enabled"]: + group, session = run.begin_run_group(self.project, self.experiment) + signals.handlers.register(run.fail_run_group, group, session) + try: + self.project.run_tests() + if CFG["db"]["enabled"]: + run.end_run_group(group, session) + self.status = StepResult.OK + except ProcessExecutionError: + if CFG["db"]["enabled"]: + run.fail_run_group(group, session) + self.status = StepResult.ERROR + raise + except KeyboardInterrupt: + if CFG["db"]["enabled"]: + run.fail_run_group(group, session) + self.status = StepResult.ERROR + raise + finally: + if CFG["db"]["enabled"]: + signals.handlers.deregister(run.fail_run_group) + + return self.status + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent( + f"* {self.project.name}: Execute run-time tests.", indent * " " + )
+ + + +
+[docs] +class Echo(Step): + NAME = "ECHO" + DESCRIPTION = "Print a message." + + message: str + + def __init__(self, message: str = "") -> None: + super().__init__(StepResult.UNSET) + self.message = message + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent(f"* echo: {self.message}", indent * " ") + + def __call__(self) -> StepResult: + LOG.info(self.message) + return StepResult.OK
+ + + +
+[docs] +def run_any_child(child: Step) -> StepResult: + """Execute child step. + + Args: + child: The child step. + """ + return child()
+ + + +
+[docs] +class Any(MultiStep): + NAME = "ANY" + DESCRIPTION = "Just run all actions, no questions asked." + + def __call__(self) -> StepResult: + length = len(self.actions) + cnt = 0 + results = [StepResult.OK] + for a in self.actions: + cnt = cnt + 1 + result = a() + results.append(result) + + if result == StepResult.ERROR: + LOG.warning("%d actions left in queue", length - cnt) + + self.status = StepResult.OK + if StepResult.ERROR in results: + self.status = StepResult.CAN_CONTINUE + return self.status + + def __str__(self, indent: int = 0) -> str: + sub_actns = "\n".join([a.__str__(indent + 1) for a in self.actions]) + return textwrap.indent("* Execute all of:\n" + sub_actns, indent * " ")
+ + + +
+[docs] +class Experiment(Any): + NAME = "EXPERIMENT" + DESCRIPTION = "Run a experiment, wrapped in a db transaction" + + experiment: "benchbuild.experiment.Experiment" + + def __init__( + self, + experiment: "benchbuild.experiment.Experiment", + actions: tp.Optional[tp.MutableSequence[Step]], + ) -> None: + _actions: tp.MutableSequence[Step] = [ + Echo(message=f"Start experiment: {experiment.name}") + ] + _actions.extend(actions if actions else []) + _actions.extend([ + Echo(message=f"Completed experiment: {experiment.name}") + ]) + + super().__init__(_actions) + self.experiment = experiment + +
+[docs] + def begin_transaction( + self, + ) -> tp.Tuple["benchbuild.utils.schema.Experiment", tp.Any]: + import sqlalchemy as sa # pylint: disable=import-outside-toplevel + experiment, session = db.persist_experiment(self.experiment) + if experiment.begin is None: + experiment.begin = datetime.now() + experiment.end = experiment.begin + else: + experiment.begin = min(experiment.begin, datetime.now()) + session.add(experiment) + try: + session.commit() + except sa.orm.exc.StaleDataError: + LOG.error("Transaction isolation level caused a StaleDataError") + + # React to external signals + signals.handlers.register( + Experiment.end_transaction, experiment, session + ) + + return experiment, session
+ + +
+[docs] + @staticmethod + def end_transaction( + experiment: "benchbuild.utils.schema.Experiment", session: tp.Any + ) -> None: + import sqlalchemy as sa # pylint: disable=import-outside-toplevel + try: + experiment.end = max(experiment.end, datetime.now()) + session.add(experiment) + session.commit() + except sa.exc.InvalidRequestError as inv_req: + LOG.error(inv_req)
+ + + def __run_children(self, num_processes: int) -> tp.List[StepResult]: + # pylint: disable=import-outside-toplevel + import pathos.multiprocessing as mp + + results = [] + actions = self.actions + + try: + with mp.Pool(num_processes) as pool: + results = pool.map(run_any_child, actions) + except KeyboardInterrupt: + LOG.info("Experiment aborting by user request") + results.append(StepResult.ERROR) + except Exception: + LOG.error("Experiment terminates " + "because we got an exception:") + e_type, e_value, e_traceb = sys.exc_info() + lines = traceback.format_exception(e_type, e_value, e_traceb) + LOG.error("".join(lines)) + results.append(StepResult.ERROR) + return results + + def __call__(self) -> StepResult: + results = [] + session = None + if CFG["db"]["enabled"]: + experiment, session = self.begin_transaction() + try: + results = self.__run_children(int(CFG["parallel_processes"])) + finally: + if CFG["db"]["enabled"]: + self.end_transaction(experiment, session) + signals.handlers.deregister(self.end_transaction) + self.status = max(results) if results else StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + sub_actns = "\n".join([a.__str__(indent + 1) for a in self.actions]) + return textwrap.indent( + f"\nExperiment: {self.experiment.name}\n{sub_actns}", indent * " " + )
+ + + +
+[docs] +class RequireAll(MultiStep): + NAME = "REQUIRE ALL" + DESCRIPTION = "All child steps need to succeed" + + def __call__(self) -> StepResult: + results: tp.List[StepResult] = [] + + total_steps = len(self.actions) + + def no_fail(*args: tp.Any, **kwargs: tp.Any): + return StepResult.ERROR not in results + + for i, action in itertools.takewhile(no_fail, enumerate(self.actions)): + result = StepResult.UNSET + try: + result = action() + except ProcessExecutionError as proc_ex: + LOG.error("\n==== ERROR ====") + LOG.error( + "Execution of a binary failed in step: %s", str(action) + ) + LOG.error(str(proc_ex)) + LOG.error("==== ERROR ====\n") + result = StepResult.ERROR + except KeyboardInterrupt: + LOG.info("User requested termination.") + action.onerror() + action.status = StepResult.ERROR + raise + except Exception: + LOG.error( + "Exception in step #%d/%d: %s", + i, + total_steps, + str(action), + exc_info=sys.exc_info(), + ) + result = StepResult.ERROR + + results.append(result) + action.status = result + is_failed = StepResult.ERROR in results + if is_failed: + LOG.error("Execution of: '%s' failed.", str(action)) + LOG.error("'%s' cannot continue.", str(self)) + action.onerror() + + self.status = max(results) if results else StepResult.UNSET + return self.status + + def __str__(self, indent: int = 0) -> str: + sub_actns = "\n".join([a.__str__(indent + 1) for a in self.actions]) + return textwrap.indent(f"* All required:\n{sub_actns}", indent * " ")
+ + + +WorkloadTy = tp.Callable[[], tp.Any] + + +
+[docs] +class RunWorkload(ProjectStep): + NAME = "RUN WORKLOAD" + DESCRIPTION = "Run a project's workload" + + _workload: tp.Optional[WorkloadTy] + + @property + def workload_ref(self) -> WorkloadTy: + # Workaround for MyPy... + assert self._workload is not None, "non-optional optional triggered" + return self._workload + + def __init__( + self, + project: "benchbuild.project.Project", + workload: tp.Optional[WorkloadTy] = None + ) -> None: + super().__init__(project) + + self._workload = workload + + def __call__(self) -> StepResult: + try: + self.workload_ref() + self.status = StepResult.OK + except ProcessExecutionError: + self.status = StepResult.ERROR + raise + except KeyboardInterrupt: + self.status = StepResult.ERROR + raise + return self.status + + def __str__(self, indent: int = 0) -> str: + return textwrap.indent(f"* Run: {str(self.workload_ref)}", indent * " ")
+ + + +
+[docs] +class RunWorkloads(MultiStep): + NAME = "RUN WORKLOADS" + DESCRIPTION = "Generic run all project workloads" + + project: "benchbuild.project.Project" + experiment: "benchbuild.experiment.Experiment" + + def __init__( + self, + project: "benchbuild.project.Project", + experiment: "benchbuild.experiment.Experiment", + run_only: tp.Optional[command.WorkloadSet] = None, + ) -> None: + super().__init__() + + self.project = project + self.experiment = experiment + + index = command.unwrap(project.workloads, project) + workloads = itertools.chain( + *command.filter_workload_index(run_only, index) + ) + + for workload in workloads: + self.actions.extend([ + RunWorkload(project, command.ProjectCommand(project, workload)) + ]) + + def __call__(self) -> StepResult: + if CFG["db"]["enabled"]: + group, session = run.begin_run_group(self.project, self.experiment) + signals.handlers.register(run.fail_run_group, group, session) + try: + self.status = max([workload() for workload in self.actions], + default=StepResult.OK) + if CFG["db"]["enabled"]: + run.end_run_group(group, session) + except ProcessExecutionError: + if CFG["db"]["enabled"]: + run.fail_run_group(group, session) + self.status = StepResult.ERROR + raise + except KeyboardInterrupt: + if CFG["db"]["enabled"]: + run.fail_run_group(group, session) + self.status = StepResult.ERROR + raise + finally: + if CFG["db"]["enabled"]: + signals.handlers.deregister(run.fail_run_group) + + return self.status + + def __str__(self, indent: int = 0) -> str: + sub_actns = "\n".join([a.__str__(indent + 1) for a in self.actions]) + return textwrap.indent( + f"* Require all of {self.project.name}'s workloads:\n{sub_actns}", + indent * " " + )
+ + + +
+[docs] +class CleanExtra(Step): + NAME = "CLEAN EXTRA" + DESCRIPTION = "Cleans the extra directories." + + def __init__(self) -> None: + super().__init__(StepResult.UNSET) + + def __call__(self) -> StepResult: + if not CFG["clean"]: + return StepResult.OK + + paths = CFG["cleanup_paths"].value + for p in paths: + if os.path.exists(p): + rm("-r", p) + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + paths = CFG["cleanup_paths"].value + lines = [] + for p in paths: + lines.append( + textwrap.indent(f"* Clean the directory: {p}", indent * " ") + ) + return "\n".join(lines)
+ + + +
+[docs] +class ProjectEnvironment(ProjectStep): + NAME = "ENV" + DESCRIPTION = "Prepare the project environment." + + def __call__(self) -> StepResult: + project = self.project + project.clear_paths() + + revision = project.revision + + for variant in revision.variants: + name = variant.name() + LOG.info("Fetching %s @ %s", str(name), variant.version) + src = variant.source() + src.version(project.builddir, str(variant)) + + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + project = self.project + revision = project.revision + version_str = str(revision) + + return textwrap.indent( + f"* Project environment for: {project.name} @ {version_str}", + indent * " " + )
+ + + +
+[docs] +class SetProjectVersion(ProjectStep): + NAME = "SET PROJECT VERSION" + DESCRIPTION = "Checkout a project version" + + revision: source.Revision + + def __init__( + self, + project: "benchbuild.project.Project", + *revision_strings: source.base.RevisionStr, + ) -> None: + super().__init__(project) + + self.revision = source.revision_from_str( + revision_strings, type(project) + ) + + def __call__(self) -> StepResult: + project = self.project + revision = project.active_revision + revision.update(self.revision) + + for variant in revision.variants: + name = variant.name() + LOG.info("Fetching %s @ %s", str(name), variant.version) + src = variant.source() + src.version(project.builddir, str(variant)) + + project.active_revision = revision + self.status = StepResult.OK + return self.status + + def __str__(self, indent: int = 0) -> str: + project = self.project + version_str = str(self.revision) + + return textwrap.indent( + f"* Add project version {version_str} for: {project.name}", + indent * " " + )
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/benchbuild/utils/settings/index.html b/branch/f-QoLImprovements/_modules/benchbuild/utils/settings/index.html new file mode 100644 index 000000000..ed30b1cd4 --- /dev/null +++ b/branch/f-QoLImprovements/_modules/benchbuild/utils/settings/index.html @@ -0,0 +1,993 @@ + + + + + + benchbuild.utils.settings + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Source code for benchbuild.utils.settings

+"""
+Configuration utilities.
+
+Settings are stored in a dictionary-like configuration object.
+All settings are modifiable by environment variables that encode
+the path in the dictionary tree.
+
+Inner nodes in the dictionary tree can be any dictionary.
+A leaf node in the dictionary tree is represented by an inner node that
+contains a value key.
+"""
+import copy
+import logging
+import os
+import re
+import sys
+import typing as tp
+import uuid
+import warnings
+from importlib.metadata import version, PackageNotFoundError
+
+import attr
+import schema
+import six
+import yaml
+from plumbum import LocalPath, local
+
+import benchbuild.utils.user_interface as ui
+
+LOG = logging.getLogger(__name__)
+
+
+
+[docs] +class Indexable: + + def __getitem__(self: 'Indexable', key: str) -> 'Indexable': + pass
+ + + +try: + __version__ = version("benchbuild") +except PackageNotFoundError: + __version__ = "unknown" + LOG.error("could not find version information.") + + +
+[docs] +def available_cpu_count() -> int: + """ + Get the number of available CPUs. + + Number of available virtual or physical CPUs on this system, i.e. + user/real as output by time(1) when called with an optimally scaling + userspace-only program. + + Returns: + Number of avaialable CPUs. + """ + + # cpuset + # cpuset may restrict the number of *available* processors + try: + match = re.search( + r'(?m)^Cpus_allowed:\s*(.*)$', + open('/proc/self/status').read() + ) + if match: + res = bin(int(match.group(1).replace(',', ''), 16)).count('1') + if res > 0: + return res + except IOError: + LOG.debug("Could not get the number of allowed CPUs") + + # http://code.google.com/p/psutil/ + try: + import psutil + return int(psutil.cpu_count()) # psutil.NUM_CPUS on old versions + except (ImportError, AttributeError): + LOG.debug("Could not get the number of allowed CPUs") + + # POSIX + try: + res = int(os.sysconf('SC_NPROCESSORS_ONLN')) + + if res > 0: + return res + except (AttributeError, ValueError): + LOG.debug("Could not get the number of allowed CPUs") + + # Linux + try: + res = open('/proc/cpuinfo').read().count('processor\t:') + + if res > 0: + return res + except IOError: + LOG.debug("Could not get the number of allowed CPUs") + + raise Exception('Can not determine number of CPUs on this system')
+ + + +
+[docs] +def current_available_threads() -> int: + """Returns the number of currently available threads for BB.""" + return len(os.sched_getaffinity(0))
+ + + +
+[docs] +def get_number_of_jobs(config: 'Configuration') -> int: + """Returns the number of jobs set in the config.""" + jobs_configured = int(config["jobs"]) + if jobs_configured == 0: + return current_available_threads() + return jobs_configured
+ + + +
+[docs] +class InvalidConfigKey(RuntimeWarning): + """Warn, if you access a non-existing key benchbuild's configuration."""
+ + + +
+[docs] +def escape_yaml(raw_str: str) -> str: + """ + Shell-Escape a yaml input string. + + Args: + raw_str: The unescaped string. + """ + escape_list = [char for char in raw_str if char in ['!', '{', '[']] + if len(escape_list) == 0: + return raw_str + + str_quotes = '"' + i_str_quotes = "'" + if str_quotes in raw_str and str_quotes not in raw_str[1:-1]: + return raw_str + + if str_quotes in raw_str[1:-1]: + raw_str = i_str_quotes + raw_str + i_str_quotes + else: + raw_str = str_quotes + raw_str + str_quotes + return raw_str
+ + + +
+[docs] +def is_yaml(cfg_file: str) -> bool: + """Is the given cfg_file a YAML file.""" + return os.path.splitext(cfg_file)[1] in [".yml", ".yaml"]
+ + + +
+[docs] +class ConfigLoader(yaml.CSafeLoader): # type: ignore + """Avoid polluting yaml's namespace with our modifications."""
+ + + +
+[docs] +class ConfigDumper(yaml.SafeDumper): + """Avoid polluting yaml's namespace with our modifications."""
+ + + +
+[docs] +def to_yaml(value: tp.Any) -> tp.Optional[str]: + """Convert a given value to a YAML string.""" + stream = yaml.io.StringIO() + dumper = ConfigDumper(stream, default_flow_style=True, width=sys.maxsize) + val = None + try: + dumper.open() + dumper.represent(value) + val = str(stream.getvalue()).strip() + dumper.close() + finally: + dumper.dispose() + + return val
+ + + +
+[docs] +def to_env_var(env_var: str, value: tp.Any) -> str: + """ + Create an environment variable from a name and a value. + + This generates a shell-compatible representation of an + environment variable that is assigned a YAML representation of + a value. + + Args: + env_var (str): Name of the environment variable. + value (Any): A value we convert from. + """ + val = to_yaml(value) + ret_val = "%s=%s" % (env_var, escape_yaml(str(val))) + return ret_val
+ + + +InnerNode = tp.Dict[str, tp.Any] + +# This schema allows a configuration to be initialized/set from a standard +# dictionary. If you want to nest a new configuration node deeper than 1 level, +# you have to use dummy nodes to help benchbuild validate your nodes as +# Configuration nodes instead of plain dictionary values. +# +# Example: +# CFG['container'] = { +# 'strategy': { +# 'dummy': { 'default': True, 'desc': 'Update portage tree' } +# } +# } +# This opens the 'strategy' node up for deeper nesting in a second step: +# +# CFG['container']['strategy']['polyjit'] = { +# 'sync': { 'default': True', 'desc': '...' } +# } +_INNER_NODE_VALUE = schema.Schema({ + schema.Or('default', 'value'): object, + schema.Optional('desc'): str +}) +_INNER_NODE_SCHEMA = schema.Schema({ + schema.And(str, len): { + schema.Or('default', 'value'): object, + schema.Optional('desc'): str, + schema.Optional(str): dict + } +}) + + +
+[docs] +class Configuration(Indexable): + """ + Dictionary-like data structure to contain all configuration variables. + + This serves as a configuration dictionary throughout benchbuild. You can + use it to access all configuration options that are available. Whenever the + structure is updated with a new subtree, all variables defined in the new + subtree are updated from the environment. + + Environment variables are generated from the tree paths automatically. + CFG["build_dir"] becomes BB_BUILD_DIR + CFG["llvm"]["dir"] becomes BB_LLVM_DIR + + The configuration can be stored/loaded as YAML. + """ + + def __init__( + self, + parent_key: str, + node: tp.Optional[InnerNode] = None, + parent: tp.Optional['Configuration'] = None, + init: bool = True + ): + self.parent = parent + self.parent_key = parent_key + self.node = node if node is not None else {} + if init: + self.init_from_env() + +
+[docs] + def filter_exports(self) -> None: + if self.has_default(): + do_export = True + if "export" in self.node: + do_export = self.node["export"] + + if not do_export: + if self.parent: + self.parent.node.pop(self.parent_key) + else: + selfcopy = copy.deepcopy(self) + for k in self.node: + if selfcopy[k].is_leaf(): + selfcopy[k].filter_exports() + self.__dict__ = selfcopy.__dict__
+ + +
+[docs] + def store(self, config_file: LocalPath) -> None: + """ Store the configuration dictionary to a file.""" + + selfcopy = copy.deepcopy(self) + selfcopy.filter_exports() + + with open(config_file, 'w') as outf: + yaml.dump( + selfcopy.node, + outf, + width=80, + indent=4, + default_flow_style=False, + Dumper=ConfigDumper + )
+ + +
+[docs] + def load(self, _from: LocalPath) -> None: + """Load the configuration dictionary from file.""" + + def load_rec( + inode: tp.Dict[str, tp.Any], config: Configuration + ) -> None: + """Recursive part of loading.""" + for k in config: + if isinstance(config[k], dict) and \ + k not in ['value', 'default']: + if k in inode: + load_rec(inode[k], config[k]) + else: + LOG.debug("+ config element: '%s'", k) + else: + inode[k] = config[k] + + with open(str(_from), 'r') as infile: + obj: Configuration = yaml.load(infile, Loader=ConfigLoader) + upgrade(obj) + load_rec(self.node, obj) + self['config_file'] = os.path.abspath(_from)
+ + +
+[docs] + def has_value(self) -> bool: + """Check, if the node contains a 'value'.""" + return isinstance(self.node, dict) and 'value' in self.node
+ + +
+[docs] + def has_default(self) -> bool: + """Check, if the node contains a 'default' value.""" + return isinstance(self.node, dict) and 'default' in self.node
+ + +
+[docs] + def is_leaf(self) -> bool: + """Check, if the node is a 'leaf' node.""" + return self.has_value() or self.has_default()
+ + +
+[docs] + def init_from_env(self) -> None: + """ + Initialize this node from environment. + + If we're a leaf node, i.e., a node containing a dictionary that + consist of a 'default' key, compute our env variable and initialize + our value from the environment. + Otherwise, init our children. + """ + + if 'default' in self.node: + env_var = self.__to_env_var__().upper() + if not self.has_value(): + self.node['value'] = self.node['default'] + env_val = os.getenv(env_var, None) + if env_val is not None: + try: + self.node['value'] = yaml.load( + str(env_val), Loader=ConfigLoader + ) + except ValueError: + self.node['value'] = env_val + else: + if isinstance(self.node, dict): + for k in self.node: + self[k].init_from_env()
+ + + @property + def value(self) -> tp.Any: + """Return the node value, if we're a leaf node.""" + + def validate(node_value: tp.Any) -> tp.Any: + if hasattr(node_value, 'validate'): + node_value.validate() + return node_value + + if 'value' in self.node: + return validate(self.node['value']) + return self + + def __getitem__(self, key: str) -> 'Configuration': + if key not in self.node: + warnings.warn( + "Access to non-existing config element: {0}".format(key), + category=InvalidConfigKey, + stacklevel=2 + ) + return Configuration(key, init=False) + return Configuration(key, parent=self, node=self.node[key], init=False) + + def __setitem__(self, key: str, val: tp.Any) -> None: + if _INNER_NODE_SCHEMA.is_valid(val) or _INNER_NODE_VALUE.is_valid(val): + self.node[key] = val + elif key in self.node: + self.node[key]['value'] = val + else: + self.node[key] = {'value': val} + + def __iadd__(self, rhs: tp.Any) -> tp.Any: + """Append a value to a list value.""" + if not self.has_value(): + raise TypeError("Inner configuration node does not support +=.") + + value = self.node['value'] + if not hasattr(value, '__iadd__'): + raise TypeError("Configuration node value does not support +=.") + + value += rhs + return value + + def __int__(self) -> int: + """Convert the node's value to int, if available.""" + if not self.has_value(): + raise ValueError( + 'Inner configuration nodes cannot be converted to int.' + ) + return int(self.value) + + def __bool__(self) -> bool: + """Convert the node's value to bool, if available.""" + if not self.has_value(): + return True + return bool(self.value) + + def __contains__(self, key: str) -> bool: + return key in self.node + + def __str__(self) -> str: + if 'value' in self.node: + return str(self.node['value']) + return str(self.node) + + def __repr__(self) -> str: + """ + Represents the configuration as a list of environment variables. + """ + _repr = [] + + if self.has_value(): + return to_env_var(self.__to_env_var__(), self.node['value']) + if self.has_default(): + return to_env_var(self.__to_env_var__(), self.node['default']) + + for k in self.node: + _repr.append(repr(self[k])) + + return "\n".join(sorted(_repr)) + + def __to_env_var__(self) -> str: + parent_key = self.parent_key + if self.parent: + return str(self.parent.__to_env_var__() + "_" + parent_key).upper() + return parent_key.upper() + +
+[docs] + def to_env_dict(self) -> tp.Mapping[str, tp.Any]: + """Convert configuration object to a flat dictionary.""" + if self.has_value(): + return {self.__to_env_var__(): self.node['value']} + if self.has_default(): + return {self.__to_env_var__(): self.node['default']} + + entries: tp.Dict[str, str] = {} + for k in self.node: + entries.update(self[k].to_env_dict()) + + return entries
+
+ + + +
+[docs] +def convert_components(value: tp.Union[str, tp.List[str]]) -> tp.List[str]: + is_str = isinstance(value, six.string_types) + new_value = value + if is_str: + new_value = str(new_value) + if os.path.sep in new_value: + new_value = new_value.split(os.path.sep) + else: + new_value = [new_value] + new_value = [c for c in new_value if c != ''] + return new_value
+ + + +
+[docs] +@attr.s(str=False, frozen=True) +class ConfigPath: + """Wrapper around paths represented as list of strings.""" + components = attr.ib(converter=convert_components) + +
+[docs] + def validate(self) -> None: + """Make sure this configuration path exists.""" + path = local.path(ConfigPath.path_to_str(self.components)) + + if not path.exists(): + print("The path '%s' is required by your configuration." % path) + yes = ui.ask( + "Should I create '%s' for you?" % path, + default_answer=True, + default_answer_str="yes" + ) + if yes: + path.mkdir() + else: + LOG.error("User denied path creation of '%s'.", path) + if not path.exists(): + LOG.error("The path '%s' needs to exist.", path)
+ + +
+[docs] + @staticmethod + def path_to_str(components: tp.List[str]) -> str: + if components: + return os.path.sep + os.path.sep.join(components) + return os.path.sep
+ + + def __str__(self) -> str: + return ConfigPath.path_to_str(self.components)
+ + + +
+[docs] +def path_representer(dumper, data): + """ + Represent a ConfigPath object as a scalar YAML node. + """ + return dumper.represent_scalar('!create-if-needed', '%s' % data)
+ + + +
+[docs] +def path_constructor(loader, node): + """" + Construct a ConfigPath object form a scalar YAML node. + """ + value = loader.construct_scalar(node) + return ConfigPath(value)
+ + + +
+[docs] +def find_config( + test_file: tp.Optional[str] = None, + defaults: tp.Optional[tp.List[str]] = None, + root: str = os.curdir +) -> tp.Optional[LocalPath]: + """ + Find the path to the default config file. + + We look at :root: for the :default: config file. If we can't find it + there we start looking at the parent directory recursively until we + find a file named :default: and return the absolute path to it. + If we can't find anything, we return None. + + Args: + test_file: + default: The name of the config file we look for. + root: The directory to start looking for. + + Returns: + Path to the default config file, None if we can't find anything. + """ + if defaults is None: + defaults = [".benchbuild.yml", ".benchbuild.yaml"] + + def walk_rec(cfg_name: str, root: str) -> LocalPath: + cur_path = local.path(root) / cfg_name + if cur_path.exists(): + return cur_path + + new_root = local.path(root) / os.pardir + return walk_rec(cfg_name, new_root) if new_root != root else None + + if test_file is not None: + return walk_rec(test_file, root) + + for test_f in defaults: + ret = walk_rec(test_f, root) + if ret is not None: + return ret + + return None
+ + + +
+[docs] +def setup_config( + cfg: Configuration, + config_filenames: tp.Optional[tp.List[str]] = None, + env_var_name: tp.Optional[str] = None +) -> None: + """ + This will initialize the given configuration object. + + The following resources are available in the same order: + 1) Default settings. + 2) Config file. + 3) Environment variables. + + WARNING: Environment variables do _not_ take precedence over the config + file right now. (init_from_env will refuse to update the + value, if there is already one.) + + Args: + config_filenames: list of possible config filenames + env_var_name: name of the environment variable holding the config path + """ + if env_var_name is None: + env_var_name = "BB_CONFIG_FILE" + + config_path = os.getenv(env_var_name, None) + if not config_path: + config_path = find_config(defaults=config_filenames) + + if config_path: + cfg.load(config_path) + cfg["config_file"] = os.path.abspath(config_path) + cfg.init_from_env()
+ + + +
+[docs] +def update_env(cfg: Configuration) -> None: + env: tp.Dict[str, str] = dict(cfg["env"].value) + + path = env.get("PATH", "") + path = os.path.pathsep.join(path) + if "PATH" in os.environ: + path = os.path.pathsep.join([path, os.environ["PATH"]]) + os.environ["PATH"] = path + + lib_path = env.get("LD_LIBRARY_PATH", "") + lib_path = os.path.pathsep.join(lib_path) + if "LD_LIBRARY_PATH" in os.environ: + lib_path = os.path.pathsep.join([ + lib_path, os.environ["LD_LIBRARY_PATH"] + ]) + os.environ["LD_LIBRARY_PATH"] = lib_path + + home = env.get("HOME", None) + if home is not None and "HOME" in os.environ: + os.environ["HOME"] = home + + # Update local's env property because we changed the environment + # of the running python process. + local.env.update(PATH=os.environ["PATH"]) + local.env.update(LD_LIBRARY_PATH=os.environ["LD_LIBRARY_PATH"]) + if home is not None: + local.env.update(HOME=os.environ["HOME"])
+ + + +
+[docs] +def upgrade(cfg: Configuration) -> None: + """Provide forward migration for configuration files.""" + db_node = cfg["db"] + old_db_elems = ["host", "name", "port", "pass", "user", "dialect"] + has_old_db_elems = [x in db_node for x in old_db_elems] + + if any(has_old_db_elems): + print( + "Old database configuration found. " + "Converting to new connect_string. " + "This will *not* be stored in the configuration automatically." + ) + cfg["db"]["connect_string"] = \ + "{dialect}://{user}:{password}@{host}:{port}/{name}".format( + dialect=cfg["db"]["dialect"]["value"], + user=cfg["db"]["user"]["value"], + password=cfg["db"]["pass"]["value"], + host=cfg["db"]["host"]["value"], + port=cfg["db"]["port"]["value"], + name=cfg["db"]["name"]["value"])
+ + + +
+[docs] +def uuid_representer(dumper, data): + """Represent a uuid.UUID object as a scalar YAML node.""" + + return dumper.represent_scalar('!uuid', '%s' % data)
+ + + +
+[docs] +def uuid_constructor(loader, node): + """"Construct a uuid.UUID object form a scalar YAML node.""" + + value = loader.construct_scalar(node) + return uuid.UUID(value)
+ + + +
+[docs] +def uuid_add_implicit_resolver(loader=ConfigLoader, dumper=ConfigDumper): + """Attach an implicit pattern resolver for UUID objects.""" + uuid_regex = r'^\b[a-f0-9]{8}-\b[a-f0-9]{4}-\b[a-f0-9]{4}-\b[a-f0-9]{4}-\b[a-f0-9]{12}$' + pattern = re.compile(uuid_regex) + yaml.add_implicit_resolver('!uuid', pattern, Loader=loader, Dumper=dumper)
+ + + +def __init_module__() -> None: + yaml.add_representer(uuid.UUID, uuid_representer, Dumper=ConfigDumper) + yaml.add_representer(ConfigPath, path_representer, Dumper=ConfigDumper) + yaml.add_constructor('!uuid', uuid_constructor, Loader=ConfigLoader) + yaml.add_constructor( + '!create-if-needed', path_constructor, Loader=ConfigLoader + ) + uuid_add_implicit_resolver() + + +__init_module__() +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_modules/index.html b/branch/f-QoLImprovements/_modules/index.html new file mode 100644 index 000000000..9818bc502 --- /dev/null +++ b/branch/f-QoLImprovements/_modules/index.html @@ -0,0 +1,242 @@ + + + + + + Overview: module code + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/_sources/CHANGELOG.md.txt b/branch/f-QoLImprovements/_sources/CHANGELOG.md.txt new file mode 100644 index 000000000..6d83de0c8 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/CHANGELOG.md.txt @@ -0,0 +1,437 @@ + +## 6.8 (2023-10-09) + + +#### Features + +* **ci:** test with both db support and without ([af7bfd90](https://github.com/PolyJIT/benchbuild/commit/af7bfd90caf2c8fc56eb71de67384f15c6569838)) +* **coverage:** + * test with database support enabled ([0b8d6034](https://github.com/PolyJIT/benchbuild/commit/0b8d6034b3c8d58ab8034a3bdda6cc7509c25e9c)) + * add cli coverage report ([64ce9f87](https://github.com/PolyJIT/benchbuild/commit/64ce9f87cdcd32cda8665e17b84651abebead604)) + * add wrapped binaries to coverage ([d4c6841d](https://github.com/PolyJIT/benchbuild/commit/d4c6841d09fcb0c77564d5faaa29e69b4ff40822)) +* **db:** revert default setting for connect_string to sqlite:// ([806520d6](https://github.com/PolyJIT/benchbuild/commit/806520d6f34e85bdb3709e37465f7982b6d4db36)) + +#### Bug Fixes + +* use context vars instead of env vars ([e3ea47f0](https://github.com/PolyJIT/benchbuild/commit/e3ea47f01e4d85ddfedeb104ae6184d43e6957ef)) +* make github ci actually use its own env vars ([e0c7ab67](https://github.com/PolyJIT/benchbuild/commit/e0c7ab676aa3686a78bac97ed87d4c98f71e240d)) +* use BB_COVERAGE_PATH in .coveragerc ([141afafa](https://github.com/PolyJIT/benchbuild/commit/141afafa7859136bad5952c672448b92082f7551)) +* coveragerc requires curly braces for env variables ([3ae8b335](https://github.com/PolyJIT/benchbuild/commit/3ae8b3358e0d1e828f2d73f222a563bfcc01f8b6)) +* coveragerc requires curly braces for env variables ([5b9c9906](https://github.com/PolyJIT/benchbuild/commit/5b9c9906cbb5ff7f4e27a7018e1069ef24fe25bf)) +* **actions:** re-raise caught exception ([e4bff984](https://github.com/PolyJIT/benchbuild/commit/e4bff984e4f1e523ce9d685a5d3ec9a58c97a18a), closes [#561](https://github.com/PolyJIT/benchbuild/issues/561)) +* **environments:** buildah cannot find base images. ([eb03c363](https://github.com/PolyJIT/benchbuild/commit/eb03c363eac2a515e830ff3e9f0343c923348763)) + + + + +## 6.7 (2023-04-04) + + +#### Features + +* run auto-walrus over all of benchbuild's file ([79ac33d8](https://github.com/PolyJIT/benchbuild/commit/79ac33d8d69974fb6a1d049f75c5f013e444b2ce)) +* add support for auto-walrus as pre-commit hook ([d7a2165b](https://github.com/PolyJIT/benchbuild/commit/d7a2165bb22467754fd329fedc0c0f8330336e3f)) +* drop support for python 3.7 and 3.8 ([90308f2a](https://github.com/PolyJIT/benchbuild/commit/90308f2ae141fd4443f08ef55a4155e433fad929)) +* **ci:** + * update setup-python to v4 ([3e943df6](https://github.com/PolyJIT/benchbuild/commit/3e943df657cb06a4f2b47104a4e3dcb77f16793c)) + * update github setup actions to v3 ([dfa4cb81](https://github.com/PolyJIT/benchbuild/commit/dfa4cb8135d3c0256c6b99dbe40771d8ce1e5a5d)) +* **command:** use name as default value for a command's label ([07f74dd4](https://github.com/PolyJIT/benchbuild/commit/07f74dd4932eecdfbd902d231242a65984501007)) +* **environments:** force base image to alpine:3.17 ([fe5d6155](https://github.com/PolyJIT/benchbuild/commit/fe5d615574130260e1af1aaa49b1058600ed9668)) +* **setup:** + * widen allowed versions to major versions ([5d29079a](https://github.com/PolyJIT/benchbuild/commit/5d29079a973dc1d8650ee9083090eaa7bd99cbfc)) + * unlock latest versions of all packages ([7b5a704f](https://github.com/PolyJIT/benchbuild/commit/7b5a704f843872c90fa2a23eb738db4262883076)) +* **wrapping:** enforce global defaults for dill module ([489e3039](https://github.com/PolyJIT/benchbuild/commit/489e3039f8bb1ccee40219d1c27ca999cd8a3623)) + +#### Bug Fixes + +* python version for setup-python@v4 has to be string ([7a1db742](https://github.com/PolyJIT/benchbuild/commit/7a1db74237e6b35687213920bb534b5308773615)) +* remove python 3.7 and 3.8 from all workflows ([aaabc1b5](https://github.com/PolyJIT/benchbuild/commit/aaabc1b5e7a817304f9e948feb565f37916c68bb)) +* bump pathos & dill to unbreak gitlab ci ([bce45d8a](https://github.com/PolyJIT/benchbuild/commit/bce45d8a148e41914d6f56a18933f9faf26f58bf)) +* **ci:** + * disable mkdocs in github ci ([8540f880](https://github.com/PolyJIT/benchbuild/commit/8540f880607ddeae293fc6b9feb1f751fd9cc721)) + * reorder CI steps (test) ([74379d53](https://github.com/PolyJIT/benchbuild/commit/74379d5350c35cc2c76600ae7784b78aefd1a7db)) + * increase verbosity to max for all integation tasks ([b6625d31](https://github.com/PolyJIT/benchbuild/commit/b6625d31d444e2ea51dc923a80438f0eed4a962d)) +* **command:** use private label when fetching string representation ([d83aa666](https://github.com/PolyJIT/benchbuild/commit/d83aa6661d3e2e08a0849bd3b23f557bd086e5b6)) +* **commands:** preserve workload order when filtering ([3648dd5e](https://github.com/PolyJIT/benchbuild/commit/3648dd5e8d0c20a07141a05a94a4e1223f575399)) +* **setup:** unlock any major version of pygit2 ([b09d9248](https://github.com/PolyJIT/benchbuild/commit/b09d92489a57897d4e0ad39dcb8b99ce08133d36)) +* **wrapping:** remove unused code ([0d1c890d](https://github.com/PolyJIT/benchbuild/commit/0d1c890db0f674aab13b12432394699030114087)) + + + +# Changelog + + +## 6.6.4 (2023-03-16) + + + + + +## 6.6.3 (2023-03-06) + + + + + +## 6.6.2 (2023-03-06) + + +#### Bug Fixes + +* pin sqlalchemy version <2.0 ([86d45043](https://github.com/PolyJIT/benchbuild/commit/86d45043d269775d65c3b2844d9eee669824b46c)) + + + + +## 6.6.1 (2023-01-10) + + +#### Features + +* **environments:** + * do not overwrite config, if cli option is default ([b1a095c1](https://github.com/PolyJIT/benchbuild/commit/b1a095c1e5b6ceb32b7eb3a7eda61918eeb3f757)) + * improve error handling using result module ([fbb69502](https://github.com/PolyJIT/benchbuild/commit/fbb695027e83e99ab8dbbb58447bd3dc9d0073dd)) +* **slurm:** make container.runroot/container.root available for slurm customization ([616a4c69](https://github.com/PolyJIT/benchbuild/commit/616a4c69bea9ef17547cabfd2a8e076638b1e034), closes [#528](https://github.com/PolyJIT/benchbuild/issues/528)) +* **source:** make sure we manage the archive symlink properly. ([7687f0e3](https://github.com/PolyJIT/benchbuild/commit/7687f0e317b82b9e8a4b5e78a63827dd18255c06)) +* **source/http:** add auto-untar http source ([84f90e75](https://github.com/PolyJIT/benchbuild/commit/84f90e7568550a240a25c7cf06b139862f764ed0)) + +#### Bug Fixes + +* **environments:** + * add missing logging import ([aad1b287](https://github.com/PolyJIT/benchbuild/commit/aad1b2878721c466167f52c176683d97d25a9f86)) + * add missing Err import ([19c5983c](https://github.com/PolyJIT/benchbuild/commit/19c5983cd43e73d870212428bcc382d3e8255d9e)) + * notify user when commit of container image fails ([78b890af](https://github.com/PolyJIT/benchbuild/commit/78b890af5fd03093bc74631bc6ac63c19477ee70)) +* **project:** version filters should only consider expandable sources ([3d546314](https://github.com/PolyJIT/benchbuild/commit/3d5463146debb66b3448acbf3ee79c4ef17ce35f)) +* **source:** enforce sorted order of revisions ([ca973ff0](https://github.com/PolyJIT/benchbuild/commit/ca973ff0b7e01e3b79b6daafdc7848e1433f766a)) + + + +## 6.5 (2022-11-03) + +### Feat + +- **source**: re-enable project_cls in enumerate_revision interface +- **versions**: enable context-aware SingleVersionFilter +- **source**: only print context-free sources +- **source**: expand public source API +- **source**: introduce type skeleton and prototypes for context-aware version enumeration. +- **action**: replace StepClass metaclass with __init_subclass__ +- **actions**: mark StepTy covariant +- **actions**: use Stepable protocol as bound for StepTy. +- **actions**: accept any varargs in a Step's __call__ implementation + +### Fix + +- require dill version to be exactly 0.3.4 +- linter warning +- linter warnings +- **project**: remove debug print +- **utils**: variant -> revision +- **tests**: repair tests after VariantContext replacement. +- **source**: remove runtime_checkable decorator +- **source**: use project class instead of object for enumerate +- **source**: return sequence of variants instead of nestedvariant +- **source**: clean up protocol apis +- **actions**: rename StepTy -> StepTy_co +- **tests**: remove notify_step_begin_end +- **actions**: reduce mypy errors +- **actions**: use mutable generic container + +### Refactor + +- **versions**: remove BaseVersionGroup +- **source**: replace VariantContext with Revision +- **source**: remove ExpandableAndFetchableSource from API + +## 6.4 (2022-09-21) + +### Feat + +- **actions**: make MultiStep generic. +- **command**: make use of rendered and unrenderer PathToken explicit. +- **command**: safeguard pruning and backup +- **command**: add tests for enable_rollback +- **command**: add support for creates and consumes properties for commands +- **command**: add a label to commands +- **workload**: switch WorkloadSet to varargs instead of kwargs +- **command**: add example `OnlyIn` for WorkloadSet customization. + +### Fix + +- **command**: strictly less than python 3.9 +- **command**: use _is_relative_to where needed +- **command**: guard is_relative_to with else +- **command**: do not depend on Path.is_relative_to ( cleanup + +## 6.3.2 (2022-08-21) + +### Feat + +- **command**: rename NullRenderer to RootRenderer +- **command**: hook up token renderer logic with Commands +- **command**: add support for generic path tokens +- **workload**: convert scimark2 +- **command**: migrate git-based projects to workload sets +- **command**: add support for WorkloadSet. +- **command**: clear path tracker on fresh ProjectEnvironment +- **wrapping**: avoid wrapping the same command twice. +- **jobs**: add RunJob and RunJobs actions +- **command**: replace source root anywhere in command's parts +- **command**: pass environment to plumbum command +- **command**: pass args to plumbum command +- **command**: improve args and kwargs handling +- add env and __str__ to commands +- **command**: support declarative commands in projects (WIP) +- **source**: add 'fetch' support to FetchableSource derivatives +- **workloads**: add properties & tags accessors +- **workloads**: convert benchbuild.xz to support workloads + +### Fix + +- test must use render() +- **x264**: repair broken cli args +- **command**: actually run the workload +- **command**: check for existence, only after rendering +- **project**: target compile instead of run_tests, when accessing compile +- **command**: remove unused definitions +- **command**: context -> kwargs +- **typing**: python3.7 requires typing_extensions for runtime_checkable / Protocll +- **command**: missing rename job -> workload +- **command**: provide mapping type +- **workload**: strip previous workload draft +- workaround a mypy error +- correct mypy errors. +- **wrapping**: provide default arg for sprefix +- **actions**: provide default StepResult +- **command**: store args as tuple +- **bzip2**: clean draft marker +- **actions**: repair status print of actions +- **experiment**: initialize CleanExtra correctly +- **jobs**: allow jobs to run as wrapped binaries +- use oci_compliant name for image names +- **workloads**: wrong workload type +- **actions**: unbreak tests after list -> scalar conversion + +### Refactor + +- **command**: lower-case token str +- rename Job -> Workload +- **command**: remove debug prints +- **source**: remove unnecessary ellipsis + +## 6.3.1 (2022-03-01) + +### Feat + +- **actions**: clean interfaces of utils/actions +- **workloads**: make object instance accessible to workloads using descriptors +- **workloads**: hook up Compile and Run action to new workload impl +- **workloads**: add simple intersection filter to workloads +- **workloads**: change workload registration decorator style. +- **workloads**: migrate Compile/Run action to run workloads only +- **project**: remove run_tests and compile abstract methods +- **gzip**: convert gzip to workloads +- **workload**: Add prototype support for workloads. +- **environments**: strip container args when entering interactive mode + +### Fix + +- **workloads**: typo. +- **gzip**: undo wrong wrap command +- **actions**: project -> obj after rebase + +### Refactor + +- **workloads**: remove useless/unused parts + +## 6.3 (2022-02-03) + +### Feat + +- **actions**: throw error if RevisionStrings cannot match any Source. +- **source**: add FetchableSource.explore() method +- **source**: only filter context for expandable sources +- **actions**: support partial revisions in SetProjectVersion +- **source**: hook up context_from_revisions to SetProjectVersion +- **source**: provide an easy way to create a variant context +- **environments**: add container image removal to buildah adapter +- **environments**: support custom arguments in RunProjectContainer +- **actions**: track active_variant with SetProjectVersion +- **project**: add MultiVersioned Mixin to Projects +- **source**: symlink active version for http sources +- **source**: Link to active location after version() +- **actions**: Rename AddProjectVersion to SetProjectVersion +- **actions**: add AddProjectVersion action +- **actions**: remove obsolete parameters +- **actions**: remove attrs from utils/actions + +### Fix + +- **tests**: eye-breaking code alignment. +- **environments**: do not fail if no entrypoint is set. +- **environments**: supply args as dedicated subcommand args +- **environments**: use a default list factory, instead of a list class +- **source**: replace symlink to directory +- **actions**: obvious type errors in SetProjectVersion +- **actions**: assign active variant + +### Refactor + +- **pylint**: remove unused import +- **pylint**: make pylint happy. +- **pylint**: make pylint almost happy. + +## 6.2.7 (2021-09-21) + +## 6.2.6 (2021-09-16) + +### Fix + +- **sources**: do not use protocol class as ABC + +## 6.2.5 (2021-09-15) + +### Feat + +- **utils/run**: add unbuffered watch commands +- **source**: update git remote revisions. (#434) +- **log**: add force_tty switch to control RichHandler. (#435) + +## 6.2.4 (2021-09-03) + +## 6.2.3 (2021-08-26) + +### Fix + +- **schema**: silence SAWarning about caching (#428) +- **environments**: pass format string to logging call (#427) + +## 6.2.2 (2021-07-29) + +## 6.2.1 (2021-07-06) + +### Feat + +- **environments**: add an interactive mode for container runs. + +### Fix + +- **logging**: make rich log to stderr by default (#415) +- **settings**: BB_ENV is ignored when no config file is loaded" (#414) + +## 6.2 (2021-06-02) + +### Fix + +- **settings**: unbreak test cases. +- use correct schema version +- **settings**: consistent settings behavior. +- **environments**: notify the user, if image creation fails + +## 6.1.1 (2021-05-11) + +### Fix + +- **project**: do not track project classes twice + +## 6.1 (2021-05-11) + +### Feat + +- **environments**: just print env var name as error message +- **environments**: warn the user about too long paths for libpod +- **slurm**: support variable number of subcommand arguments +- tune down rich's custom log format +- **environments**: enable debugging of failed image builds +- **environments**: provide more consistent output through rich +- **environments**: add 'rmi' subcommand to delete images. +- **environments**: make an error message stand out more clearly +- **environments**: add g++ to base image +- **environments**: split image_exists into 2 implementations +- **environments**: split containers cli into 2 entitie +- **environments**: add basic error handling to environments +- **environments**: emit layer creation events +- **environments**: print layer construction progress +- **environments**: make layers hashable +- **environments**: step-wise image construction +- **environments**: split Repositories and Unit of Work into 2 entities each +- **utils/slurm**: add customizable SLURM templates +- **cli/project**: add details view for a single project +- **cli/project**: change project view to a condensed format +- **environments**: add option to replace container images +- add support for --export and --import flags in containers + +### Fix + +- **sources**: unshallow only when needed +- **environments**: unshallow git clones before dissociating +- **environments**: remove left-over parameters +- **ci**: typo. +- **environments**: do not overwrite exported images. +- **environments**: remove optional image name argument from podman load +- **slurm**: fix pylint/mypy +- **environments**: reuse same status bar structure for all other cli subcommands +- **environments**: mypy warnings +- **environments**: fix mypy/pylint annotations. +- **environments**: split return turple and baild out on error +- **environments**: mypy warnings +- **environments**: add missing type conversion +- **environments**: rework typing annotations for handlers +- **environments**: fix linter/mypy warnings +- **environments**: make Add & Copy layers hashable +- **environments**: add missing sys import +- **environments**: import Protocol from typing_extensions, if python <= 3.8 +- **environments**: handle 'None' for MaybeContainer return type +- **slurm**: do not modify slurm_node_dir +- **environments**: deal with multi-line container ids +- **environments**: do not spawn the FromLayer +- **cli/project**: annotate print_layers +- **cli/project**: add neutral element for multiplication with reduce +- **project**: project registration for groups +- **environments**: explicitly state remote registry location +- do not use global state to conffigure buildah/podman +- **x264**: use local name of source for lookup + +### Refactor + +- **environments**: fix possible unbound variable +- **slurm**: fix type error on cli_process +- **environments**: remove unused sys import +- **environments**: rmeove some linter warnings +- **environments**: replace functools.partial with custom closure function +- **environments**: unsplit image from layer creation +- **enviroments**: remove debug print +- **environments**: remove unused commands +- **cli/project**: remove version counting from project view +- **cli/project**: force use of str +- **cli/project**: add documentation to print_project +- **cli/project**: add type annotation for set_limit +- **cli/project**: add a default list limit for versions (10) +- **cli/project**: provide better layout of project information +- **cli/project**: use a multi-line string +- **cli/project**: use named fields +- **project**: provide correct type annotations + +## 6.0.1 (2020-12-29) + +### Fix + +- Avoid useless plugin spam when running with higher verbosity levels diff --git a/branch/f-QoLImprovements/_sources/about.md.txt b/branch/f-QoLImprovements/_sources/about.md.txt new file mode 100644 index 000000000..3570cdf33 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/about.md.txt @@ -0,0 +1,33 @@ +# BenchBuild Documentation + +BenchBuild is an open-source toolkit that helps with the management of case-studies used in software-driven empirical experiments. +BenchBuild was specifically designed to make defined experiments reusable between different +experiment setups. It mainly provides assistance with the following standard tasks found in empirical software experiments: + +- Add a new case-study to an existing experiment setup. +- Add a new experiment to an existing body of case-studies. + +## Design Philosophy + +BenchBuild is designed with the following main properties in mind. + +### A case-study doesn't know its experiment + +If you add a new case-study, you should never have to rely on background information about the experiment you are about to run on it. +A new case-study is only concerned with its own setup of dependencies and execution during its run-time. A case-study controls where and what can be +intercepted by an experiment. + +### An experiment doesn't know its case-studies + +Adding a new experiment never should have any knowledge about the case-studies +it runs on. +A new experiment takes care of intercepting the compilation process and/or the +execution procedure of a given case-study. This only defines what is being done at the defined extension points at compile-time or run-time. + +## Supported Python Versions + +BenchBuild supports Python 3.7 and 3.8. Main development is focused on Python 3.8, but an effort is made to support 3.7 as long as major distributions like Debian Linux only ship with 3.7 by default. + +## Getting started + +See the [Installation guide]() for help getting BenchBuild up and running quickly. diff --git a/branch/f-QoLImprovements/_sources/advanced/cli.md.txt b/branch/f-QoLImprovements/_sources/advanced/cli.md.txt new file mode 100644 index 000000000..97268ba55 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/advanced/cli.md.txt @@ -0,0 +1,4 @@ +## CLI + +* ``--force-watch-unbuffered``: This disables buffering from watched commands. + This can help with tools that call benchbuild and use their own output buffering. diff --git a/branch/f-QoLImprovements/_sources/advanced/index.md.txt b/branch/f-QoLImprovements/_sources/advanced/index.md.txt new file mode 100644 index 000000000..386708dd4 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/advanced/index.md.txt @@ -0,0 +1,28 @@ +# SLURM + +BenchBuild supports a high-level integration with the SLURM cluster resource +manager. An experiment setup can be exported as a SLURM bash script. Assuming +you have access to a configured benchbuid environment on the SLURM cluster, you +can provide the SLURM script to the ``sbatch`` command and have your experiment +run on the cluster environment. + +## Basics + +TODO + +## Template customization + +This customization is not recommended for the default use-case. However, you +might run in a situation where the existing cluster-environment requires a +more complicated setup than BenchBuild can provide. + +You can customize the template that is used for the SLURM script using a +modified copy of the base template BenchBuild uses +(see ``benchbuild/res/misc/slurm.sh.inc``). + +The customized template can be configured using the configuration option +``BB_SLURM_TEMPLATE``. If BenchBuild detects that the provided value points to +an existing file in your filesystem, it will load it. +If you change the setting and BenchBuild cannot find a file there, no script +will be generated. No validation of the template will be done, use at your own +risk. diff --git a/branch/f-QoLImprovements/_sources/basics/actions.md.txt b/branch/f-QoLImprovements/_sources/basics/actions.md.txt new file mode 100644 index 000000000..48b86fcfb --- /dev/null +++ b/branch/f-QoLImprovements/_sources/basics/actions.md.txt @@ -0,0 +1,101 @@ +# Actions + +Actions are used to declare the workflow of an experiment. BenchBuild provides +a set of default actions that should suit most experiments. +A new experiment can define a new set of actions that should be used per project, +or use those defaults. + +## Customize actions + +Whenever you define a new expeirment, you have to provide an implementation +for ``def actions_for_project(self, project: 'Project')``. +This implementation usually configures extensions on the project and returns +a set of actions that should be run during execution. + +Example: +```{python} +def actions_for_project(self, project: 'Project'): + project.runtime_extension = time.RunWithTime( + run.RuntimeExtensions(project, self)) + project.runtime_extension = time.WithTimeout( + run.RunCompiler(project, self)) + + return self.default_runtime_actions(project) +``` + +This takes care of compiling, running and cleanup during experiment execution. + +## Available Actions + +The following actions are available out of the box. You can define your own +actions at any time + +### Step (Base) + +### Clean + +### MakeBuildDir + +### Compile + +### Run + +### Echo + +### Any (Group) + +### Experiment (Any, Group) + +### RequireAll (Group) + +### CleanExtra + +### ProjectEnvironment + +### SetProjectVersion + +This action provides you with a way to change the source version used inside the +build directory of this project. +During initialization, each project is assigned a variant that determines the +source versions that will be checked out into the build directory. + +Sometimes it can be useful to do comparisons of different source revisions +inside a single experiment run. This can be achieved using ``SetProjectVersion``. + +Usage: +```{python} +from benchbuild.source.base import RevisionStr +from benchbuild.utils import actions as a + +... +git_commit_hash = 'abcdefgh' + +actions = [ + a.Clean(project), + a.MakeBuildDir(project), + # This uses the default variant of the project (not necessarily 'abcdefgh') + a.ProjectEnvironment(project), + a.Compile(project), + a.Run(project), + + # From here we will work with git sources set to 'abcdefgh' + a.SetProjectVersion(project, RevisionStr(git_commit_hash)) + a.Compile(project), + a.Run(project) +] +``` + +The match is done on all(!) sources of the project. If you happen to find a +revision string twice in different souces, both will be checked out in the +build directory. + +The match is done exact and matches agains the ``source.versions()`` output of a +source. Only sources that are marked as expandable (``source.is_expandable``) +will be checked. + +```{eval-rst} +.. automodule:: benchbuild.utils.actions + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/branch/f-QoLImprovements/_sources/basics/configuration.md.txt b/branch/f-QoLImprovements/_sources/basics/configuration.md.txt new file mode 100644 index 000000000..213513f12 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/basics/configuration.md.txt @@ -0,0 +1,19 @@ +# Configure + +## Module: settings + +```{eval-rst} +.. automodule:: benchbuild.settings + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: utils.settings + +```{eval-rst} +.. automodule:: benchbuild.utils.settings + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/branch/f-QoLImprovements/_sources/basics/containers.md.txt b/branch/f-QoLImprovements/_sources/basics/containers.md.txt new file mode 100644 index 000000000..802b5a122 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/basics/containers.md.txt @@ -0,0 +1,143 @@ +# Containers + +Benchbuild allows the definition of container images to define the base system +all experiment runs run in for a given project. + +## Usage + +If you want to run an experiment inside the project's container, simply replace +the usual ``run`` subcommand with the ``container run`` subcommand. Project and +experiment selection are done in the same way. + +Example: +``` +benchbuild container run -E raw linpack +``` + +This will run the following stages: + + 1. Build all necessary base images. + All images are initiated from a base image. Benchbuild knows how to construct + a few base images. These will be prepared with all dependencies required to + run benchbuild inside the container. + 2. Build all project images. Each project has to define its' own image. + 3. Build the experiment images. Each experiment can add anything it needs to the + project images, if required. Use this to bring tools into the image that do + not require any knowledge about the environment to run properly. + For anything else, consider using a custom base image. + +### Replace Images + +Benchbuild will reuse any existing images it can find in your image registry. +The only relevant information is the image tag, e.g., ``benchbuild:alpine``. +If you want to avoid reuse and force to rebuild images unconditionally, you can +use the ``--replace`` flag when running the ``containers`` subcommand. + +Example: +``` +benchbuild container run --replace -E raw linpack +``` + +This will ignore **any** required image for the given experiments and projects. + +## Configuration + +You can configure the container environment using the following config variables. + +- ``BB_CONTAINER_EXPORT``: Path where benchbuild stores exported container + images. By default we store it in ``./containers/export``. Will be created + automatically, if needed. +- ``BB_CONTAINER_IMPORT``: Path where to input images from into the registry. + By default we load from ``./containers/export``. +- ``BB_CONTAINER_FROM_SOURCE``: Determine, if we should use benchbuild from the + current source checkout, or from pip. +- ``BB_CONTAINER_ROOT``: Where we store our image layers. This is the image + registry. Cannot be stored on filesystems that do not support subuid/-gid + mapping, e.g. NFS. + The default location is ``./containers/lib``. +- ``BB_CONTAINER_RUNROOT``: Where we store temporary image layers of running + containers. See ``BB_CONTAINER_ROOT`` for restrictions. + The default location is: ``./containers/run``. +- ``BB_CONTAINER_RUNTIME``: Podman can use any standard OCI-container runtime to + launch containers. We use [crun](https://github.com/containers/crun) by + default. Depending on your system, this one has already been installed with + ``podman``. + The default runtime is: ``/usr/bin/crun`` +- ``BB_CONTAINER_MOUNTS``: A list of mountpoint definitions that should be added + to all containers. With this you can add arbitrary tools into all containers. + Default: ``[]`` + +## Definition + +A project that wants to use a container image needs to define it in the +``CONTAINER`` attribute it using our declarative API provided by +``benchbuild.environments.domain.declarative``. + +``` +from benchbuild.environments.domain.declarative import ContainerImage + +class Testproject(Project): + CONTAINER = ContainerImage().from_('benchbuild:alpine') +``` + +The available set of commands follows the structure of a ``Dockerfile``. + +## Runtime requirements + +For containers to work properly, you need a few systems set up beforehand. + +### Buildah + +Image construction requires the [Buildah](https://buildah.io) tool. All image +construction tasks are formulated as buildah command calls in the backend. + +Buildah is supported up to version 1.19.8. + +### Podman + +Container construction and execution is handed off to [Podman](https://podman.io). +Podman provides rootless containers and does not requires the execution of a +daemon process. However, you need to setup your user namespace properly to allow +mapping of subordinate uids/gids. Otherwise, podman will not be able to map +users other than the root user to filesystem permissions inside the container. + +Please refer to podman's documentation on how to setup podman properly on your +system. + +Podman is supported up to version 2.2.1 + +## Module: benchbuild.container + +```{eval-rst} +.. automodule:: benchbuild.container + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: benchbuild.environments.domain.declarative + +```{eval-rst} +.. automodule:: benchbuild.environments.domain.declarative + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: benchbuild.environments.domain.model + +```{eval-rst} +.. automodule:: benchbuild.environments.domain.model + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: benchbuild.environments.domain.commands + +```{eval-rst} +.. automodule:: benchbuild.environments.domain.commands + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/branch/f-QoLImprovements/_sources/basics/index.md.txt b/branch/f-QoLImprovements/_sources/basics/index.md.txt new file mode 100644 index 000000000..23e728dba --- /dev/null +++ b/branch/f-QoLImprovements/_sources/basics/index.md.txt @@ -0,0 +1,49 @@ +# Installation + +The installation instructions are tested against Ubuntu 20.04 for Python 3.7 and Python 3.8. The particular commands required for installation depend on your setup. +The dependencies below are not always mandatory, if they are not used. + +## Requirements + +Dependency | Minimum Version | Notes +-------------|-----------------|---------------------------- +Python | 3.7 | +libpq | 9.6 | Required by psycopg2. +libfuse | 2.9.9 | If uchroot is used. +unionfs-fuse | 1.0 | If unionfs support is used. +slurm-llnl | 18.08 | If slurm support is used. + + +### PostgreSQL + +The library dependency ``libpq`` is always need right now, because we make use of psycopg2 features internally. It is planned to get rid of this dependency in the future. +### FUSE + +BenchBuild can make use of ``unionfs`` and ``libfuse``. This is often used in conjunction with a tool named ``uchroot`` which provides legacy support for user-space containers. +This will be obsolete as soon as ``podman``/``buildah`` based OCI container support is considered stable. + +### SLURM + +The cluster management software ``slurm`` is only required by 'name', i.e., we have to be able to import the binaries as python objects in benchbuild. As an alternative to installing ``slurm`` on your machine, you can always provide symlinks to ``/bin/true`` to the commands ``sbatch`` and ``srun``. + +The minimum version should signal the minimum features set expected by BenchBuild when generating a ``slurm`` batch script. + +## Benchbuild + +BenchBuild is released via pip and can be installed on your system as follows: + +``` bash +pip install benchbuild +``` + +If you want to isolate BenchBuild from the rest of your system packages, you can install it in a dedicated virtual environment. + +``` bash +virtualenv -ppython3 +source /bin/activate +pip3 install benchbuild +``` + +### Bootstrapping + +BenchBuild provides a bootstrap procedure that checks a few key binaries on your system and tries to assist you in installation of any necessary binaries. diff --git a/branch/f-QoLImprovements/_sources/concepts/command.md.txt b/branch/f-QoLImprovements/_sources/concepts/command.md.txt new file mode 100644 index 000000000..87fa17a2a --- /dev/null +++ b/branch/f-QoLImprovements/_sources/concepts/command.md.txt @@ -0,0 +1,59 @@ +# Commands + +BenchBuild provides an abstraction for binaries that are provided by a project, +after compilation. These ``Command`` objects carry the path to the binary, +customizable output paramters and support for dynamic tokens inside the path +generation. + +Besides these features, a command behaves identical to any other binary +command that you make use of inside BenchBuild, e.g., ``benchbuild.utils.cmd``. + +## Usage inside Projects + +For now, you make use of BenchBuild's commands inside a project's ``WORKLOADS`` +attribute. Let's have a look at the following example: + +``` +from benchbuild import Project +from benchbuild.command import Command, WorkloadSet, SourceRoot + +class MyProject(Project): + ... + SOURCE = [ + Git( + remote="https://github.com/myproject.git", + local="myproject.git", + limit=1, + refspec="HEAD" + ] + + WORKLOADS = { + WorkloadSet("compression"): [ + Command(SourceRoot("myproject.git") / "myprj") + ] + } +``` + +Here we have a ``Command`` that belongs to the ``WorkloadSet`` with the name +``compression`` that points to the binary ``myprj`` inside the project's +source directory of the git source ``myproject.git``. What concrete path +this will be is only known after this project has been instanced inside +an experiment and is not known before. + +This is done using tokens inside the commands' path representation. One +example of an available token is the above ``SourceRoot``. + +## Tokens + +BenchBuild offers project authors a way to tokenize path components for +commands. These can be used to refer to a project's root directory or +source directory in a generic way. + +## Module: command + +```{eval-rst} +.. automodule:: benchbuild.command + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/branch/f-QoLImprovements/_sources/concepts/environments.md.txt b/branch/f-QoLImprovements/_sources/concepts/environments.md.txt new file mode 100644 index 000000000..fa34659f8 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/concepts/environments.md.txt @@ -0,0 +1 @@ +# Environment diff --git a/branch/f-QoLImprovements/_sources/concepts/experiments.md.txt b/branch/f-QoLImprovements/_sources/concepts/experiments.md.txt new file mode 100644 index 000000000..9e6d63be1 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/concepts/experiments.md.txt @@ -0,0 +1,3 @@ +# Experiment + +TODO. diff --git a/branch/f-QoLImprovements/_sources/concepts/projects.md.txt b/branch/f-QoLImprovements/_sources/concepts/projects.md.txt new file mode 100644 index 000000000..de7b96884 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/concepts/projects.md.txt @@ -0,0 +1,3 @@ +# Project + +TODO. diff --git a/branch/f-QoLImprovements/_sources/concepts/source.md.txt b/branch/f-QoLImprovements/_sources/concepts/source.md.txt new file mode 100644 index 000000000..edf9a57e5 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/concepts/source.md.txt @@ -0,0 +1,46 @@ +# Source + +## Base + +```{eval-rst} +.. automodule:: benchbuild.source.base + :members: + :undoc-members: + :show-inheritance: +``` + +## Git + +```{eval-rst} +.. automodule:: benchbuild.source.git + :members: + :undoc-members: + :show-inheritance: +``` + +## HTTP + +```{eval-rst} +.. automodule:: benchbuild.source.http + :members: + :undoc-members: + :show-inheritance: +``` + +## RSync + +```{eval-rst} +.. automodule:: benchbuild.source.rsync + :members: + :undoc-members: + :show-inheritance: +``` + +## Module: source + +```{eval-rst} +.. automodule:: benchbuild.source + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/branch/f-QoLImprovements/_sources/index.rst.txt b/branch/f-QoLImprovements/_sources/index.rst.txt new file mode 100644 index 000000000..9fcef7096 --- /dev/null +++ b/branch/f-QoLImprovements/_sources/index.rst.txt @@ -0,0 +1,31 @@ +.. bencbuild documentation master file, created by + sphinx-quickstart on Tue Mar 28 01:42:59 2023. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to bencbuild's documentation! +===================================== + +.. toctree:: + :caption: Contents: + + about.md + basics/index.md + basics/configuration.md + basics/containers.md + basics/actions.md + concepts/command.md + concepts/source.md + concepts/environments.md + concepts/projects.md + concepts/experiments.md + advanced/index.md + advanced/cli.md + CHANGELOG.md + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/branch/f-QoLImprovements/_static/basic.css b/branch/f-QoLImprovements/_static/basic.css new file mode 100644 index 000000000..f316efcb4 --- /dev/null +++ b/branch/f-QoLImprovements/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/branch/f-QoLImprovements/_static/doctools.js b/branch/f-QoLImprovements/_static/doctools.js new file mode 100644 index 000000000..4d67807d1 --- /dev/null +++ b/branch/f-QoLImprovements/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/branch/f-QoLImprovements/_static/documentation_options.js b/branch/f-QoLImprovements/_static/documentation_options.js new file mode 100644 index 000000000..4f1436c17 --- /dev/null +++ b/branch/f-QoLImprovements/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '6.9.dev8+g85c5ced8', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'dirhtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/branch/f-QoLImprovements/_static/file.png b/branch/f-QoLImprovements/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/branch/f-QoLImprovements/_static/file.png differ diff --git a/branch/f-QoLImprovements/_static/language_data.js b/branch/f-QoLImprovements/_static/language_data.js new file mode 100644 index 000000000..367b8ed81 --- /dev/null +++ b/branch/f-QoLImprovements/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/branch/f-QoLImprovements/_static/minus.png b/branch/f-QoLImprovements/_static/minus.png new file mode 100644 index 000000000..d96755fda Binary files /dev/null and b/branch/f-QoLImprovements/_static/minus.png differ diff --git a/branch/f-QoLImprovements/_static/plus.png b/branch/f-QoLImprovements/_static/plus.png new file mode 100644 index 000000000..7107cec93 Binary files /dev/null and b/branch/f-QoLImprovements/_static/plus.png differ diff --git a/branch/f-QoLImprovements/_static/pygments.css b/branch/f-QoLImprovements/_static/pygments.css new file mode 100644 index 000000000..0e1cdf3f3 --- /dev/null +++ b/branch/f-QoLImprovements/_static/pygments.css @@ -0,0 +1,85 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #49483e } +.highlight { background: #272822; color: #f8f8f2 } +.highlight .c { color: #959077 } /* Comment */ +.highlight .err { color: #ed007e; background-color: #1e0010 } /* Error */ +.highlight .esc { color: #f8f8f2 } /* Escape */ +.highlight .g { color: #f8f8f2 } /* Generic */ +.highlight .k { color: #66d9ef } /* Keyword */ +.highlight .l { color: #ae81ff } /* Literal */ +.highlight .n { color: #f8f8f2 } /* Name */ +.highlight .o { color: #ff4689 } /* Operator */ +.highlight .x { color: #f8f8f2 } /* Other */ +.highlight .p { color: #f8f8f2 } /* Punctuation */ +.highlight .ch { color: #959077 } /* Comment.Hashbang */ +.highlight .cm { color: #959077 } /* Comment.Multiline */ +.highlight .cp { color: #959077 } /* Comment.Preproc */ +.highlight .cpf { color: #959077 } /* Comment.PreprocFile */ +.highlight .c1 { color: #959077 } /* Comment.Single */ +.highlight .cs { color: #959077 } /* Comment.Special */ +.highlight .gd { color: #ff4689 } /* Generic.Deleted */ +.highlight .ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #f8f8f2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #f8f8f2 } /* Generic.Error */ +.highlight .gh { color: #f8f8f2 } /* Generic.Heading */ +.highlight .gi { color: #a6e22e } /* Generic.Inserted */ +.highlight .go { color: #66d9ef } /* Generic.Output */ +.highlight .gp { color: #ff4689; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #959077 } /* Generic.Subheading */ +.highlight .gt { color: #f8f8f2 } /* Generic.Traceback */ +.highlight .kc { color: #66d9ef } /* Keyword.Constant */ +.highlight .kd { color: #66d9ef } /* Keyword.Declaration */ +.highlight .kn { color: #ff4689 } /* Keyword.Namespace */ +.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ +.highlight .kr { color: #66d9ef } /* Keyword.Reserved */ +.highlight .kt { color: #66d9ef } /* Keyword.Type */ +.highlight .ld { color: #e6db74 } /* Literal.Date */ +.highlight .m { color: #ae81ff } /* Literal.Number */ +.highlight .s { color: #e6db74 } /* Literal.String */ +.highlight .na { color: #a6e22e } /* Name.Attribute */ +.highlight .nb { color: #f8f8f2 } /* Name.Builtin */ +.highlight .nc { color: #a6e22e } /* Name.Class */ +.highlight .no { color: #66d9ef } /* Name.Constant */ +.highlight .nd { color: #a6e22e } /* Name.Decorator */ +.highlight .ni { color: #f8f8f2 } /* Name.Entity */ +.highlight .ne { color: #a6e22e } /* Name.Exception */ +.highlight .nf { color: #a6e22e } /* Name.Function */ +.highlight .nl { color: #f8f8f2 } /* Name.Label */ +.highlight .nn { color: #f8f8f2 } /* Name.Namespace */ +.highlight .nx { color: #a6e22e } /* Name.Other */ +.highlight .py { color: #f8f8f2 } /* Name.Property */ +.highlight .nt { color: #ff4689 } /* Name.Tag */ +.highlight .nv { color: #f8f8f2 } /* Name.Variable */ +.highlight .ow { color: #ff4689 } /* Operator.Word */ +.highlight .pm { color: #f8f8f2 } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f2 } /* Text.Whitespace */ +.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ +.highlight .mf { color: #ae81ff } /* Literal.Number.Float */ +.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ +.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ +.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ +.highlight .sa { color: #e6db74 } /* Literal.String.Affix */ +.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ +.highlight .sc { color: #e6db74 } /* Literal.String.Char */ +.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ +.highlight .sd { color: #e6db74 } /* Literal.String.Doc */ +.highlight .s2 { color: #e6db74 } /* Literal.String.Double */ +.highlight .se { color: #ae81ff } /* Literal.String.Escape */ +.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ +.highlight .si { color: #e6db74 } /* Literal.String.Interpol */ +.highlight .sx { color: #e6db74 } /* Literal.String.Other */ +.highlight .sr { color: #e6db74 } /* Literal.String.Regex */ +.highlight .s1 { color: #e6db74 } /* Literal.String.Single */ +.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ +.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #a6e22e } /* Name.Function.Magic */ +.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ +.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ +.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ +.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ +.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/branch/f-QoLImprovements/_static/searchtools.js b/branch/f-QoLImprovements/_static/searchtools.js new file mode 100644 index 000000000..92da3f8b2 --- /dev/null +++ b/branch/f-QoLImprovements/_static/searchtools.js @@ -0,0 +1,619 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlinks", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/branch/f-QoLImprovements/_static/sphinx_highlight.js b/branch/f-QoLImprovements/_static/sphinx_highlight.js new file mode 100644 index 000000000..8a96c69a1 --- /dev/null +++ b/branch/f-QoLImprovements/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/branch/f-QoLImprovements/_static/theme.css b/branch/f-QoLImprovements/_static/theme.css new file mode 100644 index 000000000..16c9136ba --- /dev/null +++ b/branch/f-QoLImprovements/_static/theme.css @@ -0,0 +1 @@ +.theme-default-content code{color:var(--text-color-l20);padding:.25rem .5rem;margin:0;font-size:.85em;border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:var(--code-bg-color);border-radius:6px;overflow:auto}.theme-default-content pre code,.theme-default-content pre[class*=language-] code{color:var(--grey3);padding:0;background-color:transparent!important;border-radius:0}div[class*=language-]{position:relative;background-color:var(--code-bg-color);border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:#000000a8}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;background-color:var(--code-bg-color)}div[class~="language-$codeLang"]:before{content:"$codeLang"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.theme-light .theme-default-content code{background-color:var(--grey14)}.theme-light code[class*=language-],.theme-light pre[class*=language-]{color:#000;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}.theme-light pre[class*=language-]::-moz-selection,.theme-light pre[class*=language-] ::-moz-selection,.theme-light code[class*=language-]::-moz-selection,.theme-light code[class*=language-] ::-moz-selection{background:#b3d4fc}.theme-light pre[class*=language-]::selection,.theme-light pre[class*=language-] ::selection,.theme-light code[class*=language-]::selection,.theme-light code[class*=language-] ::selection{background:#b3d4fc}.theme-light pre[class*=language-]{margin:.5em 0;overflow:auto}.theme-light :not(pre)>code[class*=language-],.theme-light pre[class*=language-]{background:#f5f2f0}.theme-light :not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.theme-light .token.comment,.theme-light .token.prolog,.theme-light .token.doctype,.theme-light .token.cdata{color:#708090}.theme-light .token.punctuation{color:#5f6364}.theme-light .token.property,.theme-light .token.tag,.theme-light .token.boolean,.theme-light .token.number,.theme-light .token.function-name,.theme-light .token.constant,.theme-light .token.symbol,.theme-light .token.deleted{color:#c92c2c}.theme-light .token.selector,.theme-light .token.attr-name,.theme-light .token.string,.theme-light .token.char,.theme-light .token.function,.theme-light .token.builtin,.theme-light .token.inserted{color:#2f9c0a}.theme-light .token.operator,.theme-light .token.entity,.theme-light .token.url,.theme-light .token.variable{color:#a67f59;background:#ffffff80}.theme-light .token.atrule,.theme-light .token.attr-value,.theme-light .token.keyword,.theme-light .token.class-name{color:#1990b8}.theme-light .token.regex,.theme-light .token.important{color:#e90}.theme-light .language-css .token.string,.theme-light .style .token.string{color:#a67f59;background:#ffffff80}.theme-light .token.important{font-weight:400}.theme-light .token.bold{font-weight:700}.theme-light .token.italic{font-style:italic}.theme-light .token.entity{cursor:help}.theme-light .token.namespace{opacity:.7}.theme-light div[class*=language-] .highlight-lines .highlighted{background-color:#d7e9f7}.theme-light div[class*=language-] pre,.theme-light div[class*=language-] pre[class*=language-]{background:transparent}.theme-light div[class*=language-]:before{color:#0006}.theme-light div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{background-color:#d7e9f7}.theme-light div[class*=language-].line-numbers-mode .line-numbers-wrapper{color:#0000004d}.theme-light div[class*=language-].line-numbers-mode:after{border-right:1px solid #c2def3}.theme-dark .theme-default-content code{background-color:var(--grey12)}.theme-dark code[class*=language-],.theme-dark pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}.theme-dark pre[class*=language-]{margin:.5em 0;overflow:auto}.theme-dark :not(pre)>code[class*=language-],.theme-dark pre[class*=language-]{background:#2d2d2d}.theme-dark :not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.theme-dark .token.comment,.theme-dark .token.block-comment,.theme-dark .token.prolog,.theme-dark .token.doctype,.theme-dark .token.cdata{color:#999}.theme-dark .token.punctuation{color:#ccc}.theme-dark .token.tag,.theme-dark .token.attr-name,.theme-dark .token.namespace,.theme-dark .token.deleted{color:#e2777a}.theme-dark .token.function-name{color:#6196cc}.theme-dark .token.boolean,.theme-dark .token.number,.theme-dark .token.function{color:#f08d49}.theme-dark .token.property,.theme-dark .token.class-name,.theme-dark .token.constant,.theme-dark .token.symbol{color:#f8c555}.theme-dark .token.selector,.theme-dark .token.important,.theme-dark .token.atrule,.theme-dark .token.keyword,.theme-dark .token.builtin{color:#cc99cd}.theme-dark .token.string,.theme-dark .token.char,.theme-dark .token.attr-value,.theme-dark .token.regex,.theme-dark .token.variable{color:#7ec699}.theme-dark .token.operator,.theme-dark .token.entity,.theme-dark .token.url{color:#67cdcc}.theme-dark .token.important,.theme-dark .token.bold{font-weight:700}.theme-dark .token.italic{font-style:italic}.theme-dark .token.entity{cursor:help}.theme-dark .token.inserted{color:green}.theme-dark div[class*=language-] .highlight-lines .highlighted{background-color:#1d2128}.theme-dark div[class*=language-] pre,.theme-dark div[class*=language-] pre[class*=language-]{background:transparent}.theme-dark div[class*=language-]:before{color:#fff6}.theme-dark div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{background-color:#1d2128}.theme-dark div[class*=language-].line-numbers-mode .line-numbers-wrapper{color:#ffffff4d}.theme-dark div[class*=language-].line-numbers-mode:after{border-right:1px solid #191d22}.theme-light{--text-color: #2c3e50;--background-color: #fff;--border-color: #eaecef;--code-bg-color: #ecf4fa;--arrow-bg-color: #ccc;--box-shadow-color: #f0f1f2;--card-shadow-color: $cardShadowColor;--text-color-l10: #3a5169;--text-color-l20: #476582;--text-color-l25: #4e6e8e;--text-color-l40: #6a8bad;--black: #000;--dark-grey: #666;--light-grey: #999;--white: #fff;--grey3: #333;--grey12: #bbb;--grey14: #eee}.theme-dark{--text-color: #9e9e9e;--background-color: #1e1e1e;--border-color: #302d28;--code-bg-color: #282c34;--arrow-bg-color: #333;--box-shadow-color: #0f0e0d;--card-shadow-color: $nightCardShadowColor;--text-color-l10: #a8a8a8;--text-color-l20: #b1b1b1;--text-color-l25: #b6b6b6;--text-color-l40: #c5c5c5;--black: #fff;--dark-grey: #999;--light-grey: #666;--white: #000;--grey3: #ccc;--grey12: #333;--grey14: #111}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.tip,.custom-block.warning,.custom-block.danger{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{border-color:#42b983}.custom-block.warning{border-color:#e7c000}.custom-block.danger{border-color:#c00}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.theme-light .custom-block.tip{background-color:#f3f5f7}.theme-light .custom-block.warning{background-color:#ffe5644d;color:#6b5900}.theme-light .custom-block.warning .custom-block-title{color:#b29400}.theme-light .custom-block.warning a{color:var(--text-color)}.theme-light .custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.theme-light .custom-block.danger .custom-block-title{color:#900}.theme-light .custom-block.danger a{color:var(--text-color)}.theme-light .custom-block.details{background-color:#eee}.theme-dark .custom-block.tip,.theme-dark .custom-block.warning,.theme-dark .custom-block.danger,.theme-dark .custom-block.details{background-color:#404040}.theme-dark .custom-block.tip a,.theme-dark .custom-block.warning a,.theme-dark .custom-block.danger a,.theme-dark .custom-block.details a{color:#3eaf7c}.theme-dark .custom-block.warning{color:#b29400}.theme-dark .custom-block.warning .custom-block-title{color:#d5b100}.theme-dark .custom-block.danger{color:#b30000}.theme-dark .custom-block.danger .custom-block-title{color:#c00}.theme-dark .custom-block.details{color:var(--text-color)}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:6px solid var(--arrow-bg-color)}.arrow.down{border-left:4px solid transparent;border-right:4px solid transparent;border-top:6px solid var(--arrow-bg-color)}.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:6px solid var(--arrow-bg-color)}.arrow.left{border-top:4px solid transparent;border-bottom:4px solid transparent;border-right:6px solid var(--arrow-bg-color)}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width: 959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width: 419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}html,body{padding:0;margin:0;background-color:var(--background-color)}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:var(--text-color);-webkit-tap-highlight-color:transparent}.page{padding-left:20rem}.navbar{position:fixed;z-index:20;top:0;left:0;right:0;height:3.6rem;background-color:var(--background-color);box-sizing:border-box;border-bottom:1px solid var(--box-shadow-color)}.sidebar-mask{position:fixed;z-index:9;top:0;left:0;width:100vw;height:100vh;display:none}.vp-sidebar{font-size:16px;background-color:var(--background-color);width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid var(--border-color);overflow-y:auto}.theme-default-content:not(.custom)>*:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;color:#3eaf7c;text-decoration:none}p a code{font-weight:400;color:#3eaf7c}kbd{background:#eee;border:solid .15rem #ddd;border-bottom:solid .25rem #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ul,ol{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+pre,.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+.custom-block{margin-top:2rem}h1:focus .header-anchor,h2:focus .header-anchor,h3:focus .header-anchor,h4:focus .header-anchor,h5:focus .header-anchor,h6:focus .header-anchor,h1:hover .header-anchor,h2:hover .header-anchor,h3:hover .header-anchor,h4:hover .header-anchor,h5:hover .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid var(--border-color)}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}code,kbd,.line-number{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}p,ul,ol{line-height:1.7}hr{border:0;border-top:1px solid var(--border-color)}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}th,td{border:1px solid var(--grey14);padding:.6em 1em}.theme-dark tr:nth-child(2n){background-color:#252322}.theme-dark th,.theme-dark td{border:1px solid var(--grey12)}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .vp-sidebar{top:0}@media (min-width: 720px){.theme-container.no-sidebar .vp-sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}::-webkit-scrollbar,Mister-Hope marked this conversation as resolved.{width:6px;height:6px}::-webkit-scrollbar-track-piece{background-color:#0000001a;-webkit-border-radius:6px}::-webkit-scrollbar-thumb:vertical{height:6px;background-color:#3eaf7c;-webkit-border-radius:6px}::-webkit-scrollbar-thumb:horizontal{width:6px;background-color:#3eaf7c;-webkit-border-radius:6px}@media (max-width: 959px){.vp-sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width: 719px){.vp-sidebar{top:0;padding-top:3.6rem;transform:translate(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .vp-sidebar{transform:translate(0)}.theme-container.no-navbar .vp-sidebar{padding-top:0}}@media (max-width: 419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}.page{margin-left:10px;margin-right:10px}table p,dd p,li p{margin:0}.content{max-width:840px;margin:0 auto}.content pre{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:#1b1f230d;border-radius:3px}.content .footnote-reference,.content .label,.content .reference{scroll-margin-top:3.6rem}.content a:focus{outline:none}.content:not(.custom){max-width:840px}.content section{scroll-margin-top:4.1rem;margin-bottom:0}.content section:hover .headerlink{opacity:1}h1:hover a.headerlink:after,h2:hover a.headerlink:after,h3:hover a.headerlink:after,h4:hover a.headerlink:after,h5:hover a.headerlink:after,h6:hover a.headerlink:after{visibility:visible;content:"#"}a.headerlink{font-size:.85em;visibility:hidden}a.headerlink:hover{text-decoration:none}ul.page-nav{list-style:none}ul.page-nav li{display:inline-block}.body-header{display:flex}.body-header ul.page-nav{flex-grow:1;list-style:none;list-style-position:inside;text-align:right;margin-right:30px}.body-header ul.page-nav li+li:before{content:"|";padding:0 1em}ul.breadcrumbs{list-style:none}ul.breadcrumbs li{display:inline-block;margin-right:5px}.toc-backref{color:inherit}.contents.topic p.topic-title{display:none}.contents.topic{margin-bottom:3em}aside.sidebar{margin:0 0 .5em 1em;border:1px solid #ddb;padding:7px;background-color:#ffe;width:40%;float:right;clear:right;overflow-x:auto}p.sidebar-title{font-weight:700}div.admonition,div.topic,blockquote{clear:left}pre,div[class*=highlight-]{clear:both}.toctree-wrapper .caption{font-weight:600;line-height:1.25;font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}.footer{clear:both;min-height:2rem;padding-top:1rem;overflow:auto;color:gray;font-size:small;line-height:1.5rem}.content .highlight{border-radius:6px}.content .highlight pre{background-color:inherit}.content .highlighted{background-color:#fbe54e;font-weight:700;padding:0 4px}.admonition{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0;background-color:#e2e2e2;border-color:#787878}.admonition .admonition-title{font-weight:600;margin-bottom:-.4rem}.admonition.tip,.admonition.hint{background-color:#f3f5f7;border-color:#42b983}.admonition.important,.admonition.note{background-color:#e5f1fb;border-color:#5faaea}.admonition.warning,.admonition.caution{background-color:#ffe5644d;border-color:#e7c000;color:#6b5900}.admonition.warning .custom-block-title,.admonition.caution .custom-block-title{color:#b29400}.admonition.warning a,.admonition.caution a{color:var(--text-color)}.admonition.danger,.admonition.error{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.admonition.danger .custom-block-title,.admonition.error .custom-block-title{color:#900}.admonition.danger a,.admonition.error a{color:var(--text-color)}.line-block{display:block;margin-top:1em;margin-bottom:1em}.line-block .line-block{margin-top:0;margin-bottom:0;margin-left:1.5em}.guilabel,.menuselection{font-family:sans-serif}.accelerator{text-decoration:underline}.classifier{font-style:oblique}.classifier:before{font-style:normal;margin:.5em;content:":"}abbr,acronym{border-bottom:dotted 1px;cursor:help}div.topic{border:1px solid #ccc;padding:7px;margin:10px 0;background-color:var(--bg-color)}p.topic-title{font-size:1.1em;font-weight:700;margin-top:10px}a.brackets:before,span.brackets>a:before{content:"["}a.brackets:after,span.brackets>a:after{content:"]"}p.rubric{margin-top:30px;font-weight:700}code,pre,kbd,samp,.pre{font-family:SFMono-Regular,Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace}@media (max-width: 1200px){pre{font-size:.95em}}blockquote{font-size:inherit}blockquote h2{margin-left:1em}.sig .property{color:#4d6a86;padding-right:.25rem}.sig-name.descname{font-size:1.2em;font-weight:700;padding:0 0 3px}.sig-param,.sig-paren{margin-left:.3em}dt{line-height:1.5em;margin-top:1em;font-weight:700}dt.field-odd,dt.field-even,p.rubric{font-size:1.2em;font-weight:700;color:#4d6a86}dd{margin-inline-start:10px}dd.field-odd p strong{margin-left:1em}dl.method,dl.function{margin-top:1em;margin-bottom:2em}.viewcode-link{margin-left:1em;color:#9ad8bc}dl.field-list{display:grid;grid-template-columns:fit-content(30%) auto}dl.field-list dt{margin-top:0}dl.field-list dd{margin-bottom:1em}dl.field-list>dt{font-weight:700;word-break:break-word;padding-left:.5em;padding-right:5px}dl.field-list>dt:after{content:":"}dl.field-list>dd{padding-left:.5em;margin-top:0;margin-left:0;margin-bottom:0}dl{margin-bottom:15px}img.align-left,figure.align-left,.figure.align-left,object.align-left{clear:left;float:left;margin-right:1em}img.align-right,figure.align-right,.figure.align-right,object.align-right{clear:right;float:right;margin-left:1em}img.align-center,figure.align-center,.figure.align-center,object.align-center{display:block;margin-left:auto;margin-right:auto}img.align-default,figure.align-default,.figure.align-default{display:block;margin-left:auto;margin-right:auto}.align-left{text-align:left}.align-center,.align-default{text-align:center}.align-right{text-align:right}.content .section,.section{opacity:1!important}.icon.outbound{color:#aaa;display:inline-block}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width: $MQMobile){.sidebar-button{display:block}}.darkmode-switch{position:fixed;bottom:3rem;right:2rem;height:24px;display:flex}.darkmode-switch:hover{cursor:pointer}.darkmode-switch .item{padding:4px;line-height:1;border:1px solid #3eaf7c;border-left:none}.darkmode-switch .item:first-child{border-left:1px solid #3eaf7c}.darkmode-switch .item.day{border-top-left-radius:4px;border-bottom-left-radius:4px}.darkmode-switch .item.night{border-top-right-radius:4px;border-bottom-right-radius:4px}.darkmode-switch .item .icon{width:16px;height:16px;fill:#3eaf7c}.darkmode-switch .item.active{background-color:#3eaf7c}.darkmode-switch .item.active:hover{cursor:default}.darkmode-switch .item.active .icon{fill:var(--white)}.navbar{padding:.7rem 1.5rem;line-height:2.2rem;position:fixed}.navbar a,.navbar span,.navbar img{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:var(--text-color);position:relative}.navbar .links{font-size:.9rem;position:absolute;right:1.5rem;top:.7rem}@media (max-width: 719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.sidebar-button{display:block}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a:hover,.nav-links a.router-link-active{color:#3eaf7c}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .repo-link{margin-left:1.5rem}@media (max-width: 719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width: 719px){.nav-links a:hover,.nav-links a.router-link-active{color:var(--text-color)}.nav-item>a:not(.external):hover,.nav-item>a:not(.external).router-link-active{margin-bottom:-2px;border-bottom:2px solid #46bd87}}.vp-sidebar ul{padding:0;margin:0;list-style-type:none}.vp-sidebar a{display:inline-block}.vp-sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem}.vp-sidebar .nav-links a{font-weight:600}.vp-sidebar .nav-links .nav-item,.vp-sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.vp-sidebar .searchbox{font-weight:600;font-size:1.1em;line-height:1.5rem;padding:1rem 0 1.5rem .75rem;border-bottom:1px solid #eaecef}.vp-sidebar .sidebar-links{padding:1.5rem 0}@media (max-width: 719px){.vp-sidebar .nav-links{display:block}.vp-sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.vp-sidebar .sidebar-links{padding:1rem 0}}.sidebar-group:not(.first){margin-top:1em}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .caption{cursor:auto;color:inherit}.sidebar-group .caption{color:#999;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:0 1.5rem;margin-top:0;margin-bottom:.5rem}.sidebar-group .caption.open,.sidebar-group .caption:hover{color:inherit}.sidebar-group .caption .arrow{position:relative;top:-.12em;left:.5em}.sidebar-group .caption:.open .arrow{top:-.18em}.sidebar-group-items{transition:height .1s ease-out;overflow:hidden}.vp-sidebar .toctree-l1 ul{font-size:.95em}.vp-sidebar .toctree-l1 a,.vp-sidebar .toctree-l2 a{font-weight:400;display:inline-block;color:var(--text-color);line-height:1.4;width:100%;box-sizing:border-box;border-left:.5rem solid transparent}.vp-sidebar .toctree-l1 a.current,.vp-sidebar .toctree-l2 a.current{color:#3eaf7c;font-weight:600}.vp-sidebar .toctree-l1 a:hover,.vp-sidebar .toctree-l2 a:hover{color:#3eaf7c}.vp-sidebar .toctree-l1.current a{border-left:.5rem solid #86d4b1}.vp-sidebar .toctree-l1 a{padding:.35rem 1rem .35rem 1.25rem}.vp-sidebar .toctree-l1 a.current{border-left-color:#3eaf7c}.vp-sidebar .toctree-l2 a{padding:.25rem 1rem .25rem 1.75rem}.page-edit,.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width: 959px){.page-edit,.page-nav{padding:2rem}}@media (max-width: 419px){.page-edit,.page-nav{padding:1.5rem}}.page{padding-top:3.6rem;padding-bottom:2rem}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:var(--text-color, #2c3e50);margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:var(--text-color, #2c3e50)}.page-edit .last-updated .time{font-weight:400;color:#aaa}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}@media (max-width: 719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}} diff --git a/branch/f-QoLImprovements/_static/theme.js b/branch/f-QoLImprovements/_static/theme.js new file mode 100644 index 000000000..e3b3ce319 --- /dev/null +++ b/branch/f-QoLImprovements/_static/theme.js @@ -0,0 +1,38 @@ +(function(){"use strict";/** +* @vue/shared v3.4.21 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function $e(e,t){const n=new Set(e.split(","));return t?s=>n.has(s.toLowerCase()):s=>n.has(s)}const ie={},hn=[],ge=()=>{},ys=()=>!1,Dt=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),ki=e=>e.startsWith("onUpdate:"),ne=Object.assign,Ri=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},mf=Object.prototype.hasOwnProperty,se=(e,t)=>mf.call(e,t),V=Array.isArray,dn=e=>pn(e)==="[object Map]",Vt=e=>pn(e)==="[object Set]",bo=e=>pn(e)==="[object Date]",gf=e=>pn(e)==="[object RegExp]",W=e=>typeof e=="function",J=e=>typeof e=="string",Ye=e=>typeof e=="symbol",oe=e=>e!==null&&typeof e=="object",Mi=e=>(oe(e)||W(e))&&W(e.then)&&W(e.catch),So=Object.prototype.toString,pn=e=>So.call(e),yf=e=>pn(e).slice(8,-1),vo=e=>pn(e)==="[object Object]",Pi=e=>J(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,yt=$e(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),_f=$e("bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo"),_s=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},bf=/-(\w)/g,ue=_s(e=>e.replace(bf,(t,n)=>n?n.toUpperCase():"")),Sf=/\B([A-Z])/g,De=_s(e=>e.replace(Sf,"-$1").toLowerCase()),Bt=_s(e=>e.charAt(0).toUpperCase()+e.slice(1)),mn=_s(e=>e?`on${Bt(e)}`:""),Xe=(e,t)=>!Object.is(e,t),gn=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},Pn=e=>{const t=parseFloat(e);return isNaN(t)?e:t},Ss=e=>{const t=J(e)?Number(e):NaN;return isNaN(t)?e:t};let Eo;const Co=()=>Eo||(Eo=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}),vf=$e("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error");function Ln(e){if(V(e)){const t={};for(let n=0;n{if(n){const s=n.split(Cf);s.length>1&&(t[s[0].trim()]=s[1].trim())}}),t}function _t(e){let t="";if(J(e))t=e;else if(V(e))for(let n=0;nbt(n,t))}const Ff=e=>J(e)?e:e==null?"":V(e)||oe(e)&&(e.toString===So||!W(e.toString))?JSON.stringify(e,wo,2):String(e),wo=(e,t)=>t&&t.__v_isRef?wo(e,t.value):dn(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[s,i],r)=>(n[Li(s,r)+" =>"]=i,n),{})}:Vt(t)?{[`Set(${t.size})`]:[...t.values()].map(n=>Li(n))}:Ye(t)?Li(t):oe(t)&&!V(t)&&!vo(t)?String(t):t,Li=(e,t="")=>{var n;return Ye(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};/** +* @vue/reactivity v3.4.21 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let Ve;class Fi{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=Ve,!t&&Ve&&(this.index=(Ve.scopes||(Ve.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=Ve;try{return Ve=this,t()}finally{Ve=n}}}on(){Ve=this}off(){Ve=this.parent}stop(t){if(this._active){let n,s;for(n=0,s=this.effects.length;n=4))break}this._dirtyLevel===1&&(this._dirtyLevel=0),Et()}return this._dirtyLevel>=4}set dirty(t){this._dirtyLevel=t?4:0}run(){if(this._dirtyLevel=0,!this.active)return this.fn();let t=St,n=Ht;try{return St=!0,Ht=this,this._runnings++,xo(this),this.fn()}finally{Oo(this),this._runnings--,Ht=n,St=t}}stop(){var t;this.active&&(xo(this),Oo(this),(t=this.onStop)==null||t.call(this),this.active=!1)}}function Vf(e){return e.value}function xo(e){e._trackId++,e._depsLength=0}function Oo(e){if(e.deps.length>e._depsLength){for(let t=e._depsLength;t{n.dirty&&n.run()});t&&(ne(n,t),t.scope&&No(n,t.scope)),(!t||!t.lazy)&&n.run();const s=n.run.bind(n);return s.effect=n,s}function Hf(e){e.effect.stop()}let St=!0,$i=0;const Ro=[];function vt(){Ro.push(St),St=!1}function Et(){const e=Ro.pop();St=e===void 0?!0:e}function Di(){$i++}function Vi(){for($i--;!$i&&Bi.length;)Bi.shift()()}function Mo(e,t,n){if(t.get(e)!==e._trackId){t.set(e,e._trackId);const s=e.deps[e._depsLength];s!==t?(s&&ko(s,e),e.deps[e._depsLength++]=t):e._depsLength++}}const Bi=[];function Po(e,t,n){Di();for(const s of e.keys()){let i;s._dirtyLevel{const n=new Map;return n.cleanup=e,n.computed=t,n},Es=new WeakMap,Ut=Symbol(""),Hi=Symbol("");function Re(e,t,n){if(St&&Ht){let s=Es.get(e);s||Es.set(e,s=new Map);let i=s.get(n);i||s.set(n,i=Lo(()=>s.delete(n))),Mo(Ht,i)}}function at(e,t,n,s,i,r){const o=Es.get(e);if(!o)return;let l=[];if(t==="clear")l=[...o.values()];else if(n==="length"&&V(e)){const c=Number(s);o.forEach((a,u)=>{(u==="length"||!Ye(u)&&u>=c)&&l.push(a)})}else switch(n!==void 0&&l.push(o.get(n)),t){case"add":V(e)?Pi(n)&&l.push(o.get("length")):(l.push(o.get(Ut)),dn(e)&&l.push(o.get(Hi)));break;case"delete":V(e)||(l.push(o.get(Ut)),dn(e)&&l.push(o.get(Hi)));break;case"set":dn(e)&&l.push(o.get(Ut));break}Di();for(const c of l)c&&Po(c,4);Vi()}function Uf(e,t){var n;return(n=Es.get(e))==null?void 0:n.get(t)}const Kf=$e("__proto__,__v_isRef,__isVue"),Fo=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Ye)),$o=jf();function jf(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const s=Z(this);for(let r=0,o=this.length;r{e[t]=function(...n){vt(),Di();const s=Z(this)[t].apply(this,n);return Vi(),Et(),s}}),e}function qf(e){const t=Z(this);return Re(t,"has",e),t.hasOwnProperty(e)}class Do{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,s){const i=this._isReadonly,r=this._isShallow;if(n==="__v_isReactive")return!i;if(n==="__v_isReadonly")return i;if(n==="__v_isShallow")return r;if(n==="__v_raw")return s===(i?r?zo:Go:r?Wo:qo).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(s)?t:void 0;const o=V(t);if(!i){if(o&&se($o,n))return Reflect.get($o,n,s);if(n==="hasOwnProperty")return qf}const l=Reflect.get(t,n,s);return(Ye(n)?Fo.has(n):Kf(n))||(i||Re(t,"get",n),r)?l:Se(l)?o&&Pi(n)?l:l.value:oe(l)?i?Ki(l):Os(l):l}}class Vo extends Do{constructor(t=!1){super(!1,t)}set(t,n,s,i){let r=t[n];if(!this._isShallow){const c=jt(r);if(!Fn(s)&&!jt(s)&&(r=Z(r),s=Z(s)),!V(t)&&Se(r)&&!Se(s))return c?!1:(r.value=s,!0)}const o=V(t)&&Pi(n)?Number(n)e,Cs=e=>Reflect.getPrototypeOf(e);function Ts(e,t,n=!1,s=!1){e=e.__v_raw;const i=Z(e),r=Z(t);n||(Xe(t,r)&&Re(i,"get",t),Re(i,"get",r));const{has:o}=Cs(i),l=s?Ui:n?Wi:$n;if(o.call(i,t))return l(e.get(t));if(o.call(i,r))return l(e.get(r));e!==i&&e.get(t)}function As(e,t=!1){const n=this.__v_raw,s=Z(n),i=Z(e);return t||(Xe(e,i)&&Re(s,"has",e),Re(s,"has",i)),e===i?n.has(e):n.has(e)||n.has(i)}function ws(e,t=!1){return e=e.__v_raw,!t&&Re(Z(e),"iterate",Ut),Reflect.get(e,"size",e)}function Ho(e){e=Z(e);const t=Z(this);return Cs(t).has.call(t,e)||(t.add(e),at(t,"add",e,e)),this}function Uo(e,t){t=Z(t);const n=Z(this),{has:s,get:i}=Cs(n);let r=s.call(n,e);r||(e=Z(e),r=s.call(n,e));const o=i.call(n,e);return n.set(e,t),r?Xe(t,o)&&at(n,"set",e,t):at(n,"add",e,t),this}function Ko(e){const t=Z(this),{has:n,get:s}=Cs(t);let i=n.call(t,e);i||(e=Z(e),i=n.call(t,e)),s&&s.call(t,e);const r=t.delete(e);return i&&at(t,"delete",e,void 0),r}function jo(){const e=Z(this),t=e.size!==0,n=e.clear();return t&&at(e,"clear",void 0,void 0),n}function Ns(e,t){return function(s,i){const r=this,o=r.__v_raw,l=Z(o),c=t?Ui:e?Wi:$n;return!e&&Re(l,"iterate",Ut),o.forEach((a,u)=>s.call(i,c(a),c(u),r))}}function Is(e,t,n){return function(...s){const i=this.__v_raw,r=Z(i),o=dn(r),l=e==="entries"||e===Symbol.iterator&&o,c=e==="keys"&&o,a=i[e](...s),u=n?Ui:t?Wi:$n;return!t&&Re(r,"iterate",c?Hi:Ut),{next(){const{value:f,done:d}=a.next();return d?{value:f,done:d}:{value:l?[u(f[0]),u(f[1])]:u(f),done:d}},[Symbol.iterator](){return this}}}}function Ct(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function Yf(){const e={get(r){return Ts(this,r)},get size(){return ws(this)},has:As,add:Ho,set:Uo,delete:Ko,clear:jo,forEach:Ns(!1,!1)},t={get(r){return Ts(this,r,!1,!0)},get size(){return ws(this)},has:As,add:Ho,set:Uo,delete:Ko,clear:jo,forEach:Ns(!1,!0)},n={get(r){return Ts(this,r,!0)},get size(){return ws(this,!0)},has(r){return As.call(this,r,!0)},add:Ct("add"),set:Ct("set"),delete:Ct("delete"),clear:Ct("clear"),forEach:Ns(!0,!1)},s={get(r){return Ts(this,r,!0,!0)},get size(){return ws(this,!0)},has(r){return As.call(this,r,!0)},add:Ct("add"),set:Ct("set"),delete:Ct("delete"),clear:Ct("clear"),forEach:Ns(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(r=>{e[r]=Is(r,!1,!1),n[r]=Is(r,!0,!1),t[r]=Is(r,!1,!0),s[r]=Is(r,!0,!0)}),[e,n,t,s]}const[Xf,Zf,Qf,eu]=Yf();function xs(e,t){const n=t?e?eu:Qf:e?Zf:Xf;return(s,i,r)=>i==="__v_isReactive"?!e:i==="__v_isReadonly"?e:i==="__v_raw"?s:Reflect.get(se(n,i)&&i in s?n:s,i,r)}const tu={get:xs(!1,!1)},nu={get:xs(!1,!0)},su={get:xs(!0,!1)},iu={get:xs(!0,!0)},qo=new WeakMap,Wo=new WeakMap,Go=new WeakMap,zo=new WeakMap;function ru(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function ou(e){return e.__v_skip||!Object.isExtensible(e)?0:ru(yf(e))}function Os(e){return jt(e)?e:ks(e,!1,Wf,tu,qo)}function Jo(e){return ks(e,!1,zf,nu,Wo)}function Ki(e){return ks(e,!0,Gf,su,Go)}function lu(e){return ks(e,!0,Jf,iu,zo)}function ks(e,t,n,s,i){if(!oe(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const r=i.get(e);if(r)return r;const o=ou(e);if(o===0)return e;const l=new Proxy(e,o===2?s:n);return i.set(e,l),l}function Kt(e){return jt(e)?Kt(e.__v_raw):!!(e&&e.__v_isReactive)}function jt(e){return!!(e&&e.__v_isReadonly)}function Fn(e){return!!(e&&e.__v_isShallow)}function ji(e){return Kt(e)||jt(e)}function Z(e){const t=e&&e.__v_raw;return t?Z(t):e}function qi(e){return Object.isExtensible(e)&&bs(e,"__v_skip",!0),e}const $n=e=>oe(e)?Os(e):e,Wi=e=>oe(e)?Ki(e):e;class Yo{constructor(t,n,s,i){this.getter=t,this._setter=n,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this.effect=new yn(()=>t(this._value),()=>_n(this,this.effect._dirtyLevel===2?2:3)),this.effect.computed=this,this.effect.active=this._cacheable=!i,this.__v_isReadonly=s}get value(){const t=Z(this);return(!t._cacheable||t.effect.dirty)&&Xe(t._value,t._value=t.effect.run())&&_n(t,4),Gi(t),t.effect._dirtyLevel>=2&&_n(t,2),t._value}set value(t){this._setter(t)}get _dirty(){return this.effect.dirty}set _dirty(t){this.effect.dirty=t}}function cu(e,t,n=!1){let s,i;const r=W(e);return r?(s=e,i=ge):(s=e.get,i=e.set),new Yo(s,i,r||!i,n)}function Gi(e){var t;St&&Ht&&(e=Z(e),Mo(Ht,(t=e.dep)!=null?t:e.dep=Lo(()=>e.dep=void 0,e instanceof Yo?e:void 0)))}function _n(e,t=4,n){e=Z(e);const s=e.dep;s&&Po(s,t)}function Se(e){return!!(e&&e.__v_isRef===!0)}function Dn(e){return Xo(e,!1)}function au(e){return Xo(e,!0)}function Xo(e,t){return Se(e)?e:new fu(e,t)}class fu{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!0,this._rawValue=n?t:Z(t),this._value=n?t:$n(t)}get value(){return Gi(this),this._value}set value(t){const n=this.__v_isShallow||Fn(t)||jt(t);t=n?t:Z(t),Xe(t,this._rawValue)&&(this._rawValue=t,this._value=n?t:$n(t),_n(this,4))}}function uu(e){_n(e,4)}function zi(e){return Se(e)?e.value:e}function hu(e){return W(e)?e():zi(e)}const du={get:(e,t,n)=>zi(Reflect.get(e,t,n)),set:(e,t,n,s)=>{const i=e[t];return Se(i)&&!Se(n)?(i.value=n,!0):Reflect.set(e,t,n,s)}};function Ji(e){return Kt(e)?e:new Proxy(e,du)}class pu{constructor(t){this.dep=void 0,this.__v_isRef=!0;const{get:n,set:s}=t(()=>Gi(this),()=>_n(this));this._get=n,this._set=s}get value(){return this._get()}set value(t){this._set(t)}}function Zo(e){return new pu(e)}function mu(e){const t=V(e)?new Array(e.length):{};for(const n in e)t[n]=Qo(e,n);return t}class gu{constructor(t,n,s){this._object=t,this._key=n,this._defaultValue=s,this.__v_isRef=!0}get value(){const t=this._object[this._key];return t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return Uf(Z(this._object),this._key)}}class yu{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0}get value(){return this._getter()}}function _u(e,t,n){return Se(e)?e:W(e)?new yu(e):oe(e)&&arguments.length>1?Qo(e,t,n):Dn(e)}function Qo(e,t,n){const s=e[t];return Se(s)?s:new gu(e,t,n)}const bu={GET:"get",HAS:"has",ITERATE:"iterate"},Su={SET:"set",ADD:"add",DELETE:"delete",CLEAR:"clear"};/** +* @vue/runtime-core v3.4.21 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/const Vn=[];function vg(e,...t){vt();const n=Vn.length?Vn[Vn.length-1].component:null,s=n&&n.appContext.config.warnHandler,i=vu();if(s)st(s,n,11,[e+t.map(r=>{var o,l;return(l=(o=r.toString)==null?void 0:o.call(r))!=null?l:JSON.stringify(r)}).join(""),n&&n.proxy,i.map(({vnode:r})=>`at <${hc(n,r.type)}>`).join(` +`),i]);else{const r=[`[Vue warn]: ${e}`,...t];i.length&&r.push(` +`,...Eu(i)),console.warn(...r)}Et()}function vu(){let e=Vn[Vn.length-1];if(!e)return[];const t=[];for(;e;){const n=t[0];n&&n.vnode===e?n.recurseCount++:t.push({vnode:e,recurseCount:0});const s=e.component&&e.component.parent;e=s&&s.vnode}return t}function Eu(e){const t=[];return e.forEach((n,s)=>{t.push(...s===0?[]:[` +`],...Cu(n))}),t}function Cu({vnode:e,recurseCount:t}){const n=t>0?`... (${t} recursive calls)`:"",s=e.component?e.component.parent==null:!1,i=` at <${hc(e.component,e.type,s)}`,r=">"+n;return e.props?[i,...Tu(e.props),r]:[i+r]}function Tu(e){const t=[],n=Object.keys(e);return n.slice(0,3).forEach(s=>{t.push(...el(s,e[s]))}),n.length>3&&t.push(" ..."),t}function el(e,t,n){return J(t)?(t=JSON.stringify(t),n?t:[`${e}=${t}`]):typeof t=="number"||typeof t=="boolean"||t==null?n?t:[`${e}=${t}`]:Se(t)?(t=el(e,Z(t.value),!0),n?t:[`${e}=Ref<`,t,">"]):W(t)?[`${e}=fn${t.name?`<${t.name}>`:""}`]:(t=Z(t),n?t:[`${e}=`,t])}function Au(e,t){}const wu={SETUP_FUNCTION:0,0:"SETUP_FUNCTION",RENDER_FUNCTION:1,1:"RENDER_FUNCTION",WATCH_GETTER:2,2:"WATCH_GETTER",WATCH_CALLBACK:3,3:"WATCH_CALLBACK",WATCH_CLEANUP:4,4:"WATCH_CLEANUP",NATIVE_EVENT_HANDLER:5,5:"NATIVE_EVENT_HANDLER",COMPONENT_EVENT_HANDLER:6,6:"COMPONENT_EVENT_HANDLER",VNODE_HOOK:7,7:"VNODE_HOOK",DIRECTIVE_HOOK:8,8:"DIRECTIVE_HOOK",TRANSITION_HOOK:9,9:"TRANSITION_HOOK",APP_ERROR_HANDLER:10,10:"APP_ERROR_HANDLER",APP_WARN_HANDLER:11,11:"APP_WARN_HANDLER",FUNCTION_REF:12,12:"FUNCTION_REF",ASYNC_COMPONENT_LOADER:13,13:"ASYNC_COMPONENT_LOADER",SCHEDULER:14,14:"SCHEDULER"},Nu={sp:"serverPrefetch hook",bc:"beforeCreate hook",c:"created hook",bm:"beforeMount hook",m:"mounted hook",bu:"beforeUpdate hook",u:"updated",bum:"beforeUnmount hook",um:"unmounted hook",a:"activated hook",da:"deactivated hook",ec:"errorCaptured hook",rtc:"renderTracked hook",rtg:"renderTriggered hook",0:"setup function",1:"render function",2:"watcher getter",3:"watcher callback",4:"watcher cleanup function",5:"native event handler",6:"component event handler",7:"vnode hook",8:"directive hook",9:"transition hook",10:"app errorHandler",11:"app warnHandler",12:"ref function",13:"async component loader",14:"scheduler flush. This is likely a Vue internals bug. Please open an issue at https://github.com/vuejs/core ."};function st(e,t,n,s){try{return s?e(...s):e()}catch(i){qt(i,t,n)}}function Be(e,t,n,s){if(W(e)){const r=st(e,t,n,s);return r&&Mi(r)&&r.catch(o=>{qt(o,t,n)}),r}const i=[];for(let r=0;r>>1,i=Ae[s],r=Hn(i);rit&&Ae.splice(t,1)}function Ps(e){V(e)?bn.push(...e):(!Tt||!Tt.includes(e,e.allowRecurse?Wt+1:Wt))&&bn.push(e),nl()}function sl(e,t,n=Bn?it+1:0){for(;nHn(n)-Hn(s));if(bn.length=0,Tt){Tt.push(...t);return}for(Tt=t,Wt=0;Wte.id==null?1/0:e.id,ku=(e,t)=>{const n=Hn(e)-Hn(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function il(e){Yi=!1,Bn=!0,Ae.sort(ku);try{for(it=0;itSn.emit(i,...r)),Fs=[]):typeof window<"u"&&window.HTMLElement&&!((s=(n=window.navigator)==null?void 0:n.userAgent)!=null&&s.includes("jsdom"))?((t.__VUE_DEVTOOLS_HOOK_REPLAY__=t.__VUE_DEVTOOLS_HOOK_REPLAY__||[]).push(r=>{rl(r,t)}),setTimeout(()=>{Sn||(t.__VUE_DEVTOOLS_HOOK_REPLAY__=null,Fs=[])},3e3)):Fs=[]}function Ru(e,t,...n){if(e.isUnmounted)return;const s=e.vnode.props||ie;let i=n;const r=t.startsWith("update:"),o=r&&t.slice(7);if(o&&o in s){const u=`${o==="modelValue"?"model":o}Modifiers`,{number:f,trim:d}=s[u]||ie;d&&(i=n.map(g=>J(g)?g.trim():g)),f&&(i=n.map(Pn))}let l,c=s[l=mn(t)]||s[l=mn(ue(t))];!c&&r&&(c=s[l=mn(De(t))]),c&&Be(c,e,6,i);const a=s[l+"Once"];if(a){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,Be(a,e,6,i)}}function ol(e,t,n=!1){const s=t.emitsCache,i=s.get(e);if(i!==void 0)return i;const r=e.emits;let o={},l=!1;if(!W(e)){const c=a=>{const u=ol(a,t,!0);u&&(l=!0,ne(o,u))};!n&&t.mixins.length&&t.mixins.forEach(c),e.extends&&c(e.extends),e.mixins&&e.mixins.forEach(c)}return!r&&!l?(oe(e)&&s.set(e,null),null):(V(r)?r.forEach(c=>o[c]=null):ne(o,r),oe(e)&&s.set(e,o),o)}function $s(e,t){return!e||!Dt(t)?!1:(t=t.slice(2).replace(/Once$/,""),se(e,t[0].toLowerCase()+t.slice(1))||se(e,De(t))||se(e,t))}let me=null,Ds=null;function Un(e){const t=me;return me=e,Ds=e&&e.type.__scopeId||null,t}function Mu(e){Ds=e}function Pu(){Ds=null}const Lu=e=>Zi;function Zi(e,t=me,n){if(!t||e._n)return e;const s=(...i)=>{s._d&&Cr(-1);const r=Un(t);let o;try{o=e(...i)}finally{Un(r),s._d&&Cr(1)}return o};return s._n=!0,s._c=!0,s._d=!0,s}function Eg(){}function Vs(e){const{type:t,vnode:n,proxy:s,withProxy:i,props:r,propsOptions:[o],slots:l,attrs:c,emit:a,render:u,renderCache:f,data:d,setupState:g,ctx:_,inheritAttrs:x}=e;let M,P;const A=Un(e);try{if(n.shapeFlag&4){const y=i||s,S=y;M=He(u.call(S,y,f,r,g,d,_)),P=c}else{const y=t;M=He(y.length>1?y(r,{attrs:c,slots:l,emit:a}):y(r,null)),P=t.props?c:$u(c)}}catch(y){es.length=0,qt(y,e,1),M=ce(we)}let m=M;if(P&&x!==!1){const y=Object.keys(P),{shapeFlag:S}=m;y.length&&S&7&&(o&&y.some(ki)&&(P=Du(P,o)),m=ot(m,P))}return n.dirs&&(m=ot(m),m.dirs=m.dirs?m.dirs.concat(n.dirs):n.dirs),n.transition&&(m.transition=n.transition),M=m,Un(A),M}function Fu(e,t=!0){let n;for(let s=0;s{let t;for(const n in e)(n==="class"||n==="style"||Dt(n))&&((t||(t={}))[n]=e[n]);return t},Du=(e,t)=>{const n={};for(const s in e)(!ki(s)||!(s.slice(9)in t))&&(n[s]=e[s]);return n};function Vu(e,t,n){const{props:s,children:i,component:r}=e,{props:o,children:l,patchFlag:c}=t,a=r.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&c>=0){if(c&1024)return!0;if(c&16)return s?ll(s,o,a):!!o;if(c&8){const u=t.dynamicProps;for(let f=0;fe.__isSuspense;let sr=0;const Ku={name:"Suspense",__isSuspense:!0,process(e,t,n,s,i,r,o,l,c,a){if(e==null)ju(t,n,s,i,r,o,l,c,a);else{if(r&&r.deps>0&&!e.suspense.isInFallback){t.suspense=e.suspense,t.suspense.vnode=t,t.el=e.el;return}qu(e,t,n,s,i,o,l,c,a)}},hydrate:Wu,create:ir,normalize:Gu};function Kn(e,t){const n=e.props&&e.props[t];W(n)&&n()}function ju(e,t,n,s,i,r,o,l,c){const{p:a,o:{createElement:u}}=c,f=u("div"),d=e.suspense=ir(e,i,s,t,f,n,r,o,l,c);a(null,d.pendingBranch=e.ssContent,f,null,s,d,r,o),d.deps>0?(Kn(e,"onPending"),Kn(e,"onFallback"),a(null,e.ssFallback,t,n,s,null,r,o),vn(d,e.ssFallback)):d.resolve(!1,!0)}function qu(e,t,n,s,i,r,o,l,{p:c,um:a,o:{createElement:u}}){const f=t.suspense=e.suspense;f.vnode=t,t.el=e.el;const d=t.ssContent,g=t.ssFallback,{activeBranch:_,pendingBranch:x,isInFallback:M,isHydrating:P}=f;if(x)f.pendingBranch=d,Qe(d,x)?(c(x,d,f.hiddenContainer,null,i,f,r,o,l),f.deps<=0?f.resolve():M&&(P||(c(_,g,n,s,i,null,r,o,l),vn(f,g)))):(f.pendingId=sr++,P?(f.isHydrating=!1,f.activeBranch=x):a(x,i,f),f.deps=0,f.effects.length=0,f.hiddenContainer=u("div"),M?(c(null,d,f.hiddenContainer,null,i,f,r,o,l),f.deps<=0?f.resolve():(c(_,g,n,s,i,null,r,o,l),vn(f,g))):_&&Qe(d,_)?(c(_,d,n,s,i,f,r,o,l),f.resolve(!0)):(c(null,d,f.hiddenContainer,null,i,f,r,o,l),f.deps<=0&&f.resolve()));else if(_&&Qe(d,_))c(_,d,n,s,i,f,r,o,l),vn(f,d);else if(Kn(t,"onPending"),f.pendingBranch=d,d.shapeFlag&512?f.pendingId=d.component.suspenseId:f.pendingId=sr++,c(null,d,f.hiddenContainer,null,i,f,r,o,l),f.deps<=0)f.resolve();else{const{timeout:A,pendingId:m}=f;A>0?setTimeout(()=>{f.pendingId===m&&f.fallback(g)},A):A===0&&f.fallback(g)}}function ir(e,t,n,s,i,r,o,l,c,a,u=!1){const{p:f,m:d,um:g,n:_,o:{parentNode:x,remove:M}}=a;let P;const A=zu(e);A&&t!=null&&t.pendingBranch&&(P=t.pendingId,t.deps++);const m=e.props?Ss(e.props.timeout):void 0,y=r,S={vnode:e,parent:t,parentComponent:n,namespace:o,container:s,hiddenContainer:i,deps:0,pendingId:sr++,timeout:typeof m=="number"?m:-1,activeBranch:null,pendingBranch:null,isInFallback:!u,isHydrating:u,isUnmounted:!1,effects:[],resolve(C=!1,F=!1){const{vnode:b,activeBranch:E,pendingBranch:T,pendingId:k,effects:w,parentComponent:B,container:G}=S;let Q=!1;S.isHydrating?S.isHydrating=!1:C||(Q=E&&T.transition&&T.transition.mode==="out-in",Q&&(E.transition.afterLeave=()=>{k===S.pendingId&&(d(T,G,r===y?_(E):r,0),Ps(w))}),E&&(x(E.el)!==S.hiddenContainer&&(r=_(E)),g(E,B,S,!0)),Q||d(T,G,r,0)),vn(S,T),S.pendingBranch=null,S.isInFallback=!1;let H=S.parent,Y=!1;for(;H;){if(H.pendingBranch){H.effects.push(...w),Y=!0;break}H=H.parent}!Y&&!Q&&Ps(w),S.effects=[],A&&t&&t.pendingBranch&&P===t.pendingId&&(t.deps--,t.deps===0&&!F&&t.resolve()),Kn(b,"onResolve")},fallback(C){if(!S.pendingBranch)return;const{vnode:F,activeBranch:b,parentComponent:E,container:T,namespace:k}=S;Kn(F,"onFallback");const w=_(b),B=()=>{S.isInFallback&&(f(null,C,T,w,E,null,k,l,c),vn(S,C))},G=C.transition&&C.transition.mode==="out-in";G&&(b.transition.afterLeave=B),S.isInFallback=!0,g(b,E,null,!0),G||B()},move(C,F,b){S.activeBranch&&d(S.activeBranch,C,F,b),S.container=C},next(){return S.activeBranch&&_(S.activeBranch)},registerDep(C,F){const b=!!S.pendingBranch;b&&S.deps++;const E=C.vnode.el;C.asyncDep.catch(T=>{qt(T,C,0)}).then(T=>{if(C.isUnmounted||S.isUnmounted||S.pendingId!==C.suspenseId)return;C.asyncResolved=!0;const{vnode:k}=C;xr(C,T,!1),E&&(k.el=E);const w=!E&&C.subTree.el;F(C,k,x(E||C.subTree.el),E?null:_(C.subTree),S,o,c),w&&M(w),Qi(C,k.el),b&&--S.deps===0&&S.resolve()})},unmount(C,F){S.isUnmounted=!0,S.activeBranch&&g(S.activeBranch,n,C,F),S.pendingBranch&&g(S.pendingBranch,n,C,F)}};return S}function Wu(e,t,n,s,i,r,o,l,c){const a=t.suspense=ir(t,s,n,e.parentNode,document.createElement("div"),null,i,r,o,l,!0),u=c(e,a.pendingBranch=t.ssContent,n,a,r,o);return a.deps===0&&a.resolve(!1,!0),u}function Gu(e){const{shapeFlag:t,children:n}=e,s=t&32;e.ssContent=ul(s?n.default:n),e.ssFallback=s?ul(n.fallback):ce(we)}function ul(e){let t;if(W(e)){const n=Qt&&e._c;n&&(e._d=!1,Ze()),e=e(),n&&(e._d=!0,t=Me,tc())}return V(e)&&(e=Fu(e)),e=He(e),t&&!e.dynamicChildren&&(e.dynamicChildren=t.filter(n=>n!==e)),e}function hl(e,t){t&&t.pendingBranch?V(e)?t.effects.push(...e):t.effects.push(e):Ps(e)}function vn(e,t){e.activeBranch=t;const{vnode:n,parentComponent:s}=e;let i=t.el;for(;!i&&t.component;)t=t.component.subTree,i=t.el;n.el=i,s&&s.subTree===n&&(s.vnode.el=i,Qi(s,i))}function zu(e){var t;return((t=e.props)==null?void 0:t.suspensible)!=null&&e.props.suspensible!==!1}const dl=Symbol.for("v-scx"),pl=()=>Zn(dl);function Ju(e,t){return qn(e,null,t)}function ml(e,t){return qn(e,null,{flush:"post"})}function gl(e,t){return qn(e,null,{flush:"sync"})}const Bs={};function jn(e,t,n){return qn(e,t,n)}function qn(e,t,{immediate:n,deep:s,flush:i,once:r,onTrack:o,onTrigger:l}=ie){if(t&&r){const C=t;t=(...F)=>{C(...F),S()}}const c=ye,a=C=>s===!0?C:Gt(C,s===!1?1:void 0);let u,f=!1,d=!1;if(Se(e)?(u=()=>e.value,f=Fn(e)):Kt(e)?(u=()=>a(e),f=!0):V(e)?(d=!0,f=e.some(C=>Kt(C)||Fn(C)),u=()=>e.map(C=>{if(Se(C))return C.value;if(Kt(C))return a(C);if(W(C))return st(C,c,2)})):W(e)?t?u=()=>st(e,c,2):u=()=>(g&&g(),Be(e,c,3,[_])):u=ge,t&&s){const C=u;u=()=>Gt(C())}let g,_=C=>{g=m.onStop=()=>{st(C,c,4),g=m.onStop=void 0}},x;if(ts)if(_=ge,t?n&&Be(t,c,3,[u(),d?[]:void 0,_]):u(),i==="sync"){const C=pl();x=C.__watcherHandles||(C.__watcherHandles=[])}else return ge;let M=d?new Array(e.length).fill(Bs):Bs;const P=()=>{if(!(!m.active||!m.dirty))if(t){const C=m.run();(s||f||(d?C.some((F,b)=>Xe(F,M[b])):Xe(C,M)))&&(g&&g(),Be(t,c,3,[C,M===Bs?void 0:d&&M[0]===Bs?[]:M,_]),M=C)}else m.run()};P.allowRecurse=!!t;let A;i==="sync"?A=P:i==="post"?A=()=>Ee(P,c&&c.suspense):(P.pre=!0,c&&(P.id=c.uid),A=()=>Ms(P));const m=new yn(u,ge,A),y=Io(),S=()=>{m.stop(),y&&Ri(y.effects,m)};return t?n?P():M=m.run():i==="post"?Ee(m.run.bind(m),c&&c.suspense):m.run(),x&&x.push(S),S}function Yu(e,t,n){const s=this.proxy,i=J(e)?e.includes(".")?yl(s,e):()=>s[e]:e.bind(s,s);let r;W(t)?r=t:(r=t.handler,n=t);const o=en(this),l=qn(i,r.bind(s),n);return o(),l}function yl(e,t){const n=t.split(".");return()=>{let s=e;for(let i=0;i0){if(n>=t)return e;n++}if(s=s||new Set,s.has(e))return e;if(s.add(e),Se(e))Gt(e.value,t,n,s);else if(V(e))for(let i=0;i{Gt(i,t,n,s)});else if(vo(e))for(const i in e)Gt(e[i],t,n,s);return e}function Xu(e,t){if(me===null)return e;const n=ni(me)||me.proxy,s=e.dirs||(e.dirs=[]);for(let i=0;i{e.isMounted=!0}),qs(()=>{e.isUnmounting=!0}),e}const We=[Function,Array],or={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:We,onEnter:We,onAfterEnter:We,onEnterCancelled:We,onBeforeLeave:We,onLeave:We,onAfterLeave:We,onLeaveCancelled:We,onBeforeAppear:We,onAppear:We,onAfterAppear:We,onAppearCancelled:We},_l={name:"BaseTransition",props:or,setup(e,{slots:t}){const n=ut(),s=rr();return()=>{const i=t.default&&Us(t.default(),!0);if(!i||!i.length)return;let r=i[0];if(i.length>1){for(const d of i)if(d.type!==we){r=d;break}}const o=Z(e),{mode:l}=o;if(s.isLeaving)return lr(r);const c=Sl(r);if(!c)return lr(r);const a=En(c,o,s,n);zt(c,a);const u=n.subTree,f=u&&Sl(u);if(f&&f.type!==we&&!Qe(c,f)){const d=En(f,o,s,n);if(zt(f,d),l==="out-in")return s.isLeaving=!0,d.afterLeave=()=>{s.isLeaving=!1,n.update.active!==!1&&(n.effect.dirty=!0,n.update())},lr(r);l==="in-out"&&c.type!==we&&(d.delayLeave=(g,_,x)=>{const M=bl(s,f);M[String(f.key)]=f,g[At]=()=>{_(),g[At]=void 0,delete a.delayedLeave},a.delayedLeave=x})}return r}}};function bl(e,t){const{leavingVNodes:n}=e;let s=n.get(t.type);return s||(s=Object.create(null),n.set(t.type,s)),s}function En(e,t,n,s){const{appear:i,mode:r,persisted:o=!1,onBeforeEnter:l,onEnter:c,onAfterEnter:a,onEnterCancelled:u,onBeforeLeave:f,onLeave:d,onAfterLeave:g,onLeaveCancelled:_,onBeforeAppear:x,onAppear:M,onAfterAppear:P,onAppearCancelled:A}=t,m=String(e.key),y=bl(n,e),S=(b,E)=>{b&&Be(b,s,9,E)},C=(b,E)=>{const T=E[1];S(b,E),V(b)?b.every(k=>k.length<=1)&&T():b.length<=1&&T()},F={mode:r,persisted:o,beforeEnter(b){let E=l;if(!n.isMounted)if(i)E=x||l;else return;b[At]&&b[At](!0);const T=y[m];T&&Qe(e,T)&&T.el[At]&&T.el[At](),S(E,[b])},enter(b){let E=c,T=a,k=u;if(!n.isMounted)if(i)E=M||c,T=P||a,k=A||u;else return;let w=!1;const B=b[Hs]=G=>{w||(w=!0,G?S(k,[b]):S(T,[b]),F.delayedLeave&&F.delayedLeave(),b[Hs]=void 0)};E?C(E,[b,B]):B()},leave(b,E){const T=String(e.key);if(b[Hs]&&b[Hs](!0),n.isUnmounting)return E();S(f,[b]);let k=!1;const w=b[At]=B=>{k||(k=!0,E(),B?S(_,[b]):S(g,[b]),b[At]=void 0,y[T]===e&&delete y[T])};y[T]=e,d?C(d,[b,w]):w()},clone(b){return En(b,t,n,s)}};return F}function lr(e){if(Wn(e))return e=ot(e),e.children=null,e}function Sl(e){return Wn(e)?e.children?e.children[0]:void 0:e}function zt(e,t){e.shapeFlag&6&&e.component?zt(e.component.subTree,t):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Us(e,t=!1,n){let s=[],i=0;for(let r=0;r1)for(let r=0;r!!e.type.__asyncLoader;/*! #__NO_SIDE_EFFECTS__ */function Zu(e){W(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:s,delay:i=200,timeout:r,suspensible:o=!0,onError:l}=e;let c=null,a,u=0;const f=()=>(u++,c=null,d()),d=()=>{let g;return c||(g=c=t().catch(_=>{if(_=_ instanceof Error?_:new Error(String(_)),l)return new Promise((x,M)=>{l(_,()=>x(f()),()=>M(_),u+1)});throw _}).then(_=>g!==c&&c?c:(_&&(_.__esModule||_[Symbol.toStringTag]==="Module")&&(_=_.default),a=_,_)))};return cr({name:"AsyncComponentWrapper",__asyncLoader:d,get __asyncResolved(){return a},setup(){const g=ye;if(a)return()=>ar(a,g);const _=A=>{c=null,qt(A,g,13,!s)};if(o&&g.suspense||ts)return d().then(A=>()=>ar(A,g)).catch(A=>(_(A),()=>s?ce(s,{error:A}):null));const x=Dn(!1),M=Dn(),P=Dn(!!i);return i&&setTimeout(()=>{P.value=!1},i),r!=null&&setTimeout(()=>{if(!x.value&&!M.value){const A=new Error(`Async component timed out after ${r}ms.`);_(A),M.value=A}},r),d().then(()=>{x.value=!0,g.parent&&Wn(g.parent.vnode)&&(g.parent.effect.dirty=!0,Ms(g.parent.update))}).catch(A=>{_(A),M.value=A}),()=>{if(x.value&&a)return ar(a,g);if(M.value&&s)return ce(s,{error:M.value});if(n&&!P.value)return ce(n)}}})}function ar(e,t){const{ref:n,props:s,children:i,ce:r}=t.vnode,o=ce(e,s,i);return o.ref=n,o.ce=r,delete t.vnode.ce,o}const Wn=e=>e.type.__isKeepAlive,Qu={name:"KeepAlive",__isKeepAlive:!0,props:{include:[String,RegExp,Array],exclude:[String,RegExp,Array],max:[String,Number]},setup(e,{slots:t}){const n=ut(),s=n.ctx;if(!s.renderer)return()=>{const A=t.default&&t.default();return A&&A.length===1?A[0]:A};const i=new Map,r=new Set;let o=null;const l=n.suspense,{renderer:{p:c,m:a,um:u,o:{createElement:f}}}=s,d=f("div");s.activate=(A,m,y,S,C)=>{const F=A.component;a(A,m,y,0,l),c(F.vnode,A,m,y,F,l,S,A.slotScopeIds,C),Ee(()=>{F.isDeactivated=!1,F.a&&gn(F.a);const b=A.props&&A.props.onVnodeMounted;b&&Pe(b,F.parent,A)},l)},s.deactivate=A=>{const m=A.component;a(A,d,null,1,l),Ee(()=>{m.da&&gn(m.da);const y=A.props&&A.props.onVnodeUnmounted;y&&Pe(y,m.parent,A),m.isDeactivated=!0},l)};function g(A){fr(A),u(A,n,l,!0)}function _(A){i.forEach((m,y)=>{const S=si(m.type);S&&(!A||!A(S))&&x(y)})}function x(A){const m=i.get(A);!o||!Qe(m,o)?g(m):o&&fr(o),i.delete(A),r.delete(A)}jn(()=>[e.include,e.exclude],([A,m])=>{A&&_(y=>Gn(A,y)),m&&_(y=>!Gn(m,y))},{flush:"post",deep:!0});let M=null;const P=()=>{M!=null&&i.set(M,ur(n.subTree))};return zn(P),js(P),qs(()=>{i.forEach(A=>{const{subTree:m,suspense:y}=n,S=ur(m);if(A.type===S.type&&A.key===S.key){fr(S);const C=S.component.da;C&&Ee(C,y);return}g(A)})}),()=>{if(M=null,!t.default)return null;const A=t.default(),m=A[0];if(A.length>1)return o=null,A;if(!It(m)||!(m.shapeFlag&4)&&!(m.shapeFlag&128))return o=null,m;let y=ur(m);const S=y.type,C=si(Jt(y)?y.type.__asyncResolved||{}:S),{include:F,exclude:b,max:E}=e;if(F&&(!C||!Gn(F,C))||b&&C&&Gn(b,C))return o=y,m;const T=y.key==null?S:y.key,k=i.get(T);return y.el&&(y=ot(y),m.shapeFlag&128&&(m.ssContent=y)),M=T,k?(y.el=k.el,y.component=k.component,y.transition&&zt(y,y.transition),y.shapeFlag|=512,r.delete(T),r.add(T)):(r.add(T),E&&r.size>parseInt(E,10)&&x(r.values().next().value)),y.shapeFlag|=256,o=y,fl(m.type)?m:y}}};function Gn(e,t){return V(e)?e.some(n=>Gn(n,t)):J(e)?e.split(",").includes(t):gf(e)?e.test(t):!1}function vl(e,t){Cl(e,"a",t)}function El(e,t){Cl(e,"da",t)}function Cl(e,t,n=ye){const s=e.__wdc||(e.__wdc=()=>{let i=n;for(;i;){if(i.isDeactivated)return;i=i.parent}return e()});if(Ks(t,s,n),n){let i=n.parent;for(;i&&i.parent;)Wn(i.parent.vnode)&&eh(s,t,n,i),i=i.parent}}function eh(e,t,n,s){const i=Ks(t,e,s,!0);Ws(()=>{Ri(s[t],i)},n)}function fr(e){e.shapeFlag&=-257,e.shapeFlag&=-513}function ur(e){return e.shapeFlag&128?e.ssContent:e}function Ks(e,t,n=ye,s=!1){if(n){const i=n[e]||(n[e]=[]),r=t.__weh||(t.__weh=(...o)=>{if(n.isUnmounted)return;vt();const l=en(n),c=Be(t,n,e,o);return l(),Et(),c});return s?i.unshift(r):i.push(r),r}}const ft=e=>(t,n=ye)=>(!ts||e==="sp")&&Ks(e,(...s)=>t(...s),n),Tl=ft("bm"),zn=ft("m"),Al=ft("bu"),js=ft("u"),qs=ft("bum"),Ws=ft("um"),wl=ft("sp"),Nl=ft("rtg"),Il=ft("rtc");function xl(e,t=ye){Ks("ec",e,t)}function th(e,t,n,s){let i;const r=n&&n[s];if(V(e)||J(e)){i=new Array(e.length);for(let o=0,l=e.length;ot(o,l,void 0,r&&r[l]));else{const o=Object.keys(e);i=new Array(o.length);for(let l=0,c=o.length;l{const r=s.fn(...i);return r&&(r.key=s.key),r}:s.fn)}return e}function Cn(e,t,n={},s,i){if(me.isCE||me.parent&&Jt(me.parent)&&me.parent.isCE)return t!=="default"&&(n.name=t),ce("slot",n,s&&s());let r=e[t];r&&r._c&&(r._d=!1),Ze();const o=r&&Ol(r(n)),l=Tr(Ce,{key:n.key||o&&o.key||`_${t}`},o||(s?s():[]),o&&e._===1?64:-2);return!i&&l.scopeId&&(l.slotScopeIds=[l.scopeId+"-s"]),r&&r._c&&(r._d=!0),l}function Ol(e){return e.some(t=>It(t)?!(t.type===we||t.type===Ce&&!Ol(t.children)):!0)?e:null}function sh(e,t){const n={};for(const s in e)n[t&&/[A-Z]/.test(s)?`on:${s}`:mn(s)]=e[s];return n}const hr=e=>e?lc(e)?ni(e)||e.proxy:hr(e.parent):null,Jn=ne(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>hr(e.parent),$root:e=>hr(e.root),$emit:e=>e.emit,$options:e=>gr(e),$forceUpdate:e=>e.f||(e.f=()=>{e.effect.dirty=!0,Ms(e.update)}),$nextTick:e=>e.n||(e.n=Rs.bind(e.proxy)),$watch:e=>Yu.bind(e)}),dr=(e,t)=>e!==ie&&!e.__isScriptSetup&&se(e,t),pr={get({_:e},t){const{ctx:n,setupState:s,data:i,props:r,accessCache:o,type:l,appContext:c}=e;let a;if(t[0]!=="$"){const g=o[t];if(g!==void 0)switch(g){case 1:return s[t];case 2:return i[t];case 4:return n[t];case 3:return r[t]}else{if(dr(s,t))return o[t]=1,s[t];if(i!==ie&&se(i,t))return o[t]=2,i[t];if((a=e.propsOptions[0])&&se(a,t))return o[t]=3,r[t];if(n!==ie&&se(n,t))return o[t]=4,n[t];mr&&(o[t]=0)}}const u=Jn[t];let f,d;if(u)return t==="$attrs"&&Re(e,"get",t),u(e);if((f=l.__cssModules)&&(f=f[t]))return f;if(n!==ie&&se(n,t))return o[t]=4,n[t];if(d=c.config.globalProperties,se(d,t))return d[t]},set({_:e},t,n){const{data:s,setupState:i,ctx:r}=e;return dr(i,t)?(i[t]=n,!0):s!==ie&&se(s,t)?(s[t]=n,!0):se(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(r[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:s,appContext:i,propsOptions:r}},o){let l;return!!n[o]||e!==ie&&se(e,o)||dr(t,o)||(l=r[0])&&se(l,o)||se(s,o)||se(Jn,o)||se(i.config.globalProperties,o)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:se(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}},ih=ne({},pr,{get(e,t){if(t!==Symbol.unscopables)return pr.get(e,t,e)},has(e,t){return t[0]!=="_"&&!vf(t)}});function rh(){return null}function oh(){return null}function lh(e){}function ch(e){}function ah(){return null}function fh(){}function uh(e,t){return null}function hh(){return kl().slots}function dh(){return kl().attrs}function kl(){const e=ut();return e.setupContext||(e.setupContext=uc(e))}function Yn(e){return V(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}function ph(e,t){const n=Yn(e);for(const s in t){if(s.startsWith("__skip"))continue;let i=n[s];i?V(i)||W(i)?i=n[s]={type:i,default:t[s]}:i.default=t[s]:i===null&&(i=n[s]={default:t[s]}),i&&t[`__skip_${s}`]&&(i.skipFactory=!0)}return n}function mh(e,t){return!e||!t?e||t:V(e)&&V(t)?e.concat(t):ne({},Yn(e),Yn(t))}function gh(e,t){const n={};for(const s in e)t.includes(s)||Object.defineProperty(n,s,{enumerable:!0,get:()=>e[s]});return n}function yh(e){const t=ut();let n=e();return Ir(),Mi(n)&&(n=n.catch(s=>{throw en(t),s})),[n,()=>en(t)]}let mr=!0;function _h(e){const t=gr(e),n=e.proxy,s=e.ctx;mr=!1,t.beforeCreate&&Rl(t.beforeCreate,e,"bc");const{data:i,computed:r,methods:o,watch:l,provide:c,inject:a,created:u,beforeMount:f,mounted:d,beforeUpdate:g,updated:_,activated:x,deactivated:M,beforeDestroy:P,beforeUnmount:A,destroyed:m,unmounted:y,render:S,renderTracked:C,renderTriggered:F,errorCaptured:b,serverPrefetch:E,expose:T,inheritAttrs:k,components:w,directives:B,filters:G}=t;if(a&&bh(a,s,null),o)for(const Y in o){const K=o[Y];W(K)&&(s[Y]=K.bind(n))}if(i){const Y=i.call(n,n);oe(Y)&&(e.data=Os(Y))}if(mr=!0,r)for(const Y in r){const K=r[Y],je=W(K)?K.bind(n,n):W(K.get)?K.get.bind(n,n):ge,$t=!W(K)&&W(K.set)?K.set.bind(n):ge,un=dc({get:je,set:$t});Object.defineProperty(s,Y,{enumerable:!0,configurable:!0,get:()=>un.value,set:lt=>un.value=lt})}if(l)for(const Y in l)Ml(l[Y],s,n,Y);if(c){const Y=W(c)?c.call(n):c;Reflect.ownKeys(Y).forEach(K=>{$l(K,Y[K])})}u&&Rl(u,e,"c");function H(Y,K){V(K)?K.forEach(je=>Y(je.bind(n))):K&&Y(K.bind(n))}if(H(Tl,f),H(zn,d),H(Al,g),H(js,_),H(vl,x),H(El,M),H(xl,b),H(Il,C),H(Nl,F),H(qs,A),H(Ws,y),H(wl,E),V(T))if(T.length){const Y=e.exposed||(e.exposed={});T.forEach(K=>{Object.defineProperty(Y,K,{get:()=>n[K],set:je=>n[K]=je})})}else e.exposed||(e.exposed={});S&&e.render===ge&&(e.render=S),k!=null&&(e.inheritAttrs=k),w&&(e.components=w),B&&(e.directives=B)}function bh(e,t,n=ge){V(e)&&(e=yr(e));for(const s in e){const i=e[s];let r;oe(i)?"default"in i?r=Zn(i.from||s,i.default,!0):r=Zn(i.from||s):r=Zn(i),Se(r)?Object.defineProperty(t,s,{enumerable:!0,configurable:!0,get:()=>r.value,set:o=>r.value=o}):t[s]=r}}function Rl(e,t,n){Be(V(e)?e.map(s=>s.bind(t.proxy)):e.bind(t.proxy),t,n)}function Ml(e,t,n,s){const i=s.includes(".")?yl(n,s):()=>n[s];if(J(e)){const r=t[e];W(r)&&jn(i,r)}else if(W(e))jn(i,e.bind(n));else if(oe(e))if(V(e))e.forEach(r=>Ml(r,t,n,s));else{const r=W(e.handler)?e.handler.bind(n):t[e.handler];W(r)&&jn(i,r,e)}}function gr(e){const t=e.type,{mixins:n,extends:s}=t,{mixins:i,optionsCache:r,config:{optionMergeStrategies:o}}=e.appContext,l=r.get(t);let c;return l?c=l:!i.length&&!n&&!s?c=t:(c={},i.length&&i.forEach(a=>Gs(c,a,o,!0)),Gs(c,t,o)),oe(t)&&r.set(t,c),c}function Gs(e,t,n,s=!1){const{mixins:i,extends:r}=t;r&&Gs(e,r,n,!0),i&&i.forEach(o=>Gs(e,o,n,!0));for(const o in t)if(!(s&&o==="expose")){const l=Sh[o]||n&&n[o];e[o]=l?l(e[o],t[o]):t[o]}return e}const Sh={data:Pl,props:Ll,emits:Ll,methods:Xn,computed:Xn,beforeCreate:ke,created:ke,beforeMount:ke,mounted:ke,beforeUpdate:ke,updated:ke,beforeDestroy:ke,beforeUnmount:ke,destroyed:ke,unmounted:ke,activated:ke,deactivated:ke,errorCaptured:ke,serverPrefetch:ke,components:Xn,directives:Xn,watch:Eh,provide:Pl,inject:vh};function Pl(e,t){return t?e?function(){return ne(W(e)?e.call(this,this):e,W(t)?t.call(this,this):t)}:t:e}function vh(e,t){return Xn(yr(e),yr(t))}function yr(e){if(V(e)){const t={};for(let n=0;n1)return n&&W(t)?t.call(s&&s.proxy):t}}function Ah(){return!!(ye||me||Tn)}function wh(e,t,n,s=!1){const i={},r={};bs(r,Zs,1),e.propsDefaults=Object.create(null),Dl(e,t,i,r);for(const o in e.propsOptions[0])o in i||(i[o]=void 0);n?e.props=s?i:Jo(i):e.type.props?e.props=i:e.props=r,e.attrs=r}function Nh(e,t,n,s){const{props:i,attrs:r,vnode:{patchFlag:o}}=e,l=Z(i),[c]=e.propsOptions;let a=!1;if((s||o>0)&&!(o&16)){if(o&8){const u=e.vnode.dynamicProps;for(let f=0;f{c=!0;const[d,g]=Vl(f,t,!0);ne(o,d),g&&l.push(...g)};!n&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}if(!r&&!c)return oe(e)&&s.set(e,hn),hn;if(V(r))for(let u=0;u-1,g[1]=x<0||_-1||se(g,"default"))&&l.push(f)}}}const a=[o,l];return oe(e)&&s.set(e,a),a}function Bl(e){return e[0]!=="$"&&!yt(e)}function Hl(e){return e===null?"null":typeof e=="function"?e.name||"":typeof e=="object"&&e.constructor&&e.constructor.name||""}function Ul(e,t){return Hl(e)===Hl(t)}function Kl(e,t){return V(t)?t.findIndex(n=>Ul(n,e)):W(t)&&Ul(t,e)?0:-1}const jl=e=>e[0]==="_"||e==="$stable",br=e=>V(e)?e.map(He):[He(e)],Ih=(e,t,n)=>{if(t._n)return t;const s=Zi((...i)=>br(t(...i)),n);return s._c=!1,s},ql=(e,t,n)=>{const s=e._ctx;for(const i in e){if(jl(i))continue;const r=e[i];if(W(r))t[i]=Ih(i,r,s);else if(r!=null){const o=br(r);t[i]=()=>o}}},Wl=(e,t)=>{const n=br(t);e.slots.default=()=>n},xh=(e,t)=>{if(e.vnode.shapeFlag&32){const n=t._;n?(e.slots=Z(t),bs(t,"_",n)):ql(t,e.slots={})}else e.slots={},t&&Wl(e,t);bs(e.slots,Zs,1)},Oh=(e,t,n)=>{const{vnode:s,slots:i}=e;let r=!0,o=ie;if(s.shapeFlag&32){const l=t._;l?n&&l===1?r=!1:(ne(i,t),!n&&l===1&&delete i._):(r=!t.$stable,ql(t,i)),o=t}else t&&(Wl(e,t),o={default:1});if(r)for(const l in i)!jl(l)&&o[l]==null&&delete i[l]};function zs(e,t,n,s,i=!1){if(V(e)){e.forEach((d,g)=>zs(d,t&&(V(t)?t[g]:t),n,s,i));return}if(Jt(s)&&!i)return;const r=s.shapeFlag&4?ni(s.component)||s.component.proxy:s.el,o=i?null:r,{i:l,r:c}=e,a=t&&t.r,u=l.refs===ie?l.refs={}:l.refs,f=l.setupState;if(a!=null&&a!==c&&(J(a)?(u[a]=null,se(f,a)&&(f[a]=null)):Se(a)&&(a.value=null)),W(c))st(c,l,12,[o,u]);else{const d=J(c),g=Se(c);if(d||g){const _=()=>{if(e.f){const x=d?se(f,c)?f[c]:u[c]:c.value;i?V(x)&&Ri(x,r):V(x)?x.includes(r)||x.push(r):d?(u[c]=[r],se(f,c)&&(f[c]=u[c])):(c.value=[r],e.k&&(u[e.k]=c.value))}else d?(u[c]=o,se(f,c)&&(f[c]=o)):g&&(c.value=o,e.k&&(u[e.k]=o))};o?(_.id=-1,Ee(_,n)):_()}}}let wt=!1;const kh=e=>e.namespaceURI.includes("svg")&&e.tagName!=="foreignObject",Rh=e=>e.namespaceURI.includes("MathML"),Js=e=>{if(kh(e))return"svg";if(Rh(e))return"mathml"},Ys=e=>e.nodeType===8;function Mh(e){const{mt:t,p:n,o:{patchProp:s,createText:i,nextSibling:r,parentNode:o,remove:l,insert:c,createComment:a}}=e,u=(m,y)=>{if(!y.hasChildNodes()){n(null,m,y),Ls(),y._vnode=m;return}wt=!1,f(y.firstChild,m,null,null,null),Ls(),y._vnode=m,wt&&console.error("Hydration completed but contains mismatches.")},f=(m,y,S,C,F,b=!1)=>{const E=Ys(m)&&m.data==="[",T=()=>x(m,y,S,C,F,E),{type:k,ref:w,shapeFlag:B,patchFlag:G}=y;let Q=m.nodeType;y.el=m,G===-2&&(b=!1,y.dynamicChildren=null);let H=null;switch(k){case Xt:Q!==3?y.children===""?(c(y.el=i(""),o(m),m),H=m):H=T():(m.data!==y.children&&(wt=!0,m.data=y.children),H=r(m));break;case we:A(m)?(H=r(m),P(y.el=m.content.firstChild,m,S)):Q!==8||E?H=T():H=r(m);break;case Zt:if(E&&(m=r(m),Q=m.nodeType),Q===1||Q===3){H=m;const Y=!y.children.length;for(let K=0;K{b=b||!!y.dynamicChildren;const{type:E,props:T,patchFlag:k,shapeFlag:w,dirs:B,transition:G}=y,Q=E==="input"||E==="option";if(Q||k!==-1){B&&rt(y,null,S,"created");let H=!1;if(A(m)){H=Yl(C,G)&&S&&S.vnode.props&&S.vnode.props.appear;const K=m.content.firstChild;H&&G.beforeEnter(K),P(K,m,S),y.el=m=K}if(w&16&&!(T&&(T.innerHTML||T.textContent))){let K=g(m.firstChild,y,m,S,C,F,b);for(;K;){wt=!0;const je=K;K=K.nextSibling,l(je)}}else w&8&&m.textContent!==y.children&&(wt=!0,m.textContent=y.children);if(T)if(Q||!b||k&48)for(const K in T)(Q&&(K.endsWith("value")||K==="indeterminate")||Dt(K)&&!yt(K)||K[0]===".")&&s(m,K,null,T[K],void 0,void 0,S);else T.onClick&&s(m,"onClick",null,T.onClick,void 0,void 0,S);let Y;(Y=T&&T.onVnodeBeforeMount)&&Pe(Y,S,y),B&&rt(y,null,S,"beforeMount"),((Y=T&&T.onVnodeMounted)||B||H)&&hl(()=>{Y&&Pe(Y,S,y),H&&G.enter(m),B&&rt(y,null,S,"mounted")},C)}return m.nextSibling},g=(m,y,S,C,F,b,E)=>{E=E||!!y.dynamicChildren;const T=y.children,k=T.length;for(let w=0;w{const{slotScopeIds:E}=y;E&&(F=F?F.concat(E):E);const T=o(m),k=g(r(m),y,T,S,C,F,b);return k&&Ys(k)&&k.data==="]"?r(y.anchor=k):(wt=!0,c(y.anchor=a("]"),T,k),k)},x=(m,y,S,C,F,b)=>{if(wt=!0,y.el=null,b){const k=M(m);for(;;){const w=r(m);if(w&&w!==k)l(w);else break}}const E=r(m),T=o(m);return l(m),n(null,y,T,E,S,C,Js(T),F),E},M=(m,y="[",S="]")=>{let C=0;for(;m;)if(m=r(m),m&&Ys(m)&&(m.data===y&&C++,m.data===S)){if(C===0)return r(m);C--}return m},P=(m,y,S)=>{const C=y.parentNode;C&&C.replaceChild(m,y);let F=S;for(;F;)F.vnode.el===y&&(F.vnode.el=F.subTree.el=m),F=F.parent},A=m=>m.nodeType===1&&m.tagName.toLowerCase()==="template";return[u,f]}const Ee=hl;function Gl(e){return Jl(e)}function zl(e){return Jl(e,Mh)}function Jl(e,t){const n=Co();n.__VUE__=!0;const{insert:s,remove:i,patchProp:r,createElement:o,createText:l,createComment:c,setText:a,setElementText:u,parentNode:f,nextSibling:d,setScopeId:g=ge,insertStaticContent:_}=e,x=(h,p,v,N=null,I=null,L=null,D=void 0,R=null,$=!!p.dynamicChildren)=>{if(h===p)return;h&&!Qe(h,p)&&(N=Oi(h),lt(h,I,L,!0),h=null),p.patchFlag===-2&&($=!1,p.dynamicChildren=null);const{type:O,ref:U,shapeFlag:q}=p;switch(O){case Xt:M(h,p,v,N);break;case we:P(h,p,v,N);break;case Zt:h==null&&A(p,v,N,D);break;case Ce:w(h,p,v,N,I,L,D,R,$);break;default:q&1?S(h,p,v,N,I,L,D,R,$):q&6?B(h,p,v,N,I,L,D,R,$):(q&64||q&128)&&O.process(h,p,v,N,I,L,D,R,$,Rn)}U!=null&&I&&zs(U,h&&h.ref,L,p||h,!p)},M=(h,p,v,N)=>{if(h==null)s(p.el=l(p.children),v,N);else{const I=p.el=h.el;p.children!==h.children&&a(I,p.children)}},P=(h,p,v,N)=>{h==null?s(p.el=c(p.children||""),v,N):p.el=h.el},A=(h,p,v,N)=>{[h.el,h.anchor]=_(h.children,p,v,N,h.el,h.anchor)},m=({el:h,anchor:p},v,N)=>{let I;for(;h&&h!==p;)I=d(h),s(h,v,N),h=I;s(p,v,N)},y=({el:h,anchor:p})=>{let v;for(;h&&h!==p;)v=d(h),i(h),h=v;i(p)},S=(h,p,v,N,I,L,D,R,$)=>{p.type==="svg"?D="svg":p.type==="math"&&(D="mathml"),h==null?C(p,v,N,I,L,D,R,$):E(h,p,I,L,D,R,$)},C=(h,p,v,N,I,L,D,R)=>{let $,O;const{props:U,shapeFlag:q,transition:j,dirs:z}=h;if($=h.el=o(h.type,L,U&&U.is,U),q&8?u($,h.children):q&16&&b(h.children,$,null,N,I,Sr(h,L),D,R),z&&rt(h,null,N,"created"),F($,h,h.scopeId,D,N),U){for(const le in U)le!=="value"&&!yt(le)&&r($,le,null,U[le],L,h.children,N,I,gt);"value"in U&&r($,"value",null,U.value,L),(O=U.onVnodeBeforeMount)&&Pe(O,N,h)}z&&rt(h,null,N,"beforeMount");const ee=Yl(I,j);ee&&j.beforeEnter($),s($,p,v),((O=U&&U.onVnodeMounted)||ee||z)&&Ee(()=>{O&&Pe(O,N,h),ee&&j.enter($),z&&rt(h,null,N,"mounted")},I)},F=(h,p,v,N,I)=>{if(v&&g(h,v),N)for(let L=0;L{for(let O=$;O{const R=p.el=h.el;let{patchFlag:$,dynamicChildren:O,dirs:U}=p;$|=h.patchFlag&16;const q=h.props||ie,j=p.props||ie;let z;if(v&&Yt(v,!1),(z=j.onVnodeBeforeUpdate)&&Pe(z,v,p,h),U&&rt(p,h,v,"beforeUpdate"),v&&Yt(v,!0),O?T(h.dynamicChildren,O,R,v,N,Sr(p,I),L):D||K(h,p,R,null,v,N,Sr(p,I),L,!1),$>0){if($&16)k(R,p,q,j,v,N,I);else if($&2&&q.class!==j.class&&r(R,"class",null,j.class,I),$&4&&r(R,"style",q.style,j.style,I),$&8){const ee=p.dynamicProps;for(let le=0;le{z&&Pe(z,v,p,h),U&&rt(p,h,v,"updated")},N)},T=(h,p,v,N,I,L,D)=>{for(let R=0;R{if(v!==N){if(v!==ie)for(const R in v)!yt(R)&&!(R in N)&&r(h,R,v[R],null,D,p.children,I,L,gt);for(const R in N){if(yt(R))continue;const $=N[R],O=v[R];$!==O&&R!=="value"&&r(h,R,O,$,D,p.children,I,L,gt)}"value"in N&&r(h,"value",v.value,N.value,D)}},w=(h,p,v,N,I,L,D,R,$)=>{const O=p.el=h?h.el:l(""),U=p.anchor=h?h.anchor:l("");let{patchFlag:q,dynamicChildren:j,slotScopeIds:z}=p;z&&(R=R?R.concat(z):z),h==null?(s(O,v,N),s(U,v,N),b(p.children||[],v,U,I,L,D,R,$)):q>0&&q&64&&j&&h.dynamicChildren?(T(h.dynamicChildren,j,v,I,L,D,R),(p.key!=null||I&&p===I.subTree)&&vr(h,p,!0)):K(h,p,v,U,I,L,D,R,$)},B=(h,p,v,N,I,L,D,R,$)=>{p.slotScopeIds=R,h==null?p.shapeFlag&512?I.ctx.activate(p,v,N,D,$):G(p,v,N,I,L,D,$):Q(h,p,$)},G=(h,p,v,N,I,L,D)=>{const R=h.component=oc(h,N,I);if(Wn(h)&&(R.ctx.renderer=Rn),cc(R),R.asyncDep){if(I&&I.registerDep(R,H),!h.el){const $=R.subTree=ce(we);P(null,$,p,v)}}else H(R,h,p,v,I,L,D)},Q=(h,p,v)=>{const N=p.component=h.component;if(Vu(h,p,v))if(N.asyncDep&&!N.asyncResolved){Y(N,p,v);return}else N.next=p,Ou(N.update),N.effect.dirty=!0,N.update();else p.el=h.el,N.vnode=p},H=(h,p,v,N,I,L,D)=>{const R=()=>{if(h.isMounted){let{next:U,bu:q,u:j,parent:z,vnode:ee}=h;{const Mn=Xl(h);if(Mn){U&&(U.el=ee.el,Y(h,U,D)),Mn.asyncDep.then(()=>{h.isUnmounted||R()});return}}let le=U,fe;Yt(h,!1),U?(U.el=ee.el,Y(h,U,D)):U=ee,q&&gn(q),(fe=U.props&&U.props.onVnodeBeforeUpdate)&&Pe(fe,z,U,ee),Yt(h,!0);const ve=Vs(h),nt=h.subTree;h.subTree=ve,x(nt,ve,f(nt.el),Oi(nt),h,I,L),U.el=ve.el,le===null&&Qi(h,ve.el),j&&Ee(j,I),(fe=U.props&&U.props.onVnodeUpdated)&&Ee(()=>Pe(fe,z,U,ee),I)}else{let U;const{el:q,props:j}=p,{bm:z,m:ee,parent:le}=h,fe=Jt(p);if(Yt(h,!1),z&&gn(z),!fe&&(U=j&&j.onVnodeBeforeMount)&&Pe(U,le,p),Yt(h,!0),q&&_o){const ve=()=>{h.subTree=Vs(h),_o(q,h.subTree,h,I,null)};fe?p.type.__asyncLoader().then(()=>!h.isUnmounted&&ve()):ve()}else{const ve=h.subTree=Vs(h);x(null,ve,v,N,h,I,L),p.el=ve.el}if(ee&&Ee(ee,I),!fe&&(U=j&&j.onVnodeMounted)){const ve=p;Ee(()=>Pe(U,le,ve),I)}(p.shapeFlag&256||le&&Jt(le.vnode)&&le.vnode.shapeFlag&256)&&h.a&&Ee(h.a,I),h.isMounted=!0,p=v=N=null}},$=h.effect=new yn(R,ge,()=>Ms(O),h.scope),O=h.update=()=>{$.dirty&&$.run()};O.id=h.uid,Yt(h,!0),O()},Y=(h,p,v)=>{p.component=h;const N=h.vnode.props;h.vnode=p,h.next=null,Nh(h,p.props,N,v),Oh(h,p.children,v),vt(),sl(h),Et()},K=(h,p,v,N,I,L,D,R,$=!1)=>{const O=h&&h.children,U=h?h.shapeFlag:0,q=p.children,{patchFlag:j,shapeFlag:z}=p;if(j>0){if(j&128){$t(O,q,v,N,I,L,D,R,$);return}else if(j&256){je(O,q,v,N,I,L,D,R,$);return}}z&8?(U&16&>(O,I,L),q!==O&&u(v,q)):U&16?z&16?$t(O,q,v,N,I,L,D,R,$):gt(O,I,L,!0):(U&8&&u(v,""),z&16&&b(q,v,N,I,L,D,R,$))},je=(h,p,v,N,I,L,D,R,$)=>{h=h||hn,p=p||hn;const O=h.length,U=p.length,q=Math.min(O,U);let j;for(j=0;jU?gt(h,I,L,!0,!1,q):b(p,v,N,I,L,D,R,$,q)},$t=(h,p,v,N,I,L,D,R,$)=>{let O=0;const U=p.length;let q=h.length-1,j=U-1;for(;O<=q&&O<=j;){const z=h[O],ee=p[O]=$?xt(p[O]):He(p[O]);if(Qe(z,ee))x(z,ee,v,null,I,L,D,R,$);else break;O++}for(;O<=q&&O<=j;){const z=h[q],ee=p[j]=$?xt(p[j]):He(p[j]);if(Qe(z,ee))x(z,ee,v,null,I,L,D,R,$);else break;q--,j--}if(O>q){if(O<=j){const z=j+1,ee=zj)for(;O<=q;)lt(h[O],I,L,!0),O++;else{const z=O,ee=O,le=new Map;for(O=ee;O<=j;O++){const qe=p[O]=$?xt(p[O]):He(p[O]);qe.key!=null&&le.set(qe.key,O)}let fe,ve=0;const nt=j-ee+1;let Mn=!1,hf=0;const gs=new Array(nt);for(O=0;O=nt){lt(qe,I,L,!0);continue}let ct;if(qe.key!=null)ct=le.get(qe.key);else for(fe=ee;fe<=j;fe++)if(gs[fe-ee]===0&&Qe(qe,p[fe])){ct=fe;break}ct===void 0?lt(qe,I,L,!0):(gs[ct-ee]=O+1,ct>=hf?hf=ct:Mn=!0,x(qe,p[ct],v,null,I,L,D,R,$),ve++)}const df=Mn?Ph(gs):hn;for(fe=df.length-1,O=nt-1;O>=0;O--){const qe=ee+O,ct=p[qe],pf=qe+1{const{el:L,type:D,transition:R,children:$,shapeFlag:O}=h;if(O&6){un(h.component.subTree,p,v,N);return}if(O&128){h.suspense.move(p,v,N);return}if(O&64){D.move(h,p,v,Rn);return}if(D===Ce){s(L,p,v);for(let q=0;q<$.length;q++)un($[q],p,v,N);s(h.anchor,p,v);return}if(D===Zt){m(h,p,v);return}if(N!==2&&O&1&&R)if(N===0)R.beforeEnter(L),s(L,p,v),Ee(()=>R.enter(L),I);else{const{leave:q,delayLeave:j,afterLeave:z}=R,ee=()=>s(L,p,v),le=()=>{q(L,()=>{ee(),z&&z()})};j?j(L,ee,le):le()}else s(L,p,v)},lt=(h,p,v,N=!1,I=!1)=>{const{type:L,props:D,ref:R,children:$,dynamicChildren:O,shapeFlag:U,patchFlag:q,dirs:j}=h;if(R!=null&&zs(R,null,v,h,!0),U&256){p.ctx.deactivate(h);return}const z=U&1&&j,ee=!Jt(h);let le;if(ee&&(le=D&&D.onVnodeBeforeUnmount)&&Pe(le,p,h),U&6)_g(h.component,v,N);else{if(U&128){h.suspense.unmount(v,N);return}z&&rt(h,null,p,"beforeUnmount"),U&64?h.type.remove(h,p,v,I,Rn,N):O&&(L!==Ce||q>0&&q&64)?gt(O,p,v,!1,!0):(L===Ce&&q&384||!I&&U&16)&>($,p,v),N&&ff(h)}(ee&&(le=D&&D.onVnodeUnmounted)||z)&&Ee(()=>{le&&Pe(le,p,h),z&&rt(h,null,p,"unmounted")},v)},ff=h=>{const{type:p,el:v,anchor:N,transition:I}=h;if(p===Ce){yg(v,N);return}if(p===Zt){y(h);return}const L=()=>{i(v),I&&!I.persisted&&I.afterLeave&&I.afterLeave()};if(h.shapeFlag&1&&I&&!I.persisted){const{leave:D,delayLeave:R}=I,$=()=>D(v,L);R?R(h.el,L,$):$()}else L()},yg=(h,p)=>{let v;for(;h!==p;)v=d(h),i(h),h=v;i(p)},_g=(h,p,v)=>{const{bum:N,scope:I,update:L,subTree:D,um:R}=h;N&&gn(N),I.stop(),L&&(L.active=!1,lt(D,h,p,v)),R&&Ee(R,p),Ee(()=>{h.isUnmounted=!0},p),p&&p.pendingBranch&&!p.isUnmounted&&h.asyncDep&&!h.asyncResolved&&h.suspenseId===p.pendingId&&(p.deps--,p.deps===0&&p.resolve())},gt=(h,p,v,N=!1,I=!1,L=0)=>{for(let D=L;Dh.shapeFlag&6?Oi(h.component.subTree):h.shapeFlag&128?h.suspense.next():d(h.anchor||h.el);let go=!1;const uf=(h,p,v)=>{h==null?p._vnode&<(p._vnode,null,null,!0):x(p._vnode||null,h,p,null,null,null,v),go||(go=!0,sl(),Ls(),go=!1),p._vnode=h},Rn={p:x,um:lt,m:un,r:ff,mt:G,mc:b,pc:K,pbc:T,n:Oi,o:e};let yo,_o;return t&&([yo,_o]=t(Rn)),{render:uf,hydrate:yo,createApp:Th(uf,yo)}}function Sr({type:e,props:t},n){return n==="svg"&&e==="foreignObject"||n==="mathml"&&e==="annotation-xml"&&t&&t.encoding&&t.encoding.includes("html")?void 0:n}function Yt({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function Yl(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function vr(e,t,n=!1){const s=e.children,i=t.children;if(V(s)&&V(i))for(let r=0;r>1,e[n[l]]0&&(t[s]=n[r-1]),n[r]=s)}}for(r=n.length,o=n[r-1];r-- >0;)n[r]=o,o=t[o];return n}function Xl(e){const t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:Xl(t)}const Lh=e=>e.__isTeleport,Qn=e=>e&&(e.disabled||e.disabled===""),Zl=e=>typeof SVGElement<"u"&&e instanceof SVGElement,Ql=e=>typeof MathMLElement=="function"&&e instanceof MathMLElement,Er=(e,t)=>{const n=e&&e.to;return J(n)?t?t(n):null:n},Fh={name:"Teleport",__isTeleport:!0,process(e,t,n,s,i,r,o,l,c,a){const{mc:u,pc:f,pbc:d,o:{insert:g,querySelector:_,createText:x,createComment:M}}=a,P=Qn(t.props);let{shapeFlag:A,children:m,dynamicChildren:y}=t;if(e==null){const S=t.el=x(""),C=t.anchor=x("");g(S,n,s),g(C,n,s);const F=t.target=Er(t.props,_),b=t.targetAnchor=x("");F&&(g(b,F),o==="svg"||Zl(F)?o="svg":(o==="mathml"||Ql(F))&&(o="mathml"));const E=(T,k)=>{A&16&&u(m,T,k,i,r,o,l,c)};P?E(n,C):F&&E(F,b)}else{t.el=e.el;const S=t.anchor=e.anchor,C=t.target=e.target,F=t.targetAnchor=e.targetAnchor,b=Qn(e.props),E=b?n:C,T=b?S:F;if(o==="svg"||Zl(C)?o="svg":(o==="mathml"||Ql(C))&&(o="mathml"),y?(d(e.dynamicChildren,y,E,i,r,o,l),vr(e,t,!0)):c||f(e,t,E,T,i,r,o,l,!1),P)b?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):Xs(t,n,S,a,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const k=t.target=Er(t.props,_);k&&Xs(t,k,null,a,0)}else b&&Xs(t,C,F,a,1)}ec(t)},remove(e,t,n,s,{um:i,o:{remove:r}},o){const{shapeFlag:l,children:c,anchor:a,targetAnchor:u,target:f,props:d}=e;if(f&&r(u),o&&r(a),l&16){const g=o||!Qn(d);for(let _=0;_0?Me||hn:null,tc(),Qt>0&&Me&&Me.push(e),e}function Nt(e,t,n,s,i,r){return nc(Ne(e,t,n,s,i,r,!0))}function Tr(e,t,n,s,i){return nc(ce(e,t,n,s,i,!0))}function It(e){return e?e.__v_isVNode===!0:!1}function Qe(e,t){return e.type===t.type&&e.key===t.key}function Vh(e){}const Zs="__vInternal",sc=({key:e})=>e??null,Qs=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?J(e)||Se(e)||W(e)?{i:me,r:e,k:t,f:!!n}:e:null);function Ne(e,t=null,n=null,s=0,i=null,r=e===Ce?0:1,o=!1,l=!1){const c={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&sc(t),ref:t&&Qs(t),scopeId:Ds,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:r,patchFlag:s,dynamicProps:i,dynamicChildren:null,appContext:null,ctx:me};return l?(wr(c,n),r&128&&e.normalize(c)):n&&(c.shapeFlag|=J(n)?8:16),Qt>0&&!o&&Me&&(c.patchFlag>0||r&6)&&c.patchFlag!==32&&Me.push(c),c}const ce=Bh;function Bh(e,t=null,n=null,s=0,i=null,r=!1){if((!e||e===cl)&&(e=we),It(e)){const l=ot(e,t,!0);return n&&wr(l,n),Qt>0&&!r&&Me&&(l.shapeFlag&6?Me[Me.indexOf(e)]=l:Me.push(l)),l.patchFlag|=-2,l}if(Yh(e)&&(e=e.__vccOpts),t){t=ic(t);let{class:l,style:c}=t;l&&!J(l)&&(t.class=_t(l)),oe(c)&&(ji(c)&&!V(c)&&(c=ne({},c)),t.style=Ln(c))}const o=J(e)?1:fl(e)?128:Lh(e)?64:oe(e)?4:W(e)?2:0;return Ne(e,t,n,s,i,o,r,!0)}function ic(e){return e?ji(e)||Zs in e?ne({},e):e:null}function ot(e,t,n=!1){const{props:s,ref:i,patchFlag:r,children:o}=e,l=t?rc(s||{},t):s;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&sc(l),ref:t&&t.ref?n&&i?V(i)?i.concat(Qs(t)):[i,Qs(t)]:Qs(t):i,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:o,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==Ce?r===-1?16:r|16:r,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&ot(e.ssContent),ssFallback:e.ssFallback&&ot(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function Ar(e=" ",t=0){return ce(Xt,null,e,t)}function Hh(e,t){const n=ce(Zt,null,e);return n.staticCount=t,n}function Uh(e="",t=!1){return t?(Ze(),Tr(we,null,e)):ce(we,null,e)}function He(e){return e==null||typeof e=="boolean"?ce(we):V(e)?ce(Ce,null,e.slice()):typeof e=="object"?xt(e):ce(Xt,null,String(e))}function xt(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:ot(e)}function wr(e,t){let n=0;const{shapeFlag:s}=e;if(t==null)t=null;else if(V(t))n=16;else if(typeof t=="object")if(s&65){const i=t.default;i&&(i._c&&(i._d=!1),wr(e,i()),i._c&&(i._d=!0));return}else{n=32;const i=t._;!i&&!(Zs in t)?t._ctx=me:i===3&&me&&(me.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else W(t)?(t={default:t,_ctx:me},n=32):(t=String(t),s&64?(n=16,t=[Ar(t)]):n=8);e.children=t,e.shapeFlag|=n}function rc(...e){const t={};for(let n=0;nye||me;let ei,Nr;{const e=Co(),t=(n,s)=>{let i;return(i=e[n])||(i=e[n]=[]),i.push(s),r=>{i.length>1?i.forEach(o=>o(r)):i[0](r)}};ei=t("__VUE_INSTANCE_SETTERS__",n=>ye=n),Nr=t("__VUE_SSR_SETTERS__",n=>ts=n)}const en=e=>{const t=ye;return ei(e),e.scope.on(),()=>{e.scope.off(),ei(t)}},Ir=()=>{ye&&ye.scope.off(),ei(null)};function lc(e){return e.vnode.shapeFlag&4}let ts=!1;function cc(e,t=!1){t&&Nr(t);const{props:n,children:s}=e.vnode,i=lc(e);wh(e,n,i,t),xh(e,s);const r=i?qh(e,t):void 0;return t&&Nr(!1),r}function qh(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=qi(new Proxy(e.ctx,pr));const{setup:s}=n;if(s){const i=e.setupContext=s.length>1?uc(e):null,r=en(e);vt();const o=st(s,e,0,[e.props,i]);if(Et(),r(),Mi(o)){if(o.then(Ir,Ir),t)return o.then(l=>{xr(e,l,t)}).catch(l=>{qt(l,e,0)});e.asyncDep=o}else xr(e,o,t)}else fc(e,t)}function xr(e,t,n){W(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:oe(t)&&(e.setupState=Ji(t)),fc(e,n)}let ti,Or;function ac(e){ti=e,Or=t=>{t.render._rc&&(t.withProxy=new Proxy(t.ctx,ih))}}const Wh=()=>!ti;function fc(e,t,n){const s=e.type;if(!e.render){if(!t&&ti&&!s.render){const i=s.template||gr(e).template;if(i){const{isCustomElement:r,compilerOptions:o}=e.appContext.config,{delimiters:l,compilerOptions:c}=s,a=ne(ne({isCustomElement:r,delimiters:l},o),c);s.render=ti(i,a)}}e.render=s.render||ge,Or&&Or(e)}{const i=en(e);vt();try{_h(e)}finally{Et(),i()}}}function Gh(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return Re(e,"get","$attrs"),t[n]}}))}function uc(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return Gh(e)},slots:e.slots,emit:e.emit,expose:t}}function ni(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Ji(qi(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Jn)return Jn[n](e)},has(t,n){return n in t||n in Jn}}))}const zh=/(?:^|[-_])(\w)/g,Jh=e=>e.replace(zh,t=>t.toUpperCase()).replace(/[-_]/g,"");function si(e,t=!0){return W(e)?e.displayName||e.name:e.name||t&&e.__name}function hc(e,t,n=!1){let s=si(t);if(!s&&t.__file){const i=t.__file.match(/([^/\\]+)\.\w+$/);i&&(s=i[1])}if(!s&&e&&e.parent){const i=r=>{for(const o in r)if(r[o]===t)return o};s=i(e.components||e.parent.type.components)||i(e.appContext.components)}return s?Jh(s):n?"App":"Anonymous"}function Yh(e){return W(e)&&"__vccOpts"in e}const dc=(e,t)=>cu(e,t,ts);function Xh(e,t,n=ie){const s=ut(),i=ue(t),r=De(t),o=Zo((c,a)=>{let u;return gl(()=>{const f=e[t];Xe(u,f)&&(u=f,a())}),{get(){return c(),n.get?n.get(u):u},set(f){const d=s.vnode.props;!(d&&(t in d||i in d||r in d)&&(`onUpdate:${t}`in d||`onUpdate:${i}`in d||`onUpdate:${r}`in d))&&Xe(f,u)&&(u=f,a()),s.emit(`update:${t}`,n.set?n.set(f):f)}}}),l=t==="modelValue"?"modelModifiers":`${t}Modifiers`;return o[Symbol.iterator]=()=>{let c=0;return{next(){return c<2?{value:c++?e[l]||{}:o,done:!1}:{done:!0}}}},o}function pc(e,t,n){const s=arguments.length;return s===2?oe(t)&&!V(t)?It(t)?ce(e,null,[t]):ce(e,t):ce(e,null,t):(s>3?n=Array.prototype.slice.call(arguments,2):s===3&&It(n)&&(n=[n]),ce(e,t,n))}function Zh(){}function Qh(e,t,n,s){const i=n[s];if(i&&mc(i,e))return i;const r=t();return r.memo=e.slice(),n[s]=r}function mc(e,t){const n=e.memo;if(n.length!=t.length)return!1;for(let s=0;s0&&Me&&Me.push(e),!0}const gc="3.4.21",ed=ge,td=Nu,nd=Sn,sd=rl,id={createComponentInstance:oc,setupComponent:cc,renderComponentRoot:Vs,setCurrentRenderingInstance:Un,isVNode:It,normalizeVNode:He},rd=null,od=null,ld=null;/** +* @vue/runtime-dom v3.4.21 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/const cd="http://www.w3.org/2000/svg",ad="http://www.w3.org/1998/Math/MathML",Ot=typeof document<"u"?document:null,yc=Ot&&Ot.createElement("template"),fd={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,s)=>{const i=t==="svg"?Ot.createElementNS(cd,e):t==="mathml"?Ot.createElementNS(ad,e):Ot.createElement(e,n?{is:n}:void 0);return e==="select"&&s&&s.multiple!=null&&i.setAttribute("multiple",s.multiple),i},createText:e=>Ot.createTextNode(e),createComment:e=>Ot.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Ot.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,s,i,r){const o=n?n.previousSibling:t.lastChild;if(i&&(i===r||i.nextSibling))for(;t.insertBefore(i.cloneNode(!0),n),!(i===r||!(i=i.nextSibling)););else{yc.innerHTML=s==="svg"?`${e}`:s==="mathml"?`${e}`:e;const l=yc.content;if(s==="svg"||s==="mathml"){const c=l.firstChild;for(;c.firstChild;)l.appendChild(c.firstChild);l.removeChild(c)}t.insertBefore(l,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},kt="transition",ns="animation",An=Symbol("_vtc"),kr=(e,{slots:t})=>pc(_l,Sc(e),t);kr.displayName="Transition";const _c={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},ud=kr.props=ne({},or,_c),tn=(e,t=[])=>{V(e)?e.forEach(n=>n(...t)):e&&e(...t)},bc=e=>e?V(e)?e.some(t=>t.length>1):e.length>1:!1;function Sc(e){const t={};for(const w in e)w in _c||(t[w]=e[w]);if(e.css===!1)return t;const{name:n="v",type:s,duration:i,enterFromClass:r=`${n}-enter-from`,enterActiveClass:o=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:c=r,appearActiveClass:a=o,appearToClass:u=l,leaveFromClass:f=`${n}-leave-from`,leaveActiveClass:d=`${n}-leave-active`,leaveToClass:g=`${n}-leave-to`}=e,_=hd(i),x=_&&_[0],M=_&&_[1],{onBeforeEnter:P,onEnter:A,onEnterCancelled:m,onLeave:y,onLeaveCancelled:S,onBeforeAppear:C=P,onAppear:F=A,onAppearCancelled:b=m}=t,E=(w,B,G)=>{Rt(w,B?u:l),Rt(w,B?a:o),G&&G()},T=(w,B)=>{w._isLeaving=!1,Rt(w,f),Rt(w,g),Rt(w,d),B&&B()},k=w=>(B,G)=>{const Q=w?F:A,H=()=>E(B,w,G);tn(Q,[B,H]),vc(()=>{Rt(B,w?c:r),ht(B,w?u:l),bc(Q)||Ec(B,s,x,H)})};return ne(t,{onBeforeEnter(w){tn(P,[w]),ht(w,r),ht(w,o)},onBeforeAppear(w){tn(C,[w]),ht(w,c),ht(w,a)},onEnter:k(!1),onAppear:k(!0),onLeave(w,B){w._isLeaving=!0;const G=()=>T(w,B);ht(w,f),wc(),ht(w,d),vc(()=>{w._isLeaving&&(Rt(w,f),ht(w,g),bc(y)||Ec(w,s,M,G))}),tn(y,[w,G])},onEnterCancelled(w){E(w,!1),tn(m,[w])},onAppearCancelled(w){E(w,!0),tn(b,[w])},onLeaveCancelled(w){T(w),tn(S,[w])}})}function hd(e){if(e==null)return null;if(oe(e))return[Rr(e.enter),Rr(e.leave)];{const t=Rr(e);return[t,t]}}function Rr(e){return Ss(e)}function ht(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[An]||(e[An]=new Set)).add(t)}function Rt(e,t){t.split(/\s+/).forEach(s=>s&&e.classList.remove(s));const n=e[An];n&&(n.delete(t),n.size||(e[An]=void 0))}function vc(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let dd=0;function Ec(e,t,n,s){const i=e._endId=++dd,r=()=>{i===e._endId&&s()};if(n)return setTimeout(r,n);const{type:o,timeout:l,propCount:c}=Cc(e,t);if(!o)return s();const a=o+"end";let u=0;const f=()=>{e.removeEventListener(a,d),r()},d=g=>{g.target===e&&++u>=c&&f()};setTimeout(()=>{u(n[_]||"").split(", "),i=s(`${kt}Delay`),r=s(`${kt}Duration`),o=Tc(i,r),l=s(`${ns}Delay`),c=s(`${ns}Duration`),a=Tc(l,c);let u=null,f=0,d=0;t===kt?o>0&&(u=kt,f=o,d=r.length):t===ns?a>0&&(u=ns,f=a,d=c.length):(f=Math.max(o,a),u=f>0?o>a?kt:ns:null,d=u?u===kt?r.length:c.length:0);const g=u===kt&&/\b(transform|all)(,|$)/.test(s(`${kt}Property`).toString());return{type:u,timeout:f,propCount:d,hasTransform:g}}function Tc(e,t){for(;e.lengthAc(n)+Ac(e[s])))}function Ac(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function wc(){return document.body.offsetHeight}function pd(e,t,n){const s=e[An];s&&(t=(t?[t,...s]:[...s]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const ii=Symbol("_vod"),Nc=Symbol("_vsh"),Ic={beforeMount(e,{value:t},{transition:n}){e[ii]=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):ss(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:s}){!t!=!n&&(s?t?(s.beforeEnter(e),ss(e,!0),s.enter(e)):s.leave(e,()=>{ss(e,!1)}):ss(e,t))},beforeUnmount(e,{value:t}){ss(e,t)}};function ss(e,t){e.style.display=t?e[ii]:"none",e[Nc]=!t}function md(){Ic.getSSRProps=({value:e})=>{if(!e)return{style:{display:"none"}}}}const xc=Symbol("");function gd(e){const t=ut();if(!t)return;const n=t.ut=(i=e(t.proxy))=>{Array.from(document.querySelectorAll(`[data-v-owner="${t.uid}"]`)).forEach(r=>Pr(r,i))},s=()=>{const i=e(t.proxy);Mr(t.subTree,i),n(i)};ml(s),zn(()=>{const i=new MutationObserver(s);i.observe(t.subTree.el.parentNode,{childList:!0}),Ws(()=>i.disconnect())})}function Mr(e,t){if(e.shapeFlag&128){const n=e.suspense;e=n.activeBranch,n.pendingBranch&&!n.isHydrating&&n.effects.push(()=>{Mr(n.activeBranch,t)})}for(;e.component;)e=e.component.subTree;if(e.shapeFlag&1&&e.el)Pr(e.el,t);else if(e.type===Ce)e.children.forEach(n=>Mr(n,t));else if(e.type===Zt){let{el:n,anchor:s}=e;for(;n&&(Pr(n,t),n!==s);)n=n.nextSibling}}function Pr(e,t){if(e.nodeType===1){const n=e.style;let s="";for(const i in t)n.setProperty(`--${i}`,t[i]),s+=`--${i}: ${t[i]};`;n[xc]=s}}const yd=/(^|;)\s*display\s*:/;function _d(e,t,n){const s=e.style,i=J(n);let r=!1;if(n&&!i){if(t)if(J(t))for(const o of t.split(";")){const l=o.slice(0,o.indexOf(":")).trim();n[l]==null&&ri(s,l,"")}else for(const o in t)n[o]==null&&ri(s,o,"");for(const o in n)o==="display"&&(r=!0),ri(s,o,n[o])}else if(i){if(t!==n){const o=s[xc];o&&(n+=";"+o),s.cssText=n,r=yd.test(n)}}else t&&e.removeAttribute("style");ii in e&&(e[ii]=r?s.display:"",e[Nc]&&(s.display="none"))}const Oc=/\s*!important$/;function ri(e,t,n){if(V(n))n.forEach(s=>ri(e,t,s));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const s=bd(e,t);Oc.test(n)?e.setProperty(De(s),n.replace(Oc,""),"important"):e[s]=n}}const kc=["Webkit","Moz","ms"],Lr={};function bd(e,t){const n=Lr[t];if(n)return n;let s=ue(t);if(s!=="filter"&&s in e)return Lr[t]=s;s=Bt(s);for(let i=0;iFr||(Ad.then(()=>Fr=0),Fr=Date.now());function Nd(e,t){const n=s=>{if(!s._vts)s._vts=Date.now();else if(s._vts<=n.attached)return;Be(Id(s,n.value),t,5,[s])};return n.value=e,n.attached=wd(),n}function Id(e,t){if(V(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(s=>i=>!i._stopped&&s&&s(i))}else return t}const Lc=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,xd=(e,t,n,s,i,r,o,l,c)=>{const a=i==="svg";t==="class"?pd(e,s,a):t==="style"?_d(e,n,s):Dt(t)?ki(t)||Cd(e,t,n,s,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):Od(e,t,s,a))?vd(e,t,s,r,o,l,c):(t==="true-value"?e._trueValue=s:t==="false-value"&&(e._falseValue=s),Sd(e,t,s,a))};function Od(e,t,n,s){if(s)return!!(t==="innerHTML"||t==="textContent"||t in e&&Lc(t)&&W(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const i=e.tagName;if(i==="IMG"||i==="VIDEO"||i==="CANVAS"||i==="SOURCE")return!1}return Lc(t)&&J(n)?!1:t in e}/*! #__NO_SIDE_EFFECTS__ */function Fc(e,t){const n=cr(e);class s extends oi{constructor(r){super(n,r,t)}}return s.def=n,s}/*! #__NO_SIDE_EFFECTS__ */const kd=e=>Fc(e,Zc),Rd=typeof HTMLElement<"u"?HTMLElement:class{};class oi extends Rd{constructor(t,n={},s){super(),this._def=t,this._props=n,this._instance=null,this._connected=!1,this._resolved=!1,this._numberProps=null,this._ob=null,this.shadowRoot&&s?s(this._createVNode(),this.shadowRoot):(this.attachShadow({mode:"open"}),this._def.__asyncLoader||this._resolveProps(this._def))}connectedCallback(){this._connected=!0,this._instance||(this._resolved?this._update():this._resolveDef())}disconnectedCallback(){this._connected=!1,this._ob&&(this._ob.disconnect(),this._ob=null),Rs(()=>{this._connected||(Vr(null,this.shadowRoot),this._instance=null)})}_resolveDef(){this._resolved=!0;for(let s=0;s{for(const i of s)this._setAttr(i.attributeName)}),this._ob.observe(this,{attributes:!0});const t=(s,i=!1)=>{const{props:r,styles:o}=s;let l;if(r&&!V(r))for(const c in r){const a=r[c];(a===Number||a&&a.type===Number)&&(c in this._props&&(this._props[c]=Ss(this._props[c])),(l||(l=Object.create(null)))[ue(c)]=!0)}this._numberProps=l,i&&this._resolveProps(s),this._applyStyles(o),this._update()},n=this._def.__asyncLoader;n?n().then(s=>t(s,!0)):t(this._def)}_resolveProps(t){const{props:n}=t,s=V(n)?n:Object.keys(n||{});for(const i of Object.keys(this))i[0]!=="_"&&s.includes(i)&&this._setProp(i,this[i],!0,!1);for(const i of s.map(ue))Object.defineProperty(this,i,{get(){return this._getProp(i)},set(r){this._setProp(i,r)}})}_setAttr(t){let n=this.getAttribute(t);const s=ue(t);this._numberProps&&this._numberProps[s]&&(n=Ss(n)),this._setProp(s,n,!1)}_getProp(t){return this._props[t]}_setProp(t,n,s=!0,i=!0){n!==this._props[t]&&(this._props[t]=n,i&&this._instance&&this._update(),s&&(n===!0?this.setAttribute(De(t),""):typeof n=="string"||typeof n=="number"?this.setAttribute(De(t),n+""):n||this.removeAttribute(De(t))))}_update(){Vr(this._createVNode(),this.shadowRoot)}_createVNode(){const t=ce(this._def,ne({},this._props));return this._instance||(t.ce=n=>{this._instance=n,n.isCE=!0;const s=(r,o)=>{this.dispatchEvent(new CustomEvent(r,{detail:o}))};n.emit=(r,...o)=>{s(r,o),De(r)!==r&&s(De(r),o)};let i=this;for(;i=i&&(i.parentNode||i.host);)if(i instanceof oi){n.parent=i._instance,n.provides=i._instance.provides;break}}),t}_applyStyles(t){t&&t.forEach(n=>{const s=document.createElement("style");s.textContent=n,this.shadowRoot.appendChild(s)})}}function Md(e="$style"){{const t=ut();if(!t)return ie;const n=t.type.__cssModules;if(!n)return ie;const s=n[e];return s||ie}}const $c=new WeakMap,Dc=new WeakMap,li=Symbol("_moveCb"),Vc=Symbol("_enterCb"),Bc={name:"TransitionGroup",props:ne({},ud,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=ut(),s=rr();let i,r;return js(()=>{if(!i.length)return;const o=e.moveClass||`${e.name||"v"}-move`;if(!Vd(i[0].el,n.vnode.el,o))return;i.forEach(Fd),i.forEach($d);const l=i.filter(Dd);wc(),l.forEach(c=>{const a=c.el,u=a.style;ht(a,o),u.transform=u.webkitTransform=u.transitionDuration="";const f=a[li]=d=>{d&&d.target!==a||(!d||/transform$/.test(d.propertyName))&&(a.removeEventListener("transitionend",f),a[li]=null,Rt(a,o))};a.addEventListener("transitionend",f)})}),()=>{const o=Z(e),l=Sc(o);let c=o.tag||Ce;i=r,r=t.default?Us(t.default()):[];for(let a=0;adelete e.mode;Bc.props;const Ld=Bc;function Fd(e){const t=e.el;t[li]&&t[li](),t[Vc]&&t[Vc]()}function $d(e){Dc.set(e,e.el.getBoundingClientRect())}function Dd(e){const t=$c.get(e),n=Dc.get(e),s=t.left-n.left,i=t.top-n.top;if(s||i){const r=e.el.style;return r.transform=r.webkitTransform=`translate(${s}px,${i}px)`,r.transitionDuration="0s",e}}function Vd(e,t,n){const s=e.cloneNode(),i=e[An];i&&i.forEach(l=>{l.split(/\s+/).forEach(c=>c&&s.classList.remove(c))}),n.split(/\s+/).forEach(l=>l&&s.classList.add(l)),s.style.display="none";const r=t.nodeType===1?t:t.parentNode;r.appendChild(s);const{hasTransform:o}=Cc(s);return r.removeChild(s),o}const Mt=e=>{const t=e.props["onUpdate:modelValue"]||!1;return V(t)?n=>gn(t,n):t};function Bd(e){e.target.composing=!0}function Hc(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const Ge=Symbol("_assign"),ci={created(e,{modifiers:{lazy:t,trim:n,number:s}},i){e[Ge]=Mt(i);const r=s||i.props&&i.props.type==="number";dt(e,t?"change":"input",o=>{if(o.target.composing)return;let l=e.value;n&&(l=l.trim()),r&&(l=Pn(l)),e[Ge](l)}),n&&dt(e,"change",()=>{e.value=e.value.trim()}),t||(dt(e,"compositionstart",Bd),dt(e,"compositionend",Hc),dt(e,"change",Hc))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:s,number:i}},r){if(e[Ge]=Mt(r),e.composing)return;const o=i||e.type==="number"?Pn(e.value):e.value,l=t??"";o!==l&&(document.activeElement===e&&e.type!=="range"&&(n||s&&e.value.trim()===l)||(e.value=l))}},$r={deep:!0,created(e,t,n){e[Ge]=Mt(n),dt(e,"change",()=>{const s=e._modelValue,i=wn(e),r=e.checked,o=e[Ge];if(V(s)){const l=vs(s,i),c=l!==-1;if(r&&!c)o(s.concat(i));else if(!r&&c){const a=[...s];a.splice(l,1),o(a)}}else if(Vt(s)){const l=new Set(s);r?l.add(i):l.delete(i),o(l)}else o(qc(e,r))})},mounted:Uc,beforeUpdate(e,t,n){e[Ge]=Mt(n),Uc(e,t,n)}};function Uc(e,{value:t,oldValue:n},s){e._modelValue=t,V(t)?e.checked=vs(t,s.props.value)>-1:Vt(t)?e.checked=t.has(s.props.value):t!==n&&(e.checked=bt(t,qc(e,!0)))}const Dr={created(e,{value:t},n){e.checked=bt(t,n.props.value),e[Ge]=Mt(n),dt(e,"change",()=>{e[Ge](wn(e))})},beforeUpdate(e,{value:t,oldValue:n},s){e[Ge]=Mt(s),t!==n&&(e.checked=bt(t,s.props.value))}},Kc={deep:!0,created(e,{value:t,modifiers:{number:n}},s){const i=Vt(t);dt(e,"change",()=>{const r=Array.prototype.filter.call(e.options,o=>o.selected).map(o=>n?Pn(wn(o)):wn(o));e[Ge](e.multiple?i?new Set(r):r:r[0]),e._assigning=!0,Rs(()=>{e._assigning=!1})}),e[Ge]=Mt(s)},mounted(e,{value:t,modifiers:{number:n}}){jc(e,t,n)},beforeUpdate(e,t,n){e[Ge]=Mt(n)},updated(e,{value:t,modifiers:{number:n}}){e._assigning||jc(e,t,n)}};function jc(e,t,n){const s=e.multiple,i=V(t);if(!(s&&!i&&!Vt(t))){for(let r=0,o=e.options.length;r-1}else l.selected=t.has(c);else if(bt(wn(l),t)){e.selectedIndex!==r&&(e.selectedIndex=r);return}}!s&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function wn(e){return"_value"in e?e._value:e.value}function qc(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}const Wc={created(e,t,n){ai(e,t,n,null,"created")},mounted(e,t,n){ai(e,t,n,null,"mounted")},beforeUpdate(e,t,n,s){ai(e,t,n,s,"beforeUpdate")},updated(e,t,n,s){ai(e,t,n,s,"updated")}};function Gc(e,t){switch(e){case"SELECT":return Kc;case"TEXTAREA":return ci;default:switch(t){case"checkbox":return $r;case"radio":return Dr;default:return ci}}}function ai(e,t,n,s,i){const o=Gc(e.tagName,n.props&&n.props.type)[i];o&&o(e,t,n,s)}function Hd(){ci.getSSRProps=({value:e})=>({value:e}),Dr.getSSRProps=({value:e},t)=>{if(t.props&&bt(t.props.value,e))return{checked:!0}},$r.getSSRProps=({value:e},t)=>{if(V(e)){if(t.props&&vs(e,t.props.value)>-1)return{checked:!0}}else if(Vt(e)){if(t.props&&e.has(t.props.value))return{checked:!0}}else if(e)return{checked:!0}},Wc.getSSRProps=(e,t)=>{if(typeof t.type!="string")return;const n=Gc(t.type.toUpperCase(),t.props&&t.props.type);if(n.getSSRProps)return n.getSSRProps(e,t)}}const Ud=["ctrl","shift","alt","meta"],Kd={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>Ud.some(n=>e[`${n}Key`]&&!t.includes(n))},jd=(e,t)=>{const n=e._withMods||(e._withMods={}),s=t.join(".");return n[s]||(n[s]=(i,...r)=>{for(let o=0;o{const n=e._withKeys||(e._withKeys={}),s=t.join(".");return n[s]||(n[s]=i=>{if(!("key"in i))return;const r=De(i.key);if(t.some(o=>o===r||qd[o]===r))return e(i)})},zc=ne({patchProp:xd},fd);let is,Jc=!1;function Yc(){return is||(is=Gl(zc))}function Xc(){return is=Jc?is:zl(zc),Jc=!0,is}const Vr=(...e)=>{Yc().render(...e)},Zc=(...e)=>{Xc().hydrate(...e)},Qc=(...e)=>{const t=Yc().createApp(...e),{mount:n}=t;return t.mount=s=>{const i=ta(s);if(!i)return;const r=t._component;!W(r)&&!r.render&&!r.template&&(r.template=i.innerHTML),i.innerHTML="";const o=n(i,!1,ea(i));return i instanceof Element&&(i.removeAttribute("v-cloak"),i.setAttribute("data-v-app","")),o},t},Gd=(...e)=>{const t=Xc().createApp(...e),{mount:n}=t;return t.mount=s=>{const i=ta(s);if(i)return n(i,!0,ea(i))},t};function ea(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function ta(e){return J(e)?document.querySelector(e):e}let na=!1;const zd=Object.freeze(Object.defineProperty({__proto__:null,BaseTransition:_l,BaseTransitionPropsValidators:or,Comment:we,DeprecationTypes:ld,EffectScope:Fi,ErrorCodes:wu,ErrorTypeStrings:td,Fragment:Ce,KeepAlive:Qu,ReactiveEffect:yn,Static:Zt,Suspense:Ku,Teleport:Dh,Text:Xt,TrackOpTypes:bu,Transition:kr,TransitionGroup:Ld,TriggerOpTypes:Su,VueElement:oi,assertNumber:Au,callWithAsyncErrorHandling:Be,callWithErrorHandling:st,camelize:ue,capitalize:Bt,cloneVNode:ot,compatUtils:od,computed:dc,createApp:Qc,createBlock:Tr,createCommentVNode:Uh,createElementBlock:Nt,createElementVNode:Ne,createHydrationRenderer:zl,createPropsRestProxy:gh,createRenderer:Gl,createSSRApp:Gd,createSlots:nh,createStaticVNode:Hh,createTextVNode:Ar,createVNode:ce,customRef:Zo,defineAsyncComponent:Zu,defineComponent:cr,defineCustomElement:Fc,defineEmits:oh,defineExpose:lh,defineModel:fh,defineOptions:ch,defineProps:rh,defineSSRCustomElement:kd,defineSlots:ah,devtools:nd,effect:Bf,effectScope:$f,getCurrentInstance:ut,getCurrentScope:Io,getTransitionRawChildren:Us,guardReactiveProps:ic,h:pc,handleError:qt,hasInjectionContext:Ah,hydrate:Zc,initCustomFormatter:Zh,initDirectivesForSSR:()=>{na||(na=!0,Hd(),md())},inject:Zn,isMemoSame:mc,isProxy:ji,isReactive:Kt,isReadonly:jt,isRef:Se,isRuntimeOnly:Wh,isShallow:Fn,isVNode:It,markRaw:qi,mergeDefaults:ph,mergeModels:mh,mergeProps:rc,nextTick:Rs,normalizeClass:_t,normalizeProps:Af,normalizeStyle:Ln,onActivated:vl,onBeforeMount:Tl,onBeforeUnmount:qs,onBeforeUpdate:Al,onDeactivated:El,onErrorCaptured:xl,onMounted:zn,onRenderTracked:Il,onRenderTriggered:Nl,onScopeDispose:Df,onServerPrefetch:wl,onUnmounted:Ws,onUpdated:js,openBlock:Ze,popScopeId:Pu,provide:$l,proxyRefs:Ji,pushScopeId:Mu,queuePostFlushCb:Ps,reactive:Os,readonly:Ki,ref:Dn,registerRuntimeCompiler:ac,render:Vr,renderList:th,renderSlot:Cn,resolveComponent:tr,resolveDirective:Uu,resolveDynamicComponent:Hu,resolveFilter:rd,resolveTransitionHooks:En,setBlockTracking:Cr,setDevtoolsHook:sd,setTransitionHooks:zt,shallowReactive:Jo,shallowReadonly:lu,shallowRef:au,ssrContextKey:dl,ssrUtils:id,stop:Hf,toDisplayString:Ff,toHandlerKey:mn,toHandlers:sh,toRaw:Z,toRef:_u,toRefs:mu,toValue:hu,transformVNodeArgs:Vh,triggerRef:uu,unref:zi,useAttrs:dh,useCssModule:Md,useCssVars:gd,useModel:Xh,useSSRContext:pl,useSlots:hh,useTransitionState:rr,vModelCheckbox:$r,vModelDynamic:Wc,vModelRadio:Dr,vModelSelect:Kc,vModelText:ci,vShow:Ic,version:gc,warn:ed,watch:jn,watchEffect:Ju,watchPostEffect:ml,watchSyncEffect:gl,withAsyncContext:yh,withCtx:Zi,withDefaults:uh,withDirectives:Xu,withKeys:Wd,withMemo:Qh,withModifiers:jd,withScopeId:Lu},Symbol.toStringTag,{value:"Module"}));/** +* @vue/compiler-core v3.4.21 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/const rs=Symbol(""),os=Symbol(""),Br=Symbol(""),fi=Symbol(""),sa=Symbol(""),nn=Symbol(""),ia=Symbol(""),ra=Symbol(""),Hr=Symbol(""),Ur=Symbol(""),ls=Symbol(""),Kr=Symbol(""),oa=Symbol(""),jr=Symbol(""),qr=Symbol(""),Wr=Symbol(""),Gr=Symbol(""),zr=Symbol(""),Jr=Symbol(""),la=Symbol(""),ca=Symbol(""),ui=Symbol(""),hi=Symbol(""),Yr=Symbol(""),Xr=Symbol(""),cs=Symbol(""),as=Symbol(""),Zr=Symbol(""),Qr=Symbol(""),Jd=Symbol(""),eo=Symbol(""),di=Symbol(""),Yd=Symbol(""),Xd=Symbol(""),to=Symbol(""),Zd=Symbol(""),Qd=Symbol(""),no=Symbol(""),aa=Symbol(""),Nn={[rs]:"Fragment",[os]:"Teleport",[Br]:"Suspense",[fi]:"KeepAlive",[sa]:"BaseTransition",[nn]:"openBlock",[ia]:"createBlock",[ra]:"createElementBlock",[Hr]:"createVNode",[Ur]:"createElementVNode",[ls]:"createCommentVNode",[Kr]:"createTextVNode",[oa]:"createStaticVNode",[jr]:"resolveComponent",[qr]:"resolveDynamicComponent",[Wr]:"resolveDirective",[Gr]:"resolveFilter",[zr]:"withDirectives",[Jr]:"renderList",[la]:"renderSlot",[ca]:"createSlots",[ui]:"toDisplayString",[hi]:"mergeProps",[Yr]:"normalizeClass",[Xr]:"normalizeStyle",[cs]:"normalizeProps",[as]:"guardReactiveProps",[Zr]:"toHandlers",[Qr]:"camelize",[Jd]:"capitalize",[eo]:"toHandlerKey",[di]:"setBlockTracking",[Yd]:"pushScopeId",[Xd]:"popScopeId",[to]:"withCtx",[Zd]:"unref",[Qd]:"isRef",[no]:"withMemo",[aa]:"isMemoSame"};function ep(e){Object.getOwnPropertySymbols(e).forEach(t=>{Nn[t]=e[t]})}const Ue={start:{line:1,column:1,offset:0},end:{line:1,column:1,offset:0},source:""};function tp(e,t=""){return{type:0,source:t,children:e,helpers:new Set,components:[],directives:[],hoists:[],imports:[],cached:0,temps:0,codegenNode:void 0,loc:Ue}}function fs(e,t,n,s,i,r,o,l=!1,c=!1,a=!1,u=Ue){return e&&(l?(e.helper(nn),e.helper(On(e.inSSR,a))):e.helper(xn(e.inSSR,a)),o&&e.helper(zr)),{type:13,tag:t,props:n,children:s,patchFlag:i,dynamicProps:r,directives:o,isBlock:l,disableTracking:c,isComponent:a,loc:u}}function us(e,t=Ue){return{type:17,loc:t,elements:e}}function ze(e,t=Ue){return{type:15,loc:t,properties:e}}function he(e,t){return{type:16,loc:Ue,key:J(e)?X(e,!0):e,value:t}}function X(e,t=!1,n=Ue,s=0){return{type:4,loc:n,content:e,isStatic:t,constType:t?3:s}}function et(e,t=Ue){return{type:8,loc:t,children:e}}function _e(e,t=[],n=Ue){return{type:14,loc:n,callee:e,arguments:t}}function In(e,t=void 0,n=!1,s=!1,i=Ue){return{type:18,params:e,returns:t,newline:n,isSlot:s,loc:i}}function so(e,t,n,s=!0){return{type:19,test:e,consequent:t,alternate:n,newline:s,loc:Ue}}function np(e,t,n=!1){return{type:20,index:e,value:t,isVNode:n,loc:Ue}}function sp(e){return{type:21,body:e,loc:Ue}}function xn(e,t){return e||t?Hr:Ur}function On(e,t){return e||t?ia:ra}function io(e,{helper:t,removeHelper:n,inSSR:s}){e.isBlock||(e.isBlock=!0,n(xn(s,e.isComponent)),t(nn),t(On(s,e.isComponent)))}const fa=new Uint8Array([123,123]),ua=new Uint8Array([125,125]);function ha(e){return e>=97&&e<=122||e>=65&&e<=90}function Ke(e){return e===32||e===10||e===9||e===12||e===13}function Pt(e){return e===47||e===62||Ke(e)}function pi(e){const t=new Uint8Array(e.length);for(let n=0;n=0;i--){const r=this.newlines[i];if(t>r){n=i+2,s=t-r;break}}return{column:s,line:n,offset:t}}peek(){return this.buffer.charCodeAt(this.index+1)}stateText(t){t===60?(this.index>this.sectionStart&&this.cbs.ontext(this.sectionStart,this.index),this.state=5,this.sectionStart=this.index):!this.inVPre&&t===this.delimiterOpen[0]&&(this.state=2,this.delimiterIndex=0,this.stateInterpolationOpen(t))}stateInterpolationOpen(t){if(t===this.delimiterOpen[this.delimiterIndex])if(this.delimiterIndex===this.delimiterOpen.length-1){const n=this.index+1-this.delimiterOpen.length;n>this.sectionStart&&this.cbs.ontext(this.sectionStart,n),this.state=3,this.sectionStart=n}else this.delimiterIndex++;else this.inRCDATA?(this.state=32,this.stateInRCDATA(t)):(this.state=1,this.stateText(t))}stateInterpolation(t){t===this.delimiterClose[0]&&(this.state=4,this.delimiterIndex=0,this.stateInterpolationClose(t))}stateInterpolationClose(t){t===this.delimiterClose[this.delimiterIndex]?this.delimiterIndex===this.delimiterClose.length-1?(this.cbs.oninterpolation(this.sectionStart,this.index+1),this.inRCDATA?this.state=32:this.state=1,this.sectionStart=this.index+1):this.delimiterIndex++:(this.state=3,this.stateInterpolation(t))}stateSpecialStartSequence(t){const n=this.sequenceIndex===this.currentSequence.length;if(!(n?Pt(t):(t|32)===this.currentSequence[this.sequenceIndex]))this.inRCDATA=!1;else if(!n){this.sequenceIndex++;return}this.sequenceIndex=0,this.state=6,this.stateInTagName(t)}stateInRCDATA(t){if(this.sequenceIndex===this.currentSequence.length){if(t===62||Ke(t)){const n=this.index-this.currentSequence.length;if(this.sectionStart=t||(this.state===28?this.currentSequence===Ie.CdataEnd?this.cbs.oncdata(this.sectionStart,t):this.cbs.oncomment(this.sectionStart,t):this.state===6||this.state===11||this.state===18||this.state===17||this.state===12||this.state===13||this.state===14||this.state===15||this.state===16||this.state===20||this.state===19||this.state===21||this.state===9||this.cbs.ontext(this.sectionStart,t))}emitCodePoint(t,n){}}function da(e,{compatConfig:t}){const n=t&&t[e];return e==="MODE"?n||3:n}function sn(e,t){const n=da("MODE",t),s=da(e,t);return n===3?s===!0:s!==!1}function hs(e,t,n,...s){return sn(e,t)}function ro(e){throw e}function pa(e){}function ae(e,t,n,s){const i=`https://vuejs.org/error-reference/#compiler-${e}`,r=new SyntaxError(String(i));return r.code=e,r.loc=t,r}const Le=e=>e.type===4&&e.isStatic;function ma(e){switch(e){case"Teleport":case"teleport":return os;case"Suspense":case"suspense":return Br;case"KeepAlive":case"keep-alive":return fi;case"BaseTransition":case"base-transition":return sa}}const rp=/^\d|[^\$\w]/,oo=e=>!rp.test(e),op=/[A-Za-z_$\xA0-\uFFFF]/,lp=/[\.\?\w$\xA0-\uFFFF]/,cp=/\s+[.[]\s*|\s*[.[]\s+/g,ga=e=>{e=e.trim().replace(cp,o=>o.trim());let t=0,n=[],s=0,i=0,r=null;for(let o=0;ot.type===7&&t.name==="bind"&&(!t.arg||t.arg.type!==4||!t.arg.isStatic))}function lo(e){return e.type===5||e.type===2}function fp(e){return e.type===7&&e.name==="slot"}function gi(e){return e.type===1&&e.tagType===3}function yi(e){return e.type===1&&e.tagType===2}const up=new Set([cs,as]);function ya(e,t=[]){if(e&&!J(e)&&e.type===14){const n=e.callee;if(!J(n)&&up.has(n))return ya(e.arguments[0],t.concat(e))}return[e,t]}function _i(e,t,n){let s,i=e.type===13?e.props:e.arguments[2],r=[],o;if(i&&!J(i)&&i.type===14){const l=ya(i);i=l[0],r=l[1],o=r[r.length-1]}if(i==null||J(i))s=ze([t]);else if(i.type===14){const l=i.arguments[0];!J(l)&&l.type===15?_a(t,l)||l.properties.unshift(t):i.callee===Zr?s=_e(n.helper(hi),[ze([t]),i]):i.arguments.unshift(ze([t])),!s&&(s=i)}else i.type===15?(_a(t,i)||i.properties.unshift(t),s=i):(s=_e(n.helper(hi),[ze([t]),i]),o&&o.callee===as&&(o=r[r.length-2]));e.type===13?o?o.arguments[0]=s:e.props=s:o?o.arguments[0]=s:e.arguments[2]=s}function _a(e,t){let n=!1;if(e.key.type===4){const s=e.key.content;n=t.properties.some(i=>i.key.type===4&&i.key.content===s)}return n}function ds(e,t){return`_${t}_${e.replace(/[^\w]/g,(n,s)=>n==="-"?"_":e.charCodeAt(s).toString())}`}function hp(e){return e.type===14&&e.callee===no?e.arguments[1].returns:e}const dp=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,ba={parseMode:"base",ns:0,delimiters:["{{","}}"],getNamespace:()=>0,isVoidTag:ys,isPreTag:ys,isCustomElement:ys,onError:ro,onWarn:pa,comments:!1,prefixIdentifiers:!1};let re=ba,ps=null,on="",xe=null,te=null,Fe="",pt=-1,ln=-1,bi=0,Lt=!1,co=null;const de=[],pe=new ip(de,{onerr:mt,ontext(e,t){Si(Te(e,t),e,t)},ontextentity(e,t,n){Si(e,t,n)},oninterpolation(e,t){if(Lt)return Si(Te(e,t),e,t);let n=e+pe.delimiterOpen.length,s=t-pe.delimiterClose.length;for(;Ke(on.charCodeAt(n));)n++;for(;Ke(on.charCodeAt(s-1));)s--;let i=Te(n,s);i.includes("&")&&(i=re.decodeEntities(i,!1)),ao({type:5,content:Ei(i,!1,be(n,s)),loc:be(e,t)})},onopentagname(e,t){const n=Te(e,t);xe={type:1,tag:n,ns:re.getNamespace(n,de[0],re.ns),tagType:0,props:[],children:[],loc:be(e-1,t),codegenNode:void 0}},onopentagend(e){va(e)},onclosetag(e,t){const n=Te(e,t);if(!re.isVoidTag(n)){let s=!1;for(let i=0;i0&&mt(24,de[0].loc.start.offset);for(let o=0;o<=i;o++){const l=de.shift();vi(l,t,o(s.type===7?s.rawName:s.name)===n)&&mt(2,t)},onattribend(e,t){if(xe&&te){if(cn(te.loc,t),e!==0)if(Fe.includes("&")&&(Fe=re.decodeEntities(Fe,!0)),te.type===6)te.name==="class"&&(Fe=Aa(Fe).trim()),e===1&&!Fe&&mt(13,t),te.value={type:2,content:Fe,loc:e===1?be(pt,ln):be(pt-1,ln+1)},pe.inSFCRoot&&xe.tag==="template"&&te.name==="lang"&&Fe&&Fe!=="html"&&pe.enterRCDATA(pi("-1&&hs("COMPILER_V_BIND_SYNC",re,te.loc,te.rawName)&&(te.name="model",te.modifiers.splice(s,1))}(te.type!==7||te.name!=="pre")&&xe.props.push(te)}Fe="",pt=ln=-1},oncomment(e,t){re.comments&&ao({type:3,content:Te(e,t),loc:be(e-4,t+3)})},onend(){const e=on.length;for(let t=0;t{const _=t.start.offset+d,x=_+f.length;return Ei(f,!1,be(_,x),0,g?1:0)},l={source:o(r.trim(),n.indexOf(r,i.length)),value:void 0,key:void 0,index:void 0,finalized:!1};let c=i.trim().replace(pp,"").trim();const a=i.indexOf(c),u=c.match(Sa);if(u){c=c.replace(Sa,"").trim();const f=u[1].trim();let d;if(f&&(d=n.indexOf(f,a+c.length),l.key=o(f,d,!0)),u[2]){const g=u[2].trim();g&&(l.index=o(g,n.indexOf(g,l.key?d+f.length:a+c.length),!0))}}return c&&(l.value=o(c,a,!0)),l}function Te(e,t){return on.slice(e,t)}function va(e){pe.inSFCRoot&&(xe.innerLoc=be(e+1,e+1)),ao(xe);const{tag:t,ns:n}=xe;n===0&&re.isPreTag(t)&&bi++,re.isVoidTag(t)?vi(xe,e):(de.unshift(xe),(n===1||n===2)&&(pe.inXML=!0)),xe=null}function Si(e,t,n){var s;{const o=(s=de[0])==null?void 0:s.tag;o!=="script"&&o!=="style"&&e.includes("&")&&(e=re.decodeEntities(e,!1))}const i=de[0]||ps,r=i.children[i.children.length-1];(r==null?void 0:r.type)===2?(r.content+=e,cn(r.loc,n)):i.children.push({type:2,content:e,loc:be(t,n)})}function vi(e,t,n=!1){n?cn(e.loc,Ea(t,60)):cn(e.loc,t+1),pe.inSFCRoot&&(e.children.length?e.innerLoc.end=ne({},e.children[e.children.length-1].loc.end):e.innerLoc.end=ne({},e.innerLoc.start),e.innerLoc.source=Te(e.innerLoc.start.offset,e.innerLoc.end.offset));const{tag:s,ns:i}=e;Lt||(s==="slot"?e.tagType=2:Ca(e)?e.tagType=3:yp(e)&&(e.tagType=1)),pe.inRCDATA||(e.children=Ta(e.children,e.tag)),i===0&&re.isPreTag(s)&&bi--,co===e&&(Lt=pe.inVPre=!1,co=null),pe.inXML&&(de[0]?de[0].ns:re.ns)===0&&(pe.inXML=!1);{const r=e.props;if(!pe.inSFCRoot&&sn("COMPILER_NATIVE_TEMPLATE",re)&&e.tag==="template"&&!Ca(e)){const l=de[0]||ps,c=l.children.indexOf(e);l.children.splice(c,1,...e.children)}const o=r.find(l=>l.type===6&&l.name==="inline-template");o&&hs("COMPILER_INLINE_TEMPLATE",re,o.loc)&&e.children.length&&(o.value={type:2,content:Te(e.children[0].loc.start.offset,e.children[e.children.length-1].loc.end.offset),loc:o.loc})}}function Ea(e,t){let n=e;for(;on.charCodeAt(n)!==t&&n>=0;)n--;return n}const gp=new Set(["if","else","else-if","for","slot"]);function Ca({tag:e,props:t}){if(e==="template"){for(let n=0;n64&&e<91}const bp=/\r\n/g;function Ta(e,t){var n,s;const i=re.whitespace!=="preserve";let r=!1;for(let o=0;o0){if(c>=2){l.codegenNode.patchFlag="-1",l.codegenNode=t.hoist(l.codegenNode),r++;continue}}else{const a=l.codegenNode;if(a.type===13){const u=Oa(a);if((!u||u===512||u===1)&&Ia(l,t)>=2){const f=xa(l);f&&(a.props=t.hoist(f))}a.dynamicProps&&(a.dynamicProps=t.hoist(a.dynamicProps))}}}if(l.type===1){const c=l.tagType===1;c&&t.scopes.vSlot++,Ci(l,t),c&&t.scopes.vSlot--}else if(l.type===11)Ci(l,t,l.children.length===1);else if(l.type===9)for(let c=0;c1)for(let a=0;ak&&(b.childIndex--,b.onNodeRemoved()),b.parent.children.splice(k,1)},onNodeRemoved:ge,addIdentifiers(E){},removeIdentifiers(E){},hoist(E){J(E)&&(E=X(E)),b.hoists.push(E);const T=X(`_hoisted_${b.hoists.length}`,!1,E.loc,2);return T.hoisted=E,T},cache(E,T=!1){return np(b.cached++,E,T)}};return b.filters=new Set,b}function Ip(e,t){const n=Np(e,t);Ti(e,n),t.hoistStatic&&Ap(e,n),t.ssr||xp(e,n),e.helpers=new Set([...n.helpers.keys()]),e.components=[...n.components],e.directives=[...n.directives],e.imports=n.imports,e.hoists=n.hoists,e.temps=n.temps,e.cached=n.cached,e.transformed=!0,e.filters=[...n.filters]}function xp(e,t){const{helper:n}=t,{children:s}=e;if(s.length===1){const i=s[0];if(wa(e,i)&&i.codegenNode){const r=i.codegenNode;r.type===13&&io(r,t),e.codegenNode=r}else e.codegenNode=i}else if(s.length>1){let i=64;e.codegenNode=fs(t,n(rs),void 0,e.children,i+"",void 0,void 0,!0,void 0,!1)}}function Op(e,t){let n=0;const s=()=>{n--};for(;ns===e:s=>e.test(s);return(s,i)=>{if(s.type===1){const{props:r}=s;if(s.tagType===3&&r.some(fp))return;const o=[];for(let l=0;l`${Nn[e]}: _${Nn[e]}`;function kp(e,{mode:t="function",prefixIdentifiers:n=t==="module",sourceMap:s=!1,filename:i="template.vue.html",scopeId:r=null,optimizeImports:o=!1,runtimeGlobalName:l="Vue",runtimeModuleName:c="vue",ssrRuntimeModuleName:a="vue/server-renderer",ssr:u=!1,isTS:f=!1,inSSR:d=!1}){const g={mode:t,prefixIdentifiers:n,sourceMap:s,filename:i,scopeId:r,optimizeImports:o,runtimeGlobalName:l,runtimeModuleName:c,ssrRuntimeModuleName:a,ssr:u,isTS:f,inSSR:d,source:e.source,code:"",column:1,line:1,offset:0,indentLevel:0,pure:!1,map:void 0,helper(x){return`_${Nn[x]}`},push(x,M=-2,P){g.code+=x},indent(){_(++g.indentLevel)},deindent(x=!1){x?--g.indentLevel:_(--g.indentLevel)},newline(){_(g.indentLevel)}};function _(x){g.push(` +`+" ".repeat(x),0)}return g}function Rp(e,t={}){const n=kp(e,t);t.onContextCreated&&t.onContextCreated(n);const{mode:s,push:i,prefixIdentifiers:r,indent:o,deindent:l,newline:c,scopeId:a,ssr:u}=n,f=Array.from(e.helpers),d=f.length>0,g=!r&&s!=="module";Mp(e,n);const x=u?"ssrRender":"render",P=(u?["_ctx","_push","_parent","_attrs"]:["_ctx","_cache"]).join(", ");if(i(`function ${x}(${P}) {`),o(),g&&(i("with (_ctx) {"),o(),d&&(i(`const { ${f.map(Ra).join(", ")} } = _Vue +`,-1),c())),e.components.length&&(fo(e.components,"component",n),(e.directives.length||e.temps>0)&&c()),e.directives.length&&(fo(e.directives,"directive",n),e.temps>0&&c()),e.filters&&e.filters.length&&(c(),fo(e.filters,"filter",n),c()),e.temps>0){i("let ");for(let A=0;A0?", ":""}_temp${A}`)}return(e.components.length||e.directives.length||e.temps)&&(i(` +`,0),c()),u||i("return "),e.codegenNode?Oe(e.codegenNode,n):i("null"),g&&(l(),i("}")),l(),i("}"),{ast:e,code:n.code,preamble:"",map:n.map?n.map.toJSON():void 0}}function Mp(e,t){const{ssr:n,prefixIdentifiers:s,push:i,newline:r,runtimeModuleName:o,runtimeGlobalName:l,ssrRuntimeModuleName:c}=t,a=l,u=Array.from(e.helpers);if(u.length>0&&(i(`const _Vue = ${a} +`,-1),e.hoists.length)){const f=[Hr,Ur,ls,Kr,oa].filter(d=>u.includes(d)).map(Ra).join(", ");i(`const { ${f} } = _Vue +`,-1)}Pp(e.hoists,t),r(),i("return ")}function fo(e,t,{helper:n,push:s,newline:i,isTS:r}){const o=n(t==="filter"?Gr:t==="component"?jr:Wr);for(let l=0;l3||!1;t.push("["),n&&t.indent(),ms(e,t,n),n&&t.deindent(),t.push("]")}function ms(e,t,n=!1,s=!0){const{push:i,newline:r}=t;for(let o=0;on||"null")}function Hp(e,t){const{push:n,helper:s,pure:i}=t,r=J(e.callee)?e.callee:s(e.callee);i&&n(Ai),n(r+"(",-2,e),ms(e.arguments,t),n(")")}function Up(e,t){const{push:n,indent:s,deindent:i,newline:r}=t,{properties:o}=e;if(!o.length){n("{}",-2,e);return}const l=o.length>1||!1;n(l?"{":"{ "),l&&s();for(let c=0;c "),(c||l)&&(n("{"),s()),o?(c&&n("return "),V(o)?uo(o,t):Oe(o,t)):l&&Oe(l,t),(c||l)&&(i(),n("}")),a&&(e.isNonScopedSlot&&n(", undefined, true"),n(")"))}function qp(e,t){const{test:n,consequent:s,alternate:i,newline:r}=e,{push:o,indent:l,deindent:c,newline:a}=t;if(n.type===4){const f=!oo(n.content);f&&o("("),Ma(n,t),f&&o(")")}else o("("),Oe(n,t),o(")");r&&l(),t.indentLevel++,r||o(" "),o("? "),Oe(s,t),t.indentLevel--,r&&a(),r||o(" "),o(": ");const u=i.type===19;u||t.indentLevel++,Oe(i,t),u||t.indentLevel--,r&&c(!0)}function Wp(e,t){const{push:n,helper:s,indent:i,deindent:r,newline:o}=t;n(`_cache[${e.index}] || (`),e.isVNode&&(i(),n(`${s(di)}(-1),`),o()),n(`_cache[${e.index}] = `),Oe(e.value,t),e.isVNode&&(n(","),o(),n(`${s(di)}(1),`),o(),n(`_cache[${e.index}]`),r()),n(")")}new RegExp("\\b"+"arguments,await,break,case,catch,class,const,continue,debugger,default,delete,do,else,export,extends,finally,for,function,if,import,let,new,return,super,switch,throw,try,var,void,while,with,yield".split(",").join("\\b|\\b")+"\\b");const Gp=ka(/^(if|else|else-if)$/,(e,t,n)=>zp(e,t,n,(s,i,r)=>{const o=n.parent.children;let l=o.indexOf(s),c=0;for(;l-->=0;){const a=o[l];a&&a.type===9&&(c+=a.branches.length)}return()=>{if(r)s.codegenNode=Fa(i,c,n);else{const a=Jp(s.codegenNode);a.alternate=Fa(i,c+s.branches.length-1,n)}}}));function zp(e,t,n,s){if(t.name!=="else"&&(!t.exp||!t.exp.content.trim())){const i=t.exp?t.exp.loc:e.loc;n.onError(ae(28,t.loc)),t.exp=X("true",!1,i)}if(t.name==="if"){const i=La(e,t),r={type:9,loc:e.loc,branches:[i]};if(n.replaceNode(r),s)return s(r,i,!0)}else{const i=n.parent.children;let r=i.indexOf(e);for(;r-->=-1;){const o=i[r];if(o&&o.type===3){n.removeNode(o);continue}if(o&&o.type===2&&!o.content.trim().length){n.removeNode(o);continue}if(o&&o.type===9){t.name==="else-if"&&o.branches[o.branches.length-1].condition===void 0&&n.onError(ae(30,e.loc)),n.removeNode();const l=La(e,t);o.branches.push(l);const c=s&&s(o,l,!1);Ti(l,n),c&&c(),n.currentNode=null}else n.onError(ae(30,e.loc));break}}}function La(e,t){const n=e.tagType===3;return{type:10,loc:e.loc,condition:t.name==="else"?void 0:t.exp,children:n&&!tt(e,"for")?e.children:[e],userKey:mi(e,"key"),isTemplateIf:n}}function Fa(e,t,n){return e.condition?so(e.condition,$a(e,t,n),_e(n.helper(ls),['""',"true"])):$a(e,t,n)}function $a(e,t,n){const{helper:s}=n,i=he("key",X(`${t}`,!1,Ue,2)),{children:r}=e,o=r[0];if(r.length!==1||o.type!==1)if(r.length===1&&o.type===11){const c=o.codegenNode;return _i(c,i,n),c}else return fs(n,s(rs),ze([i]),r,64+"",void 0,void 0,!0,!1,!1,e.loc);else{const c=o.codegenNode,a=hp(c);return a.type===13&&io(a,n),_i(a,i,n),c}}function Jp(e){for(;;)if(e.type===19)if(e.alternate.type===19)e=e.alternate;else return e;else e.type===20&&(e=e.value)}const Yp=ka("for",(e,t,n)=>{const{helper:s,removeHelper:i}=n;return Xp(e,t,n,r=>{const o=_e(s(Jr),[r.source]),l=gi(e),c=tt(e,"memo"),a=mi(e,"key"),u=a&&(a.type===6?X(a.value.content,!0):a.exp),f=a?he("key",u):null,d=r.source.type===4&&r.source.constType>0,g=d?64:a?128:256;return r.codegenNode=fs(n,s(rs),void 0,o,g+"",void 0,void 0,!0,!d,!1,e.loc),()=>{let _;const{children:x}=r,M=x.length!==1||x[0].type!==1,P=yi(e)?e:l&&e.children.length===1&&yi(e.children[0])?e.children[0]:null;if(P?(_=P.codegenNode,l&&f&&_i(_,f,n)):M?_=fs(n,s(rs),f?ze([f]):void 0,e.children,"64",void 0,void 0,!0,void 0,!1):(_=x[0].codegenNode,l&&f&&_i(_,f,n),_.isBlock!==!d&&(_.isBlock?(i(nn),i(On(n.inSSR,_.isComponent))):i(xn(n.inSSR,_.isComponent))),_.isBlock=!d,_.isBlock?(s(nn),s(On(n.inSSR,_.isComponent))):s(xn(n.inSSR,_.isComponent))),c){const A=In(ho(r.parseResult,[X("_cached")]));A.body=sp([et(["const _memo = (",c.exp,")"]),et(["if (_cached",...u?[" && _cached.key === ",u]:[],` && ${n.helperString(aa)}(_cached, _memo)) return _cached`]),et(["const _item = ",_]),X("_item.memo = _memo"),X("return _item")]),o.arguments.push(A,X("_cache"),X(String(n.cached++)))}else o.arguments.push(In(ho(r.parseResult),_,!0))}})});function Xp(e,t,n,s){if(!t.exp){n.onError(ae(31,t.loc));return}const i=t.forParseResult;if(!i){n.onError(ae(32,t.loc));return}Da(i);const{addIdentifiers:r,removeIdentifiers:o,scopes:l}=n,{source:c,value:a,key:u,index:f}=i,d={type:11,loc:t.loc,source:c,valueAlias:a,keyAlias:u,objectIndexAlias:f,parseResult:i,children:gi(e)?e.children:[e]};n.replaceNode(d),l.vFor++;const g=s&&s(d);return()=>{l.vFor--,g&&g()}}function Da(e,t){e.finalized||(e.finalized=!0)}function ho({value:e,key:t,index:n},s=[]){return Zp([e,t,n,...s])}function Zp(e){let t=e.length;for(;t--&&!e[t];);return e.slice(0,t+1).map((n,s)=>n||X("_".repeat(s+1),!1))}const Va=X("undefined",!1),Qp=(e,t)=>{if(e.type===1&&(e.tagType===1||e.tagType===3)){const n=tt(e,"slot");if(n)return n.exp,t.scopes.vSlot++,()=>{t.scopes.vSlot--}}},em=(e,t,n,s)=>In(e,n,!1,!0,n.length?n[0].loc:s);function tm(e,t,n=em){t.helper(to);const{children:s,loc:i}=e,r=[],o=[];let l=t.scopes.vSlot>0||t.scopes.vFor>0;const c=tt(e,"slot",!0);if(c){const{arg:M,exp:P}=c;M&&!Le(M)&&(l=!0),r.push(he(M||X("default",!0),n(P,void 0,s,i)))}let a=!1,u=!1;const f=[],d=new Set;let g=0;for(let M=0;M{const m=n(P,void 0,A,i);return t.compatConfig&&(m.isNonScopedSlot=!0),he("default",m)};a?f.length&&f.some(P=>Ba(P))&&(u?t.onError(ae(39,f[0].loc)):r.push(M(void 0,f))):r.push(M(void 0,s))}const _=l?2:Ni(e.children)?3:1;let x=ze(r.concat(he("_",X(_+"",!1))),i);return o.length&&(x=_e(t.helper(ca),[x,us(o)])),{slots:x,hasDynamicSlots:l}}function wi(e,t,n){const s=[he("name",e),he("fn",t)];return n!=null&&s.push(he("key",X(String(n),!0))),ze(s)}function Ni(e){for(let t=0;tfunction(){if(e=t.currentNode,!(e.type===1&&(e.tagType===0||e.tagType===1)))return;const{tag:s,props:i}=e,r=e.tagType===1;let o=r?sm(e,t):`"${s}"`;const l=oe(o)&&o.callee===qr;let c,a,u,f=0,d,g,_,x=l||o===os||o===Br||!r&&(s==="svg"||s==="foreignObject");if(i.length>0){const M=Ua(e,t,void 0,r,l);c=M.props,f=M.patchFlag,g=M.dynamicPropNames;const P=M.directives;_=P&&P.length?us(P.map(A=>rm(A,t))):void 0,M.shouldUseBlock&&(x=!0)}if(e.children.length>0)if(o===fi&&(x=!0,f|=1024),r&&o!==os&&o!==fi){const{slots:P,hasDynamicSlots:A}=tm(e,t);a=P,A&&(f|=1024)}else if(e.children.length===1&&o!==os){const P=e.children[0],A=P.type,m=A===5||A===8;m&&Je(P,t)===0&&(f|=1),m||A===2?a=P:a=e.children}else a=e.children;f!==0&&(u=String(f),g&&g.length&&(d=om(g))),e.codegenNode=fs(t,o,c,a,u,d,_,!!x,!1,r,e.loc)};function sm(e,t,n=!1){let{tag:s}=e;const i=po(s),r=mi(e,"is");if(r)if(i||sn("COMPILER_IS_ON_ELEMENT",t)){const l=r.type===6?r.value&&X(r.value.content,!0):r.exp;if(l)return _e(t.helper(qr),[l])}else r.type===6&&r.value.content.startsWith("vue:")&&(s=r.value.content.slice(4));const o=ma(s)||t.isBuiltInComponent(s);return o?(n||t.helper(o),o):(t.helper(jr),t.components.add(s),ds(s,"component"))}function Ua(e,t,n=e.props,s,i,r=!1){const{tag:o,loc:l,children:c}=e;let a=[];const u=[],f=[],d=c.length>0;let g=!1,_=0,x=!1,M=!1,P=!1,A=!1,m=!1,y=!1;const S=[],C=E=>{a.length&&(u.push(ze(Ka(a),l)),a=[]),E&&u.push(E)},F=({key:E,value:T})=>{if(Le(E)){const k=E.content,w=Dt(k);if(w&&(!s||i)&&k.toLowerCase()!=="onclick"&&k!=="onUpdate:modelValue"&&!yt(k)&&(A=!0),w&&yt(k)&&(y=!0),w&&T.type===14&&(T=T.arguments[0]),T.type===20||(T.type===4||T.type===8)&&Je(T,t)>0)return;k==="ref"?x=!0:k==="class"?M=!0:k==="style"?P=!0:k!=="key"&&!S.includes(k)&&S.push(k),s&&(k==="class"||k==="style")&&!S.includes(k)&&S.push(k)}else m=!0};for(let E=0;E0&&a.push(he(X("ref_for",!0),X("true")))),w==="is"&&(po(o)||G&&G.content.startsWith("vue:")||sn("COMPILER_IS_ON_ELEMENT",t)))continue;a.push(he(X(w,!0,B),X(G?G.content:"",Q,G?G.loc:k)))}else{const{name:k,arg:w,exp:B,loc:G,modifiers:Q}=T,H=k==="bind",Y=k==="on";if(k==="slot"){s||t.onError(ae(40,G));continue}if(k==="once"||k==="memo"||k==="is"||H&&rn(w,"is")&&(po(o)||sn("COMPILER_IS_ON_ELEMENT",t))||Y&&r)continue;if((H&&rn(w,"key")||Y&&d&&rn(w,"vue:before-update"))&&(g=!0),H&&rn(w,"ref")&&t.scopes.vFor>0&&a.push(he(X("ref_for",!0),X("true"))),!w&&(H||Y)){if(m=!0,B)if(H){if(C(),sn("COMPILER_V_BIND_OBJECT_ORDER",t)){u.unshift(B);continue}u.push(B)}else C({type:14,loc:G,callee:t.helper(Zr),arguments:s?[B]:[B,"true"]});else t.onError(ae(H?34:35,G));continue}H&&Q.includes("prop")&&(_|=32);const K=t.directiveTransforms[k];if(K){const{props:je,needRuntime:$t}=K(T,e,t);!r&&je.forEach(F),Y&&w&&!Le(w)?C(ze(je,l)):a.push(...je),$t&&(f.push(T),Ye($t)&&Ha.set(T,$t))}else _f(k)||(f.push(T),d&&(g=!0))}}let b;if(u.length?(C(),u.length>1?b=_e(t.helper(hi),u,l):b=u[0]):a.length&&(b=ze(Ka(a),l)),m?_|=16:(M&&!s&&(_|=2),P&&!s&&(_|=4),S.length&&(_|=8),A&&(_|=32)),!g&&(_===0||_===32)&&(x||y||f.length>0)&&(_|=512),!t.inSSR&&b)switch(b.type){case 15:let E=-1,T=-1,k=!1;for(let G=0;Ghe(o,r)),i))}return us(n,e.loc)}function om(e){let t="[";for(let n=0,s=e.length;n{if(yi(e)){const{children:n,loc:s}=e,{slotName:i,slotProps:r}=cm(e,t),o=[t.prefixIdentifiers?"_ctx.$slots":"$slots",i,"{}","undefined","true"];let l=2;r&&(o[2]=r,l=3),n.length&&(o[3]=In([],n,!1,!1,s),l=4),t.scopeId&&!t.slotted&&(l=5),o.splice(l),e.codegenNode=_e(t.helper(la),o,s)}};function cm(e,t){let n='"default"',s;const i=[];for(let r=0;r0){const{props:r,directives:o}=Ua(e,t,i,!1,!1);s=r,o.length&&t.onError(ae(36,o[0].loc))}return{slotName:n,slotProps:s}}const am=/^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*(:[^=]+)?=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/,ja=(e,t,n,s)=>{const{loc:i,modifiers:r,arg:o}=e;!e.exp&&!r.length&&n.onError(ae(35,i));let l;if(o.type===4)if(o.isStatic){let f=o.content;f.startsWith("vue:")&&(f=`vnode-${f.slice(4)}`);const d=t.tagType!==0||f.startsWith("vnode")||!/[A-Z]/.test(f)?mn(ue(f)):`on:${f}`;l=X(d,!0,o.loc)}else l=et([`${n.helperString(eo)}(`,o,")"]);else l=o,l.children.unshift(`${n.helperString(eo)}(`),l.children.push(")");let c=e.exp;c&&!c.content.trim()&&(c=void 0);let a=n.cacheHandlers&&!c&&!n.inVOnce;if(c){const f=ga(c.content),d=!(f||am.test(c.content)),g=c.content.includes(";");(d||a&&f)&&(c=et([`${d?"$event":"(...args)"} => ${g?"{":"("}`,c,g?"}":")"]))}let u={props:[he(l,c||X("() => {}",!1,i))]};return s&&(u=s(u)),a&&(u.props[0].value=n.cache(u.props[0].value)),u.props.forEach(f=>f.key.isHandlerKey=!0),u},fm=(e,t,n)=>{const{modifiers:s,loc:i}=e,r=e.arg;let{exp:o}=e;if(o&&o.type===4&&!o.content.trim()&&(o=void 0),!o){if(r.type!==4||!r.isStatic)return n.onError(ae(52,r.loc)),{props:[he(r,X("",!0,i))]};const l=ue(r.content);o=e.exp=X(l,!1,r.loc)}return r.type!==4?(r.children.unshift("("),r.children.push(') || ""')):r.isStatic||(r.content=`${r.content} || ""`),s.includes("camel")&&(r.type===4?r.isStatic?r.content=ue(r.content):r.content=`${n.helperString(Qr)}(${r.content})`:(r.children.unshift(`${n.helperString(Qr)}(`),r.children.push(")"))),n.inSSR||(s.includes("prop")&&qa(r,"."),s.includes("attr")&&qa(r,"^")),{props:[he(r,o)]}},qa=(e,t)=>{e.type===4?e.isStatic?e.content=t+e.content:e.content=`\`${t}\${${e.content}}\``:(e.children.unshift(`'${t}' + (`),e.children.push(")"))},um=(e,t)=>{if(e.type===0||e.type===1||e.type===11||e.type===10)return()=>{const n=e.children;let s,i=!1;for(let r=0;rr.type===7&&!t.directiveTransforms[r.name])&&e.tag!=="template")))for(let r=0;r{if(e.type===1&&tt(e,"once",!0))return Wa.has(e)||t.inVOnce||t.inSSR?void 0:(Wa.add(e),t.inVOnce=!0,t.helper(di),()=>{t.inVOnce=!1;const n=t.currentNode;n.codegenNode&&(n.codegenNode=t.cache(n.codegenNode,!0))})},Ga=(e,t,n)=>{const{exp:s,arg:i}=e;if(!s)return n.onError(ae(41,e.loc)),Ii();const r=s.loc.source,o=s.type===4?s.content:r,l=n.bindingMetadata[r];if(l==="props"||l==="props-aliased")return n.onError(ae(44,s.loc)),Ii();if(!o.trim()||!ga(o)&&!!1)return n.onError(ae(42,s.loc)),Ii();const a=i||X("modelValue",!0),u=i?Le(i)?`onUpdate:${ue(i.content)}`:et(['"onUpdate:" + ',i]):"onUpdate:modelValue";let f;const d=n.isTS?"($event: any)":"$event";f=et([`${d} => ((`,s,") = $event)"]);const g=[he(a,e.exp),he(u,f)];if(e.modifiers.length&&t.tagType===1){const _=e.modifiers.map(M=>(oo(M)?M:JSON.stringify(M))+": true").join(", "),x=i?Le(i)?`${i.content}Modifiers`:et([i,' + "Modifiers"']):"modelModifiers";g.push(he(x,X(`{ ${_} }`,!1,e.loc,2)))}return Ii(g)};function Ii(e=[]){return{props:e}}const dm=/[\w).+\-_$\]]/,pm=(e,t)=>{sn("COMPILER_FILTERS",t)&&(e.type===5&&xi(e.content,t),e.type===1&&e.props.forEach(n=>{n.type===7&&n.name!=="for"&&n.exp&&xi(n.exp,t)}))};function xi(e,t){if(e.type===4)za(e,t);else for(let n=0;n=0&&(A=n.charAt(P),A===" ");P--);(!A||!dm.test(A))&&(o=!0)}}_===void 0?_=n.slice(0,g).trim():u!==0&&M();function M(){x.push(n.slice(u,g).trim()),u=g+1}if(x.length){for(g=0;g{if(e.type===1){const n=tt(e,"memo");return!n||Ja.has(e)?void 0:(Ja.add(e),()=>{const s=e.codegenNode||t.currentNode.codegenNode;s&&s.type===13&&(e.tagType!==1&&io(s,t),e.codegenNode=_e(t.helper(no),[n.exp,In(void 0,s),"_cache",String(t.cached++)]))})}};function ym(e){return[[hm,Gp,gm,Yp,pm,lm,nm,Qp,um],{on:ja,bind:fm,model:Ga}]}function _m(e,t={}){const n=t.onError||ro,s=t.mode==="module";t.prefixIdentifiers===!0?n(ae(47)):s&&n(ae(48));const i=!1;t.cacheHandlers&&n(ae(49)),t.scopeId&&!s&&n(ae(50));const r=ne({},t,{prefixIdentifiers:i}),o=J(e)?Tp(e,r):e,[l,c]=ym();return Ip(o,ne({},r,{nodeTransforms:[...l,...t.nodeTransforms||[]],directiveTransforms:ne({},c,t.directiveTransforms||{})})),Rp(o,r)}const bm=()=>({props:[]});/** +* @vue/compiler-dom v3.4.21 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/const Ya=Symbol(""),Xa=Symbol(""),Za=Symbol(""),Qa=Symbol(""),mo=Symbol(""),ef=Symbol(""),tf=Symbol(""),nf=Symbol(""),sf=Symbol(""),rf=Symbol("");ep({[Ya]:"vModelRadio",[Xa]:"vModelCheckbox",[Za]:"vModelText",[Qa]:"vModelSelect",[mo]:"vModelDynamic",[ef]:"withModifiers",[tf]:"withKeys",[nf]:"vShow",[sf]:"Transition",[rf]:"TransitionGroup"});let kn;function Sm(e,t=!1){return kn||(kn=document.createElement("div")),t?(kn.innerHTML=`
`,kn.children[0].getAttribute("foo")):(kn.innerHTML=e,kn.textContent)}const vm={parseMode:"html",isVoidTag:Mf,isNativeTag:e=>Of(e)||kf(e)||Rf(e),isPreTag:e=>e==="pre",decodeEntities:Sm,isBuiltInComponent:e=>{if(e==="Transition"||e==="transition")return sf;if(e==="TransitionGroup"||e==="transition-group")return rf},getNamespace(e,t,n){let s=t?t.ns:n;if(t&&s===2)if(t.tag==="annotation-xml"){if(e==="svg")return 1;t.props.some(i=>i.type===6&&i.name==="encoding"&&i.value!=null&&(i.value.content==="text/html"||i.value.content==="application/xhtml+xml"))&&(s=0)}else/^m(?:[ions]|text)$/.test(t.tag)&&e!=="mglyph"&&e!=="malignmark"&&(s=0);else t&&s===1&&(t.tag==="foreignObject"||t.tag==="desc"||t.tag==="title")&&(s=0);if(s===0){if(e==="svg")return 1;if(e==="math")return 2}return s}},Em=e=>{e.type===1&&e.props.forEach((t,n)=>{t.type===6&&t.name==="style"&&t.value&&(e.props[n]={type:7,name:"bind",arg:X("style",!0,t.loc),exp:Cm(t.value.content,t.loc),modifiers:[],loc:t.loc})})},Cm=(e,t)=>{const n=To(e);return X(JSON.stringify(n),!1,t,3)};function Ft(e,t){return ae(e,t)}const Tm=(e,t,n)=>{const{exp:s,loc:i}=e;return s||n.onError(Ft(53,i)),t.children.length&&(n.onError(Ft(54,i)),t.children.length=0),{props:[he(X("innerHTML",!0,i),s||X("",!0))]}},Am=(e,t,n)=>{const{exp:s,loc:i}=e;return s||n.onError(Ft(55,i)),t.children.length&&(n.onError(Ft(56,i)),t.children.length=0),{props:[he(X("textContent",!0),s?Je(s,n)>0?s:_e(n.helperString(ui),[s],i):X("",!0))]}},wm=(e,t,n)=>{const s=Ga(e,t,n);if(!s.props.length||t.tagType===1)return s;e.arg&&n.onError(Ft(58,e.arg.loc));const{tag:i}=t,r=n.isCustomElement(i);if(i==="input"||i==="textarea"||i==="select"||r){let o=Za,l=!1;if(i==="input"||r){const c=mi(t,"type");if(c){if(c.type===7)o=mo;else if(c.value)switch(c.value.content){case"radio":o=Ya;break;case"checkbox":o=Xa;break;case"file":l=!0,n.onError(Ft(59,e.loc));break}}else ap(t)&&(o=mo)}else i==="select"&&(o=Qa);l||(s.needRuntime=n.helper(o))}else n.onError(Ft(57,e.loc));return s.props=s.props.filter(o=>!(o.key.type===4&&o.key.content==="modelValue")),s},Nm=$e("passive,once,capture"),Im=$e("stop,prevent,self,ctrl,shift,alt,meta,exact,middle"),xm=$e("left,right"),of=$e("onkeyup,onkeydown,onkeypress",!0),Om=(e,t,n,s)=>{const i=[],r=[],o=[];for(let l=0;lLe(e)&&e.content.toLowerCase()==="onclick"?X(t,!0):e.type!==4?et(["(",e,`) === "onClick" ? "${t}" : (`,e,")"]):e,km=(e,t,n)=>ja(e,t,n,s=>{const{modifiers:i}=e;if(!i.length)return s;let{key:r,value:o}=s.props[0];const{keyModifiers:l,nonKeyModifiers:c,eventOptionModifiers:a}=Om(r,i,n,e.loc);if(c.includes("right")&&(r=lf(r,"onContextmenu")),c.includes("middle")&&(r=lf(r,"onMouseup")),c.length&&(o=_e(n.helper(ef),[o,JSON.stringify(c)])),l.length&&(!Le(r)||of(r.content))&&(o=_e(n.helper(tf),[o,JSON.stringify(l)])),a.length){const u=a.map(Bt).join("");r=Le(r)?X(`${r.content}${u}`,!0):et(["(",r,`) + "${u}"`])}return{props:[he(r,o)]}}),Rm=(e,t,n)=>{const{exp:s,loc:i}=e;return s||n.onError(Ft(61,i)),{props:[],needRuntime:n.helper(nf)}},Mm=(e,t)=>{e.type===1&&e.tagType===0&&(e.tag==="script"||e.tag==="style")&&t.removeNode()},Pm=[Em],Lm={cloak:bm,html:Tm,text:Am,model:wm,on:km,show:Rm};function Fm(e,t={}){return _m(e,ne({},vm,t,{nodeTransforms:[Mm,...Pm,...t.nodeTransforms||[]],directiveTransforms:ne({},Lm,t.directiveTransforms||{}),transformHoist:null}))}/** +* vue v3.4.21 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/const cf=new WeakMap;function $m(e){let t=cf.get(e??ie);return t||(t=Object.create(null),cf.set(e??ie,t)),t}function Dm(e,t){if(!J(e))if(e.nodeType)e=e.innerHTML;else return ge;const n=e,s=$m(t),i=s[n];if(i)return i;if(e[0]==="#"){const c=document.querySelector(e);e=c?c.innerHTML:""}const r=ne({hoistStatic:!0,onError:void 0,onWarn:ge},t);!r.isCustomElement&&typeof customElements<"u"&&(r.isCustomElement=c=>!!customElements.get(c));const{code:o}=Fm(e,r),l=new Function("Vue",o)(zd);return l._rc=!0,s[n]=l}ac(Dm);const Vm={name:"App",data(){return{isSidebarOpen:!1,swUpdateEvent:null}},computed:{pageClasses(){return[{"sidebar-open":this.isSidebarOpen}]}},methods:{toggleSidebar(e){this.isSidebarOpen=typeof e=="boolean"?e:!this.isSidebarOpen}}},an=(e,t)=>{const n=e.__vccOpts||e;for(const[s,i]of t)n[s]=i;return n},Bm={},Hm={class:"icon outbound",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",x:"0px",y:"0px",viewBox:"0 0 100 100",width:"15",height:"15"},Um=[Ne("path",{fill:"currentColor",d:"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"},null,-1),Ne("polygon",{fill:"currentColor",points:"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"},null,-1)];function Km(e,t){return Ze(),Nt("svg",Hm,Um)}const jm=an(Bm,[["render",Km]]),qm={},Wm=[Ne("svg",{class:"icon",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"},[Ne("path",{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z",class:""})],-1)];function Gm(e,t){return Ze(),Nt("div",{class:"sidebar-button",onClick:t[0]||(t[0]=n=>e.$emit("toggle-sidebar"))},Wm)}const zm=an(qm,[["render",Gm]]);function af(e,t,n){e.remove(...n);const s=[...e];e.value="",e.add(...t,...s)}const Jm={data(){return{darkmode:"auto"}},mounted(){const e=localStorage.getItem("darkmode");this.setDarkmode(e||"auto")},methods:{setDarkmode(e){if(console.log(e),e==="on")this.toggleDarkmode(!0);else if(e==="off")this.toggleDarkmode(!1);else{const t=window.matchMedia("(prefers-color-scheme: dark)").matches,n=window.matchMedia("(prefers-color-scheme: light)").matches;if(window.matchMedia("(prefers-color-scheme: dark)").addListener(s=>s.matches&&this.toggleDarkmode(!0)),window.matchMedia("(prefers-color-scheme: light)").addListener(s=>s.matches&&this.toggleDarkmode(!1)),t)this.toggleDarkmode(!0);else if(n)this.toggleDarkmode(!1);else{const s=new Date().getHours();this.toggleDarkmode(s<6||s>=18)}}this.darkmode=e,localStorage.setItem("darkmode",e)},toggleDarkmode(e){const t=document.body.classList;e?af(t,["theme-dark"],["theme-light"]):af(t,["theme-light"],["theme-dark"])}}},Ym={class:"darkmode-switch"},Xm=[Ne("svg",{class:"icon",viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg"},[Ne("path",{d:"M512 256a42.666667 42.666667 0 0 0 42.666667-42.666667V128a42.666667 42.666667 0 0 0-85.333334 0v85.333333a42.666667 42.666667 0 0 0 42.666667 42.666667zM896 469.333333h-85.333333a42.666667 42.666667 0 0 0 0 85.333334h85.333333a42.666667 42.666667 0 0 0 0-85.333334zM256 512a42.666667 42.666667 0 0 0-42.666667-42.666667H128a42.666667 42.666667 0 0 0 0 85.333334h85.333333a42.666667 42.666667 0 0 0 42.666667-42.666667zM265.386667 213.333333a42.666667 42.666667 0 0 0-59.306667 62.72l61.44 59.306667a42.666667 42.666667 0 0 0 31.146667 11.946667 42.666667 42.666667 0 0 0 30.72-13.226667 42.666667 42.666667 0 0 0 0-60.16zM725.333333 347.306667a42.666667 42.666667 0 0 0 29.44-11.946667l61.44-59.306667A42.666667 42.666667 0 0 0 758.613333 213.333333l-61.44 60.586667a42.666667 42.666667 0 0 0 0 60.16 42.666667 42.666667 0 0 0 28.16 13.226667zM512 768a42.666667 42.666667 0 0 0-42.666667 42.666667v85.333333a42.666667 42.666667 0 0 0 85.333334 0v-85.333333a42.666667 42.666667 0 0 0-42.666667-42.666667zM756.48 688.64a42.666667 42.666667 0 0 0-59.306667 61.44L758.613333 810.666667a42.666667 42.666667 0 0 0 29.44 11.946666 42.666667 42.666667 0 0 0 30.72-12.8 42.666667 42.666667 0 0 0 0-60.586666zM267.52 688.64l-61.44 59.306667a42.666667 42.666667 0 0 0 0 60.586666 42.666667 42.666667 0 0 0 30.72 12.8 42.666667 42.666667 0 0 0 28.586667-10.666666l61.44-59.306667a42.666667 42.666667 0 0 0-59.306667-61.44zM512 341.333333a170.666667 170.666667 0 1 0 170.666667 170.666667 170.666667 170.666667 0 0 0-170.666667-170.666667z"})],-1)],Zm=[Ne("svg",{class:"icon",viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg"},[Ne("path",{d:"M460.864 539.072h103.936l-54.208-163.072-49.728 163.072z m411.136-176.704V149.504h-212.352L510.528 0l-149.12 149.504H149.12v212.928L0 511.872l149.12 149.504v212.928h212.352l149.12 149.504 149.12-149.504h212.352v-212.928l149.12-149.504-149.184-149.504zM614.464 693.12l-31.616-90.624H438.272l-31.616 90.624H320.768l144.576-407.68h90.368l144.576 407.68H614.464z m0 0"})],-1)],Qm=[Ne("svg",{class:"icon",viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg"},[Ne("path",{d:"M935.538601 630.40178c-11.43005-11.432249-28.673759-14.738607-43.531086-8.353536-46.733115 20.10317-96.362866 30.296859-147.50719 30.296859-99.589478 0-193.221796-38.783705-263.640252-109.20316-108.636744-108.636744-139.609745-270.022125-78.9083-411.148441 6.388069-14.85233 3.078713-32.098837-8.353536-43.532285-11.432249-11.432249-28.675758-14.743604-43.532285-8.354536-52.637312 22.64025-100.017388 54.809439-140.82552 95.616372-85.346135 85.346135-132.346869 198.821199-132.346869 319.519766 0 120.699566 47.001733 234.172631 132.347868 319.518766s198.821199 132.349067 319.517567 132.349067c120.699566 0 234.172431-47.002932 319.520765-132.351066 40.808132-40.810131 72.977122-88.190207 95.615373-140.82552C950.282205 659.081735 946.971849 641.834029 935.538601 630.40178z","p-id":"3638"})],-1)];function eg(e,t,n,s,i,r){return Ze(),Nt("div",Ym,[Ne("div",{class:_t(["item day",{active:i.darkmode==="off"}]),onClick:t[0]||(t[0]=o=>r.setDarkmode("off"))},Xm,2),Ne("div",{class:_t(["item auto",{active:i.darkmode==="auto"}]),onClick:t[1]||(t[1]=o=>r.setDarkmode("auto"))},Zm,2),Ne("div",{class:_t(["item night",{active:i.darkmode==="on"}]),onClick:t[2]||(t[2]=o=>r.setDarkmode("on"))},Qm,2)])}const tg={components:{SidebarButton:zm,DarkmodeSwitch:an(Jm,[["render",eg]])}},ng={class:"navbar"};function sg(e,t,n,s,i,r){const o=tr("SidebarButton"),l=tr("DarkmodeSwitch");return Ze(),Nt("header",ng,[ce(o,{onToggleSidebar:t[0]||(t[0]=c=>e.$emit("toggle-sidebar"))}),Cn(e.$slots,"default"),ce(l)])}const ig=an(tg,[["render",sg]]),rg={},og={class:"nav-links"};function lg(e,t,n,s,i,r){return Ze(),Nt("nav",og,[Cn(e.$slots,"default")])}const cg=an(rg,[["render",lg]]),ag={},fg={class:"vp-sidebar"};function ug(e,t,n,s,i,r){return Ze(),Nt("div",fg,[Cn(e.$slots,"default")])}const hg=an(ag,[["render",ug]]),dg={},pg={class:"page"};function mg(e,t,n,s,i,r){return Ze(),Nt("div",pg,[Cn(e.$slots,"default"),Cn(e.$slots,"bottom")])}const gg=an(dg,[["render",mg]]),fn=Qc(Vm);fn.component("outboundlink",jm),fn.component("navbar",ig),fn.component("navlinks",cg),fn.component("sidebar",hg),fn.component("page",gg),fn.component("router-link",{props:["to"],template:''}),fn.mount("#app",!0)})(); diff --git a/branch/f-QoLImprovements/about/index.html b/branch/f-QoLImprovements/about/index.html new file mode 100644 index 000000000..2001b625b --- /dev/null +++ b/branch/f-QoLImprovements/about/index.html @@ -0,0 +1,295 @@ + + + + + + + BenchBuild Documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

BenchBuild Documentation

+

BenchBuild is an open-source toolkit that helps with the management of case-studies used in software-driven empirical experiments. +BenchBuild was specifically designed to make defined experiments reusable between different +experiment setups. It mainly provides assistance with the following standard tasks found in empirical software experiments:

+
    +
  • Add a new case-study to an existing experiment setup.

  • +
  • Add a new experiment to an existing body of case-studies.

  • +
+
+

Design Philosophy

+

BenchBuild is designed with the following main properties in mind.

+
+

A case-study doesn’t know its experiment

+

If you add a new case-study, you should never have to rely on background information about the experiment you are about to run on it. +A new case-study is only concerned with its own setup of dependencies and execution during its run-time. A case-study controls where and what can be +intercepted by an experiment.

+
+
+

An experiment doesn’t know its case-studies

+

Adding a new experiment never should have any knowledge about the case-studies +it runs on. +A new experiment takes care of intercepting the compilation process and/or the +execution procedure of a given case-study. This only defines what is being done at the defined extension points at compile-time or run-time.

+
+
+
+

Supported Python Versions

+

BenchBuild supports Python 3.7 and 3.8. Main development is focused on Python 3.8, but an effort is made to support 3.7 as long as major distributions like Debian Linux only ship with 3.7 by default.

+
+
+

Getting started

+

See the Installation guide for help getting BenchBuild up and running quickly.

+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/advanced/cli/index.html b/branch/f-QoLImprovements/advanced/cli/index.html new file mode 100644 index 000000000..dcc0fe145 --- /dev/null +++ b/branch/f-QoLImprovements/advanced/cli/index.html @@ -0,0 +1,263 @@ + + + + + + + CLI + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

CLI

+
    +
  • --force-watch-unbuffered: This disables buffering from watched commands. +This can help with tools that call benchbuild and use their own output buffering.

  • +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/advanced/index.html b/branch/f-QoLImprovements/advanced/index.html new file mode 100644 index 000000000..0672434b5 --- /dev/null +++ b/branch/f-QoLImprovements/advanced/index.html @@ -0,0 +1,285 @@ + + + + + + + SLURM + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

SLURM

+

BenchBuild supports a high-level integration with the SLURM cluster resource +manager. An experiment setup can be exported as a SLURM bash script. Assuming +you have access to a configured benchbuid environment on the SLURM cluster, you +can provide the SLURM script to the sbatch command and have your experiment +run on the cluster environment.

+
+

Basics

+

TODO

+
+
+

Template customization

+

This customization is not recommended for the default use-case. However, you +might run in a situation where the existing cluster-environment requires a +more complicated setup than BenchBuild can provide.

+

You can customize the template that is used for the SLURM script using a +modified copy of the base template BenchBuild uses +(see benchbuild/res/misc/slurm.sh.inc).

+

The customized template can be configured using the configuration option +BB_SLURM_TEMPLATE. If BenchBuild detects that the provided value points to +an existing file in your filesystem, it will load it. +If you change the setting and BenchBuild cannot find a file there, no script +will be generated. No validation of the template will be done, use at your own +risk.

+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/basics/actions/index.html b/branch/f-QoLImprovements/basics/actions/index.html new file mode 100644 index 000000000..2faaa5ae6 --- /dev/null +++ b/branch/f-QoLImprovements/basics/actions/index.html @@ -0,0 +1,799 @@ + + + + + + + Actions + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Actions

+

Actions are used to declare the workflow of an experiment. BenchBuild provides +a set of default actions that should suit most experiments. +A new experiment can define a new set of actions that should be used per project, +or use those defaults.

+
+

Customize actions

+

Whenever you define a new expeirment, you have to provide an implementation +for def actions_for_project(self, project: 'Project'). +This implementation usually configures extensions on the project and returns +a set of actions that should be run during execution.

+

Example:

+

This takes care of compiling, running and cleanup during experiment execution.

+
+
+

Available Actions

+

The following actions are available out of the box. You can define your own +actions at any time

+
+

Step (Base)

+
+
+

Clean

+
+
+

MakeBuildDir

+
+
+

Compile

+
+
+

Run

+
+
+

Echo

+
+
+

Any (Group)

+
+
+

Experiment (Any, Group)

+
+
+

RequireAll (Group)

+
+
+

CleanExtra

+
+
+

ProjectEnvironment

+
+
+

SetProjectVersion

+

This action provides you with a way to change the source version used inside the +build directory of this project. +During initialization, each project is assigned a variant that determines the +source versions that will be checked out into the build directory.

+

Sometimes it can be useful to do comparisons of different source revisions +inside a single experiment run. This can be achieved using SetProjectVersion.

+

Usage:

+

The match is done on all(!) sources of the project. If you happen to find a +revision string twice in different souces, both will be checked out in the +build directory.

+

The match is done exact and matches agains the source.versions() output of a +source. Only sources that are marked as expandable (source.is_expandable) +will be checked.

+

# Actions

+

Actions are enhanced callables that are used by Experiments to define +the order of operations a project is put through when the experiment +executes.

+

## Example

+

TODO +`python +`

+
+
+class benchbuild.utils.actions.Any(actions=None)[source]
+

Bases: MultiStep

+
+
+DESCRIPTION: ClassVar[str] = 'Just run all actions, no questions asked.'
+
+ +
+
+NAME: ClassVar[str] = 'ANY'
+
+ +
+ +
+
+class benchbuild.utils.actions.Clean(project, check_empty=False)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Cleans the build directory'
+
+ +
+
+NAME: tp.ClassVar[str] = 'CLEAN'
+
+ +
+
+static clean_mountpoints(root)[source]
+

Unmount any remaining mountpoints under :root.

+
+
Parameters:
+

root (str) – All UnionFS-mountpoints under this directory will be +unmounted.

+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class benchbuild.utils.actions.CleanExtra[source]
+

Bases: Step

+
+
+DESCRIPTION: ClassVar[str] = 'Cleans the extra directories.'
+
+ +
+
+NAME: ClassVar[str] = 'CLEAN EXTRA'
+
+ +
+ +
+
+class benchbuild.utils.actions.Compile(project)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Compile the project'
+
+ +
+
+NAME: tp.ClassVar[str] = 'COMPILE'
+
+ +
+ +
+
+class benchbuild.utils.actions.Echo(message='')[source]
+

Bases: Step

+
+
+DESCRIPTION: ClassVar[str] = 'Print a message.'
+
+ +
+
+NAME: ClassVar[str] = 'ECHO'
+
+ +
+
+message: str
+
+ +
+ +
+
+class benchbuild.utils.actions.Experiment(experiment, actions)[source]
+

Bases: Any

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Run a experiment, wrapped in a db transaction'
+
+ +
+
+NAME: tp.ClassVar[str] = 'EXPERIMENT'
+
+ +
+
+begin_transaction()[source]
+
+
Return type:
+

tp.Tuple[‘benchbuild.utils.schema.Experiment’, tp.Any]

+
+
+
+ +
+
+static end_transaction(experiment, session)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+experiment: benchbuild.experiment.Experiment
+
+ +
+ +
+
+class benchbuild.utils.actions.MakeBuildDir(project)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Create the build directory'
+
+ +
+
+NAME: tp.ClassVar[str] = 'MKDIR'
+
+ +
+ +
+
+class benchbuild.utils.actions.MultiStep(actions=None)[source]
+

Bases: Step, Generic[StepTy_co]

+

Group multiple actions into one step.

+

Usually used to define behavior on error, e.g., execute everything +regardless of any errors, or fail everything upon first error.

+
+
+DESCRIPTION: ClassVar[str] = ''
+
+ +
+
+NAME: ClassVar[str] = ''
+
+ +
+
+actions: MutableSequence[TypeVar(StepTy_co, bound= Step, covariant=True)]
+
+ +
+
+onerror()[source]
+

Default implementation does nothing.

+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class benchbuild.utils.actions.ProjectEnvironment(project)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Prepare the project environment.'
+
+ +
+
+NAME: tp.ClassVar[str] = 'ENV'
+
+ +
+ +
+
+class benchbuild.utils.actions.ProjectStep(project)[source]
+

Bases: Step

+

Base class of a project step.

+

Adds a project attribute to the Step base class and some defaults.

+
+
Raises:
+

StopIteration – If we do not encapsulate more substeps.

+
+
+
+
+DESCRIPTION: tp.ClassVar[str] = ''
+
+ +
+
+NAME: tp.ClassVar[str] = ''
+
+ +
+
+onerror()[source]
+

Default implementation does nothing.

+
+
Return type:
+

None

+
+
+
+ +
+
+project: benchbuild.project.Project
+
+ +
+ +
+
+class benchbuild.utils.actions.RequireAll(actions=None)[source]
+

Bases: MultiStep

+
+
+DESCRIPTION: ClassVar[str] = 'All child steps need to succeed'
+
+ +
+
+NAME: ClassVar[str] = 'REQUIRE ALL'
+
+ +
+ +
+
+class benchbuild.utils.actions.Run(project, experiment)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Execute the run action'
+
+ +
+
+NAME: tp.ClassVar[str] = 'RUN'
+
+ +
+
+experiment: benchbuild.experiment.Experiment
+
+ +
+ +
+
+class benchbuild.utils.actions.RunWorkload(project, workload=None)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = "Run a project's workload"
+
+ +
+
+NAME: tp.ClassVar[str] = 'RUN WORKLOAD'
+
+ +
+
+property workload_ref: Callable[[], Any]
+
+ +
+ +
+
+class benchbuild.utils.actions.RunWorkloads(project, experiment, run_only=None)[source]
+

Bases: MultiStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Generic run all project workloads'
+
+ +
+
+NAME: tp.ClassVar[str] = 'RUN WORKLOADS'
+
+ +
+
+experiment: benchbuild.experiment.Experiment
+
+ +
+
+project: benchbuild.project.Project
+
+ +
+ +
+
+class benchbuild.utils.actions.SetProjectVersion(project, *revision_strings)[source]
+

Bases: ProjectStep

+
+
+DESCRIPTION: tp.ClassVar[str] = 'Checkout a project version'
+
+ +
+
+NAME: tp.ClassVar[str] = 'SET PROJECT VERSION'
+
+ +
+
+revision: source.Revision
+
+ +
+ +
+
+class benchbuild.utils.actions.Step(status)[source]
+

Bases: object

+

Base class of a step.

+
+
Raises:
+

StopIteration – If we do not encapsulate more substeps.

+
+
+
+
+DESCRIPTION: ClassVar[str] = ''
+
+ +
+
+NAME: ClassVar[str] = ''
+
+ +
+
+onerror()[source]
+

Default implementation does nothing.

+
+
Return type:
+

None

+
+
+
+ +
+
+status: StepResult
+
+ +
+ +
+
+class benchbuild.utils.actions.StepResult(value)[source]
+

Bases: IntEnum

+

Result type for action results.

+
+
+CAN_CONTINUE = 2
+
+ +
+
+ERROR = 3
+
+ +
+
+OK = 1
+
+ +
+
+UNSET = 0
+
+ +
+ +
+
+benchbuild.utils.actions.log_before_after(name, desc)[source]
+

Log customized string before & after running func.

+
+
Return type:
+

Callable[[Callable[..., StepResult]], Callable[..., StepResult]]

+
+
+
+ +
+
+benchbuild.utils.actions.prepend_status(func)[source]
+

Prepends the output of func with the status.

+
+
Return type:
+

Callable[..., str]

+
+
+
+ +
+
+benchbuild.utils.actions.run_any_child(child)[source]
+

Execute child step.

+
+
Parameters:
+

child (Step) – The child step.

+
+
Return type:
+

StepResult

+
+
+
+ +
+
+benchbuild.utils.actions.step_has_failed(result, error_status=None)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/basics/configuration/index.html b/branch/f-QoLImprovements/basics/configuration/index.html new file mode 100644 index 000000000..1c6f8259b --- /dev/null +++ b/branch/f-QoLImprovements/basics/configuration/index.html @@ -0,0 +1,676 @@ + + + + + + + Configure + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Configure

+
+

Module: settings

+

Settings module for benchbuild.

+

All settings are stored in a simple dictionary. Each +setting should be modifiable via environment variable.

+
+
+

Module: utils.settings

+

Configuration utilities.

+

Settings are stored in a dictionary-like configuration object. +All settings are modifiable by environment variables that encode +the path in the dictionary tree.

+

Inner nodes in the dictionary tree can be any dictionary. +A leaf node in the dictionary tree is represented by an inner node that +contains a value key.

+
+
+class benchbuild.utils.settings.ConfigDumper(stream, default_style=None, default_flow_style=False, canonical=None, indent=None, width=None, allow_unicode=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, version=None, tags=None, sort_keys=True)[source]
+

Bases: SafeDumper

+

Avoid polluting yaml’s namespace with our modifications.

+
+
+yaml_implicit_resolvers = {'!': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '&': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '': [('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], '*': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '+': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE))], '-': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE))], '.': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE))], '0': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '1': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '2': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '3': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '4': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '5': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '6': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '7': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '8': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '9': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '<': [('tag:yaml.org,2002:merge', re.compile('^(?:<<)$'))], '=': [('tag:yaml.org,2002:value', re.compile('^(?:=)$'))], 'F': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'N': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE)), ('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], 'O': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'T': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'Y': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'f': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'n': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE)), ('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], 'o': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 't': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'y': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], '~': [('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], None: [('!uuid', re.compile('^\\b[a-f0-9]{8}-\\b[a-f0-9]{4}-\\b[a-f0-9]{4}-\\b[a-f0-9]{4}-\\b[a-f0-9]{12}$'))]}
+
+ +
+
+yaml_representers = {<class 'NoneType'>: <function SafeRepresenter.represent_none>, <class 'benchbuild.utils.settings.ConfigPath'>: <function path_representer>, <class 'bool'>: <function SafeRepresenter.represent_bool>, <class 'bytes'>: <function SafeRepresenter.represent_binary>, <class 'datetime.date'>: <function SafeRepresenter.represent_date>, <class 'datetime.datetime'>: <function SafeRepresenter.represent_datetime>, <class 'dict'>: <function SafeRepresenter.represent_dict>, <class 'float'>: <function SafeRepresenter.represent_float>, <class 'int'>: <function SafeRepresenter.represent_int>, <class 'list'>: <function SafeRepresenter.represent_list>, <class 'set'>: <function SafeRepresenter.represent_set>, <class 'str'>: <function SafeRepresenter.represent_str>, <class 'tuple'>: <function SafeRepresenter.represent_list>, <class 'uuid.UUID'>: <function uuid_representer>, None: <function SafeRepresenter.represent_undefined>}
+
+ +
+ +
+
+class benchbuild.utils.settings.ConfigLoader(stream)[source]
+

Bases: CSafeLoader

+

Avoid polluting yaml’s namespace with our modifications.

+
+
+yaml_constructors = {'!create-if-needed': <function path_constructor>, '!uuid': <function uuid_constructor>, 'tag:yaml.org,2002:binary': <function SafeConstructor.construct_yaml_binary>, 'tag:yaml.org,2002:bool': <function SafeConstructor.construct_yaml_bool>, 'tag:yaml.org,2002:float': <function SafeConstructor.construct_yaml_float>, 'tag:yaml.org,2002:int': <function SafeConstructor.construct_yaml_int>, 'tag:yaml.org,2002:map': <function SafeConstructor.construct_yaml_map>, 'tag:yaml.org,2002:null': <function SafeConstructor.construct_yaml_null>, 'tag:yaml.org,2002:omap': <function SafeConstructor.construct_yaml_omap>, 'tag:yaml.org,2002:pairs': <function SafeConstructor.construct_yaml_pairs>, 'tag:yaml.org,2002:seq': <function SafeConstructor.construct_yaml_seq>, 'tag:yaml.org,2002:set': <function SafeConstructor.construct_yaml_set>, 'tag:yaml.org,2002:str': <function SafeConstructor.construct_yaml_str>, 'tag:yaml.org,2002:timestamp': <function SafeConstructor.construct_yaml_timestamp>, None: <function SafeConstructor.construct_undefined>}
+
+ +
+
+yaml_implicit_resolvers = {'!': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '&': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '': [('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], '*': [('tag:yaml.org,2002:yaml', re.compile('^(?:!|&|\\*)$'))], '+': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE))], '-': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE))], '.': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE))], '0': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '1': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '2': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '3': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '4': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '5': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '6': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '7': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '8': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '9': [('tag:yaml.org,2002:float', re.compile('^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?\n                    |\\.[0-9][0-9_]*(?:[eE][-+][0-9]+)?\n                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*\n                   , re.VERBOSE)), ('tag:yaml.org,2002:int', re.compile('^(?:[-+]?0b[0-1_]+\n                    |[-+]?0[0-7_]+\n                    |[-+]?(?:0|[1-9][0-9_]*)\n                    |[-+]?0x[0-9a-fA-F_]+\n                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9]), re.VERBOSE)), ('tag:yaml.org,2002:timestamp', re.compile('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n                     (?:[Tt]|[ \\t]+)[0-9][0-9]?\n                     :[0-9][0-9], re.VERBOSE))], '<': [('tag:yaml.org,2002:merge', re.compile('^(?:<<)$'))], '=': [('tag:yaml.org,2002:value', re.compile('^(?:=)$'))], 'F': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'N': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE)), ('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], 'O': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'T': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'Y': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'f': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'n': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE)), ('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], 'o': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 't': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], 'y': [('tag:yaml.org,2002:bool', re.compile('^(?:yes|Yes|YES|no|No|NO\n                    |true|True|TRUE|false|False|FALSE\n                    |on|On|ON|off|Off|OFF)$', re.VERBOSE))], '~': [('tag:yaml.org,2002:null', re.compile('^(?: ~\n                    |null|Null|NULL\n                    | )$', re.VERBOSE))], None: [('!uuid', re.compile('^\\b[a-f0-9]{8}-\\b[a-f0-9]{4}-\\b[a-f0-9]{4}-\\b[a-f0-9]{4}-\\b[a-f0-9]{12}$'))]}
+
+ +
+ +
+
+class benchbuild.utils.settings.ConfigPath(components)[source]
+

Bases: object

+

Wrapper around paths represented as list of strings.

+
+
+static path_to_str(components)[source]
+
+
Return type:
+

str

+
+
+
+ +
+
+validate()[source]
+

Make sure this configuration path exists.

+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class benchbuild.utils.settings.Configuration(parent_key, node=None, parent=None, init=True)[source]
+

Bases: Indexable

+

Dictionary-like data structure to contain all configuration variables.

+

This serves as a configuration dictionary throughout benchbuild. You can +use it to access all configuration options that are available. Whenever the +structure is updated with a new subtree, all variables defined in the new +subtree are updated from the environment.

+
+
Environment variables are generated from the tree paths automatically.

CFG[“build_dir”] becomes BB_BUILD_DIR +CFG[“llvm”][“dir”] becomes BB_LLVM_DIR

+
+
+

The configuration can be stored/loaded as YAML.

+
+
+filter_exports()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+has_default()[source]
+

Check, if the node contains a ‘default’ value.

+
+
Return type:
+

bool

+
+
+
+ +
+
+has_value()[source]
+

Check, if the node contains a ‘value’.

+
+
Return type:
+

bool

+
+
+
+ +
+
+init_from_env()[source]
+

Initialize this node from environment.

+

If we’re a leaf node, i.e., a node containing a dictionary that +consist of a ‘default’ key, compute our env variable and initialize +our value from the environment. +Otherwise, init our children.

+
+
Return type:
+

None

+
+
+
+ +
+
+is_leaf()[source]
+

Check, if the node is a ‘leaf’ node.

+
+
Return type:
+

bool

+
+
+
+ +
+
+load(_from)[source]
+

Load the configuration dictionary from file.

+
+
Return type:
+

None

+
+
+
+ +
+
+store(config_file)[source]
+

Store the configuration dictionary to a file.

+
+
Return type:
+

None

+
+
+
+ +
+
+to_env_dict()[source]
+

Convert configuration object to a flat dictionary.

+
+
Return type:
+

Mapping[str, Any]

+
+
+
+ +
+
+property value: Any
+

Return the node value, if we’re a leaf node.

+
+ +
+ +
+
+class benchbuild.utils.settings.Indexable[source]
+

Bases: object

+
+ +
+
+exception benchbuild.utils.settings.InvalidConfigKey[source]
+

Bases: RuntimeWarning

+

Warn, if you access a non-existing key benchbuild’s configuration.

+
+ +
+
+benchbuild.utils.settings.available_cpu_count()[source]
+

Get the number of available CPUs.

+

Number of available virtual or physical CPUs on this system, i.e. +user/real as output by time(1) when called with an optimally scaling +userspace-only program.

+
+
Return type:
+

int

+
+
Returns:
+

Number of avaialable CPUs.

+
+
+
+ +
+
+benchbuild.utils.settings.convert_components(value)[source]
+
+
Return type:
+

List[str]

+
+
+
+ +
+
+benchbuild.utils.settings.current_available_threads()[source]
+

Returns the number of currently available threads for BB.

+
+
Return type:
+

int

+
+
+
+ +
+
+benchbuild.utils.settings.escape_yaml(raw_str)[source]
+

Shell-Escape a yaml input string.

+
+
Parameters:
+

raw_str (str) – The unescaped string.

+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.utils.settings.find_config(test_file=None, defaults=None, root='.')[source]
+

Find the path to the default config file.

+

We look at :root: for the :default: config file. If we can’t find it +there we start looking at the parent directory recursively until we +find a file named :default: and return the absolute path to it. +If we can’t find anything, we return None.

+
+
Parameters:
+
    +
  • test_file (Optional[str])

  • +
  • default – The name of the config file we look for.

  • +
  • root (str) – The directory to start looking for.

  • +
+
+
Return type:
+

Optional[LocalPath]

+
+
Returns:
+

Path to the default config file, None if we can’t find anything.

+
+
+
+ +
+
+benchbuild.utils.settings.get_number_of_jobs(config)[source]
+

Returns the number of jobs set in the config.

+
+
Return type:
+

int

+
+
+
+ +
+
+benchbuild.utils.settings.is_yaml(cfg_file)[source]
+

Is the given cfg_file a YAML file.

+
+
Return type:
+

bool

+
+
+
+ +
+
+benchbuild.utils.settings.path_constructor(loader, node)[source]
+

” +Construct a ConfigPath object form a scalar YAML node.

+
+ +
+
+benchbuild.utils.settings.path_representer(dumper, data)[source]
+

Represent a ConfigPath object as a scalar YAML node.

+
+ +
+
+benchbuild.utils.settings.setup_config(cfg, config_filenames=None, env_var_name=None)[source]
+

This will initialize the given configuration object.

+
+
The following resources are available in the same order:
    +
  1. Default settings.

  2. +
  3. Config file.

  4. +
  5. Environment variables.

  6. +
+
+
WARNING: Environment variables do _not_ take precedence over the config

file right now. (init_from_env will refuse to update the +value, if there is already one.)

+
+
+
+
Parameters:
+
    +
  • config_filenames (Optional[List[str]]) – list of possible config filenames

  • +
  • env_var_name (Optional[str]) – name of the environment variable holding the config path

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+benchbuild.utils.settings.to_env_var(env_var, value)[source]
+

Create an environment variable from a name and a value.

+

This generates a shell-compatible representation of an +environment variable that is assigned a YAML representation of +a value.

+
+
Parameters:
+
    +
  • env_var (str) – Name of the environment variable.

  • +
  • value (Any) – A value we convert from.

  • +
+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.utils.settings.to_yaml(value)[source]
+

Convert a given value to a YAML string.

+
+
Return type:
+

Optional[str]

+
+
+
+ +
+
+benchbuild.utils.settings.update_env(cfg)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+benchbuild.utils.settings.upgrade(cfg)[source]
+

Provide forward migration for configuration files.

+
+
Return type:
+

None

+
+
+
+ +
+
+benchbuild.utils.settings.uuid_add_implicit_resolver(loader=<class 'benchbuild.utils.settings.ConfigLoader'>, dumper=<class 'benchbuild.utils.settings.ConfigDumper'>)[source]
+

Attach an implicit pattern resolver for UUID objects.

+
+ +
+
+benchbuild.utils.settings.uuid_constructor(loader, node)[source]
+

“Construct a uuid.UUID object form a scalar YAML node.

+
+ +
+
+benchbuild.utils.settings.uuid_representer(dumper, data)[source]
+

Represent a uuid.UUID object as a scalar YAML node.

+
+ +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/basics/containers/index.html b/branch/f-QoLImprovements/basics/containers/index.html new file mode 100644 index 000000000..decf5e3bf --- /dev/null +++ b/branch/f-QoLImprovements/basics/containers/index.html @@ -0,0 +1,1323 @@ + + + + + + + Containers + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Containers

+

Benchbuild allows the definition of container images to define the base system +all experiment runs run in for a given project.

+
+

Usage

+

If you want to run an experiment inside the project’s container, simply replace +the usual run subcommand with the container run subcommand. Project and +experiment selection are done in the same way.

+

Example:

+
benchbuild container run -E raw linpack
+
+
+

This will run the following stages:

+
    +
  1. Build all necessary base images. +All images are initiated from a base image. Benchbuild knows how to construct +a few base images. These will be prepared with all dependencies required to +run benchbuild inside the container.

  2. +
  3. Build all project images. Each project has to define its’ own image.

  4. +
  5. Build the experiment images. Each experiment can add anything it needs to the +project images, if required. Use this to bring tools into the image that do +not require any knowledge about the environment to run properly. +For anything else, consider using a custom base image.

  6. +
+
+

Replace Images

+

Benchbuild will reuse any existing images it can find in your image registry. +The only relevant information is the image tag, e.g., benchbuild:alpine. +If you want to avoid reuse and force to rebuild images unconditionally, you can +use the --replace flag when running the containers subcommand.

+

Example:

+
benchbuild container run --replace -E raw linpack
+
+
+

This will ignore any required image for the given experiments and projects.

+
+
+
+

Configuration

+

You can configure the container environment using the following config variables.

+
    +
  • BB_CONTAINER_EXPORT: Path where benchbuild stores exported container +images. By default we store it in ./containers/export. Will be created +automatically, if needed.

  • +
  • BB_CONTAINER_IMPORT: Path where to input images from into the registry. +By default we load from ./containers/export.

  • +
  • BB_CONTAINER_FROM_SOURCE: Determine, if we should use benchbuild from the +current source checkout, or from pip.

  • +
  • BB_CONTAINER_ROOT: Where we store our image layers. This is the image +registry. Cannot be stored on filesystems that do not support subuid/-gid +mapping, e.g. NFS. +The default location is ./containers/lib.

  • +
  • BB_CONTAINER_RUNROOT: Where we store temporary image layers of running +containers. See BB_CONTAINER_ROOT for restrictions. +The default location is: ./containers/run.

  • +
  • BB_CONTAINER_RUNTIME: Podman can use any standard OCI-container runtime to +launch containers. We use crun by +default. Depending on your system, this one has already been installed with +podman. +The default runtime is: /usr/bin/crun

  • +
  • BB_CONTAINER_MOUNTS: A list of mountpoint definitions that should be added +to all containers. With this you can add arbitrary tools into all containers. +Default: []

  • +
+
+
+

Definition

+

A project that wants to use a container image needs to define it in the +CONTAINER attribute it using our declarative API provided by +benchbuild.environments.domain.declarative.

+
from benchbuild.environments.domain.declarative import ContainerImage
+
+class Testproject(Project):
+  CONTAINER = ContainerImage().from_('benchbuild:alpine')
+
+
+

The available set of commands follows the structure of a Dockerfile.

+
+
+

Runtime requirements

+

For containers to work properly, you need a few systems set up beforehand.

+
+

Buildah

+

Image construction requires the Buildah tool. All image +construction tasks are formulated as buildah command calls in the backend.

+

Buildah is supported up to version 1.19.8.

+
+
+

Podman

+

Container construction and execution is handed off to Podman. +Podman provides rootless containers and does not requires the execution of a +daemon process. However, you need to setup your user namespace properly to allow +mapping of subordinate uids/gids. Otherwise, podman will not be able to map +users other than the root user to filesystem permissions inside the container.

+

Please refer to podman’s documentation on how to setup podman properly on your +system.

+

Podman is supported up to version 2.2.1

+
+
+
+

Module: benchbuild.container

+

Container construction tool.

+

This tool assists in the creation of customized uchroot containers. +You can define strategies and apply them on a given container base-image +to have a fixed way of creating a user-space environment.

+
+
+class benchbuild.container.BashStrategy[source]
+

Bases: ContainerStrategy

+

The user interface for setting up a bash inside the container.

+
+
+run(context)[source]
+

Execute a container strategy.

+
+
Parameters:
+

context – A context object with attributes used for the strategy.

+
+
+
+ +
+ +
+
+class benchbuild.container.Container(executable=None)[source]
+

Bases: Application

+

Manage uchroot containers.

+
+
+VERSION = '6.9.dev8+g85c5ced8'
+
+ +
+
+builddir(tmpdir)[source]
+

Set the current builddir of the container.

+
+ +
+
+input_file(_container)[source]
+

Find the input path of a uchroot container.

+
+ +
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+
+mounts(user_mount)[source]
+

Save the current mount of the container into the settings.

+
+ +
+
+output_file(_container)[source]
+

Find and writes the output path of a chroot container.

+
+ +
+
+shell(custom_shell)[source]
+

The command to run inside the container.

+
+ +
+
+verbosity
+

Sets an attribute

+
+ +
+ +
+
+class benchbuild.container.ContainerBootstrap(executable=None)[source]
+

Bases: Application

+

Check for the needed files.

+
+
+install_cmake_and_exit()[source]
+

Tell the user to install cmake and aborts the current process.

+
+ +
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+ +
+
+class benchbuild.container.ContainerCreate(executable=None)[source]
+

Bases: Application

+

Create a new container with a predefined strategy.

+

We offer a variety of creation policies for a new container. By default a +basic ‘spawn a bash’ policy is used. This just leaves you inside a bash +that is started in the extracted container. After customization you can +exit the bash and pack up the result.

+
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+
+strategy(strategy)[source]
+

Select strategy based on key.

+
+
Parameters:
+

strategy (str) – The strategy to select.

+
+
Returns:
+

A strategy object.

+
+
+
+ +
+ +
+
+class benchbuild.container.ContainerList(executable=None)[source]
+

Bases: Application

+

Prints a list of the known containers.

+
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+ +
+
+class benchbuild.container.ContainerRun(executable=None)[source]
+

Bases: Application

+

Execute commannds inside a prebuilt container.

+
+
+main(*args)[source]
+

Implement me (no need to call super)

+
+ +
+ +
+
+class benchbuild.container.ContainerStrategy[source]
+

Bases: object

+

Interfaces for the different containers chosen by the experiment.

+
+
+abstract run(context)[source]
+

Execute a container strategy.

+
+
Parameters:
+

context – A context object with attributes used for the strategy.

+
+
+
+ +
+ +
+
+class benchbuild.container.MockObj(**kwargs)[source]
+

Bases: object

+

Context object to be used in strategies.

+

This object’s attributes are initialized on construction.

+
+ +
+
+class benchbuild.container.SetupPolyJITGentooStrategy[source]
+

Bases: ContainerStrategy

+

Interface of using gentoo as a container for an experiment.

+
+
+run(context)[source]
+

Setup a gentoo container suitable for PolyJIT.

+
+ +
+ +
+
+benchbuild.container.clean_directories(builddir, in_dir=True, out_dir=True)[source]
+

Remove the in and out of the container if confirmed by the user.

+
+ +
+
+benchbuild.container.find_hash(container_db, key)[source]
+

Find the first container in the database with the given key.

+
+ +
+
+benchbuild.container.main(*args)[source]
+

Main entry point for the container tool.

+
+ +
+
+benchbuild.container.pack_container(in_container, out_file)[source]
+

Pack a container image into a .tar.bz2 archive.

+
+
Parameters:
+
    +
  • in_container (str) – Path string to the container image.

  • +
  • out_file (str) – Output file name.

  • +
+
+
+
+ +
+
+benchbuild.container.run_in_container(command, container_dir)[source]
+

Run a given command inside a container.

+

Mounts a directory as a container at the given mountpoint and tries to run +the given command inside the new container.

+
+ +
+
+benchbuild.container.set_input_container(_container, cfg)[source]
+

Save the input for the container in the configurations.

+
+ +
+
+benchbuild.container.setup_bash_in_container(builddir, _container, outfile, shell)[source]
+

Setup a bash environment inside a container.

+

Creates a new chroot, which the user can use as a bash to run the wanted +projects inside the mounted container, that also gets returned afterwards.

+
+ +
+
+benchbuild.container.setup_container(builddir, _container)[source]
+

Prepare the container and returns the path where it can be found.

+
+ +
+
+benchbuild.container.setup_directories(builddir)[source]
+

Create the in and out directories of the container.

+
+ +
+
+

Module: benchbuild.environments.domain.declarative

+

BenchBuild supports containerized execution of all experiments. This gives you +full control about the environment your [projects](/concepts/projects/) and +[experiments](/concepts/experiments/) may run in.

+

The following example uses the latest alpine:latest:

+
ContainerImage().from_('alpine:latest')
+    .run('apk', 'update')
+    .run('apk', 'add', 'python3')
+
+
+
+
+class benchbuild.environments.domain.declarative.ContainerImage(iterable=(), /)[source]
+

Bases: list

+

Define a container image declaratively.

+

Start a new image using the .from_ method and provide a base image. +Each method creates a new layer in the container image.

+
+
+add(sources, tgt)[source]
+

Add given files from the source to the container image.

+

Dockerfile syntax: ADD <source> [<source>…] <target>

+
+
Parameters:
+
    +
  • sources (tp.Iterable[str]) – Source path to add to the target

  • +
  • tgt (str) – Absolute target path.

  • +
+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+property base: str
+
+ +
+
+command(*args)[source]
+

Set the default command the container runs.

+

Dockerfile syntax: CMD <command>

+
+
Parameters:
+

*args (str) – A list of command components.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+context(func)[source]
+

Interact with the build context of the container.

+

Sometimes you have to interact with the build context of a container +image. For example, you need to add artifacts to the build context +before you can add the to the container image. +BenchBuild uses this to add the sources to the container image +automatically.

+
+
Parameters:
+

func (tp.Callable[[], None]) – A callable that is executed in the +build-context directory.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+copy_(sources, tgt)[source]
+

Copy given files from the source to the container image.

+

Dockerfile syntax: COPY <source> [<source>…] <target>

+
+
Parameters:
+
    +
  • sources (tp.Iterable[str]) – Source path to add to the target

  • +
  • tgt (str) – Absolute target path.

  • +
+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+entrypoint(*args)[source]
+

Set the entrypoint of the container.

+

Dockerfile syntax: ENTRYPOINT <command>

+

This sets the default binary to run to the given command.

+
+
Parameters:
+

*args (str) – A list of command components.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+env(**kwargs)[source]
+

Create an environment layer in this image.

+

Dockerfile syntax: ENV

+
+
Parameters:
+

kwargs (str) – a dictionary containing name/value pairings to be +set as environment variables.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+from_(base_image)[source]
+

Specify a new base layer for this image.

+

Dockerfile syntax: FROM <image>

+
+
Parameters:
+

base_image (str) – The base image for our new container image.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+run(command, *args, **kwargs)[source]
+

Run a command in the container image.

+

Dockerfile syntax: RUN <command>

+
+
Parameters:
+
    +
  • command (str) – The binary to execute in the container.

  • +
  • *args (str) – Arguments that will be passed to the container.

  • +
  • **kwargs (str) – Additional options that will be passed to the +backend run command.

  • +
+
+
Return type:
+

ContainerImage

+
+
+
+ +
+
+workingdir(directory)[source]
+

Change the working directory in the container.

+

Dockerfile syntax: WORKINGDIR <absolute-path>

+

All layers that follow this layer will be run with their working +directory set to directory.

+
+
Parameters:
+

directory (str) – The target directory to set our cwd to.

+
+
Return type:
+

ContainerImage

+
+
+
+ +
+ +
+
+benchbuild.environments.domain.declarative.add_benchbuild_layers(layers)[source]
+

Add benchbuild into the given container image.

+

This assumes all necessary depenencies are available in the image already. +The installation is done, either using pip from a remote mirror, or using +the source checkout of benchbuild.

+

A source installation requires your buildah/podman installation to be +able to complete a bind-mount as the user that runs benchbuild.

+
+
Parameters:
+

layers (ContainerImage) – a container image we will add our install layers to.

+
+
Return type:
+

ContainerImage

+
+
Returns:
+

the modified container image.

+
+
+
+ +
+
+

Module: benchbuild.environments.domain.model

+
+
+class benchbuild.environments.domain.model.AddLayer(sources, destination)[source]
+

Bases: Layer

+
+
+destination: str
+
+ +
+
+sources: Tuple[str, ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Command[source]
+

Bases: Message

+
+ +
+
+class benchbuild.environments.domain.model.Container(container_id, image, context, name, events=NOTHING)[source]
+

Bases: object

+
+
+container_id: str
+
+ +
+
+context: str
+
+ +
+
+events: List[Message]
+
+ +
+
+image: Image
+
+ +
+
+name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.model.ContextLayer(func)[source]
+

Bases: Layer

+
+
+func: Callable[[], None]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.CopyLayer(sources, destination)[source]
+

Bases: Layer

+
+
+destination: str
+
+ +
+
+sources: Tuple[str, ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.EntryPoint(command)[source]
+

Bases: Layer

+
+
+command: Tuple[str, ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Event[source]
+

Bases: Message

+
+ +
+
+class benchbuild.environments.domain.model.FromLayer(base)[source]
+

Bases: Layer

+
+
+base: str
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Image(name, from_, layers, events=NOTHING, env=NOTHING, mounts=NOTHING, layer_index=NOTHING)[source]
+

Bases: object

+
+
+append(*layers)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+env: Dict[str, str]
+
+ +
+
+events: List[Message]
+
+ +
+
+from_: FromLayer
+
+ +
+
+is_complete()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+is_present(layer)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+layer_index: Dict[Layer, LayerState]
+
+ +
+
+layers: List[Layer]
+
+ +
+
+mounts: List[Mount]
+
+ +
+
+name: str
+
+ +
+
+prepend(layer)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+present(layer)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+update_env(**kwargs)[source]
+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Layer[source]
+

Bases: ABC

+

A layer represents a filesystem layer in a container image.

+

Layers can be ‘virtual’ in the sense that they do not lead to changes +in the container image filesystem, e.g. setting up the build context.

+

This more or less represents commands/statements available in buildah +or Dockerfiles.

+
+

Examples

+

buildah add -> AddLayer +buildah copy -> CopyLayer +buildah from -> FromLayer

+
+
+ +
+
+class benchbuild.environments.domain.model.LayerState(value)[source]
+

Bases: Enum

+

An enumeration.

+
+
+ABSENT = 2
+
+ +
+
+PRESENT = 1
+
+ +
+ +
+
+class benchbuild.environments.domain.model.Message[source]
+

Bases: object

+
+ +
+
+class benchbuild.environments.domain.model.Mount(source, target)[source]
+

Bases: object

+
+
+source: str
+
+ +
+
+target: str
+
+ +
+ +
+
+class benchbuild.environments.domain.model.RunLayer(command, args, kwargs)[source]
+

Bases: Layer

+
+
+args: Tuple[str, ...]
+
+ +
+
+command: str
+
+ +
+
+kwargs: Tuple[Tuple[str, str], ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.SetCommand(command)[source]
+

Bases: Layer

+
+
+command: Tuple[str, ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.UpdateEnv(env)[source]
+

Bases: Layer

+
+
+env: Tuple[Tuple[str, str], ...]
+
+ +
+ +
+
+class benchbuild.environments.domain.model.WorkingDirectory(directory)[source]
+

Bases: Layer

+
+
+directory: str
+
+ +
+ +
+
+benchbuild.environments.domain.model.immutable_kwargs(kwargs)[source]
+

Convert str-typed kwargs into a hashable tuple.

+
+
Return type:
+

Tuple[Tuple[str, str], ...]

+
+
+
+ +
+
+

Module: benchbuild.environments.domain.commands

+
+
+class benchbuild.environments.domain.commands.CreateBenchbuildBase(name, layers)[source]
+

Bases: Command

+
+
+layers: ContainerImage
+
+ +
+
+name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.CreateImage(name, layers)[source]
+

Bases: Command

+
+
+layers: ContainerImage
+
+ +
+
+name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.DeleteImage(name)[source]
+

Bases: Command

+
+
+name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.ExportImage(image, out_name)[source]
+

Bases: Command

+
+
+image: str
+
+ +
+
+out_name: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.ImportImage(image, in_path)[source]
+

Bases: Command

+
+
+image: str
+
+ +
+
+in_path: str
+
+ +
+ +
+
+class benchbuild.environments.domain.commands.RunProjectContainer(image, name, build_dir, tmp_dir, mount_build_dir, mount_tmp_dir, args=NOTHING)[source]
+

Bases: Command

+
+
+args: Sequence[str]
+
+ +
+
+build_dir: str
+
+ +
+
+image: str
+
+ +
+
+mount_build_dir: bool
+
+ +
+
+mount_tmp_dir: bool
+
+ +
+
+name: str
+
+ +
+
+tmp_dir: str
+
+ +
+ +
+
+benchbuild.environments.domain.commands.fs_compliant_name(name)[source]
+

Convert a name to a valid filename.

+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.environments.domain.commands.oci_compliant_name(name)[source]
+

Convert a name to an OCI compliant name.

+

For now, we just make sure it is lower-case. This is depending on +the implementation of your container registry. podman/buildah require +lower-case repository names for now.

+
+
Parameters:
+

name (str) – the name to convert

+
+
Return type:
+

str

+
+
+
+

Examples

+
>>> oci_compliant_name("foo")
+'foo'
+>>> oci_compliant_name("FoO")
+'foo'
+
+
+
+
+ +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/basics/index.html b/branch/f-QoLImprovements/basics/index.html new file mode 100644 index 000000000..11acf3f6a --- /dev/null +++ b/branch/f-QoLImprovements/basics/index.html @@ -0,0 +1,327 @@ + + + + + + + Installation + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Installation

+

The installation instructions are tested against Ubuntu 20.04 for Python 3.7 and Python 3.8. The particular commands required for installation depend on your setup. +The dependencies below are not always mandatory, if they are not used.

+
+

Requirements

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Dependency

Minimum Version

Notes

Python

3.7

libpq

9.6

Required by psycopg2.

libfuse

2.9.9

If uchroot is used.

unionfs-fuse

1.0

If unionfs support is used.

slurm-llnl

18.08

If slurm support is used.

+
+

PostgreSQL

+

The library dependency libpq is always need right now, because we make use of psycopg2 features internally. It is planned to get rid of this dependency in the future.

+
+
+

FUSE

+

BenchBuild can make use of unionfs and libfuse. This is often used in conjunction with a tool named uchroot which provides legacy support for user-space containers. +This will be obsolete as soon as podman/buildah based OCI container support is considered stable.

+
+
+

SLURM

+

The cluster management software slurm is only required by ‘name’, i.e., we have to be able to import the binaries as python objects in benchbuild. As an alternative to installing slurm on your machine, you can always provide symlinks to /bin/true to the commands sbatch and srun.

+

The minimum version should signal the minimum features set expected by BenchBuild when generating a slurm batch script.

+
+
+
+

Benchbuild

+

BenchBuild is released via pip and can be installed on your system as follows:

+
pip install benchbuild
+
+
+

If you want to isolate BenchBuild from the rest of your system packages, you can install it in a dedicated virtual environment.

+
virtualenv -ppython3 <venv_path>
+source <venv_path>/bin/activate
+pip3 install benchbuild
+
+
+
+

Bootstrapping

+

BenchBuild provides a bootstrap procedure that checks a few key binaries on your system and tries to assist you in installation of any necessary binaries.

+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/concepts/command/index.html b/branch/f-QoLImprovements/concepts/command/index.html new file mode 100644 index 000000000..cd2fa70e3 --- /dev/null +++ b/branch/f-QoLImprovements/concepts/command/index.html @@ -0,0 +1,958 @@ + + + + + + + Commands + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Commands

+

BenchBuild provides an abstraction for binaries that are provided by a project, +after compilation. These Command objects carry the path to the binary, +customizable output paramters and support for dynamic tokens inside the path +generation.

+

Besides these features, a command behaves identical to any other binary +command that you make use of inside BenchBuild, e.g., benchbuild.utils.cmd.

+
+

Usage inside Projects

+

For now, you make use of BenchBuild’s commands inside a project’s WORKLOADS +attribute. Let’s have a look at the following example:

+
from benchbuild import Project
+from benchbuild.command import Command, WorkloadSet, SourceRoot
+
+class MyProject(Project):
+  ...
+  SOURCE = [
+    Git(
+      remote="https://github.com/myproject.git",
+      local="myproject.git",
+      limit=1,
+      refspec="HEAD"
+  ]
+
+  WORKLOADS = {
+    WorkloadSet("compression"): [
+      Command(SourceRoot("myproject.git") / "myprj")
+    ]
+  }
+
+
+

Here we have a Command that belongs to the WorkloadSet with the name +compression that points to the binary myprj inside the project’s +source directory of the git source myproject.git. What concrete path +this will be is only known after this project has been instanced inside +an experiment and is not known before.

+

This is done using tokens inside the commands’ path representation. One +example of an available token is the above SourceRoot.

+
+
+

Tokens

+

BenchBuild offers project authors a way to tokenize path components for +commands. These can be used to refer to a project’s root directory or +source directory in a generic way.

+
+
+

Module: command

+
+
+class benchbuild.command.ArgsRenderStrategy(*args, **kwargs)[source]
+

Bases: Protocol

+

Rendering strategy protocol for command line argument tokens.

+
+
+rendered(**kwargs)[source]
+

Renders this strategy.

+
+
Return type:
+

Tuple[str, ...]

+
+
+
+ +
+
+property unrendered: str
+

Returns an unrendered representation of this strategy.

+
+ +
+ +
+
+class benchbuild.command.ArgsToken(renderer)[source]
+

Bases: object

+

Base class for tokens that can be rendered into command-line arguments.

+
+
+classmethod make_token(renderer)[source]
+
+
Return type:
+

ArgsToken

+
+
+
+ +
+
+render(**kwargs)[source]
+

Renders the PathToken as a standard pathlib Path.

+

Any kwargs will be forwarded to the PathRenderStrategy.

+
+
Return type:
+

Tuple[str, ...]

+
+
+
+ +
+
+renderer: ArgsRenderStrategy
+
+ +
+ +
+
+class benchbuild.command.BackupFn(*args, **kwargs)[source]
+

Bases: Protocol

+

Backup callback function protocol.

+
+ +
+
+class benchbuild.command.BuilddirRenderer[source]
+

Bases: object

+

Renders the build directory of the assigned project.

+
+
+rendered(project=None, **kwargs)[source]
+

Render the project’s build directory.

+

If rendering is not possible, the unrendered representation is +provided and an error will be loggged.

+
+
Parameters:
+

project (Optional[benchbuild.project.Project]) – the project to render the build directory from.

+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+
+ +
+ +
+
+class benchbuild.command.Command(path, *args, output=None, output_param=None, label=None, creates=None, consumes=None, **kwargs)[source]
+

Bases: object

+

A command wrapper for benchbuild’s commands.

+

Commands are defined by a path to an executable binary and it’s arguments. +Optional, commands can provide output and output_param parameters to +declare the Command’s output behavior.

+
+
+path
+

The binary path of the command

+
+ +
+
+\*args
+

Command arguments.

+
+ +
+
+output_param
+

A format string that encodes the output parameter argument +using the output attribute.

+

Example: output_param = f”–out {output}”. +BenchBuild will construct the output argument from this.

+
+ +
+
+output
+

An optional PathToken to declare an output file of the command.

+
+ +
+
+label
+

An optional Label that can be used to name a command.

+
+ +
+
+creates
+

A list of PathToken that encodes any artifacts that are +created by this command. +This will include the output PathToken automatically. Any +additional PathTokens provided will be provided for cleanup.

+
+ +
+
+consumes
+

A list of PathToken that holds any artifacts that will be +consumed by this command.

+
+ +
+
+\*\*kwargs
+

Any remaining kwargs will be added as environment variables +to the command.

+
+ +

Base command path: +>>> ROOT = PathToken.make_token() +>>> base_c = Command(ROOT / “bin” / “true”) +>>> base_c +Command(path=/bin/true) +>>> str(base_c) +‘/bin/true’

+

Test environment representations: +>>> env_c = Command(ROOT / “bin”/ “true”, BB_ENV_TEST=1) +>>> env_c +Command(path=/bin/true env={‘BB_ENV_TEST’: 1}) +>>> str(env_c) +‘BB_ENV_TEST=1 /bin/true’

+

Argument representations: +>>> args_c = Command(ROOT / “bin” / “true”, “–arg1”, “–arg2”) +>>> args_c +Command(path=/bin/true args=(’–arg1’, ‘–arg2’)) +>>> str(args_c) +‘/bin/true –arg1 –arg2’

+

Use str for creates: +>>> cmd = Command(ROOT / “bin” / “true”, creates=[“tmp/foo”]) +>>> cmd.creates +[<builddir>/tmp/foo]

+

Use absolute path-str for creates: +>>> cmd = Command(ROOT / “bin” / “true”, creates=[“/tmp/foo”]) +>>> cmd.creates +[/tmp/foo]

+
+
+as_plumbum(**kwargs)[source]
+

Convert this command into a plumbum compatible command.

+

This renders all tokens in the command’s path and creates a new +plumbum command with the given parameters and environment.

+
+
Parameters:
+

**kwargs (Any) – parameters passed to the path renderers.

+
+
Return type:
+

BoundEnvCommand

+
+
Returns:
+

An executable plumbum command.

+
+
+
+ +
+
+property consumes: Sequence[PathToken]
+
+ +
+
+property creates: Sequence[PathToken]
+
+ +
+
+property dirname: Path
+
+ +
+
+env(**kwargs)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+property label: str
+
+ +
+
+property name: str
+
+ +
+
+property output: PathToken | None
+
+ +
+
+property path: PathToken
+
+ +
+
+rendered_args(**kwargs)[source]
+
+
Return type:
+

Tuple[str, ...]

+
+
+
+ +
+ +
+
+class benchbuild.command.ConstStrRenderer(value)[source]
+

Bases: object

+

Renders a constant string defined by the user.

+
+
+rendered(**kwargs)[source]
+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+
+ +
+
+value: str
+
+ +
+ +
+
+class benchbuild.command.OnlyIn(rev_range, workload_set)[source]
+

Bases: object

+

Provide a filled WorkloadSet only if, given revision is inside the range.

+

This makes use of the unwrap protocol and returns the given WorkloadSet, +iff, the Project’s revision is included in the range specified by the +RevisionRange.

+
+
+rev_range: RevisionRange
+
+ +
+
+unwrap(project)[source]
+

Provide the store WorkloadSet only if our revision is in the range.

+
+
Return type:
+

WorkloadSet

+
+
+
+ +
+
+workload_set: WorkloadSet
+
+ +
+ +
+
+class benchbuild.command.PathRenderStrategy(*args, **kwargs)[source]
+

Bases: Protocol

+

Rendering strategy protocol for path components.

+
+
+rendered(**kwargs)[source]
+

Renders this strategy.

+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+

Returns an unrendered representation of this strategy.

+
+ +
+ +
+
+class benchbuild.command.PathToken(renderer, left=None, right=None)[source]
+

Bases: object

+

Base class used for command token substitution.

+

A path token can use similar to pathlib’s Path components. However, each +token can render dynamically based on the given render context.

+
+
+property dirname: Path
+
+ +
+
+exists()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+left: Optional[PathToken]
+
+ +
+
+classmethod make_token(renderer=None)[source]
+
+
Return type:
+

PathToken

+
+
+
+ +
+
+property name: str
+
+ +
+
+render(**kwargs)[source]
+

Renders the PathToken as a standard pathlib Path.

+

Any kwargs will be forwarded to the PathRenderStrategy.

+
+
Return type:
+

Path

+
+
+
+ +
+
+renderer: PathRenderStrategy
+
+ +
+
+right: Optional[PathToken]
+
+ +
+ +
+
+class benchbuild.command.ProjectCommand(project, command)[source]
+

Bases: object

+

ProjectCommands associate a command to a benchbuild project.

+

A project command can wrap the given command with the assigned +runtime extension. +If the binary is located inside a subdirectory relative to one of the +project’s sources, you can provide a path relative to it’s local +directory. +A project command will always try to resolve any reference to a local +source directory in a command’s path.

+

A call to a project command will drop the current configuration inside +the project’s build directory and confine the run into the project’s +build directory. The binary will be replaced with a wrapper that +calls the project’s runtime_extension.

+
+
+command: Command
+
+ +
+
+property path: Path
+
+ +
+
+project: benchbuild.project.Project
+
+ +
+ +
+
+benchbuild.command.ProjectRoot()
+
+
Return type:
+

PathToken

+
+
+
+ +
+
+class benchbuild.command.PruneFn(*args, **kwargs)[source]
+

Bases: Protocol

+

Prune function protocol.

+
+ +
+
+class benchbuild.command.RestoreFn(*args, **kwargs)[source]
+

Bases: Protocol

+

Restore function protocol.

+
+ +
+
+class benchbuild.command.RootRenderer[source]
+

Bases: object

+

Renders the root directory.

+
+
+rendered(**kwargs)[source]
+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+
+ +
+ +
+
+benchbuild.command.SourceRoot(local_name)
+

Create a SourceRoot token for the given name.

+
+
Parameters:
+

local_name (str) – The source’s local name to access.

+
+
Return type:
+

PathToken

+
+
+
+ +
+
+class benchbuild.command.SourceRootRenderer(local_name)[source]
+

Bases: object

+

Renders the source root of the given local source name.

+

The attribute ‘local’ refers to the local attribute in a project’s +source definition. +If the local name cannot be found inside the project’s source definition, +it will concatenate the project’s builddir with the given name.

+
+
+local: str
+
+ +
+
+rendered(project=None, **kwargs)[source]
+

Render the project’s source directory.

+

If rendering is not possible, the unrendered representation is +provided and an error will be loggged.

+
+
Parameters:
+

project (Optional[benchbuild.project.Project]) – the project to render the build directory from.

+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+
+ +
+ +
+
+class benchbuild.command.SupportsUnwrap(*args, **kwargs)[source]
+

Bases: Protocol

+

Support unwrapping a WorkloadSet.

+

Unwrapping ensures access to a WorkloadSet from any wrapper object.

+
+
+unwrap(project)[source]
+
+
Return type:
+

WorkloadSet

+
+
+
+ +
+ +
+
+class benchbuild.command.WorkloadSet(*args)[source]
+

Bases: object

+

An immutable set of workload descriptors.

+

A WorkloadSet is immutable and usable as a key in a job mapping. +WorkloadSets support composition through intersection and union.

+

Example: +>>> WorkloadSet(1, 0) & WorkloadSet(1) +WorkloadSet({1}) +>>> WorkloadSet(1, 0) & WorkloadSet(2) +WorkloadSet({}) +>>> WorkloadSet(1, 0) | WorkloadSet(2) +WorkloadSet({0, 1, 2}) +>>> WorkloadSet(1, 0) | WorkloadSet(“1”) +WorkloadSet({0, 1, 1})

+

A workload set is not sorted, therefore, requires no comparability between +inserted values.

+
+
+unwrap(project)[source]
+

Implement the SupportsUnwrap protocol.

+

WorkloadSets only implement identity.

+
+
Return type:
+

WorkloadSet

+
+
+
+ +
+ +
+
+benchbuild.command.cleanup(project_command, backup=<function _default_backup>, restore=<function _default_restore>, prune=<function _default_prune>)[source]
+

Encapsulate a command in automatic backup, restore and prune.

+

This will wrap a ProjectCommand inside a contextmanager. All consumed +files inside the project’s build directory will be backed up by benchbuild. +You can then run your command as usual. +When you leave the context, all created paths are deleted and all consumed +paths restored.

+
+ +
+
+benchbuild.command.filter_workload_index(only, index)[source]
+

Yield only commands from the index that match the filter.

+

This removes all command lists from the index not matching only.

+
+
Return type:
+

Generator[List[Command], None, None]

+
+
+
+ +
+
+benchbuild.command.project_root()[source]
+
+
Return type:
+

PathToken

+
+
+
+ +
+
+benchbuild.command.source_root(local_name)[source]
+

Create a SourceRoot token for the given name.

+
+
Parameters:
+

local_name (str) – The source’s local name to access.

+
+
Return type:
+

PathToken

+
+
+
+ +
+
+benchbuild.command.unwrap(index, project)[source]
+

Unwrap all keys in a workload index.

+

‘Empty’ WorkloadSets will be removed. A WorkloadSet is empty, if it’s +boolean representation evaluates to False.

+
+
Return type:
+

MutableMapping[WorkloadSet, List[Command]]

+
+
+
+ +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/concepts/environments/index.html b/branch/f-QoLImprovements/concepts/environments/index.html new file mode 100644 index 000000000..f256d7ff3 --- /dev/null +++ b/branch/f-QoLImprovements/concepts/environments/index.html @@ -0,0 +1,259 @@ + + + + + + + Environment + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Environment

+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/concepts/experiments/index.html b/branch/f-QoLImprovements/concepts/experiments/index.html new file mode 100644 index 000000000..684db938e --- /dev/null +++ b/branch/f-QoLImprovements/concepts/experiments/index.html @@ -0,0 +1,260 @@ + + + + + + + Experiment + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Experiment

+

TODO.

+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/concepts/projects/index.html b/branch/f-QoLImprovements/concepts/projects/index.html new file mode 100644 index 000000000..d672ea3dd --- /dev/null +++ b/branch/f-QoLImprovements/concepts/projects/index.html @@ -0,0 +1,260 @@ + + + + + + + Project + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Project

+

TODO.

+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/concepts/source/index.html b/branch/f-QoLImprovements/concepts/source/index.html new file mode 100644 index 000000000..47ddc095f --- /dev/null +++ b/branch/f-QoLImprovements/concepts/source/index.html @@ -0,0 +1,1228 @@ + + + + + + + Source + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Source

+
+

Base

+

Provide a base interface for downloadable sources.

+
+
+class benchbuild.source.base.BaseSource(*args, **kwargs)[source]
+

Bases: Expandable, Versioned, ContextAwareSource, Protocol

+

Composition of source protocols.

+
+ +
+
+class benchbuild.source.base.ContextAwareSource(*args, **kwargs)[source]
+

Bases: Protocol

+
+
+is_context_free()[source]
+

Return, if this source needs context to evaluate it’s own +list of available versions.

+
+
Return type:
+

bool

+
+
+
+ +
+
+versions_with_context(ctx)[source]
+

Augment the given revision with new variants associated with this source.

+
+
Parameters:
+

ctx (Revision) – the project revision, containing information about every +context-free variant.

+
+
Return type:
+

Sequence[Variant]

+
+
Returns:
+

a sequence of project revisions.

+
+
+
+ +
+ +
+
+class benchbuild.source.base.ContextEnumeratorFn(*args, **kwargs)[source]
+

Bases: Protocol

+
+ +
+
+class benchbuild.source.base.ContextFreeMixin[source]
+

Bases: object

+

Make a context-free source context-aware.

+

This will setup default implementations that avoids interaction with any context.

+
+
+is_context_free()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+versions_with_context(ctx)[source]
+
+
Return type:
+

Sequence[Variant]

+
+
+
+ +
+ +
+
+class benchbuild.source.base.EnumeratorFn(*args, **kwargs)[source]
+

Bases: Protocol

+
+ +
+
+class benchbuild.source.base.Expandable(*args, **kwargs)[source]
+

Bases: Protocol

+
+
+property is_expandable: bool
+

Returns true, if this source should take part in version expansion.

+

Some sources may only be treated as virtual and would not take part +in the version expansion of an associated project.

+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.base.Fetchable(*args, **kwargs)[source]
+

Bases: Protocol

+
+
+fetch()[source]
+

Fetch the necessary source files into benchbuild’s cache.

+
+
Return type:
+

LocalPath

+
+
+
+ +
+
+property key: str
+

Return the source’s key property.

+

This provides you with a key component that identifes a single source. +It should (no guarantee) be unique among all sources for this project.

+

While this make no further assumption, but a good candidate is a +file-system name/path.

+
+ +
+
+property local: str
+

The source location (path-like) after fetching it from its remote.

+
+ +
+
+property remote: str | Dict[str, str]
+

The source location in the remote location.

+
+ +
+ +
+
+class benchbuild.source.base.FetchableSource(local, remote)[source]
+

Bases: ContextFreeMixin

+

Base class for fetchable sources.

+
+
Subclasses have to provide the following protocols:
    +
  • Expandable

  • +
  • Fetchable

  • +
  • Versioned

  • +
+
+
+
+
+abstract property default: Variant
+

The default version for this source.

+
+ +
+
+explore()[source]
+

Explore revisions of this source.

+

This provides access to all revisions this source can offer. +BenchBuild own filters will not block any revision here.

+

Custom sources or source filters can opt in to block revisions +anyways.

+
+
Returns:
+

The list of versions to explore.

+
+
Return type:
+

List[str]

+
+
+
+ +
+
+abstract fetch()[source]
+

Fetch the necessary source files into benchbuild’s cache.

+
+
Return type:
+

LocalPath

+
+
+
+ +
+
+property is_expandable: bool
+
+ +
+
+property key: str
+
+ +
+
+property local: str
+
+ +
+
+property remote: str | Dict[str, str]
+
+ +
+
+abstract version(target_dir, version)[source]
+

Fetch the requested version and place it in the target_dir

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the version should be placed in.

  • +
  • version (str) – The version that should be fetched from the local cache.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+abstract versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.base.NoSource(local, remote)[source]
+

Bases: FetchableSource

+
+
+property default: Variant
+

The default version for this source.

+
+ +
+
+fetch()[source]
+

Fetch the necessary source files into benchbuild’s cache.

+
+
Return type:
+

LocalPath

+
+
+
+ +
+
+version(target_dir, version)[source]
+

Fetch the requested version and place it in the target_dir

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the version should be placed in.

  • +
  • version (str) – The version that should be fetched from the local cache.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.base.Revision(project_cls, _primary, *variants)[source]
+

Bases: object

+

A revision captures all variants that form a single project revision.

+

A project may have an arbitrary number of input sources that are +required for it’s defined workloads, e.g., test input files, optional +dependencies, or submodules.

+

BenchBuild considers each source to have different version numbers, +encoded as “Variants”. The complete set of “Variants” for a project +then forms a project revision.

+
+
+extend(*variants)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+has_variant(name)[source]
+

Check if a variant with the given source name exists.

+
+
Parameters:
+

name (str) – The local name of the source.

+
+
Return type:
+

bool

+
+
Returns:
+

True, should a variant with the given name exists

+
+
+
+ +
+
+property primary: Variant
+
+ +
+
+project_cls: Type[Project]
+
+ +
+
+sorted()[source]
+

Return an ordered list of Variants from this revision.

+

The order is defined by the order in the SOURCE attribute of the +associated project class.

+
+
Return type:
+

Sequence[Variant]

+
+
+
+ +
+
+source_by_name(name)[source]
+

Return the source object that matches the key.

+
+
Parameters:
+

name (str) – The local name of the source.

+
+
Return type:
+

FetchableSource

+
+
Returns:
+

the found source object

+
+
Raises:
+

KeyError, if we cannot find the source with this name.

+
+
+
+ +
+
+update(revision)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+variant_by_name(name)[source]
+

Return the variant for the given source name.

+
+
Parameters:
+

name (str) – The local name of the source.

+
+
Return type:
+

Variant

+
+
Returns:
+

then version of the found source.

+
+
+
+ +
+
+variants: Sequence[Variant]
+
+ +
+ +
+
+class benchbuild.source.base.RevisionStr(value)[source]
+

Bases: object

+
+
+value: str
+
+ +
+ +
+
+class benchbuild.source.base.Variant(owner, version)[source]
+

Bases: object

+

Provide a ‘string’-like wrapper around source version information.

+

Use this, whenever you need a ‘version’ string somewhere in benchbuild. +In terms of output/logging or use as program arguments, this should not +carry more semantics than a simple version string.

+

However, this wrapper is linked to its ‘owner’. The owner serves as +the back-reference to the source code where it originated from.

+

This can serve as a ‘hook’ to deal with version information the +same way as a program variant like a specific configuraiton.

+
+
+name()[source]
+
+
Return type:
+

str

+
+
+
+ +
+
+owner: FetchableSource
+
+ +
+
+source()[source]
+
+
Return type:
+

FetchableSource

+
+
+
+ +
+
+version: str
+
+ +
+ +
+
+class benchbuild.source.base.Versioned(*args, **kwargs)[source]
+

Bases: Protocol

+
+
+property default: Variant
+

The default version for this source.

+
+ +
+
+version(target_dir, version)[source]
+

Fetch the requested version and place it in the target_dir

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the version should be placed in.

  • +
  • version (str) – The version that should be fetched from the local cache.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+benchbuild.source.base.enumerate_revisions(project_cls, context_free_enumerator=<function _default_enumerator>, context_aware_enumerator=<function _default_caw_enumerator>)[source]
+

Enumerates the given sources.

+

The enumeration requires two phases. +1. A phase for all sources that do not require a context to evaluate. +2. A phase for all sources that require a static context.

+
+
Return type:
+

Sequence[Revision]

+
+
+
+ +
+
+benchbuild.source.base.nosource()[source]
+
+
Return type:
+

NoSource

+
+
+
+ +
+
+benchbuild.source.base.primary(*sources)[source]
+

Return the implicit ‘main’ source of a project.

+

We define the main source as the first source listed in a project.

+

If you define a new project and rely on the existence of a ‘main’ +source code repository, make sure to define it as the first one.

+
+
Return type:
+

TypeVar(SourceT)

+
+
+
+ +
+
+benchbuild.source.base.product(*sources)[source]
+

Return the cross product of the given sources.

+
+
Return type:
+

Iterable[Tuple[Variant, ...]]

+
+
Returns:
+

An iterable containing the cross product of all source variants.

+
+
+
+ +
+
+benchbuild.source.base.revision_from_str(revs, project_cls)[source]
+

Create a Revision from a sequence of revision strings.

+

A valid Revision can only be created, if the number of valid revision +strings is equivalent to the number of sources. +A valid revision string is one that has been found in the a source’s +version. +It is required that each revision string is found in a different source +version.

+

We assume that the first source is the primary source of the revision.

+
+
Parameters:
+
    +
  • revs (Sequence[RevisionStr]) – sequence of revision strings, e.g. a commit-hash.

  • +
  • *sources – sources of a project.

  • +
+
+
Return type:
+

Revision

+
+
Returns:
+

A variant context.

+
+
+
+ +
+
+benchbuild.source.base.secondaries(*sources)[source]
+

Return the complement to the primary source of a project.

+
+
Return type:
+

Sequence[TypeVar(SourceT)]

+
+
Returns:
+

A list of all sources not considered primary.

+
+
+
+ +
+
+benchbuild.source.base.sources_as_dict(*sources)[source]
+

Convert fetchables to a dictionary.

+

The dictionary will be indexed by the Fetchable’s local attribute.

+
+
Parameters:
+

*sources (Fetchable) – Fetchables stored in the dictionary.

+
+
Return type:
+

Dict[str, Fetchable]

+
+
+
+ +
+
+benchbuild.source.base.target_prefix()[source]
+

Return the prefix directory for all downloads.

+
+
Returns:
+

the prefix where we download everything to.

+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.source.base.to_str(*variants)[source]
+

Convert an arbitrary number of variants into their string representation.

+
+
Return type:
+

str

+
+
Returns:
+

string representation of all input variants joined by ‘,’.

+
+
+
+ +
+
+

Git

+

Declare a git source.

+
+
+class benchbuild.source.git.Git(remote, local, clone=True, limit=10, refspec='HEAD', shallow=True, version_filter=<function Git.<lambda>>)[source]
+

Bases: FetchableSource

+

Fetch the downloadable source via git.

+
+
+property default: Variant
+

Return current HEAD as default version for this Git project.

+
+ +
+
+fetch()[source]
+

Clone the repository, if needed.

+

This will create a git clone inside the global cache directory.

+
+
Parameters:
+

version (Optional[str], optional) – [description]. Defaults to None.

+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+version(target_dir, version='HEAD')[source]
+

Create a new git worktree pointing to the requested version.

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the new worktree should live.

  • +
  • version (str) – The desired version the new worktree needs to point to. +Defaults to ‘HEAD’.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.git.GitSubmodule(remote, local, clone=True, limit=10, refspec='HEAD', shallow=True, version_filter=<function Git.<lambda>>)[source]
+

Bases: Git

+
+
+property is_expandable: bool
+

Submodules will not participate in version expansion.

+
+ +
+ +
+
+benchbuild.source.git.clone_needed(repository, repo_loc)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+benchbuild.source.git.maybe_shallow(cmd, enable)[source]
+

Conditionally add the shallow clone to the given git command.

+
+
Parameters:
+
    +
  • cmd (Any) – A git clone command (shallow doesn’t make sense anywhere else.

  • +
  • shallow (bool) – Should we add the shallow options?

  • +
+
+
Returns:
+

A new git clone command, with shallow clone enabled, if selected.

+
+
Return type:
+

Any

+
+
+
+ +
+
+

HTTP

+

Declare a http source.

+
+
+class benchbuild.source.http.HTTP(local, remote, check_certificate=True)[source]
+

Bases: FetchableSource

+

Fetch the downloadable source via http.

+
+
+property default: Variant
+

The default version for this source.

+
+ +
+
+fetch()[source]
+

Fetch via http using default version string.

+
+
Return type:
+

LocalPath

+
+
+
+ +
+
+fetch_version(version)[source]
+

Fetch via http using given version string.

+
+
Parameters:
+

version (str) – the version string to pull via http.

+
+
Return type:
+

LocalPath

+
+
Returns:
+

local path to fetched version.

+
+
+
+ +
+
+version(target_dir, version)[source]
+

Fetch the requested version and place it in the target_dir

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the version should be placed in.

  • +
  • version (str) – The version that should be fetched from the local cache.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.http.HTTPMultiple(local, remote, files, check_certificate=True)[source]
+

Bases: HTTP

+

Fetch and download multiple files via HTTP.

+
+
+fetch_version(version)[source]
+

Fetch via http using given version string.

+
+
Parameters:
+

version (str) – the version string to pull via http.

+
+
Return type:
+

LocalPath

+
+
Returns:
+

local path to fetched version.

+
+
+
+ +
+ +
+
+class benchbuild.source.http.HTTPUntar(local, remote, check_certificate=True)[source]
+

Bases: HTTP

+

Fetch and download source via http and auto-unpack using GNU tar

+
+
+version(target_dir, version)[source]
+

Setup the given version of this HTTPUntar source.

+

This will fetch the given version from the remote source and unpack the +archive into the build directory using tar.

+

The location matches the behavior of other sources. However, you need +to consider that benchbuild will return a directory instead of a file path.

+

When using workloads, you can refer to a directory with the SourceRootRenderer using +benchbuild.command.source_root. +:rtype: LocalPath

+
+

Example

+

You specify a remote version 1.0 of an archive compression.tar.gz and +a local name of “compression.tar.gz”. +The build directory will look as follows:

+

<builddir>/1.0-compression.dir/ +<builddir>/1.0-compression.tar.gz +<builddir>/compression.tar.gz -> ./1.0-compression.tar.dir

+

The content of the archive is found in the directory compression.tar.gz. +Your workloads need to make sure to reference this directory (e.g. using tokens), +e.g., source_root("compression.tar.gz")

+
+
+ +
+ +
+
+benchbuild.source.http.download_required(target_path)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+benchbuild.source.http.download_single_version(url, target_path, check_certificate)[source]
+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.source.http.normalize_remotes(remote)[source]
+
+
Return type:
+

Dict[str, str]

+
+
+
+ +
+
+benchbuild.source.http.versioned_target_name(target_name, version)[source]
+
+
Return type:
+

str

+
+
+
+ +
+
+

RSync

+
+
+

Module: source

+

Declarative API for downloading sources required by benchbuild.

+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/genindex/index.html b/branch/f-QoLImprovements/genindex/index.html new file mode 100644 index 000000000..9daabd5af --- /dev/null +++ b/branch/f-QoLImprovements/genindex/index.html @@ -0,0 +1,1434 @@ + + + + + + + Index + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | K + | L + | M + | N + | O + | P + | R + | S + | T + | U + | V + | W + | Y + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

K

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ +

Y

+ + + +
+ + + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/index.html b/branch/f-QoLImprovements/index.html new file mode 100644 index 000000000..226a109f1 --- /dev/null +++ b/branch/f-QoLImprovements/index.html @@ -0,0 +1,1003 @@ + + + + + + + Welcome to bencbuild’s documentation! + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Welcome to bencbuild’s documentation!

+
+

Contents:

+ +
+
+
+

Indices and tables

+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/objects.inv b/branch/f-QoLImprovements/objects.inv new file mode 100644 index 000000000..e7192ebdf Binary files /dev/null and b/branch/f-QoLImprovements/objects.inv differ diff --git a/branch/f-QoLImprovements/py-modindex/index.html b/branch/f-QoLImprovements/py-modindex/index.html new file mode 100644 index 000000000..97a57192c --- /dev/null +++ b/branch/f-QoLImprovements/py-modindex/index.html @@ -0,0 +1,317 @@ + + + + + + Python Module Index + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ + +

Python Module Index

+ +
+ b +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ b
+ benchbuild +
    + benchbuild.command +
    + benchbuild.container +
    + benchbuild.environments.domain.commands +
    + benchbuild.environments.domain.declarative +
    + benchbuild.environments.domain.model +
    + benchbuild.settings +
    + benchbuild.source +
    + benchbuild.source.base +
    + benchbuild.source.git +
    + benchbuild.source.http +
    + benchbuild.source.rsync +
    + benchbuild.utils.actions +
    + benchbuild.utils.settings +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/search/index.html b/branch/f-QoLImprovements/search/index.html new file mode 100644 index 000000000..081e59713 --- /dev/null +++ b/branch/f-QoLImprovements/search/index.html @@ -0,0 +1,263 @@ + + + + + + Search + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Search

+
+

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/branch/f-QoLImprovements/searchindex.js b/branch/f-QoLImprovements/searchindex.js new file mode 100644 index 000000000..008a2c39a --- /dev/null +++ b/branch/f-QoLImprovements/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"6.0.1 (2020-12-29)": [[0, "id49"]], "6.1 (2021-05-11)": [[0, "id45"]], "6.1.1 (2021-05-11)": [[0, "id43"]], "6.2 (2021-06-02)": [[0, "id41"]], "6.2.1 (2021-07-06)": [[0, "id38"]], "6.2.2 (2021-07-29)": [[0, "id37"]], "6.2.3 (2021-08-26)": [[0, "id35"]], "6.2.4 (2021-09-03)": [[0, "id34"]], "6.2.5 (2021-09-15)": [[0, "id32"]], "6.2.6 (2021-09-16)": [[0, "id30"]], "6.2.7 (2021-09-21)": [[0, "id29"]], "6.3 (2022-02-03)": [[0, "id25"]], "6.3.1 (2022-03-01)": [[0, "id21"]], "6.3.2 (2022-08-21)": [[0, "id17"]], "6.4 (2022-09-21)": [[0, "id13"]], "6.5 (2022-11-03)": [[0, "id12"]], "6.6.1 (2023-01-10)": [[0, "id9"]], "6.6.2 (2023-03-06)": [[0, "id7"]], "6.6.3 (2023-03-06)": [[0, "id6"]], "6.6.4 (2023-03-16)": [[0, "id5"]], "6.7 (2023-04-04)": [[0, "id2"]], "6.8 (2023-10-09)": [[0, "id1"]], "A case-study doesn\u2019t know its experiment": [[1, "a-case-study-doesn-t-know-its-experiment"]], "Actions": [[4, "actions"]], "An experiment doesn\u2019t know its case-studies": [[1, "an-experiment-doesn-t-know-its-case-studies"]], "Any (Group)": [[4, "any-group"]], "Available Actions": [[4, "available-actions"]], "Base": [[12, "module-benchbuild.source.base"]], "Basics": [[3, "basics"]], "BenchBuild Documentation": [[1, "benchbuild-documentation"]], "Benchbuild": [[7, "benchbuild"]], "Bootstrapping": [[7, "bootstrapping"]], "Bug Fixes": [[0, "bug-fixes"], [0, "id4"], [0, "id8"], [0, "id11"]], "Buildah": [[6, "buildah"]], "CLI": [[2, "cli"]], "Changelog": [[0, "changelog"]], "Clean": [[4, "clean"]], "CleanExtra": [[4, "cleanextra"]], "Commands": [[8, "commands"]], "Compile": [[4, "compile"]], "Configuration": [[6, "configuration"]], "Configure": [[5, "configure"]], "Containers": [[6, "containers"]], "Contents:": [[13, null]], "Customize actions": [[4, "customize-actions"]], "Definition": [[6, "definition"]], "Design Philosophy": [[1, "design-philosophy"]], "Echo": [[4, "echo"]], "Environment": [[9, "environment"]], "Example": [[12, null]], "Examples": [[6, null], [6, null]], "Experiment": [[10, "experiment"]], "Experiment (Any, Group)": [[4, "experiment-any-group"]], "FUSE": [[7, "fuse"]], "Feat": [[0, "feat"], [0, "id14"], [0, "id18"], [0, "id22"], [0, "id26"], [0, "id33"], [0, "id39"], [0, "id46"]], "Features": [[0, "features"], [0, "id3"], [0, "id10"]], "Fix": [[0, "fix"], [0, "id15"], [0, "id19"], [0, "id23"], [0, "id27"], [0, "id31"], [0, "id36"], [0, "id40"], [0, "id42"], [0, "id44"], [0, "id47"], [0, "id50"]], "Getting started": [[1, "getting-started"]], "Git": [[12, "module-benchbuild.source.git"]], "HTTP": [[12, "module-benchbuild.source.http"]], "Indices and tables": [[13, "indices-and-tables"]], "Installation": [[7, "installation"]], "MakeBuildDir": [[4, "makebuilddir"]], "Module: benchbuild.container": [[6, "module-benchbuild.container"]], "Module: benchbuild.environments.domain.commands": [[6, "module-benchbuild.environments.domain.commands"]], "Module: benchbuild.environments.domain.declarative": [[6, "module-benchbuild.environments.domain.declarative"]], "Module: benchbuild.environments.domain.model": [[6, "module-benchbuild.environments.domain.model"]], "Module: command": [[8, "module-benchbuild.command"]], "Module: settings": [[5, "module-benchbuild.settings"]], "Module: source": [[12, "module-benchbuild.source"]], "Module: utils.settings": [[5, "module-benchbuild.utils.settings"]], "Podman": [[6, "podman"]], "PostgreSQL": [[7, "postgresql"]], "Project": [[11, "project"]], "ProjectEnvironment": [[4, "projectenvironment"]], "RSync": [[12, "module-benchbuild.source.rsync"]], "Refactor": [[0, "refactor"], [0, "id16"], [0, "id20"], [0, "id24"], [0, "id28"], [0, "id48"]], "Replace Images": [[6, "replace-images"]], "RequireAll (Group)": [[4, "requireall-group"]], "Requirements": [[7, "requirements"]], "Run": [[4, "run"]], "Runtime requirements": [[6, "runtime-requirements"]], "SLURM": [[3, "slurm"], [7, "slurm"]], "SetProjectVersion": [[4, "setprojectversion"]], "Source": [[12, "source"]], "Step (Base)": [[4, "step-base"]], "Supported Python Versions": [[1, "supported-python-versions"]], "Template customization": [[3, "template-customization"]], "Tokens": [[8, "tokens"]], "Usage": [[6, "usage"]], "Usage inside Projects": [[8, "usage-inside-projects"]], "Welcome to bencbuild\u2019s documentation!": [[13, "welcome-to-bencbuild-s-documentation"]]}, "docnames": ["CHANGELOG", "about", "advanced/cli", "advanced/index", "basics/actions", "basics/configuration", "basics/containers", "basics/index", "concepts/command", "concepts/environments", "concepts/experiments", "concepts/projects", "concepts/source", "index"], "envversion": {"sphinx": 61, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1}, "filenames": ["CHANGELOG.md", "about.md", "advanced/cli.md", "advanced/index.md", "basics/actions.md", "basics/configuration.md", "basics/containers.md", "basics/index.md", "concepts/command.md", "concepts/environments.md", "concepts/experiments.md", "concepts/projects.md", "concepts/source.md", "index.rst"], "indexentries": {"absent (benchbuild.environments.domain.model.layerstate attribute)": [[6, "benchbuild.environments.domain.model.LayerState.ABSENT", false]], "actions (benchbuild.utils.actions.multistep attribute)": [[4, "benchbuild.utils.actions.MultiStep.actions", false]], "add() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.add", false]], "add_benchbuild_layers() (in module benchbuild.environments.domain.declarative)": [[6, "benchbuild.environments.domain.declarative.add_benchbuild_layers", false]], "addlayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.AddLayer", false]], "any (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Any", false]], "append() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.append", false]], "args (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.args", false]], "args (benchbuild.environments.domain.model.runlayer attribute)": [[6, "benchbuild.environments.domain.model.RunLayer.args", false]], "argsrenderstrategy (class in benchbuild.command)": [[8, "benchbuild.command.ArgsRenderStrategy", false]], "argstoken (class in benchbuild.command)": [[8, "benchbuild.command.ArgsToken", false]], "as_plumbum() (benchbuild.command.command method)": [[8, "benchbuild.command.Command.as_plumbum", false]], "available_cpu_count() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.available_cpu_count", false]], "backupfn (class in benchbuild.command)": [[8, "benchbuild.command.BackupFn", false]], "base (benchbuild.environments.domain.declarative.containerimage property)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.base", false]], "base (benchbuild.environments.domain.model.fromlayer attribute)": [[6, "benchbuild.environments.domain.model.FromLayer.base", false]], "basesource (class in benchbuild.source.base)": [[12, "benchbuild.source.base.BaseSource", false]], "bashstrategy (class in benchbuild.container)": [[6, "benchbuild.container.BashStrategy", false]], "begin_transaction() (benchbuild.utils.actions.experiment method)": [[4, "benchbuild.utils.actions.Experiment.begin_transaction", false]], "benchbuild.command": [[8, "module-benchbuild.command", false]], "benchbuild.container": [[6, "module-benchbuild.container", false]], "benchbuild.environments.domain.commands": [[6, "module-benchbuild.environments.domain.commands", false]], "benchbuild.environments.domain.declarative": [[6, "module-benchbuild.environments.domain.declarative", false]], "benchbuild.environments.domain.model": [[6, "module-benchbuild.environments.domain.model", false]], "benchbuild.settings": [[5, "module-benchbuild.settings", false]], "benchbuild.source": [[12, "module-benchbuild.source", false]], "benchbuild.source.base": [[12, "module-benchbuild.source.base", false]], "benchbuild.source.git": [[12, "module-benchbuild.source.git", false]], "benchbuild.source.http": [[12, "module-benchbuild.source.http", false]], "benchbuild.source.rsync": [[12, "module-benchbuild.source.rsync", false]], "benchbuild.utils.actions": [[4, "module-benchbuild.utils.actions", false]], "benchbuild.utils.settings": [[5, "module-benchbuild.utils.settings", false]], "build_dir (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.build_dir", false]], "builddir() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.builddir", false]], "builddirrenderer (class in benchbuild.command)": [[8, "benchbuild.command.BuilddirRenderer", false]], "can_continue (benchbuild.utils.actions.stepresult attribute)": [[4, "benchbuild.utils.actions.StepResult.CAN_CONTINUE", false]], "clean (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Clean", false]], "clean_directories() (in module benchbuild.container)": [[6, "benchbuild.container.clean_directories", false]], "clean_mountpoints() (benchbuild.utils.actions.clean static method)": [[4, "benchbuild.utils.actions.Clean.clean_mountpoints", false]], "cleanextra (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.CleanExtra", false]], "cleanup() (in module benchbuild.command)": [[8, "benchbuild.command.cleanup", false]], "clone_needed() (in module benchbuild.source.git)": [[12, "benchbuild.source.git.clone_needed", false]], "command (benchbuild.command.projectcommand attribute)": [[8, "benchbuild.command.ProjectCommand.command", false]], "command (benchbuild.environments.domain.model.entrypoint attribute)": [[6, "benchbuild.environments.domain.model.EntryPoint.command", false]], "command (benchbuild.environments.domain.model.runlayer attribute)": [[6, "benchbuild.environments.domain.model.RunLayer.command", false]], "command (benchbuild.environments.domain.model.setcommand attribute)": [[6, "benchbuild.environments.domain.model.SetCommand.command", false]], "command (class in benchbuild.command)": [[8, "benchbuild.command.Command", false]], "command (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Command", false]], "command() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.command", false]], "compile (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Compile", false]], "configdumper (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.ConfigDumper", false]], "configloader (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.ConfigLoader", false]], "configpath (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.ConfigPath", false]], "configuration (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.Configuration", false]], "conststrrenderer (class in benchbuild.command)": [[8, "benchbuild.command.ConstStrRenderer", false]], "consumes (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.consumes", false]], "consumes (benchbuild.command.command property)": [[8, "id0", false]], "container (class in benchbuild.container)": [[6, "benchbuild.container.Container", false]], "container (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Container", false]], "container_id (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.container_id", false]], "containerbootstrap (class in benchbuild.container)": [[6, "benchbuild.container.ContainerBootstrap", false]], "containercreate (class in benchbuild.container)": [[6, "benchbuild.container.ContainerCreate", false]], "containerimage (class in benchbuild.environments.domain.declarative)": [[6, "benchbuild.environments.domain.declarative.ContainerImage", false]], "containerlist (class in benchbuild.container)": [[6, "benchbuild.container.ContainerList", false]], "containerrun (class in benchbuild.container)": [[6, "benchbuild.container.ContainerRun", false]], "containerstrategy (class in benchbuild.container)": [[6, "benchbuild.container.ContainerStrategy", false]], "context (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.context", false]], "context() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.context", false]], "contextawaresource (class in benchbuild.source.base)": [[12, "benchbuild.source.base.ContextAwareSource", false]], "contextenumeratorfn (class in benchbuild.source.base)": [[12, "benchbuild.source.base.ContextEnumeratorFn", false]], "contextfreemixin (class in benchbuild.source.base)": [[12, "benchbuild.source.base.ContextFreeMixin", false]], "contextlayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.ContextLayer", false]], "convert_components() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.convert_components", false]], "copy_() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.copy_", false]], "copylayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.CopyLayer", false]], "createbenchbuildbase (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.CreateBenchbuildBase", false]], "createimage (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.CreateImage", false]], "creates (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.creates", false]], "creates (benchbuild.command.command property)": [[8, "id1", false]], "current_available_threads() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.current_available_threads", false]], "default (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.default", false]], "default (benchbuild.source.base.nosource property)": [[12, "benchbuild.source.base.NoSource.default", false]], "default (benchbuild.source.base.versioned property)": [[12, "benchbuild.source.base.Versioned.default", false]], "default (benchbuild.source.git.git property)": [[12, "benchbuild.source.git.Git.default", false]], "default (benchbuild.source.http.http property)": [[12, "benchbuild.source.http.HTTP.default", false]], "deleteimage (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.DeleteImage", false]], "description (benchbuild.utils.actions.any attribute)": [[4, "benchbuild.utils.actions.Any.DESCRIPTION", false]], "description (benchbuild.utils.actions.clean attribute)": [[4, "benchbuild.utils.actions.Clean.DESCRIPTION", false]], "description (benchbuild.utils.actions.cleanextra attribute)": [[4, "benchbuild.utils.actions.CleanExtra.DESCRIPTION", false]], "description (benchbuild.utils.actions.compile attribute)": [[4, "benchbuild.utils.actions.Compile.DESCRIPTION", false]], "description (benchbuild.utils.actions.echo attribute)": [[4, "benchbuild.utils.actions.Echo.DESCRIPTION", false]], "description (benchbuild.utils.actions.experiment attribute)": [[4, "benchbuild.utils.actions.Experiment.DESCRIPTION", false]], "description (benchbuild.utils.actions.makebuilddir attribute)": [[4, "benchbuild.utils.actions.MakeBuildDir.DESCRIPTION", false]], "description (benchbuild.utils.actions.multistep attribute)": [[4, "benchbuild.utils.actions.MultiStep.DESCRIPTION", false]], "description (benchbuild.utils.actions.projectenvironment attribute)": [[4, "benchbuild.utils.actions.ProjectEnvironment.DESCRIPTION", false]], "description (benchbuild.utils.actions.projectstep attribute)": [[4, "benchbuild.utils.actions.ProjectStep.DESCRIPTION", false]], "description (benchbuild.utils.actions.requireall attribute)": [[4, "benchbuild.utils.actions.RequireAll.DESCRIPTION", false]], "description (benchbuild.utils.actions.run attribute)": [[4, "benchbuild.utils.actions.Run.DESCRIPTION", false]], "description (benchbuild.utils.actions.runworkload attribute)": [[4, "benchbuild.utils.actions.RunWorkload.DESCRIPTION", false]], "description (benchbuild.utils.actions.runworkloads attribute)": [[4, "benchbuild.utils.actions.RunWorkloads.DESCRIPTION", false]], "description (benchbuild.utils.actions.setprojectversion attribute)": [[4, "benchbuild.utils.actions.SetProjectVersion.DESCRIPTION", false]], "description (benchbuild.utils.actions.step attribute)": [[4, "benchbuild.utils.actions.Step.DESCRIPTION", false]], "destination (benchbuild.environments.domain.model.addlayer attribute)": [[6, "benchbuild.environments.domain.model.AddLayer.destination", false]], "destination (benchbuild.environments.domain.model.copylayer attribute)": [[6, "benchbuild.environments.domain.model.CopyLayer.destination", false]], "directory (benchbuild.environments.domain.model.workingdirectory attribute)": [[6, "benchbuild.environments.domain.model.WorkingDirectory.directory", false]], "dirname (benchbuild.command.command property)": [[8, "benchbuild.command.Command.dirname", false]], "dirname (benchbuild.command.pathtoken property)": [[8, "benchbuild.command.PathToken.dirname", false]], "download_required() (in module benchbuild.source.http)": [[12, "benchbuild.source.http.download_required", false]], "download_single_version() (in module benchbuild.source.http)": [[12, "benchbuild.source.http.download_single_version", false]], "echo (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Echo", false]], "end_transaction() (benchbuild.utils.actions.experiment static method)": [[4, "benchbuild.utils.actions.Experiment.end_transaction", false]], "entrypoint (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.EntryPoint", false]], "entrypoint() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.entrypoint", false]], "enumerate_revisions() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.enumerate_revisions", false]], "enumeratorfn (class in benchbuild.source.base)": [[12, "benchbuild.source.base.EnumeratorFn", false]], "env (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.env", false]], "env (benchbuild.environments.domain.model.updateenv attribute)": [[6, "benchbuild.environments.domain.model.UpdateEnv.env", false]], "env() (benchbuild.command.command method)": [[8, "benchbuild.command.Command.env", false]], "env() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.env", false]], "error (benchbuild.utils.actions.stepresult attribute)": [[4, "benchbuild.utils.actions.StepResult.ERROR", false]], "escape_yaml() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.escape_yaml", false]], "event (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Event", false]], "events (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.events", false]], "events (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.events", false]], "exists() (benchbuild.command.pathtoken method)": [[8, "benchbuild.command.PathToken.exists", false]], "expandable (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Expandable", false]], "experiment (benchbuild.utils.actions.experiment attribute)": [[4, "benchbuild.utils.actions.Experiment.experiment", false]], "experiment (benchbuild.utils.actions.run attribute)": [[4, "benchbuild.utils.actions.Run.experiment", false]], "experiment (benchbuild.utils.actions.runworkloads attribute)": [[4, "benchbuild.utils.actions.RunWorkloads.experiment", false]], "experiment (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Experiment", false]], "explore() (benchbuild.source.base.fetchablesource method)": [[12, "benchbuild.source.base.FetchableSource.explore", false]], "exportimage (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.ExportImage", false]], "extend() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.extend", false]], "fetch() (benchbuild.source.base.fetchable method)": [[12, "benchbuild.source.base.Fetchable.fetch", false]], "fetch() (benchbuild.source.base.fetchablesource method)": [[12, "benchbuild.source.base.FetchableSource.fetch", false]], "fetch() (benchbuild.source.base.nosource method)": [[12, "benchbuild.source.base.NoSource.fetch", false]], "fetch() (benchbuild.source.git.git method)": [[12, "benchbuild.source.git.Git.fetch", false]], "fetch() (benchbuild.source.http.http method)": [[12, "benchbuild.source.http.HTTP.fetch", false]], "fetch_version() (benchbuild.source.http.http method)": [[12, "benchbuild.source.http.HTTP.fetch_version", false]], "fetch_version() (benchbuild.source.http.httpmultiple method)": [[12, "benchbuild.source.http.HTTPMultiple.fetch_version", false]], "fetchable (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Fetchable", false]], "fetchablesource (class in benchbuild.source.base)": [[12, "benchbuild.source.base.FetchableSource", false]], "filter_exports() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.filter_exports", false]], "filter_workload_index() (in module benchbuild.command)": [[8, "benchbuild.command.filter_workload_index", false]], "find_config() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.find_config", false]], "find_hash() (in module benchbuild.container)": [[6, "benchbuild.container.find_hash", false]], "from_ (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.from_", false]], "from_() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.from_", false]], "fromlayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.FromLayer", false]], "fs_compliant_name() (in module benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.fs_compliant_name", false]], "func (benchbuild.environments.domain.model.contextlayer attribute)": [[6, "benchbuild.environments.domain.model.ContextLayer.func", false]], "get_number_of_jobs() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.get_number_of_jobs", false]], "git (class in benchbuild.source.git)": [[12, "benchbuild.source.git.Git", false]], "gitsubmodule (class in benchbuild.source.git)": [[12, "benchbuild.source.git.GitSubmodule", false]], "has_default() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.has_default", false]], "has_value() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.has_value", false]], "has_variant() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.has_variant", false]], "http (class in benchbuild.source.http)": [[12, "benchbuild.source.http.HTTP", false]], "httpmultiple (class in benchbuild.source.http)": [[12, "benchbuild.source.http.HTTPMultiple", false]], "httpuntar (class in benchbuild.source.http)": [[12, "benchbuild.source.http.HTTPUntar", false]], "image (benchbuild.environments.domain.commands.exportimage attribute)": [[6, "benchbuild.environments.domain.commands.ExportImage.image", false]], "image (benchbuild.environments.domain.commands.importimage attribute)": [[6, "benchbuild.environments.domain.commands.ImportImage.image", false]], "image (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.image", false]], "image (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.image", false]], "image (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Image", false]], "immutable_kwargs() (in module benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.immutable_kwargs", false]], "importimage (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.ImportImage", false]], "in_path (benchbuild.environments.domain.commands.importimage attribute)": [[6, "benchbuild.environments.domain.commands.ImportImage.in_path", false]], "indexable (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.Indexable", false]], "init_from_env() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.init_from_env", false]], "input_file() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.input_file", false]], "install_cmake_and_exit() (benchbuild.container.containerbootstrap method)": [[6, "benchbuild.container.ContainerBootstrap.install_cmake_and_exit", false]], "invalidconfigkey": [[5, "benchbuild.utils.settings.InvalidConfigKey", false]], "is_complete() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.is_complete", false]], "is_context_free() (benchbuild.source.base.contextawaresource method)": [[12, "benchbuild.source.base.ContextAwareSource.is_context_free", false]], "is_context_free() (benchbuild.source.base.contextfreemixin method)": [[12, "benchbuild.source.base.ContextFreeMixin.is_context_free", false]], "is_expandable (benchbuild.source.base.expandable property)": [[12, "benchbuild.source.base.Expandable.is_expandable", false]], "is_expandable (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.is_expandable", false]], "is_expandable (benchbuild.source.git.gitsubmodule property)": [[12, "benchbuild.source.git.GitSubmodule.is_expandable", false]], "is_leaf() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.is_leaf", false]], "is_present() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.is_present", false]], "is_yaml() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.is_yaml", false]], "key (benchbuild.source.base.fetchable property)": [[12, "benchbuild.source.base.Fetchable.key", false]], "key (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.key", false]], "kwargs (benchbuild.environments.domain.model.runlayer attribute)": [[6, "benchbuild.environments.domain.model.RunLayer.kwargs", false]], "label (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.label", false]], "label (benchbuild.command.command property)": [[8, "id2", false]], "layer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Layer", false]], "layer_index (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.layer_index", false]], "layers (benchbuild.environments.domain.commands.createbenchbuildbase attribute)": [[6, "benchbuild.environments.domain.commands.CreateBenchbuildBase.layers", false]], "layers (benchbuild.environments.domain.commands.createimage attribute)": [[6, "benchbuild.environments.domain.commands.CreateImage.layers", false]], "layers (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.layers", false]], "layerstate (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.LayerState", false]], "left (benchbuild.command.pathtoken attribute)": [[8, "benchbuild.command.PathToken.left", false]], "load() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.load", false]], "local (benchbuild.command.sourcerootrenderer attribute)": [[8, "benchbuild.command.SourceRootRenderer.local", false]], "local (benchbuild.source.base.fetchable property)": [[12, "benchbuild.source.base.Fetchable.local", false]], "local (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.local", false]], "log_before_after() (in module benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.log_before_after", false]], "main() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.main", false]], "main() (benchbuild.container.containerbootstrap method)": [[6, "benchbuild.container.ContainerBootstrap.main", false]], "main() (benchbuild.container.containercreate method)": [[6, "benchbuild.container.ContainerCreate.main", false]], "main() (benchbuild.container.containerlist method)": [[6, "benchbuild.container.ContainerList.main", false]], "main() (benchbuild.container.containerrun method)": [[6, "benchbuild.container.ContainerRun.main", false]], "main() (in module benchbuild.container)": [[6, "benchbuild.container.main", false]], "make_token() (benchbuild.command.argstoken class method)": [[8, "benchbuild.command.ArgsToken.make_token", false]], "make_token() (benchbuild.command.pathtoken class method)": [[8, "benchbuild.command.PathToken.make_token", false]], "makebuilddir (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.MakeBuildDir", false]], "maybe_shallow() (in module benchbuild.source.git)": [[12, "benchbuild.source.git.maybe_shallow", false]], "message (benchbuild.utils.actions.echo attribute)": [[4, "benchbuild.utils.actions.Echo.message", false]], "message (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Message", false]], "mockobj (class in benchbuild.container)": [[6, "benchbuild.container.MockObj", false]], "module": [[4, "module-benchbuild.utils.actions", false], [5, "module-benchbuild.settings", false], [5, "module-benchbuild.utils.settings", false], [6, "module-benchbuild.container", false], [6, "module-benchbuild.environments.domain.commands", false], [6, "module-benchbuild.environments.domain.declarative", false], [6, "module-benchbuild.environments.domain.model", false], [8, "module-benchbuild.command", false], [12, "module-benchbuild.source", false], [12, "module-benchbuild.source.base", false], [12, "module-benchbuild.source.git", false], [12, "module-benchbuild.source.http", false], [12, "module-benchbuild.source.rsync", false]], "mount (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Mount", false]], "mount_build_dir (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.mount_build_dir", false]], "mount_tmp_dir (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.mount_tmp_dir", false]], "mounts (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.mounts", false]], "mounts() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.mounts", false]], "multistep (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.MultiStep", false]], "name (benchbuild.command.command property)": [[8, "benchbuild.command.Command.name", false]], "name (benchbuild.command.pathtoken property)": [[8, "benchbuild.command.PathToken.name", false]], "name (benchbuild.environments.domain.commands.createbenchbuildbase attribute)": [[6, "benchbuild.environments.domain.commands.CreateBenchbuildBase.name", false]], "name (benchbuild.environments.domain.commands.createimage attribute)": [[6, "benchbuild.environments.domain.commands.CreateImage.name", false]], "name (benchbuild.environments.domain.commands.deleteimage attribute)": [[6, "benchbuild.environments.domain.commands.DeleteImage.name", false]], "name (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.name", false]], "name (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.name", false]], "name (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.name", false]], "name (benchbuild.utils.actions.any attribute)": [[4, "benchbuild.utils.actions.Any.NAME", false]], "name (benchbuild.utils.actions.clean attribute)": [[4, "benchbuild.utils.actions.Clean.NAME", false]], "name (benchbuild.utils.actions.cleanextra attribute)": [[4, "benchbuild.utils.actions.CleanExtra.NAME", false]], "name (benchbuild.utils.actions.compile attribute)": [[4, "benchbuild.utils.actions.Compile.NAME", false]], "name (benchbuild.utils.actions.echo attribute)": [[4, "benchbuild.utils.actions.Echo.NAME", false]], "name (benchbuild.utils.actions.experiment attribute)": [[4, "benchbuild.utils.actions.Experiment.NAME", false]], "name (benchbuild.utils.actions.makebuilddir attribute)": [[4, "benchbuild.utils.actions.MakeBuildDir.NAME", false]], "name (benchbuild.utils.actions.multistep attribute)": [[4, "benchbuild.utils.actions.MultiStep.NAME", false]], "name (benchbuild.utils.actions.projectenvironment attribute)": [[4, "benchbuild.utils.actions.ProjectEnvironment.NAME", false]], "name (benchbuild.utils.actions.projectstep attribute)": [[4, "benchbuild.utils.actions.ProjectStep.NAME", false]], "name (benchbuild.utils.actions.requireall attribute)": [[4, "benchbuild.utils.actions.RequireAll.NAME", false]], "name (benchbuild.utils.actions.run attribute)": [[4, "benchbuild.utils.actions.Run.NAME", false]], "name (benchbuild.utils.actions.runworkload attribute)": [[4, "benchbuild.utils.actions.RunWorkload.NAME", false]], "name (benchbuild.utils.actions.runworkloads attribute)": [[4, "benchbuild.utils.actions.RunWorkloads.NAME", false]], "name (benchbuild.utils.actions.setprojectversion attribute)": [[4, "benchbuild.utils.actions.SetProjectVersion.NAME", false]], "name (benchbuild.utils.actions.step attribute)": [[4, "benchbuild.utils.actions.Step.NAME", false]], "name() (benchbuild.source.base.variant method)": [[12, "benchbuild.source.base.Variant.name", false]], "normalize_remotes() (in module benchbuild.source.http)": [[12, "benchbuild.source.http.normalize_remotes", false]], "nosource (class in benchbuild.source.base)": [[12, "benchbuild.source.base.NoSource", false]], "nosource() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.nosource", false]], "oci_compliant_name() (in module benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.oci_compliant_name", false]], "ok (benchbuild.utils.actions.stepresult attribute)": [[4, "benchbuild.utils.actions.StepResult.OK", false]], "onerror() (benchbuild.utils.actions.multistep method)": [[4, "benchbuild.utils.actions.MultiStep.onerror", false]], "onerror() (benchbuild.utils.actions.projectstep method)": [[4, "benchbuild.utils.actions.ProjectStep.onerror", false]], "onerror() (benchbuild.utils.actions.step method)": [[4, "benchbuild.utils.actions.Step.onerror", false]], "onlyin (class in benchbuild.command)": [[8, "benchbuild.command.OnlyIn", false]], "out_name (benchbuild.environments.domain.commands.exportimage attribute)": [[6, "benchbuild.environments.domain.commands.ExportImage.out_name", false]], "output (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.output", false]], "output (benchbuild.command.command property)": [[8, "id3", false]], "output_file() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.output_file", false]], "output_param (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.output_param", false]], "owner (benchbuild.source.base.variant attribute)": [[12, "benchbuild.source.base.Variant.owner", false]], "pack_container() (in module benchbuild.container)": [[6, "benchbuild.container.pack_container", false]], "path (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.path", false]], "path (benchbuild.command.command property)": [[8, "id4", false]], "path (benchbuild.command.projectcommand property)": [[8, "benchbuild.command.ProjectCommand.path", false]], "path_constructor() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.path_constructor", false]], "path_representer() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.path_representer", false]], "path_to_str() (benchbuild.utils.settings.configpath static method)": [[5, "benchbuild.utils.settings.ConfigPath.path_to_str", false]], "pathrenderstrategy (class in benchbuild.command)": [[8, "benchbuild.command.PathRenderStrategy", false]], "pathtoken (class in benchbuild.command)": [[8, "benchbuild.command.PathToken", false]], "prepend() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.prepend", false]], "prepend_status() (in module benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.prepend_status", false]], "present (benchbuild.environments.domain.model.layerstate attribute)": [[6, "benchbuild.environments.domain.model.LayerState.PRESENT", false]], "present() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.present", false]], "primary (benchbuild.source.base.revision property)": [[12, "benchbuild.source.base.Revision.primary", false]], "primary() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.primary", false]], "product() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.product", false]], "project (benchbuild.command.projectcommand attribute)": [[8, "benchbuild.command.ProjectCommand.project", false]], "project (benchbuild.utils.actions.projectstep attribute)": [[4, "benchbuild.utils.actions.ProjectStep.project", false]], "project (benchbuild.utils.actions.runworkloads attribute)": [[4, "benchbuild.utils.actions.RunWorkloads.project", false]], "project_cls (benchbuild.source.base.revision attribute)": [[12, "benchbuild.source.base.Revision.project_cls", false]], "project_root() (in module benchbuild.command)": [[8, "benchbuild.command.project_root", false]], "projectcommand (class in benchbuild.command)": [[8, "benchbuild.command.ProjectCommand", false]], "projectenvironment (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.ProjectEnvironment", false]], "projectroot() (in module benchbuild.command)": [[8, "benchbuild.command.ProjectRoot", false]], "projectstep (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.ProjectStep", false]], "prunefn (class in benchbuild.command)": [[8, "benchbuild.command.PruneFn", false]], "remote (benchbuild.source.base.fetchable property)": [[12, "benchbuild.source.base.Fetchable.remote", false]], "remote (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.remote", false]], "render() (benchbuild.command.argstoken method)": [[8, "benchbuild.command.ArgsToken.render", false]], "render() (benchbuild.command.pathtoken method)": [[8, "benchbuild.command.PathToken.render", false]], "rendered() (benchbuild.command.argsrenderstrategy method)": [[8, "benchbuild.command.ArgsRenderStrategy.rendered", false]], "rendered() (benchbuild.command.builddirrenderer method)": [[8, "benchbuild.command.BuilddirRenderer.rendered", false]], "rendered() (benchbuild.command.conststrrenderer method)": [[8, "benchbuild.command.ConstStrRenderer.rendered", false]], "rendered() (benchbuild.command.pathrenderstrategy method)": [[8, "benchbuild.command.PathRenderStrategy.rendered", false]], "rendered() (benchbuild.command.rootrenderer method)": [[8, "benchbuild.command.RootRenderer.rendered", false]], "rendered() (benchbuild.command.sourcerootrenderer method)": [[8, "benchbuild.command.SourceRootRenderer.rendered", false]], "rendered_args() (benchbuild.command.command method)": [[8, "benchbuild.command.Command.rendered_args", false]], "renderer (benchbuild.command.argstoken attribute)": [[8, "benchbuild.command.ArgsToken.renderer", false]], "renderer (benchbuild.command.pathtoken attribute)": [[8, "benchbuild.command.PathToken.renderer", false]], "requireall (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.RequireAll", false]], "restorefn (class in benchbuild.command)": [[8, "benchbuild.command.RestoreFn", false]], "rev_range (benchbuild.command.onlyin attribute)": [[8, "benchbuild.command.OnlyIn.rev_range", false]], "revision (benchbuild.utils.actions.setprojectversion attribute)": [[4, "benchbuild.utils.actions.SetProjectVersion.revision", false]], "revision (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Revision", false]], "revision_from_str() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.revision_from_str", false]], "revisionstr (class in benchbuild.source.base)": [[12, "benchbuild.source.base.RevisionStr", false]], "right (benchbuild.command.pathtoken attribute)": [[8, "benchbuild.command.PathToken.right", false]], "rootrenderer (class in benchbuild.command)": [[8, "benchbuild.command.RootRenderer", false]], "run (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Run", false]], "run() (benchbuild.container.bashstrategy method)": [[6, "benchbuild.container.BashStrategy.run", false]], "run() (benchbuild.container.containerstrategy method)": [[6, "benchbuild.container.ContainerStrategy.run", false]], "run() (benchbuild.container.setuppolyjitgentoostrategy method)": [[6, "benchbuild.container.SetupPolyJITGentooStrategy.run", false]], "run() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.run", false]], "run_any_child() (in module benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.run_any_child", false]], "run_in_container() (in module benchbuild.container)": [[6, "benchbuild.container.run_in_container", false]], "runlayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.RunLayer", false]], "runprojectcontainer (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer", false]], "runworkload (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.RunWorkload", false]], "runworkloads (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.RunWorkloads", false]], "secondaries() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.secondaries", false]], "set_input_container() (in module benchbuild.container)": [[6, "benchbuild.container.set_input_container", false]], "setcommand (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.SetCommand", false]], "setprojectversion (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.SetProjectVersion", false]], "setup_bash_in_container() (in module benchbuild.container)": [[6, "benchbuild.container.setup_bash_in_container", false]], "setup_config() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.setup_config", false]], "setup_container() (in module benchbuild.container)": [[6, "benchbuild.container.setup_container", false]], "setup_directories() (in module benchbuild.container)": [[6, "benchbuild.container.setup_directories", false]], "setuppolyjitgentoostrategy (class in benchbuild.container)": [[6, "benchbuild.container.SetupPolyJITGentooStrategy", false]], "shell() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.shell", false]], "sorted() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.sorted", false]], "source (benchbuild.environments.domain.model.mount attribute)": [[6, "benchbuild.environments.domain.model.Mount.source", false]], "source() (benchbuild.source.base.variant method)": [[12, "benchbuild.source.base.Variant.source", false]], "source_by_name() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.source_by_name", false]], "source_root() (in module benchbuild.command)": [[8, "benchbuild.command.source_root", false]], "sourceroot() (in module benchbuild.command)": [[8, "benchbuild.command.SourceRoot", false]], "sourcerootrenderer (class in benchbuild.command)": [[8, "benchbuild.command.SourceRootRenderer", false]], "sources (benchbuild.environments.domain.model.addlayer attribute)": [[6, "benchbuild.environments.domain.model.AddLayer.sources", false]], "sources (benchbuild.environments.domain.model.copylayer attribute)": [[6, "benchbuild.environments.domain.model.CopyLayer.sources", false]], "sources_as_dict() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.sources_as_dict", false]], "status (benchbuild.utils.actions.step attribute)": [[4, "benchbuild.utils.actions.Step.status", false]], "step (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Step", false]], "step_has_failed() (in module benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.step_has_failed", false]], "stepresult (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.StepResult", false]], "store() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.store", false]], "strategy() (benchbuild.container.containercreate method)": [[6, "benchbuild.container.ContainerCreate.strategy", false]], "supportsunwrap (class in benchbuild.command)": [[8, "benchbuild.command.SupportsUnwrap", false]], "target (benchbuild.environments.domain.model.mount attribute)": [[6, "benchbuild.environments.domain.model.Mount.target", false]], "target_prefix() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.target_prefix", false]], "tmp_dir (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.tmp_dir", false]], "to_env_dict() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.to_env_dict", false]], "to_env_var() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.to_env_var", false]], "to_str() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.to_str", false]], "to_yaml() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.to_yaml", false]], "unrendered (benchbuild.command.argsrenderstrategy property)": [[8, "benchbuild.command.ArgsRenderStrategy.unrendered", false]], "unrendered (benchbuild.command.builddirrenderer property)": [[8, "benchbuild.command.BuilddirRenderer.unrendered", false]], "unrendered (benchbuild.command.conststrrenderer property)": [[8, "benchbuild.command.ConstStrRenderer.unrendered", false]], "unrendered (benchbuild.command.pathrenderstrategy property)": [[8, "benchbuild.command.PathRenderStrategy.unrendered", false]], "unrendered (benchbuild.command.rootrenderer property)": [[8, "benchbuild.command.RootRenderer.unrendered", false]], "unrendered (benchbuild.command.sourcerootrenderer property)": [[8, "benchbuild.command.SourceRootRenderer.unrendered", false]], "unset (benchbuild.utils.actions.stepresult attribute)": [[4, "benchbuild.utils.actions.StepResult.UNSET", false]], "unwrap() (benchbuild.command.onlyin method)": [[8, "benchbuild.command.OnlyIn.unwrap", false]], "unwrap() (benchbuild.command.supportsunwrap method)": [[8, "benchbuild.command.SupportsUnwrap.unwrap", false]], "unwrap() (benchbuild.command.workloadset method)": [[8, "benchbuild.command.WorkloadSet.unwrap", false]], "unwrap() (in module benchbuild.command)": [[8, "benchbuild.command.unwrap", false]], "update() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.update", false]], "update_env() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.update_env", false]], "update_env() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.update_env", false]], "updateenv (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.UpdateEnv", false]], "upgrade() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.upgrade", false]], "uuid_add_implicit_resolver() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.uuid_add_implicit_resolver", false]], "uuid_constructor() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.uuid_constructor", false]], "uuid_representer() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.uuid_representer", false]], "validate() (benchbuild.utils.settings.configpath method)": [[5, "benchbuild.utils.settings.ConfigPath.validate", false]], "value (benchbuild.command.conststrrenderer attribute)": [[8, "benchbuild.command.ConstStrRenderer.value", false]], "value (benchbuild.source.base.revisionstr attribute)": [[12, "benchbuild.source.base.RevisionStr.value", false]], "value (benchbuild.utils.settings.configuration property)": [[5, "benchbuild.utils.settings.Configuration.value", false]], "variant (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Variant", false]], "variant_by_name() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.variant_by_name", false]], "variants (benchbuild.source.base.revision attribute)": [[12, "benchbuild.source.base.Revision.variants", false]], "verbosity (benchbuild.container.container attribute)": [[6, "benchbuild.container.Container.verbosity", false]], "version (benchbuild.container.container attribute)": [[6, "benchbuild.container.Container.VERSION", false]], "version (benchbuild.source.base.variant attribute)": [[12, "benchbuild.source.base.Variant.version", false]], "version() (benchbuild.source.base.fetchablesource method)": [[12, "benchbuild.source.base.FetchableSource.version", false]], "version() (benchbuild.source.base.nosource method)": [[12, "benchbuild.source.base.NoSource.version", false]], "version() (benchbuild.source.base.versioned method)": [[12, "benchbuild.source.base.Versioned.version", false]], "version() (benchbuild.source.git.git method)": [[12, "benchbuild.source.git.Git.version", false]], "version() (benchbuild.source.http.http method)": [[12, "benchbuild.source.http.HTTP.version", false]], "version() (benchbuild.source.http.httpuntar method)": [[12, "benchbuild.source.http.HTTPUntar.version", false]], "versioned (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Versioned", false]], "versioned_target_name() (in module benchbuild.source.http)": [[12, "benchbuild.source.http.versioned_target_name", false]], "versions() (benchbuild.source.base.expandable method)": [[12, "benchbuild.source.base.Expandable.versions", false]], "versions() (benchbuild.source.base.fetchablesource method)": [[12, "benchbuild.source.base.FetchableSource.versions", false]], "versions() (benchbuild.source.base.nosource method)": [[12, "benchbuild.source.base.NoSource.versions", false]], "versions() (benchbuild.source.base.versioned method)": [[12, "benchbuild.source.base.Versioned.versions", false]], "versions() (benchbuild.source.git.git method)": [[12, "benchbuild.source.git.Git.versions", false]], "versions() (benchbuild.source.http.http method)": [[12, "benchbuild.source.http.HTTP.versions", false]], "versions_with_context() (benchbuild.source.base.contextawaresource method)": [[12, "benchbuild.source.base.ContextAwareSource.versions_with_context", false]], "versions_with_context() (benchbuild.source.base.contextfreemixin method)": [[12, "benchbuild.source.base.ContextFreeMixin.versions_with_context", false]], "workingdir() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.workingdir", false]], "workingdirectory (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.WorkingDirectory", false]], "workload_ref (benchbuild.utils.actions.runworkload property)": [[4, "benchbuild.utils.actions.RunWorkload.workload_ref", false]], "workload_set (benchbuild.command.onlyin attribute)": [[8, "benchbuild.command.OnlyIn.workload_set", false]], "workloadset (class in benchbuild.command)": [[8, "benchbuild.command.WorkloadSet", false]], "yaml_constructors (benchbuild.utils.settings.configloader attribute)": [[5, "benchbuild.utils.settings.ConfigLoader.yaml_constructors", false]], "yaml_implicit_resolvers (benchbuild.utils.settings.configdumper attribute)": [[5, "benchbuild.utils.settings.ConfigDumper.yaml_implicit_resolvers", false]], "yaml_implicit_resolvers (benchbuild.utils.settings.configloader attribute)": [[5, "benchbuild.utils.settings.ConfigLoader.yaml_implicit_resolvers", false]], "yaml_representers (benchbuild.utils.settings.configdumper attribute)": [[5, "benchbuild.utils.settings.ConfigDumper.yaml_representers", false]]}, "objects": {"benchbuild": [[8, 0, 0, "-", "command"], [6, 0, 0, "-", "container"], [5, 0, 0, "-", "settings"], [12, 0, 0, "-", "source"]], "benchbuild.command": [[8, 1, 1, "", "ArgsRenderStrategy"], [8, 1, 1, "", "ArgsToken"], [8, 1, 1, "", "BackupFn"], [8, 1, 1, "", "BuilddirRenderer"], [8, 1, 1, "", "Command"], [8, 1, 1, "", "ConstStrRenderer"], [8, 1, 1, "", "OnlyIn"], [8, 1, 1, "", "PathRenderStrategy"], [8, 1, 1, "", "PathToken"], [8, 1, 1, "", "ProjectCommand"], [8, 5, 1, "", "ProjectRoot"], [8, 1, 1, "", "PruneFn"], [8, 1, 1, "", "RestoreFn"], [8, 1, 1, "", "RootRenderer"], [8, 5, 1, "", "SourceRoot"], [8, 1, 1, "", "SourceRootRenderer"], [8, 1, 1, "", "SupportsUnwrap"], [8, 1, 1, "", "WorkloadSet"], [8, 5, 1, "", "cleanup"], [8, 5, 1, "", "filter_workload_index"], [8, 5, 1, "", "project_root"], [8, 5, 1, "", "source_root"], [8, 5, 1, "", "unwrap"]], "benchbuild.command.ArgsRenderStrategy": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.ArgsToken": [[8, 2, 1, "", "make_token"], [8, 2, 1, "", "render"], [8, 4, 1, "", "renderer"]], "benchbuild.command.BuilddirRenderer": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.Command": [[8, 2, 1, "", "as_plumbum"], [8, 3, 1, "id0", "consumes"], [8, 3, 1, "id1", "creates"], [8, 3, 1, "", "dirname"], [8, 2, 1, "", "env"], [8, 3, 1, "id2", "label"], [8, 3, 1, "", "name"], [8, 3, 1, "id3", "output"], [8, 4, 1, "", "output_param"], [8, 3, 1, "id4", "path"], [8, 2, 1, "", "rendered_args"]], "benchbuild.command.ConstStrRenderer": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"], [8, 4, 1, "", "value"]], "benchbuild.command.OnlyIn": [[8, 4, 1, "", "rev_range"], [8, 2, 1, "", "unwrap"], [8, 4, 1, "", "workload_set"]], "benchbuild.command.PathRenderStrategy": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.PathToken": [[8, 3, 1, "", "dirname"], [8, 2, 1, "", "exists"], [8, 4, 1, "", "left"], [8, 2, 1, "", "make_token"], [8, 3, 1, "", "name"], [8, 2, 1, "", "render"], [8, 4, 1, "", "renderer"], [8, 4, 1, "", "right"]], "benchbuild.command.ProjectCommand": [[8, 4, 1, "", "command"], [8, 3, 1, "", "path"], [8, 4, 1, "", "project"]], "benchbuild.command.RootRenderer": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.SourceRootRenderer": [[8, 4, 1, "", "local"], [8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.SupportsUnwrap": [[8, 2, 1, "", "unwrap"]], "benchbuild.command.WorkloadSet": [[8, 2, 1, "", "unwrap"]], "benchbuild.container": [[6, 1, 1, "", "BashStrategy"], [6, 1, 1, "", "Container"], [6, 1, 1, "", "ContainerBootstrap"], [6, 1, 1, "", "ContainerCreate"], [6, 1, 1, "", "ContainerList"], [6, 1, 1, "", "ContainerRun"], [6, 1, 1, "", "ContainerStrategy"], [6, 1, 1, "", "MockObj"], [6, 1, 1, "", "SetupPolyJITGentooStrategy"], [6, 5, 1, "", "clean_directories"], [6, 5, 1, "", "find_hash"], [6, 5, 1, "", "main"], [6, 5, 1, "", "pack_container"], [6, 5, 1, "", "run_in_container"], [6, 5, 1, "", "set_input_container"], [6, 5, 1, "", "setup_bash_in_container"], [6, 5, 1, "", "setup_container"], [6, 5, 1, "", "setup_directories"]], "benchbuild.container.BashStrategy": [[6, 2, 1, "", "run"]], "benchbuild.container.Container": [[6, 4, 1, "", "VERSION"], [6, 2, 1, "", "builddir"], [6, 2, 1, "", "input_file"], [6, 2, 1, "", "main"], [6, 2, 1, "", "mounts"], [6, 2, 1, "", "output_file"], [6, 2, 1, "", "shell"], [6, 4, 1, "", "verbosity"]], "benchbuild.container.ContainerBootstrap": [[6, 2, 1, "", "install_cmake_and_exit"], [6, 2, 1, "", "main"]], "benchbuild.container.ContainerCreate": [[6, 2, 1, "", "main"], [6, 2, 1, "", "strategy"]], "benchbuild.container.ContainerList": [[6, 2, 1, "", "main"]], "benchbuild.container.ContainerRun": [[6, 2, 1, "", "main"]], "benchbuild.container.ContainerStrategy": [[6, 2, 1, "", "run"]], "benchbuild.container.SetupPolyJITGentooStrategy": [[6, 2, 1, "", "run"]], "benchbuild.environments.domain": [[6, 0, 0, "-", "commands"], [6, 0, 0, "-", "declarative"], [6, 0, 0, "-", "model"]], "benchbuild.environments.domain.commands": [[6, 1, 1, "", "CreateBenchbuildBase"], [6, 1, 1, "", "CreateImage"], [6, 1, 1, "", "DeleteImage"], [6, 1, 1, "", "ExportImage"], [6, 1, 1, "", "ImportImage"], [6, 1, 1, "", "RunProjectContainer"], [6, 5, 1, "", "fs_compliant_name"], [6, 5, 1, "", "oci_compliant_name"]], "benchbuild.environments.domain.commands.CreateBenchbuildBase": [[6, 4, 1, "", "layers"], [6, 4, 1, "", "name"]], "benchbuild.environments.domain.commands.CreateImage": [[6, 4, 1, "", "layers"], [6, 4, 1, "", "name"]], "benchbuild.environments.domain.commands.DeleteImage": [[6, 4, 1, "", "name"]], "benchbuild.environments.domain.commands.ExportImage": [[6, 4, 1, "", "image"], [6, 4, 1, "", "out_name"]], "benchbuild.environments.domain.commands.ImportImage": [[6, 4, 1, "", "image"], [6, 4, 1, "", "in_path"]], "benchbuild.environments.domain.commands.RunProjectContainer": [[6, 4, 1, "", "args"], [6, 4, 1, "", "build_dir"], [6, 4, 1, "", "image"], [6, 4, 1, "", "mount_build_dir"], [6, 4, 1, "", "mount_tmp_dir"], [6, 4, 1, "", "name"], [6, 4, 1, "", "tmp_dir"]], "benchbuild.environments.domain.declarative": [[6, 1, 1, "", "ContainerImage"], [6, 5, 1, "", "add_benchbuild_layers"]], "benchbuild.environments.domain.declarative.ContainerImage": [[6, 2, 1, "", "add"], [6, 3, 1, "", "base"], [6, 2, 1, "", "command"], [6, 2, 1, "", "context"], [6, 2, 1, "", "copy_"], [6, 2, 1, "", "entrypoint"], [6, 2, 1, "", "env"], [6, 2, 1, "", "from_"], [6, 2, 1, "", "run"], [6, 2, 1, "", "workingdir"]], "benchbuild.environments.domain.model": [[6, 1, 1, "", "AddLayer"], [6, 1, 1, "", "Command"], [6, 1, 1, "", "Container"], [6, 1, 1, "", "ContextLayer"], [6, 1, 1, "", "CopyLayer"], [6, 1, 1, "", "EntryPoint"], [6, 1, 1, "", "Event"], [6, 1, 1, "", "FromLayer"], [6, 1, 1, "", "Image"], [6, 1, 1, "", "Layer"], [6, 1, 1, "", "LayerState"], [6, 1, 1, "", "Message"], [6, 1, 1, "", "Mount"], [6, 1, 1, "", "RunLayer"], [6, 1, 1, "", "SetCommand"], [6, 1, 1, "", "UpdateEnv"], [6, 1, 1, "", "WorkingDirectory"], [6, 5, 1, "", "immutable_kwargs"]], "benchbuild.environments.domain.model.AddLayer": [[6, 4, 1, "", "destination"], [6, 4, 1, "", "sources"]], "benchbuild.environments.domain.model.Container": [[6, 4, 1, "", "container_id"], [6, 4, 1, "", "context"], [6, 4, 1, "", "events"], [6, 4, 1, "", "image"], [6, 4, 1, "", "name"]], "benchbuild.environments.domain.model.ContextLayer": [[6, 4, 1, "", "func"]], "benchbuild.environments.domain.model.CopyLayer": [[6, 4, 1, "", "destination"], [6, 4, 1, "", "sources"]], "benchbuild.environments.domain.model.EntryPoint": [[6, 4, 1, "", "command"]], "benchbuild.environments.domain.model.FromLayer": [[6, 4, 1, "", "base"]], "benchbuild.environments.domain.model.Image": [[6, 2, 1, "", "append"], [6, 4, 1, "", "env"], [6, 4, 1, "", "events"], [6, 4, 1, "", "from_"], [6, 2, 1, "", "is_complete"], [6, 2, 1, "", "is_present"], [6, 4, 1, "", "layer_index"], [6, 4, 1, "", "layers"], [6, 4, 1, "", "mounts"], [6, 4, 1, "", "name"], [6, 2, 1, "", "prepend"], [6, 2, 1, "", "present"], [6, 2, 1, "", "update_env"]], "benchbuild.environments.domain.model.LayerState": [[6, 4, 1, "", "ABSENT"], [6, 4, 1, "", "PRESENT"]], "benchbuild.environments.domain.model.Mount": [[6, 4, 1, "", "source"], [6, 4, 1, "", "target"]], "benchbuild.environments.domain.model.RunLayer": [[6, 4, 1, "", "args"], [6, 4, 1, "", "command"], [6, 4, 1, "", "kwargs"]], "benchbuild.environments.domain.model.SetCommand": [[6, 4, 1, "", "command"]], "benchbuild.environments.domain.model.UpdateEnv": [[6, 4, 1, "", "env"]], "benchbuild.environments.domain.model.WorkingDirectory": [[6, 4, 1, "", "directory"]], "benchbuild.source": [[12, 0, 0, "-", "base"], [12, 0, 0, "-", "git"], [12, 0, 0, "-", "http"], [12, 0, 0, "-", "rsync"]], "benchbuild.source.base": [[12, 1, 1, "", "BaseSource"], [12, 1, 1, "", "ContextAwareSource"], [12, 1, 1, "", "ContextEnumeratorFn"], [12, 1, 1, "", "ContextFreeMixin"], [12, 1, 1, "", "EnumeratorFn"], [12, 1, 1, "", "Expandable"], [12, 1, 1, "", "Fetchable"], [12, 1, 1, "", "FetchableSource"], [12, 1, 1, "", "NoSource"], [12, 1, 1, "", "Revision"], [12, 1, 1, "", "RevisionStr"], [12, 1, 1, "", "Variant"], [12, 1, 1, "", "Versioned"], [12, 5, 1, "", "enumerate_revisions"], [12, 5, 1, "", "nosource"], [12, 5, 1, "", "primary"], [12, 5, 1, "", "product"], [12, 5, 1, "", "revision_from_str"], [12, 5, 1, "", "secondaries"], [12, 5, 1, "", "sources_as_dict"], [12, 5, 1, "", "target_prefix"], [12, 5, 1, "", "to_str"]], "benchbuild.source.base.ContextAwareSource": [[12, 2, 1, "", "is_context_free"], [12, 2, 1, "", "versions_with_context"]], "benchbuild.source.base.ContextFreeMixin": [[12, 2, 1, "", "is_context_free"], [12, 2, 1, "", "versions_with_context"]], "benchbuild.source.base.Expandable": [[12, 3, 1, "", "is_expandable"], [12, 2, 1, "", "versions"]], "benchbuild.source.base.Fetchable": [[12, 2, 1, "", "fetch"], [12, 3, 1, "", "key"], [12, 3, 1, "", "local"], [12, 3, 1, "", "remote"]], "benchbuild.source.base.FetchableSource": [[12, 3, 1, "", "default"], [12, 2, 1, "", "explore"], [12, 2, 1, "", "fetch"], [12, 3, 1, "", "is_expandable"], [12, 3, 1, "", "key"], [12, 3, 1, "", "local"], [12, 3, 1, "", "remote"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.base.NoSource": [[12, 3, 1, "", "default"], [12, 2, 1, "", "fetch"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.base.Revision": [[12, 2, 1, "", "extend"], [12, 2, 1, "", "has_variant"], [12, 3, 1, "", "primary"], [12, 4, 1, "", "project_cls"], [12, 2, 1, "", "sorted"], [12, 2, 1, "", "source_by_name"], [12, 2, 1, "", "update"], [12, 2, 1, "", "variant_by_name"], [12, 4, 1, "", "variants"]], "benchbuild.source.base.RevisionStr": [[12, 4, 1, "", "value"]], "benchbuild.source.base.Variant": [[12, 2, 1, "", "name"], [12, 4, 1, "", "owner"], [12, 2, 1, "", "source"], [12, 4, 1, "", "version"]], "benchbuild.source.base.Versioned": [[12, 3, 1, "", "default"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.git": [[12, 1, 1, "", "Git"], [12, 1, 1, "", "GitSubmodule"], [12, 5, 1, "", "clone_needed"], [12, 5, 1, "", "maybe_shallow"]], "benchbuild.source.git.Git": [[12, 3, 1, "", "default"], [12, 2, 1, "", "fetch"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.git.GitSubmodule": [[12, 3, 1, "", "is_expandable"]], "benchbuild.source.http": [[12, 1, 1, "", "HTTP"], [12, 1, 1, "", "HTTPMultiple"], [12, 1, 1, "", "HTTPUntar"], [12, 5, 1, "", "download_required"], [12, 5, 1, "", "download_single_version"], [12, 5, 1, "", "normalize_remotes"], [12, 5, 1, "", "versioned_target_name"]], "benchbuild.source.http.HTTP": [[12, 3, 1, "", "default"], [12, 2, 1, "", "fetch"], [12, 2, 1, "", "fetch_version"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.http.HTTPMultiple": [[12, 2, 1, "", "fetch_version"]], "benchbuild.source.http.HTTPUntar": [[12, 2, 1, "", "version"]], "benchbuild.utils": [[4, 0, 0, "-", "actions"], [5, 0, 0, "-", "settings"]], "benchbuild.utils.actions": [[4, 1, 1, "", "Any"], [4, 1, 1, "", "Clean"], [4, 1, 1, "", "CleanExtra"], [4, 1, 1, "", "Compile"], [4, 1, 1, "", "Echo"], [4, 1, 1, "", "Experiment"], [4, 1, 1, "", "MakeBuildDir"], [4, 1, 1, "", "MultiStep"], [4, 1, 1, "", "ProjectEnvironment"], [4, 1, 1, "", "ProjectStep"], [4, 1, 1, "", "RequireAll"], [4, 1, 1, "", "Run"], [4, 1, 1, "", "RunWorkload"], [4, 1, 1, "", "RunWorkloads"], [4, 1, 1, "", "SetProjectVersion"], [4, 1, 1, "", "Step"], [4, 1, 1, "", "StepResult"], [4, 5, 1, "", "log_before_after"], [4, 5, 1, "", "prepend_status"], [4, 5, 1, "", "run_any_child"], [4, 5, 1, "", "step_has_failed"]], "benchbuild.utils.actions.Any": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.Clean": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 2, 1, "", "clean_mountpoints"]], "benchbuild.utils.actions.CleanExtra": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.Compile": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.Echo": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "message"]], "benchbuild.utils.actions.Experiment": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 2, 1, "", "begin_transaction"], [4, 2, 1, "", "end_transaction"], [4, 4, 1, "", "experiment"]], "benchbuild.utils.actions.MakeBuildDir": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.MultiStep": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "actions"], [4, 2, 1, "", "onerror"]], "benchbuild.utils.actions.ProjectEnvironment": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.ProjectStep": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 2, 1, "", "onerror"], [4, 4, 1, "", "project"]], "benchbuild.utils.actions.RequireAll": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.Run": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "experiment"]], "benchbuild.utils.actions.RunWorkload": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 3, 1, "", "workload_ref"]], "benchbuild.utils.actions.RunWorkloads": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "experiment"], [4, 4, 1, "", "project"]], "benchbuild.utils.actions.SetProjectVersion": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "revision"]], "benchbuild.utils.actions.Step": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 2, 1, "", "onerror"], [4, 4, 1, "", "status"]], "benchbuild.utils.actions.StepResult": [[4, 4, 1, "", "CAN_CONTINUE"], [4, 4, 1, "", "ERROR"], [4, 4, 1, "", "OK"], [4, 4, 1, "", "UNSET"]], "benchbuild.utils.settings": [[5, 1, 1, "", "ConfigDumper"], [5, 1, 1, "", "ConfigLoader"], [5, 1, 1, "", "ConfigPath"], [5, 1, 1, "", "Configuration"], [5, 1, 1, "", "Indexable"], [5, 6, 1, "", "InvalidConfigKey"], [5, 5, 1, "", "available_cpu_count"], [5, 5, 1, "", "convert_components"], [5, 5, 1, "", "current_available_threads"], [5, 5, 1, "", "escape_yaml"], [5, 5, 1, "", "find_config"], [5, 5, 1, "", "get_number_of_jobs"], [5, 5, 1, "", "is_yaml"], [5, 5, 1, "", "path_constructor"], [5, 5, 1, "", "path_representer"], [5, 5, 1, "", "setup_config"], [5, 5, 1, "", "to_env_var"], [5, 5, 1, "", "to_yaml"], [5, 5, 1, "", "update_env"], [5, 5, 1, "", "upgrade"], [5, 5, 1, "", "uuid_add_implicit_resolver"], [5, 5, 1, "", "uuid_constructor"], [5, 5, 1, "", "uuid_representer"]], "benchbuild.utils.settings.ConfigDumper": [[5, 4, 1, "", "yaml_implicit_resolvers"], [5, 4, 1, "", "yaml_representers"]], "benchbuild.utils.settings.ConfigLoader": [[5, 4, 1, "", "yaml_constructors"], [5, 4, 1, "", "yaml_implicit_resolvers"]], "benchbuild.utils.settings.ConfigPath": [[5, 2, 1, "", "path_to_str"], [5, 2, 1, "", "validate"]], "benchbuild.utils.settings.Configuration": [[5, 2, 1, "", "filter_exports"], [5, 2, 1, "", "has_default"], [5, 2, 1, "", "has_value"], [5, 2, 1, "", "init_from_env"], [5, 2, 1, "", "is_leaf"], [5, 2, 1, "", "load"], [5, 2, 1, "", "store"], [5, 2, 1, "", "to_env_dict"], [5, 3, 1, "", "value"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "property", "Python property"], "4": ["py", "attribute", "Python attribute"], "5": ["py", "function", "Python function"], "6": ["py", "exception", "Python exception"]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:property", "4": "py:attribute", "5": "py:function", "6": "py:exception"}, "terms": {"": [0, 4, 5, 6, 8, 12], "0": [4, 5, 7, 8, 12, 13], "01": 13, "02": 13, "03": 13, "04": [7, 13], "05": 13, "06": 13, "07": 13, "07f74dd4": 0, "08": [7, 13], "09": 13, "0b": 5, "0b8d6034": 0, "0d1c890d": 0, "0x": 5, "1": [4, 5, 6, 7, 8, 12, 13], "10": [12, 13], "11": 13, "12": [5, 13], "141afafa": 0, "15": 13, "16": 13, "17": 0, "18": 7, "19": 6, "19c5983c": 0, "1_": 5, "2": [4, 5, 6, 7, 8, 12, 13], "20": 7, "2002": 5, "2020": 13, "2021": 13, "2022": 13, "2023": 13, "21": 13, "26": 13, "29": 13, "3": [1, 4, 5, 7, 13], "3648dd5e": 0, "3ae8b335": 0, "3d546314": 0, "3e943df6": 0, "4": [5, 13], "414": 0, "415": 0, "427": 0, "428": 0, "434": 0, "435": 0, "489e3039": 0, "5": [5, 13], "528": 0, "561": 0, "5b9c9906": 0, "5d29079a": 0, "6": [5, 6, 7, 13], "616a4c69": 0, "64ce9f87": 0, "7": [1, 5, 7, 13], "74379d53": 0, "7687f0e3": 0, "78b890af": 0, "79ac33d8": 0, "7_": 5, "7a1db742": 0, "7b5a704f": 0, "8": [1, 5, 6, 7, 13], "806520d6": 0, "84f90e75": 0, "8540f880": 0, "86d45043": 0, "9": [0, 5, 6, 7], "90308f2a": 0, "9_": 5, "9a": 5, "A": [4, 5, 6, 8, 12, 13], "As": 7, "By": 6, "For": [6, 8], "If": [1, 3, 4, 5, 6, 7, 8, 12], "In": 12, "It": [1, 7, 12], "NO": 5, "No": [3, 5], "ON": 5, "On": 5, "One": 8, "The": [3, 4, 5, 6, 7, 8, 12], "These": [6, 8], "Will": 6, "With": 6, "_contain": 6, "_default_backup": 8, "_default_caw_enumer": 12, "_default_enumer": 12, "_default_prun": 8, "_default_restor": 8, "_from": 5, "_is_relative_to": 0, "_label": 0, "_not_": 5, "_primari": 12, "aaabc1b5": 0, "aad1b287": 0, "abc": [0, 6], "abl": [0, 6, 7], "abort": 6, "about": [0, 1, 6, 12], "abov": 8, "absent": [6, 13], "absolut": [5, 6, 8], "abstract": [0, 6, 8, 12], "accept": 0, "access": [0, 3, 5, 8, 12], "accessor": 0, "achiev": 4, "action": [0, 13], "actions_for_project": 4, "activ": [0, 7], "active_vari": 0, "actual": 0, "ad": [1, 6, 8], "adapt": 0, "add": [0, 1, 4, 6, 12, 13], "add_benchbuild_lay": [6, 13], "addit": [6, 8], "addlay": [6, 13], "addprojectvers": 0, "af7bfd90": 0, "after": [0, 4, 6, 8, 12], "afterward": 6, "again": 4, "against": 7, "align": 0, "all": [0, 4, 5, 6, 8, 12], "allow": [0, 6], "allow_unicod": 5, "almost": 0, "alpin": [0, 6], "alreadi": [5, 6], "also": 6, "altern": 7, "alwai": [7, 8], "among": 12, "an": [0, 3, 4, 5, 6, 7, 8, 12, 13], "ani": [0, 1, 5, 6, 7, 8, 12, 13], "annot": 0, "anyth": [5, 6], "anywai": 12, "anywher": [0, 12], "api": [0, 6, 12], "apk": 6, "append": [6, 13], "appli": 6, "applic": 6, "ar": [1, 4, 5, 6, 7, 8, 12], "arbitrari": [6, 12], "archiv": [0, 6, 12], "arg": [0, 6, 8, 12, 13], "arg1": 8, "arg2": 8, "args_c": 8, "argsrenderstrategi": [8, 13], "argstoken": [8, 13], "argument": [0, 6, 8, 12], "around": [5, 12], "artifact": [6, 8], "as_plumbum": [8, 13], "ask": 4, "assign": [0, 4, 5, 8], "assist": [1, 6, 7], "associ": [8, 12], "assum": [3, 6, 12], "assumpt": 12, "attach": 5, "attr": 0, "attribut": [0, 4, 6, 8, 12], "augment": 12, "author": 8, "auto": [0, 12], "automat": [5, 6, 8], "avaial": 5, "avail": [0, 5, 6, 8, 12, 13], "available_cpu_count": [5, 13], "avoid": [0, 5, 6, 12], "awar": [0, 12], "b": 5, "b09d9248": 0, "b1a095c1": 0, "b6625d31": 0, "back": [8, 12], "backend": 6, "background": 1, "backup": [0, 8], "backupfn": [8, 13], "baild": 0, "bar": 0, "base": [0, 3, 5, 6, 7, 8, 13], "base_c": 8, "base_imag": 6, "basesourc": [12, 13], "baseversiongroup": 0, "bash": [3, 6], "bashstrategi": [6, 13], "basic": [0, 6, 13], "batch": 7, "bb": 5, "bb_build_dir": 5, "bb_container_export": 6, "bb_container_from_sourc": 6, "bb_container_import": 6, "bb_container_mount": 6, "bb_container_root": 6, "bb_container_runroot": 6, "bb_container_runtim": 6, "bb_coverage_path": 0, "bb_env": 0, "bb_env_test": 8, "bb_llvm_dir": 5, "bb_slurm_templ": 3, "bce45d8a": 0, "becaus": 7, "becom": 5, "been": [6, 8, 12], "befor": [0, 4, 6, 8], "beforehand": 6, "begin_transact": [4, 13], "behav": 8, "behavior": [0, 4, 8, 12], "being": 1, "belong": 8, "below": 7, "benchbuid": 3, "benchbuild": [0, 2, 3, 4, 5, 8, 12, 13], "besid": 8, "better": 0, "between": [1, 8], "bin": [6, 7, 8], "binari": [0, 5, 6, 7, 8], "bind": 6, "block": 12, "bodi": 1, "bool": [4, 5, 6, 8, 12], "boolean": 8, "bootstrap": 13, "both": [0, 4], "bound": [0, 4], "boundenvcommand": 8, "box": 4, "brace": 0, "break": 0, "bring": 6, "broken": 0, "buffer": 2, "bug": 13, "build": [0, 4, 6, 8, 12], "build_dir": [5, 6, 13], "buildah": [0, 7, 13], "builddir": [0, 6, 8, 12, 13], "builddirrender": [8, 13], "bump": 0, "byte": 5, "bz2": 6, "bzip2": 0, "ca973ff0": 0, "cach": [0, 12], "call": [0, 2, 5, 6, 8], "callabl": [0, 4, 6], "callback": [0, 8], "can": [1, 2, 3, 4, 5, 6, 7, 8, 12], "can_continu": [4, 13], "candid": 12, "cannot": [0, 3, 6, 8, 12], "canon": 5, "captur": 12, "care": [1, 4], "carri": [8, 12], "case": [0, 3, 6, 13], "caught": 0, "cfg": [5, 6], "cfg_file": 5, "chang": [0, 3, 4, 6], "changelog": 13, "check": [0, 4, 5, 6, 7, 12], "check_certif": 12, "check_empti": 4, "checkout": [4, 6], "child": 4, "children": 5, "chosen": 6, "chroot": 6, "ci": 0, "class": [0, 4, 5, 6, 8, 12], "classmethod": 8, "classvar": 4, "clean": [0, 13], "clean_directori": [6, 13], "clean_mountpoint": [4, 13], "cleanextra": [0, 13], "cleanup": [0, 4, 8, 13], "clear": 0, "clearli": 0, "cli": [0, 13], "cli_process": 0, "clone": [0, 12], "clone_need": [12, 13], "close": 0, "closur": 0, "cluster": [3, 7], "cmake": 6, "cmd": [6, 8, 12], "code": [0, 12], "com": 8, "command": [0, 2, 3, 7, 12, 13], "commannd": 6, "commit": [0, 12], "compar": 8, "comparison": 4, "compat": [5, 8], "compil": [0, 1, 5, 8, 13], "complement": 12, "complet": [6, 12], "compliant": 6, "complic": 3, "compon": [5, 6, 8, 12], "composit": [8, 12], "compress": [8, 12], "comput": 5, "concaten": 8, "concept": 6, "concern": 1, "concret": 8, "condens": 0, "condition": 12, "conffigur": 0, "config": [0, 5, 6], "config_fil": 5, "config_filenam": 5, "configdump": [5, 13], "configload": [5, 13], "configpath": [5, 13], "configur": [3, 4, 8, 13], "configuraiton": 12, "confin": 8, "confirm": 6, "conjunct": 7, "connect_str": 0, "consid": [0, 6, 7, 12], "consist": [0, 5], "constant": 8, "construct": [0, 5, 6, 8], "construct_undefin": 5, "construct_yaml_binari": 5, "construct_yaml_bool": 5, "construct_yaml_float": 5, "construct_yaml_int": 5, "construct_yaml_map": 5, "construct_yaml_nul": 5, "construct_yaml_omap": 5, "construct_yaml_pair": 5, "construct_yaml_seq": 5, "construct_yaml_set": 5, "construct_yaml_str": 5, "construct_yaml_timestamp": 5, "constructor": 0, "conststrrender": [8, 13], "consum": [0, 8, 13], "contain": [0, 5, 7, 12, 13], "container": 6, "container_db": 6, "container_dir": 6, "container_id": [6, 13], "containerbootstrap": [6, 13], "containercr": [6, 13], "containerimag": [6, 13], "containerlist": [6, 13], "containerrun": [6, 13], "containerstrategi": [6, 13], "content": 12, "context": [0, 6, 8, 12, 13], "context_aware_enumer": 12, "context_free_enumer": 12, "context_from_revis": 0, "contextawaresourc": [12, 13], "contextenumeratorfn": [12, 13], "contextfreemixin": [12, 13], "contextlay": [6, 13], "contextmanag": 8, "control": [0, 1, 6], "convers": 0, "convert": [0, 5, 6, 8, 12], "convert_compon": [5, 13], "copi": [0, 3, 6], "copy_": [6, 13], "copylay": [6, 13], "correct": 0, "correctli": 0, "count": 0, "covari": [0, 4], "coverag": 0, "coveragerc": 0, "cpu": 5, "creat": [0, 4, 5, 6, 8, 12, 13], "createbenchbuildbas": [6, 13], "createimag": [6, 13], "creation": [0, 6], "cross": 12, "crun": 6, "csafeload": 5, "ctx": 12, "curli": 0, "current": [5, 6, 8, 12], "current_available_thread": [5, 13], "custom": [0, 6, 12, 13], "custom_shel": 6, "customiz": [0, 8], "cwd": 6, "d4c6841d": 0, "d7a2165b": 0, "d83aa666": 0, "daemon": 6, "data": 5, "databas": [0, 6], "date": 5, "datetim": 5, "db": [0, 4], "deal": [0, 12], "debian": 1, "debug": 0, "declar": [0, 4, 8, 12, 13], "decor": 0, "dedic": [0, 7], "def": 4, "default": [0, 1, 3, 4, 5, 6, 12, 13], "default_flow_styl": 5, "default_styl": 5, "defin": [1, 4, 5, 6, 8, 12], "definit": [0, 8, 13], "delet": [0, 8], "deleteimag": [6, 13], "depen": 6, "depend": [0, 1, 6, 7, 12], "deriv": 0, "desc": 4, "descript": [4, 12, 13], "descriptor": [0, 8], "design": 13, "desir": 12, "destin": [6, 13], "detail": 0, "detect": 3, "determin": [4, 6], "dev8": 6, "develop": 1, "dfa4cb81": 0, "dict": [5, 6, 12], "dictionari": [5, 6, 12], "differ": [1, 4, 6, 12], "dill": 0, "dir": [5, 12], "directori": [0, 4, 5, 6, 8, 12, 13], "dirnam": [8, 13], "disabl": [0, 2], "dissoci": 0, "distribut": 1, "do": [0, 4, 5, 6, 12], "dockerfil": 6, "document": [0, 6], "doe": [4, 6], "doesn": [12, 13], "domain": 13, "done": [1, 3, 4, 6, 8], "down": 0, "download": 12, "download_requir": [12, 13], "download_single_vers": [12, 13], "draft": 0, "driven": 1, "drop": [0, 8], "dumper": 5, "dure": [1, 4], "dynam": 8, "e": [4, 5, 6, 7, 8, 12], "e0c7ab67": 0, "e3ea47f0": 0, "e4bff984": 0, "each": [0, 4, 5, 6, 8, 12], "easi": 0, "eb03c363": 0, "echo": 13, "ee": 5, "effort": 1, "either": 6, "element": 0, "ellipsi": 0, "els": [0, 6, 12], "emit": 0, "empir": 1, "empti": 8, "enabl": [0, 12], "enable_rollback": 0, "encapsul": [4, 8], "encod": [5, 8, 12], "end_transact": [4, 13], "enforc": 0, "enhanc": 4, "ensur": 8, "enter": 0, "entiti": 0, "entri": 6, "entrypoint": [0, 6, 13], "enum": 6, "enumer": [0, 6, 12], "enumerate_revis": [0, 12, 13], "enumeratorfn": [12, 13], "env": [0, 4, 5, 6, 8, 13], "env_c": 8, "env_var": 5, "env_var_nam": 5, "enviro": 0, "environ": [0, 3, 4, 5, 7, 8, 13], "equival": 12, "err": 0, "error": [0, 4, 8, 13], "error_statu": 4, "escap": 5, "escape_yaml": [5, 13], "evalu": [8, 12], "event": [0, 6, 13], "everi": 12, "everyth": [4, 12], "exact": 4, "exactli": 0, "exampl": [0, 4, 8], "except": [0, 5], "execut": [1, 4, 6, 8], "exist": [0, 1, 3, 5, 6, 8, 12, 13], "exit": 6, "expand": [0, 4, 12, 13], "expandableandfetchablesourc": 0, "expans": 12, "expect": 7, "expeir": 4, "experi": [0, 3, 6, 8, 13], "explicit": 0, "explicit_end": 5, "explicit_start": 5, "explicitli": 0, "explor": [0, 12, 13], "export": [0, 3, 6], "exportimag": [6, 13], "extend": [12, 13], "extens": [1, 4, 8], "extra": 4, "extract": 6, "ey": 0, "f": [5, 8], "f0": 5, "f_": 5, "fa": 5, "factori": 0, "fail": [0, 4], "fals": [4, 5, 8], "fbb69502": 0, "fe5d6155": 0, "feat": 13, "featur": [7, 8, 13], "fetch": [0, 12, 13], "fetch_vers": [12, 13], "fetchabl": [12, 13], "fetchablesourc": [0, 12, 13], "few": [6, 7], "field": 0, "file": [0, 3, 5, 6, 8, 12], "filenam": [5, 6], "filesystem": [3, 6, 12], "fill": 8, "filter": [0, 8, 12], "filter_export": [5, 13], "filter_workload_index": [8, 13], "find": [0, 3, 4, 5, 6, 12], "find_config": [5, 13], "find_hash": [6, 13], "first": [4, 6, 12], "fix": [6, 13], "flag": [0, 6], "flat": 5, "float": 5, "focus": 1, "follow": [1, 4, 5, 6, 7, 8, 12], "foo": [6, 8], "forc": [0, 2, 6], "force_tti": 0, "form": [5, 12], "format": [0, 8], "formul": 6, "forward": [5, 8], "found": [1, 6, 8, 12], "free": [0, 12], "fresh": 0, "from": [0, 2, 5, 6, 7, 8, 12], "from_": [6, 13], "fromlay": [0, 6, 13], "fs_compliant_nam": [6, 13], "full": 6, "func": [4, 6, 13], "function": [0, 5, 8, 12], "functool": 0, "further": 12, "fuse": 13, "futur": 7, "g": [0, 4, 6, 8, 12], "g85c5ced8": 6, "gener": [0, 3, 4, 5, 7, 8], "gentoo": 6, "get": [5, 6, 7, 13], "get_number_of_job": [5, 13], "getitem": 0, "gid": 6, "git": [0, 8, 13], "github": [0, 8], "gitlab": 0, "gitsubmodul": [12, 13], "give": 6, "given": [1, 5, 6, 8, 12], "global": [0, 12], "gnu": 12, "good": 12, "group": [0, 13], "guarante": 12, "guard": 0, "guid": 1, "gz": 12, "gzip": 0, "ha": [0, 6, 8, 12], "hand": 6, "handl": 0, "handler": 0, "happen": 4, "happi": 0, "has_default": [5, 13], "has_valu": [5, 13], "has_vari": [12, 13], "hash": 12, "hashabl": [0, 6], "have": [1, 3, 4, 6, 7, 8, 12], "head": [8, 12], "help": [1, 2], "here": [8, 12], "high": 3, "higher": 0, "hold": [5, 8], "hook": [0, 12], "how": 6, "howev": [3, 6, 8, 12], "http": [0, 8, 13], "httpmultipl": [12, 13], "httpuntar": [12, 13], "i": [0, 1, 3, 4, 5, 6, 7, 8, 12], "id": 0, "ident": 8, "identif": 12, "iff": 8, "ignor": [0, 6], "imag": [0, 13], "image_exist": 0, "immut": 8, "immutable_kwarg": [6, 13], "impl": 0, "implement": [0, 4, 6, 8, 12], "implicit": [5, 12], "import": [0, 6, 7, 8], "importimag": [6, 13], "improv": 0, "in_contain": 6, "in_dir": 6, "in_path": [6, 13], "inc": 3, "includ": 8, "increas": 0, "indent": 5, "index": [5, 8, 12, 13], "inform": [0, 1, 6, 12], "init": 5, "init_from_env": [5, 13], "init_subclass": 0, "initi": [0, 4, 5, 6], "inner": 5, "input": [5, 6, 12], "input_fil": [6, 13], "insert": 8, "insid": [4, 6, 12, 13], "instal": [1, 6, 13], "install_cmake_and_exit": [6, 13], "instanc": [0, 8], "instead": [0, 12], "instruct": 7, "int": 5, "integ": 0, "integr": 3, "intenum": 4, "interact": [0, 6, 12], "intercept": 1, "interfac": [0, 6, 12], "intern": 7, "intersect": [0, 8], "introduc": 0, "invalidconfigkei": [5, 13], "is_complet": [6, 13], "is_context_fre": [12, 13], "is_expand": [4, 12, 13], "is_leaf": [5, 13], "is_pres": [6, 13], "is_relative_to": 0, "is_yaml": [5, 13], "isol": 7, "iter": [6, 12], "its": [0, 6, 12, 13], "job": [0, 5, 8], "join": 12, "just": [0, 4, 6], "kei": [5, 6, 7, 8, 12, 13], "keyerror": 12, "know": [6, 13], "knowledg": [1, 6], "known": [6, 8], "kwarg": [0, 6, 8, 12, 13], "label": [0, 8, 13], "lambda": 12, "latest": [0, 6], "launch": 6, "layer": [0, 6, 13], "layer_index": [6, 13], "layerst": [6, 13], "layout": 0, "lead": 6, "leaf": 5, "leav": [6, 8], "left": [0, 8, 13], "legaci": 7, "less": [0, 6], "let": 8, "level": [0, 3], "lib": 6, "libfus": 7, "libpod": 0, "libpq": 7, "librari": 7, "like": [1, 5, 12], "limit": [0, 8, 12], "line": [0, 8], "line_break": 5, "link": [0, 12], "linpack": 6, "linter": 0, "linux": 1, "list": [0, 5, 6, 8, 12], "live": 12, "llnl": 7, "llvm": 5, "load": [0, 3, 5, 6, 13], "loader": 5, "local": [0, 8, 12, 13], "local_nam": 8, "localpath": [5, 12], "locat": [0, 6, 8, 12], "log": [0, 4, 12], "log_before_aft": [4, 13], "logg": 8, "logic": 0, "long": [0, 1], "look": [5, 8, 12], "lookup": 0, "lower": [0, 6], "machin": 7, "made": 1, "mai": [6, 12], "main": [1, 6, 12, 13], "mainli": 1, "major": [0, 1], "make": [0, 1, 5, 6, 7, 8, 12], "make_token": [8, 13], "makebuilddir": 13, "manag": [0, 1, 3, 6, 7], "mandatori": 7, "map": [0, 5, 6, 8], "mark": [0, 4], "marker": 0, "match": [0, 4, 8, 12], "max": 0, "maybe_shallow": [12, 13], "maybecontain": 0, "me": 6, "merg": 5, "messag": [0, 4, 6, 13], "metaclass": 0, "method": [0, 6], "might": [0, 3], "migrat": [0, 5], "mind": 1, "minimum": 7, "mirror": 6, "misc": 3, "miss": 0, "missing_ok": 0, "mixin": 0, "mkdir": 4, "mkdoc": 0, "mockobj": [6, 13], "mode": 0, "model": 13, "modif": 5, "modifi": [0, 3, 5, 6], "modul": [0, 13], "more": [0, 3, 4, 6, 12], "most": 4, "mount": [6, 13], "mount_build_dir": [6, 13], "mount_tmp_dir": [6, 13], "mountpoint": [4, 6], "multi": 0, "multipl": [0, 4, 12], "multistep": [0, 4, 13], "multivers": 0, "must": 0, "mutabl": 0, "mutablemap": 8, "mutablesequ": 4, "mypi": 0, "myprj": 8, "myproject": 8, "n": 5, "name": [0, 4, 5, 6, 7, 8, 12, 13], "namespac": [5, 6], "necessari": [6, 7, 12], "need": [0, 4, 5, 6, 7, 12], "nestedvari": 0, "neutral": 0, "never": 1, "new": [0, 1, 4, 5, 6, 8, 12], "nf": 6, "node": 5, "non": 5, "none": [0, 4, 5, 6, 8, 12], "nonetyp": 5, "normalize_remot": [12, 13], "nosourc": [12, 13], "note": 7, "noth": [4, 6], "notifi": 0, "notify_step_begin_end": 0, "now": [5, 6, 7, 8], "null": 5, "nullrender": 0, "number": [0, 5, 12], "o": 5, "obj": 0, "object": [0, 4, 5, 6, 7, 8, 12], "obsolet": [0, 7], "obviou": 0, "oci": [6, 7], "oci_compli": 0, "oci_compliant_nam": [6, 13], "off": [5, 6], "offer": [6, 8, 12], "often": 7, "ok": [4, 13], "omap": 5, "one": [4, 5, 6, 8, 12], "onerror": [4, 13], "onli": [0, 1, 4, 5, 6, 7, 8, 12], "onlyin": [0, 8, 13], "open": 1, "oper": 4, "opt": 12, "optim": 5, "option": [0, 3, 5, 6, 8, 12], "order": [0, 4, 5, 12], "org": 5, "origin": 12, "other": [0, 6, 8, 12], "otherwis": [5, 6], "our": [5, 6, 8], "out": [0, 4, 6, 8], "out_dir": 6, "out_fil": 6, "out_nam": [6, 13], "outfil": 6, "output": [0, 2, 4, 5, 6, 8, 12, 13], "output_fil": [6, 13], "output_param": [8, 13], "over": [0, 5], "overwrit": 0, "own": [0, 1, 2, 3, 4, 6, 12], "owner": [12, 13], "pack": 6, "pack_contain": [6, 13], "packag": [0, 7], "page": 13, "pair": [5, 6], "paramet": [0, 4, 5, 6, 8, 12], "paramt": 8, "parent": 5, "parent_kei": 5, "part": [0, 12], "partial": 0, "particip": 12, "particular": 7, "pass": [0, 6, 8], "path": [0, 5, 6, 8, 12, 13], "path_constructor": [5, 13], "path_represent": [5, 13], "path_to_str": [5, 13], "pathlib": 8, "patho": 0, "pathrenderstrategi": [8, 13], "pathtoken": [0, 8, 13], "pattern": 5, "per": 4, "permiss": 6, "phase": 12, "philosophi": 13, "physic": 5, "pickl": 0, "pin": 0, "pip": [6, 7], "pip3": 7, "place": 12, "plan": 7, "pleas": 6, "plugin": 0, "plumbum": [0, 8], "podman": [0, 7, 13], "point": [1, 3, 6, 8, 12], "polici": 6, "pollut": 5, "polyjit": 6, "possibl": [0, 5, 8], "postgresql": 13, "ppython3": 7, "pre": 0, "prebuilt": 6, "preced": 5, "predefin": 6, "prefix": 12, "prepar": [4, 6], "prepend": [4, 6, 13], "prepend_statu": [4, 13], "present": [6, 13], "preserv": 0, "previou": 0, "primari": [12, 13], "print": [0, 4, 6], "print_lay": 0, "print_project": 0, "privat": 0, "procedur": [1, 7], "process": [1, 6], "product": [12, 13], "program": [5, 12], "progress": 0, "project": [0, 4, 6, 12, 13], "project_cl": [0, 12, 13], "project_command": 8, "project_root": [8, 13], "projectcommand": [8, 13], "projectenviron": [0, 13], "projectroot": [8, 13], "projectstep": [4, 13], "properli": [0, 6], "properti": [0, 1, 4, 5, 6, 8, 12], "protocl": 0, "protocol": [0, 8, 12], "prototyp": 0, "provid": [0, 1, 3, 4, 5, 6, 7, 8, 12], "prune": [0, 8], "prunefn": [8, 13], "psycopg2": 7, "public": 0, "pull": 12, "put": 4, "pygit2": 0, "pylint": 0, "pytest": 0, "python": [0, 4, 7, 13], "python3": [0, 6], "question": 4, "quickli": 1, "rais": [0, 4, 12], "rang": 8, "raw": 6, "raw_str": 5, "re": [0, 3, 5], "real": 5, "rebas": 0, "rebuild": 6, "recommend": 3, "recurs": 5, "reduc": 0, "refactor": 13, "refer": [6, 8, 12], "refspec": [8, 12], "refus": 5, "regardless": 4, "registr": 0, "registri": [0, 6], "rel": 8, "releas": 7, "relev": 6, "reli": [1, 12], "remain": [4, 8], "remot": [0, 6, 8, 12, 13], "remov": [0, 6, 8], "renam": 0, "render": [0, 8, 13], "rendered_arg": [8, 13], "reorder": 0, "repair": 0, "replac": [0, 8, 13], "repo_loc": 12, "report": 0, "repositori": [0, 6, 12], "repres": [5, 6], "represent": [0, 5, 8, 12], "represent_binari": 5, "represent_bool": 5, "represent_d": 5, "represent_datetim": 5, "represent_dict": 5, "represent_float": 5, "represent_int": 5, "represent_list": 5, "represent_non": 5, "represent_set": 5, "represent_str": 5, "represent_undefin": 5, "request": 12, "requir": [0, 3, 4, 8, 12, 13], "requireal": 13, "resolv": [5, 8], "resourc": [3, 5], "rest": 7, "restor": 8, "restorefn": [8, 13], "restrict": 6, "result": [0, 4, 6], "return": [0, 4, 5, 6, 8, 12], "reus": [0, 6], "reusabl": 1, "rev": 12, "rev_rang": [8, 13], "revert": 0, "revis": [0, 4, 8, 12, 13], "revision_from_str": [12, 13], "revision_str": 4, "revisionrang": 8, "revisionstr": [0, 12, 13], "rework": 0, "rich": 0, "richhandl": 0, "rid": 7, "right": [5, 7, 8, 13], "risk": 3, "rmeov": 0, "rmi": 0, "root": [0, 4, 5, 6, 8], "rootless": 6, "rootrender": [0, 8, 13], "rsync": 13, "rtype": 12, "run": [0, 1, 3, 6, 8, 13], "run_any_child": [4, 13], "run_in_contain": [6, 13], "run_onli": 4, "run_test": 0, "runjob": 0, "runlay": [6, 13], "runprojectcontain": [0, 6, 13], "runroot": 0, "runtim": [8, 13], "runtime_check": 0, "runtime_extens": 8, "runtimewarn": 5, "runworkload": [4, 13], "safeconstructor": 5, "safedump": 5, "safeguard": 0, "saferepresent": 5, "same": [0, 5, 6, 12], "save": 6, "sawarn": 0, "sbatch": [3, 7], "scalar": [0, 5], "scale": 5, "schema": [0, 4], "scimark2": 0, "script": [3, 7], "search": 13, "secondari": [12, 13], "see": [1, 3, 6], "select": [6, 12], "self": [0, 4], "semant": 12, "sens": [6, 12], "seq": 5, "sequenc": [0, 6, 8, 12], "serv": [5, 12], "session": 4, "set": [0, 3, 4, 6, 7, 8, 12, 13], "set_input_contain": [6, 13], "set_limit": 0, "setcommand": [6, 13], "setprojectvers": [0, 13], "setup": [0, 1, 3, 6, 7, 12], "setup_bash_in_contain": [6, 13], "setup_config": [5, 13], "setup_contain": [6, 13], "setup_directori": [6, 13], "setuppolyjitgentoostrategi": [6, 13], "sh": 3, "shallow": 12, "shell": [5, 6, 13], "ship": 1, "should": [0, 1, 4, 5, 6, 7, 12], "signal": 7, "silenc": 0, "similar": 8, "simpl": [0, 5, 12], "simpli": 6, "singl": [0, 4, 12], "singleversionfilt": 0, "situat": 3, "skeleton": 0, "slurm": [0, 13], "slurm_node_dir": 0, "softwar": [1, 7], "some": [0, 4, 12], "sometim": [4, 6], "somewher": 12, "soon": 7, "sort": [0, 8, 12, 13], "sort_kei": 5, "souc": 4, "sourc": [0, 1, 4, 5, 6, 7, 8, 13], "source_by_nam": [12, 13], "source_root": [8, 12, 13], "sourceroot": [8, 13], "sourcerootrender": [8, 12, 13], "sources_as_dict": [12, 13], "sourcet": 12, "space": [6, 7], "spam": 0, "spawn": [0, 6], "specif": [1, 12], "specifi": [6, 8, 12], "split": 0, "sprefix": 0, "sqlalchemi": 0, "sqlite": 0, "srun": 7, "stabl": 7, "stage": 6, "stand": 0, "standard": [1, 6, 8], "start": [5, 6, 13], "state": 0, "statement": 6, "static": [4, 5, 12], "statu": [0, 4, 13], "stderr": 0, "step": [0, 13], "step_has_fail": [4, 13], "stepabl": 0, "stepclass": 0, "stepresult": [0, 4, 13], "stepti": 0, "stepty_co": [0, 4], "stopiter": 4, "store": [0, 5, 6, 8, 12, 13], "str": [0, 4, 5, 6, 8, 12], "strategi": [6, 8, 13], "stream": 5, "strictli": 0, "string": [0, 4, 5, 6, 8, 12], "strip": 0, "structur": [0, 5, 6], "studi": 13, "style": 0, "subclass": 12, "subcommand": [0, 6], "subdirectori": 8, "submodul": 12, "subordin": 6, "substep": 4, "substitut": 8, "subtre": 5, "subuid": 6, "succe": 4, "suit": 4, "suitabl": 6, "super": 6, "suppli": 0, "support": [0, 3, 6, 7, 8, 13], "supportsunwrap": [0, 8, 13], "sure": [0, 5, 6, 12], "switch": 0, "sy": 0, "symlink": [0, 7], "syntax": 6, "system": [5, 6, 7, 12], "t": [5, 12, 13], "tag": [0, 5, 6], "take": [1, 4, 5, 12], "tar": [6, 12], "target": [0, 6, 13], "target_dir": 12, "target_nam": 12, "target_path": 12, "target_prefix": [12, 13], "task": [0, 1, 6], "tell": 6, "templat": [0, 13], "temporari": 6, "term": 12, "test": [0, 7, 8, 12], "test_command": 0, "test_fil": 5, "testproject": 6, "tgt": 6, "than": [0, 3, 6, 12], "thei": [6, 7], "them": 6, "therefor": 8, "thi": [1, 2, 3, 4, 5, 6, 7, 8, 12], "those": 4, "thread": 5, "through": [0, 4, 8], "throughout": 5, "throw": 0, "time": [1, 4, 5], "timestamp": 5, "tmp": 8, "tmp_dir": [6, 13], "tmpdir": 6, "to_env_dict": [5, 13], "to_env_var": [5, 13], "to_str": [12, 13], "to_yaml": [5, 13], "todo": [3, 4, 10, 11], "token": [0, 12, 13], "too": 0, "tool": [2, 6, 7], "toolkit": 1, "tp": [4, 6], "track": 0, "tracker": 0, "transact": 4, "treat": 12, "tree": 5, "tri": [6, 7], "true": [4, 5, 6, 7, 8, 12], "try": 8, "tt": 5, "tune": 0, "tupl": [0, 4, 5, 6, 8, 12], "turpl": 0, "twice": [0, 4], "two": 12, "type": [0, 4, 5, 6, 8, 12], "typevar": [4, 12], "typing_extens": 0, "typo": 0, "ubuntu": 7, "uchroot": [6, 7], "uid": 6, "unbound": 0, "unbreak": 0, "unbuff": [0, 2], "uncondition": 6, "under": 4, "undo": 0, "unescap": 5, "union": 8, "unionf": [4, 7], "uniqu": 12, "unit": 0, "unlink": 0, "unlock": 0, "unmount": 4, "unnecessari": 0, "unpack": 12, "unrend": [8, 13], "unrender": 0, "unset": [4, 13], "unshallow": 0, "unsplit": 0, "untar": 0, "until": 5, "unus": 0, "unwrap": [8, 13], "up": [0, 1, 6, 8], "updat": [0, 5, 6, 12, 13], "update_env": [5, 6, 13], "updateenv": [6, 13], "upgrad": [5, 13], "upon": 4, "url": 12, "us": [0, 1, 2, 3, 4, 5, 6, 7, 8, 12], "usabl": 8, "usag": [4, 13], "useless": 0, "user": [0, 5, 6, 7, 8], "user_mount": 6, "userspac": 5, "usr": 6, "usual": [4, 6, 8], "util": [0, 4, 8, 13], "uuid": 5, "uuid_add_implicit_resolv": [5, 13], "uuid_constructor": [5, 13], "uuid_represent": [5, 13], "v3": 0, "v4": 0, "valid": [3, 5, 6, 12, 13], "valu": [0, 3, 4, 5, 6, 8, 12, 13], "var": 0, "vararg": 0, "variabl": [0, 5, 6, 8], "variant": [0, 4, 12, 13], "variant_by_nam": [12, 13], "variantcontext": 0, "varieti": 6, "venv_path": 7, "verbos": [0, 5, 6, 13], "version": [0, 4, 5, 6, 7, 12, 13], "version_filt": 12, "versioned_target_nam": [12, 13], "versions_with_context": [12, 13], "via": [5, 7, 12], "view": 0, "virtual": [5, 6, 7, 12], "virtualenv": 7, "wa": 1, "wai": [0, 4, 6, 8, 12], "walru": 0, "want": [6, 7], "warn": [0, 5], "watch": [0, 2], "we": [0, 4, 5, 6, 7, 8, 12], "what": [1, 8], "when": [0, 4, 5, 6, 7, 8, 12], "whenev": [4, 5, 12], "where": [0, 1, 3, 6, 12], "which": [6, 7], "while": 12, "widen": 0, "width": 5, "wip": 0, "wise": 0, "without": 0, "work": [0, 6], "workaround": 0, "workflow": [0, 4], "workingdir": [6, 13], "workingdirectori": [6, 13], "workload": [0, 4, 8, 12], "workload_ref": [4, 13], "workload_set": [8, 13], "workloadset": [0, 8, 13], "worktre": 12, "would": 12, "wrap": [0, 4, 8], "wrapper": [5, 8, 12], "write": 6, "wrong": 0, "x264": 0, "xz": 0, "y": 5, "yaml": 5, "yaml_constructor": [5, 13], "yaml_implicit_resolv": [5, 13], "yaml_represent": [5, 13], "ye": 5, "yield": 8, "you": [1, 3, 4, 5, 6, 7, 8, 12], "your": [3, 4, 6, 7, 8, 12]}, "titles": ["6.8 (2023-10-09)", "BenchBuild Documentation", "CLI", "SLURM", "Actions", "Configure", "Containers", "Installation", "Commands", "Environment", "Experiment", "Project", "Source", "Welcome to bencbuild\u2019s documentation!"], "titleterms": {"": 13, "0": 0, "01": 0, "02": 0, "03": 0, "04": 0, "05": 0, "06": 0, "07": 0, "08": 0, "09": 0, "1": 0, "10": 0, "11": 0, "12": 0, "15": 0, "16": 0, "2": 0, "2020": 0, "2021": 0, "2022": 0, "2023": 0, "21": 0, "26": 0, "29": 0, "3": 0, "4": 0, "5": 0, "6": 0, "7": 0, "8": 0, "A": 1, "action": 4, "an": 1, "ani": 4, "avail": 4, "base": [4, 12], "basic": 3, "bencbuild": 13, "benchbuild": [1, 6, 7], "bootstrap": 7, "bug": 0, "buildah": 6, "case": 1, "changelog": 0, "clean": 4, "cleanextra": 4, "cli": 2, "command": [6, 8], "compil": 4, "configur": [5, 6], "contain": 6, "content": 13, "custom": [3, 4], "declar": 6, "definit": 6, "design": 1, "document": [1, 13], "doesn": 1, "domain": 6, "echo": 4, "environ": [6, 9], "exampl": [6, 12], "experi": [1, 4, 10], "feat": 0, "featur": 0, "fix": 0, "fuse": 7, "get": 1, "git": 12, "group": 4, "http": 12, "imag": 6, "indic": 13, "insid": 8, "instal": 7, "its": 1, "know": 1, "makebuilddir": 4, "model": 6, "modul": [5, 6, 8, 12], "philosophi": 1, "podman": 6, "postgresql": 7, "project": [8, 11], "projectenviron": 4, "python": 1, "refactor": 0, "replac": 6, "requir": [6, 7], "requireal": 4, "rsync": 12, "run": 4, "runtim": 6, "set": 5, "setprojectvers": 4, "slurm": [3, 7], "sourc": 12, "start": 1, "step": 4, "studi": 1, "support": 1, "t": 1, "tabl": 13, "templat": 3, "token": 8, "usag": [6, 8], "util": 5, "version": 1, "welcom": 13}}) \ No newline at end of file diff --git a/concepts/command/index.html b/concepts/command/index.html new file mode 100644 index 000000000..233545ea3 --- /dev/null +++ b/concepts/command/index.html @@ -0,0 +1,958 @@ + + + + + + + Commands + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Commands

+

BenchBuild provides an abstraction for binaries that are provided by a project, +after compilation. These Command objects carry the path to the binary, +customizable output paramters and support for dynamic tokens inside the path +generation.

+

Besides these features, a command behaves identical to any other binary +command that you make use of inside BenchBuild, e.g., benchbuild.utils.cmd.

+
+

Usage inside Projects

+

For now, you make use of BenchBuild’s commands inside a project’s WORKLOADS +attribute. Let’s have a look at the following example:

+
from benchbuild import Project
+from benchbuild.command import Command, WorkloadSet, SourceRoot
+
+class MyProject(Project):
+  ...
+  SOURCE = [
+    Git(
+      remote="https://github.com/myproject.git",
+      local="myproject.git",
+      limit=1,
+      refspec="HEAD"
+  ]
+
+  WORKLOADS = {
+    WorkloadSet("compression"): [
+      Command(SourceRoot("myproject.git") / "myprj")
+    ]
+  }
+
+
+

Here we have a Command that belongs to the WorkloadSet with the name +compression that points to the binary myprj inside the project’s +source directory of the git source myproject.git. What concrete path +this will be is only known after this project has been instanced inside +an experiment and is not known before.

+

This is done using tokens inside the commands’ path representation. One +example of an available token is the above SourceRoot.

+
+
+

Tokens

+

BenchBuild offers project authors a way to tokenize path components for +commands. These can be used to refer to a project’s root directory or +source directory in a generic way.

+
+
+

Module: command

+
+
+class benchbuild.command.ArgsRenderStrategy(*args, **kwargs)[source]
+

Bases: Protocol

+

Rendering strategy protocol for command line argument tokens.

+
+
+rendered(**kwargs)[source]
+

Renders this strategy.

+
+
Return type:
+

Tuple[str, ...]

+
+
+
+ +
+
+property unrendered: str
+

Returns an unrendered representation of this strategy.

+
+ +
+ +
+
+class benchbuild.command.ArgsToken(renderer)[source]
+

Bases: object

+

Base class for tokens that can be rendered into command-line arguments.

+
+
+classmethod make_token(renderer)[source]
+
+
Return type:
+

ArgsToken

+
+
+
+ +
+
+render(**kwargs)[source]
+

Renders the PathToken as a standard pathlib Path.

+

Any kwargs will be forwarded to the PathRenderStrategy.

+
+
Return type:
+

Tuple[str, ...]

+
+
+
+ +
+
+renderer: ArgsRenderStrategy
+
+ +
+ +
+
+class benchbuild.command.BackupFn(*args, **kwargs)[source]
+

Bases: Protocol

+

Backup callback function protocol.

+
+ +
+
+class benchbuild.command.BuilddirRenderer[source]
+

Bases: object

+

Renders the build directory of the assigned project.

+
+
+rendered(project=None, **kwargs)[source]
+

Render the project’s build directory.

+

If rendering is not possible, the unrendered representation is +provided and an error will be loggged.

+
+
Parameters:
+

project (Optional[benchbuild.project.Project]) – the project to render the build directory from.

+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+
+ +
+ +
+
+class benchbuild.command.Command(path, *args, output=None, output_param=None, label=None, creates=None, consumes=None, **kwargs)[source]
+

Bases: object

+

A command wrapper for benchbuild’s commands.

+

Commands are defined by a path to an executable binary and it’s arguments. +Optional, commands can provide output and output_param parameters to +declare the Command’s output behavior.

+
+
+path
+

The binary path of the command

+
+ +
+
+\*args
+

Command arguments.

+
+ +
+
+output_param
+

A format string that encodes the output parameter argument +using the output attribute.

+

Example: output_param = f”–out {output}”. +BenchBuild will construct the output argument from this.

+
+ +
+
+output
+

An optional PathToken to declare an output file of the command.

+
+ +
+
+label
+

An optional Label that can be used to name a command.

+
+ +
+
+creates
+

A list of PathToken that encodes any artifacts that are +created by this command. +This will include the output PathToken automatically. Any +additional PathTokens provided will be provided for cleanup.

+
+ +
+
+consumes
+

A list of PathToken that holds any artifacts that will be +consumed by this command.

+
+ +
+
+\*\*kwargs
+

Any remaining kwargs will be added as environment variables +to the command.

+
+ +

Base command path: +>>> ROOT = PathToken.make_token() +>>> base_c = Command(ROOT / “bin” / “true”) +>>> base_c +Command(path=/bin/true) +>>> str(base_c) +‘/bin/true’

+

Test environment representations: +>>> env_c = Command(ROOT / “bin”/ “true”, BB_ENV_TEST=1) +>>> env_c +Command(path=/bin/true env={‘BB_ENV_TEST’: 1}) +>>> str(env_c) +‘BB_ENV_TEST=1 /bin/true’

+

Argument representations: +>>> args_c = Command(ROOT / “bin” / “true”, “–arg1”, “–arg2”) +>>> args_c +Command(path=/bin/true args=(’–arg1’, ‘–arg2’)) +>>> str(args_c) +‘/bin/true –arg1 –arg2’

+

Use str for creates: +>>> cmd = Command(ROOT / “bin” / “true”, creates=[“tmp/foo”]) +>>> cmd.creates +[<builddir>/tmp/foo]

+

Use absolute path-str for creates: +>>> cmd = Command(ROOT / “bin” / “true”, creates=[“/tmp/foo”]) +>>> cmd.creates +[/tmp/foo]

+
+
+as_plumbum(**kwargs)[source]
+

Convert this command into a plumbum compatible command.

+

This renders all tokens in the command’s path and creates a new +plumbum command with the given parameters and environment.

+
+
Parameters:
+

**kwargs (Any) – parameters passed to the path renderers.

+
+
Return type:
+

BoundEnvCommand

+
+
Returns:
+

An executable plumbum command.

+
+
+
+ +
+
+property consumes: Sequence[PathToken]
+
+ +
+
+property creates: Sequence[PathToken]
+
+ +
+
+property dirname: Path
+
+ +
+
+env(**kwargs)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+property label: str
+
+ +
+
+property name: str
+
+ +
+
+property output: PathToken | None
+
+ +
+
+property path: PathToken
+
+ +
+
+rendered_args(**kwargs)[source]
+
+
Return type:
+

Tuple[str, ...]

+
+
+
+ +
+ +
+
+class benchbuild.command.ConstStrRenderer(value)[source]
+

Bases: object

+

Renders a constant string defined by the user.

+
+
+rendered(**kwargs)[source]
+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+
+ +
+
+value: str
+
+ +
+ +
+
+class benchbuild.command.OnlyIn(rev_range, workload_set)[source]
+

Bases: object

+

Provide a filled WorkloadSet only if, given revision is inside the range.

+

This makes use of the unwrap protocol and returns the given WorkloadSet, +iff, the Project’s revision is included in the range specified by the +RevisionRange.

+
+
+rev_range: RevisionRange
+
+ +
+
+unwrap(project)[source]
+

Provide the store WorkloadSet only if our revision is in the range.

+
+
Return type:
+

WorkloadSet

+
+
+
+ +
+
+workload_set: WorkloadSet
+
+ +
+ +
+
+class benchbuild.command.PathRenderStrategy(*args, **kwargs)[source]
+

Bases: Protocol

+

Rendering strategy protocol for path components.

+
+
+rendered(**kwargs)[source]
+

Renders this strategy.

+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+

Returns an unrendered representation of this strategy.

+
+ +
+ +
+
+class benchbuild.command.PathToken(renderer, left=None, right=None)[source]
+

Bases: object

+

Base class used for command token substitution.

+

A path token can use similar to pathlib’s Path components. However, each +token can render dynamically based on the given render context.

+
+
+property dirname: Path
+
+ +
+
+exists()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+left: Optional[PathToken]
+
+ +
+
+classmethod make_token(renderer=None)[source]
+
+
Return type:
+

PathToken

+
+
+
+ +
+
+property name: str
+
+ +
+
+render(**kwargs)[source]
+

Renders the PathToken as a standard pathlib Path.

+

Any kwargs will be forwarded to the PathRenderStrategy.

+
+
Return type:
+

Path

+
+
+
+ +
+
+renderer: PathRenderStrategy
+
+ +
+
+right: Optional[PathToken]
+
+ +
+ +
+
+class benchbuild.command.ProjectCommand(project, command)[source]
+

Bases: object

+

ProjectCommands associate a command to a benchbuild project.

+

A project command can wrap the given command with the assigned +runtime extension. +If the binary is located inside a subdirectory relative to one of the +project’s sources, you can provide a path relative to it’s local +directory. +A project command will always try to resolve any reference to a local +source directory in a command’s path.

+

A call to a project command will drop the current configuration inside +the project’s build directory and confine the run into the project’s +build directory. The binary will be replaced with a wrapper that +calls the project’s runtime_extension.

+
+
+command: Command
+
+ +
+
+property path: Path
+
+ +
+
+project: benchbuild.project.Project
+
+ +
+ +
+
+benchbuild.command.ProjectRoot()
+
+
Return type:
+

PathToken

+
+
+
+ +
+
+class benchbuild.command.PruneFn(*args, **kwargs)[source]
+

Bases: Protocol

+

Prune function protocol.

+
+ +
+
+class benchbuild.command.RestoreFn(*args, **kwargs)[source]
+

Bases: Protocol

+

Restore function protocol.

+
+ +
+
+class benchbuild.command.RootRenderer[source]
+

Bases: object

+

Renders the root directory.

+
+
+rendered(**kwargs)[source]
+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+
+ +
+ +
+
+benchbuild.command.SourceRoot(local_name)
+

Create a SourceRoot token for the given name.

+
+
Parameters:
+

local_name (str) – The source’s local name to access.

+
+
Return type:
+

PathToken

+
+
+
+ +
+
+class benchbuild.command.SourceRootRenderer(local_name)[source]
+

Bases: object

+

Renders the source root of the given local source name.

+

The attribute ‘local’ refers to the local attribute in a project’s +source definition. +If the local name cannot be found inside the project’s source definition, +it will concatenate the project’s builddir with the given name.

+
+
+local: str
+
+ +
+
+rendered(project=None, **kwargs)[source]
+

Render the project’s source directory.

+

If rendering is not possible, the unrendered representation is +provided and an error will be loggged.

+
+
Parameters:
+

project (Optional[benchbuild.project.Project]) – the project to render the build directory from.

+
+
Return type:
+

Path

+
+
+
+ +
+
+property unrendered: str
+
+ +
+ +
+
+class benchbuild.command.SupportsUnwrap(*args, **kwargs)[source]
+

Bases: Protocol

+

Support unwrapping a WorkloadSet.

+

Unwrapping ensures access to a WorkloadSet from any wrapper object.

+
+
+unwrap(project)[source]
+
+
Return type:
+

WorkloadSet

+
+
+
+ +
+ +
+
+class benchbuild.command.WorkloadSet(*args)[source]
+

Bases: object

+

An immutable set of workload descriptors.

+

A WorkloadSet is immutable and usable as a key in a job mapping. +WorkloadSets support composition through intersection and union.

+

Example: +>>> WorkloadSet(1, 0) & WorkloadSet(1) +WorkloadSet({1}) +>>> WorkloadSet(1, 0) & WorkloadSet(2) +WorkloadSet({}) +>>> WorkloadSet(1, 0) | WorkloadSet(2) +WorkloadSet({0, 1, 2}) +>>> WorkloadSet(1, 0) | WorkloadSet(“1”) +WorkloadSet({0, 1, 1})

+

A workload set is not sorted, therefore, requires no comparability between +inserted values.

+
+
+unwrap(project)[source]
+

Implement the SupportsUnwrap protocol.

+

WorkloadSets only implement identity.

+
+
Return type:
+

WorkloadSet

+
+
+
+ +
+ +
+
+benchbuild.command.cleanup(project_command, backup=<function _default_backup>, restore=<function _default_restore>, prune=<function _default_prune>)[source]
+

Encapsulate a command in automatic backup, restore and prune.

+

This will wrap a ProjectCommand inside a contextmanager. All consumed +files inside the project’s build directory will be backed up by benchbuild. +You can then run your command as usual. +When you leave the context, all created paths are deleted and all consumed +paths restored.

+
+ +
+
+benchbuild.command.filter_workload_index(only, index)[source]
+

Yield only commands from the index that match the filter.

+

This removes all command lists from the index not matching only.

+
+
Return type:
+

Generator[List[Command], None, None]

+
+
+
+ +
+
+benchbuild.command.project_root()[source]
+
+
Return type:
+

PathToken

+
+
+
+ +
+
+benchbuild.command.source_root(local_name)[source]
+

Create a SourceRoot token for the given name.

+
+
Parameters:
+

local_name (str) – The source’s local name to access.

+
+
Return type:
+

PathToken

+
+
+
+ +
+
+benchbuild.command.unwrap(index, project)[source]
+

Unwrap all keys in a workload index.

+

‘Empty’ WorkloadSets will be removed. A WorkloadSet is empty, if it’s +boolean representation evaluates to False.

+
+
Return type:
+

MutableMapping[WorkloadSet, List[Command]]

+
+
+
+ +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/concepts/environments/index.html b/concepts/environments/index.html new file mode 100644 index 000000000..54a447934 --- /dev/null +++ b/concepts/environments/index.html @@ -0,0 +1,259 @@ + + + + + + + Environment + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Environment

+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/concepts/experiments/index.html b/concepts/experiments/index.html new file mode 100644 index 000000000..f32c7b75a --- /dev/null +++ b/concepts/experiments/index.html @@ -0,0 +1,260 @@ + + + + + + + Experiment + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Experiment

+

TODO.

+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/concepts/projects/index.html b/concepts/projects/index.html new file mode 100644 index 000000000..297b1d8a9 --- /dev/null +++ b/concepts/projects/index.html @@ -0,0 +1,260 @@ + + + + + + + Project + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Project

+

TODO.

+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/concepts/source/index.html b/concepts/source/index.html new file mode 100644 index 000000000..bbd60e7e3 --- /dev/null +++ b/concepts/source/index.html @@ -0,0 +1,1228 @@ + + + + + + + Source + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Source

+
+

Base

+

Provide a base interface for downloadable sources.

+
+
+class benchbuild.source.base.BaseSource(*args, **kwargs)[source]
+

Bases: Expandable, Versioned, ContextAwareSource, Protocol

+

Composition of source protocols.

+
+ +
+
+class benchbuild.source.base.ContextAwareSource(*args, **kwargs)[source]
+

Bases: Protocol

+
+
+is_context_free()[source]
+

Return, if this source needs context to evaluate it’s own +list of available versions.

+
+
Return type:
+

bool

+
+
+
+ +
+
+versions_with_context(ctx)[source]
+

Augment the given revision with new variants associated with this source.

+
+
Parameters:
+

ctx (Revision) – the project revision, containing information about every +context-free variant.

+
+
Return type:
+

Sequence[Variant]

+
+
Returns:
+

a sequence of project revisions.

+
+
+
+ +
+ +
+
+class benchbuild.source.base.ContextEnumeratorFn(*args, **kwargs)[source]
+

Bases: Protocol

+
+ +
+
+class benchbuild.source.base.ContextFreeMixin[source]
+

Bases: object

+

Make a context-free source context-aware.

+

This will setup default implementations that avoids interaction with any context.

+
+
+is_context_free()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+versions_with_context(ctx)[source]
+
+
Return type:
+

Sequence[Variant]

+
+
+
+ +
+ +
+
+class benchbuild.source.base.EnumeratorFn(*args, **kwargs)[source]
+

Bases: Protocol

+
+ +
+
+class benchbuild.source.base.Expandable(*args, **kwargs)[source]
+

Bases: Protocol

+
+
+property is_expandable: bool
+

Returns true, if this source should take part in version expansion.

+

Some sources may only be treated as virtual and would not take part +in the version expansion of an associated project.

+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.base.Fetchable(*args, **kwargs)[source]
+

Bases: Protocol

+
+
+fetch()[source]
+

Fetch the necessary source files into benchbuild’s cache.

+
+
Return type:
+

LocalPath

+
+
+
+ +
+
+property key: str
+

Return the source’s key property.

+

This provides you with a key component that identifes a single source. +It should (no guarantee) be unique among all sources for this project.

+

While this make no further assumption, but a good candidate is a +file-system name/path.

+
+ +
+
+property local: str
+

The source location (path-like) after fetching it from its remote.

+
+ +
+
+property remote: str | Dict[str, str]
+

The source location in the remote location.

+
+ +
+ +
+
+class benchbuild.source.base.FetchableSource(local, remote)[source]
+

Bases: ContextFreeMixin

+

Base class for fetchable sources.

+
+
Subclasses have to provide the following protocols:
    +
  • Expandable

  • +
  • Fetchable

  • +
  • Versioned

  • +
+
+
+
+
+abstract property default: Variant
+

The default version for this source.

+
+ +
+
+explore()[source]
+

Explore revisions of this source.

+

This provides access to all revisions this source can offer. +BenchBuild own filters will not block any revision here.

+

Custom sources or source filters can opt in to block revisions +anyways.

+
+
Returns:
+

The list of versions to explore.

+
+
Return type:
+

List[str]

+
+
+
+ +
+
+abstract fetch()[source]
+

Fetch the necessary source files into benchbuild’s cache.

+
+
Return type:
+

LocalPath

+
+
+
+ +
+
+property is_expandable: bool
+
+ +
+
+property key: str
+
+ +
+
+property local: str
+
+ +
+
+property remote: str | Dict[str, str]
+
+ +
+
+abstract version(target_dir, version)[source]
+

Fetch the requested version and place it in the target_dir

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the version should be placed in.

  • +
  • version (str) – The version that should be fetched from the local cache.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+abstract versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.base.NoSource(local, remote)[source]
+

Bases: FetchableSource

+
+
+property default: Variant
+

The default version for this source.

+
+ +
+
+fetch()[source]
+

Fetch the necessary source files into benchbuild’s cache.

+
+
Return type:
+

LocalPath

+
+
+
+ +
+
+version(target_dir, version)[source]
+

Fetch the requested version and place it in the target_dir

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the version should be placed in.

  • +
  • version (str) – The version that should be fetched from the local cache.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.base.Revision(project_cls, _primary, *variants)[source]
+

Bases: object

+

A revision captures all variants that form a single project revision.

+

A project may have an arbitrary number of input sources that are +required for it’s defined workloads, e.g., test input files, optional +dependencies, or submodules.

+

BenchBuild considers each source to have different version numbers, +encoded as “Variants”. The complete set of “Variants” for a project +then forms a project revision.

+
+
+extend(*variants)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+has_variant(name)[source]
+

Check if a variant with the given source name exists.

+
+
Parameters:
+

name (str) – The local name of the source.

+
+
Return type:
+

bool

+
+
Returns:
+

True, should a variant with the given name exists

+
+
+
+ +
+
+property primary: Variant
+
+ +
+
+project_cls: Type[Project]
+
+ +
+
+sorted()[source]
+

Return an ordered list of Variants from this revision.

+

The order is defined by the order in the SOURCE attribute of the +associated project class.

+
+
Return type:
+

Sequence[Variant]

+
+
+
+ +
+
+source_by_name(name)[source]
+

Return the source object that matches the key.

+
+
Parameters:
+

name (str) – The local name of the source.

+
+
Return type:
+

FetchableSource

+
+
Returns:
+

the found source object

+
+
Raises:
+

KeyError, if we cannot find the source with this name.

+
+
+
+ +
+
+update(revision)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+variant_by_name(name)[source]
+

Return the variant for the given source name.

+
+
Parameters:
+

name (str) – The local name of the source.

+
+
Return type:
+

Variant

+
+
Returns:
+

then version of the found source.

+
+
+
+ +
+
+variants: Sequence[Variant]
+
+ +
+ +
+
+class benchbuild.source.base.RevisionStr(value)[source]
+

Bases: object

+
+
+value: str
+
+ +
+ +
+
+class benchbuild.source.base.Variant(owner, version)[source]
+

Bases: object

+

Provide a ‘string’-like wrapper around source version information.

+

Use this, whenever you need a ‘version’ string somewhere in benchbuild. +In terms of output/logging or use as program arguments, this should not +carry more semantics than a simple version string.

+

However, this wrapper is linked to its ‘owner’. The owner serves as +the back-reference to the source code where it originated from.

+

This can serve as a ‘hook’ to deal with version information the +same way as a program variant like a specific configuraiton.

+
+
+name()[source]
+
+
Return type:
+

str

+
+
+
+ +
+
+owner: FetchableSource
+
+ +
+
+source()[source]
+
+
Return type:
+

FetchableSource

+
+
+
+ +
+
+version: str
+
+ +
+ +
+
+class benchbuild.source.base.Versioned(*args, **kwargs)[source]
+

Bases: Protocol

+
+
+property default: Variant
+

The default version for this source.

+
+ +
+
+version(target_dir, version)[source]
+

Fetch the requested version and place it in the target_dir

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the version should be placed in.

  • +
  • version (str) – The version that should be fetched from the local cache.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+benchbuild.source.base.enumerate_revisions(project_cls, context_free_enumerator=<function _default_enumerator>, context_aware_enumerator=<function _default_caw_enumerator>)[source]
+

Enumerates the given sources.

+

The enumeration requires two phases. +1. A phase for all sources that do not require a context to evaluate. +2. A phase for all sources that require a static context.

+
+
Return type:
+

Sequence[Revision]

+
+
+
+ +
+
+benchbuild.source.base.nosource()[source]
+
+
Return type:
+

NoSource

+
+
+
+ +
+
+benchbuild.source.base.primary(*sources)[source]
+

Return the implicit ‘main’ source of a project.

+

We define the main source as the first source listed in a project.

+

If you define a new project and rely on the existence of a ‘main’ +source code repository, make sure to define it as the first one.

+
+
Return type:
+

TypeVar(SourceT)

+
+
+
+ +
+
+benchbuild.source.base.product(*sources)[source]
+

Return the cross product of the given sources.

+
+
Return type:
+

Iterable[Tuple[Variant, ...]]

+
+
Returns:
+

An iterable containing the cross product of all source variants.

+
+
+
+ +
+
+benchbuild.source.base.revision_from_str(revs, project_cls)[source]
+

Create a Revision from a sequence of revision strings.

+

A valid Revision can only be created, if the number of valid revision +strings is equivalent to the number of sources. +A valid revision string is one that has been found in the a source’s +version. +It is required that each revision string is found in a different source +version.

+

We assume that the first source is the primary source of the revision.

+
+
Parameters:
+
    +
  • revs (Sequence[RevisionStr]) – sequence of revision strings, e.g. a commit-hash.

  • +
  • *sources – sources of a project.

  • +
+
+
Return type:
+

Revision

+
+
Returns:
+

A variant context.

+
+
+
+ +
+
+benchbuild.source.base.secondaries(*sources)[source]
+

Return the complement to the primary source of a project.

+
+
Return type:
+

Sequence[TypeVar(SourceT)]

+
+
Returns:
+

A list of all sources not considered primary.

+
+
+
+ +
+
+benchbuild.source.base.sources_as_dict(*sources)[source]
+

Convert fetchables to a dictionary.

+

The dictionary will be indexed by the Fetchable’s local attribute.

+
+
Parameters:
+

*sources (Fetchable) – Fetchables stored in the dictionary.

+
+
Return type:
+

Dict[str, Fetchable]

+
+
+
+ +
+
+benchbuild.source.base.target_prefix()[source]
+

Return the prefix directory for all downloads.

+
+
Returns:
+

the prefix where we download everything to.

+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.source.base.to_str(*variants)[source]
+

Convert an arbitrary number of variants into their string representation.

+
+
Return type:
+

str

+
+
Returns:
+

string representation of all input variants joined by ‘,’.

+
+
+
+ +
+
+

Git

+

Declare a git source.

+
+
+class benchbuild.source.git.Git(remote, local, clone=True, limit=10, refspec='HEAD', shallow=True, version_filter=<function Git.<lambda>>)[source]
+

Bases: FetchableSource

+

Fetch the downloadable source via git.

+
+
+property default: Variant
+

Return current HEAD as default version for this Git project.

+
+ +
+
+fetch()[source]
+

Clone the repository, if needed.

+

This will create a git clone inside the global cache directory.

+
+
Parameters:
+

version (Optional[str], optional) – [description]. Defaults to None.

+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+version(target_dir, version='HEAD')[source]
+

Create a new git worktree pointing to the requested version.

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the new worktree should live.

  • +
  • version (str) – The desired version the new worktree needs to point to. +Defaults to ‘HEAD’.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.git.GitSubmodule(remote, local, clone=True, limit=10, refspec='HEAD', shallow=True, version_filter=<function Git.<lambda>>)[source]
+

Bases: Git

+
+
+property is_expandable: bool
+

Submodules will not participate in version expansion.

+
+ +
+ +
+
+benchbuild.source.git.clone_needed(repository, repo_loc)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+benchbuild.source.git.maybe_shallow(cmd, enable)[source]
+

Conditionally add the shallow clone to the given git command.

+
+
Parameters:
+
    +
  • cmd (Any) – A git clone command (shallow doesn’t make sense anywhere else.

  • +
  • shallow (bool) – Should we add the shallow options?

  • +
+
+
Returns:
+

A new git clone command, with shallow clone enabled, if selected.

+
+
Return type:
+

Any

+
+
+
+ +
+
+

HTTP

+

Declare a http source.

+
+
+class benchbuild.source.http.HTTP(local, remote)[source]
+

Bases: FetchableSource

+

Fetch the downloadable source via http.

+
+
+property default: Variant
+

The default version for this source.

+
+ +
+
+fetch()[source]
+

Fetch via http using default version string.

+
+
Return type:
+

LocalPath

+
+
+
+ +
+
+fetch_version(version)[source]
+

Fetch via http using given version string.

+
+
Parameters:
+

version (str) – the version string to pull via http.

+
+
Return type:
+

LocalPath

+
+
Returns:
+

local path to fetched version.

+
+
+
+ +
+
+version(target_dir, version)[source]
+

Fetch the requested version and place it in the target_dir

+
+
Parameters:
+
    +
  • target_dir (str) – The filesystem path where the version should be placed in.

  • +
  • version (str) – The version that should be fetched from the local cache.

  • +
+
+
Returns:
+

[description]

+
+
Return type:
+

str

+
+
+
+ +
+
+versions()[source]
+

List all available versions of this source.

+
+
Returns:
+

The list of all available versions.

+
+
Return type:
+

List[str]

+
+
+
+ +
+ +
+
+class benchbuild.source.http.HTTPMultiple(local, remote, files)[source]
+

Bases: HTTP

+

Fetch and download multiple files via HTTP.

+
+
+fetch_version(version)[source]
+

Fetch via http using given version string.

+
+
Parameters:
+

version (str) – the version string to pull via http.

+
+
Return type:
+

LocalPath

+
+
Returns:
+

local path to fetched version.

+
+
+
+ +
+ +
+
+class benchbuild.source.http.HTTPUntar(local, remote)[source]
+

Bases: HTTP

+

Fetch and download source via http and auto-unpack using GNU tar

+
+
+version(target_dir, version)[source]
+

Setup the given version of this HTTPUntar source.

+

This will fetch the given version from the remote source and unpack the +archive into the build directory using tar.

+

The location matches the behavior of other sources. However, you need +to consider that benchbuild will return a directory instead of a file path.

+

When using workloads, you can refer to a directory with the SourceRootRenderer using +benchbuild.command.source_root. +:rtype: LocalPath

+
+

Example

+

You specify a remote version 1.0 of an archive compression.tar.gz and +a local name of “compression.tar.gz”. +The build directory will look as follows:

+

<builddir>/1.0-compression.dir/ +<builddir>/1.0-compression.tar.gz +<builddir>/compression.tar.gz -> ./1.0-compression.tar.dir

+

The content of the archive is found in the directory compression.tar.gz. +Your workloads need to make sure to reference this directory (e.g. using tokens), +e.g., source_root("compression.tar.gz")

+
+
+ +
+ +
+
+benchbuild.source.http.download_required(target_path)[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+benchbuild.source.http.download_single_version(url, target_path)[source]
+
+
Return type:
+

str

+
+
+
+ +
+
+benchbuild.source.http.normalize_remotes(remote)[source]
+
+
Return type:
+

Dict[str, str]

+
+
+
+ +
+
+benchbuild.source.http.versioned_target_name(target_name, version)[source]
+
+
Return type:
+

str

+
+
+
+ +
+
+

RSync

+
+
+

Module: source

+

Declarative API for downloading sources required by benchbuild.

+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/genindex/index.html b/genindex/index.html new file mode 100644 index 000000000..0f75a5601 --- /dev/null +++ b/genindex/index.html @@ -0,0 +1,1428 @@ + + + + + + + Index + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | K + | L + | M + | N + | O + | P + | R + | S + | T + | U + | V + | W + | Y + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

K

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ +

Y

+ + + +
+ + + +
+ +
+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 000000000..7cd76effc --- /dev/null +++ b/index.html @@ -0,0 +1,1000 @@ + + + + + + + Welcome to bencbuild’s documentation! + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Welcome to bencbuild’s documentation!

+
+

Contents:

+ +
+
+
+

Indices and tables

+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 000000000..76cb9e3ec Binary files /dev/null and b/objects.inv differ diff --git a/py-modindex/index.html b/py-modindex/index.html new file mode 100644 index 000000000..76bf1666d --- /dev/null +++ b/py-modindex/index.html @@ -0,0 +1,317 @@ + + + + + + Python Module Index + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ + +

Python Module Index

+ +
+ b +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ b
+ benchbuild +
    + benchbuild.command +
    + benchbuild.container +
    + benchbuild.environments.domain.commands +
    + benchbuild.environments.domain.declarative +
    + benchbuild.environments.domain.model +
    + benchbuild.settings +
    + benchbuild.source +
    + benchbuild.source.base +
    + benchbuild.source.git +
    + benchbuild.source.http +
    + benchbuild.source.rsync +
    + benchbuild.utils.actions +
    + benchbuild.utils.settings +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/search/index.html b/search/index.html new file mode 100644 index 000000000..856a3e26f --- /dev/null +++ b/search/index.html @@ -0,0 +1,263 @@ + + + + + + Search + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + BenchBuild + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Search

+
+

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 000000000..75e92d63d --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["CHANGELOG", "about", "advanced/cli", "advanced/index", "basics/actions", "basics/configuration", "basics/containers", "basics/index", "concepts/command", "concepts/environments", "concepts/experiments", "concepts/projects", "concepts/source", "index"], "filenames": ["CHANGELOG.md", "about.md", "advanced/cli.md", "advanced/index.md", "basics/actions.md", "basics/configuration.md", "basics/containers.md", "basics/index.md", "concepts/command.md", "concepts/environments.md", "concepts/experiments.md", "concepts/projects.md", "concepts/source.md", "index.rst"], "titles": ["6.8 (2023-10-09)", "BenchBuild Documentation", "CLI", "SLURM", "Actions", "Configure", "Containers", "Installation", "Commands", "Environment", "Experiment", "Project", "Source", "Welcome to bencbuild\u2019s documentation!"], "terms": {"ci": 0, "test": [0, 7, 8, 12], "both": [0, 4], "db": [0, 4], "support": [0, 3, 6, 7, 8, 13], "without": 0, "af7bfd90": 0, "coverag": 0, "databas": [0, 6], "enabl": [0, 12], "0b8d6034": 0, "add": [0, 1, 4, 6, 12, 13], "cli": [0, 13], "report": 0, "64ce9f87": 0, "wrap": [0, 4, 8], "binari": [0, 5, 6, 7, 8], "d4c6841d": 0, "revert": 0, "default": [0, 1, 3, 4, 5, 6, 12, 13], "set": [0, 3, 4, 6, 7, 8, 12, 13], "connect_str": 0, "sqlite": 0, "806520d6": 0, "us": [0, 1, 2, 3, 4, 5, 6, 7, 8, 12], "context": [0, 6, 8, 12, 13], "var": 0, "instead": [0, 12], "env": [0, 4, 5, 6, 8, 13], "e3ea47f0": 0, "make": [0, 1, 5, 6, 7, 8, 12], "github": [0, 8], "actual": 0, "its": [0, 6, 12, 13], "own": [0, 1, 2, 3, 4, 6, 12], "e0c7ab67": 0, "bb_coverage_path": 0, "coveragerc": 0, "141afafa": 0, "requir": [0, 3, 4, 8, 12, 13], "curli": 0, "brace": 0, "variabl": [0, 5, 6, 8], "3ae8b335": 0, "5b9c9906": 0, "action": [0, 13], "re": [0, 3, 5], "rais": [0, 4, 12], "caught": 0, "except": [0, 5], "e4bff984": 0, "close": 0, "561": 0, "environ": [0, 3, 4, 5, 7, 8, 13], "buildah": [0, 7, 13], "cannot": [0, 3, 6, 8, 12], "find": [0, 3, 4, 5, 6, 12], "base": [0, 3, 5, 6, 7, 8, 13], "imag": [0, 13], "eb03c363": 0, "run": [0, 1, 3, 6, 8, 13], "auto": [0, 12], "walru": 0, "over": [0, 5], "all": [0, 4, 5, 6, 8, 12], "benchbuild": [0, 2, 3, 4, 5, 8, 12, 13], "": [0, 4, 5, 6, 8, 12], "file": [0, 3, 5, 6, 8, 12], "79ac33d8": 0, "pre": 0, "commit": [0, 12], "hook": [0, 12], "d7a2165b": 0, "drop": [0, 8], "python": [0, 4, 7, 13], "90308f2a": 0, "updat": [0, 5, 6, 12, 13], "setup": [0, 1, 3, 6, 7, 12], "v4": 0, "3e943df6": 0, "v3": 0, "dfa4cb81": 0, "command": [0, 2, 3, 7, 12, 13], "name": [0, 4, 5, 6, 7, 8, 12, 13], "valu": [0, 3, 4, 5, 6, 8, 12, 13], "label": [0, 8, 13], "07f74dd4": 0, "forc": [0, 2, 6], "alpin": [0, 6], "17": 0, "fe5d6155": 0, "widen": 0, "allow": [0, 6], "version": [0, 4, 5, 6, 7, 12, 13], "major": [0, 1], "5d29079a": 0, "unlock": 0, "latest": [0, 6], "packag": [0, 7], "7b5a704f": 0, "enforc": 0, "global": [0, 12], "dill": 0, "modul": [0, 13], "489e3039": 0, "ha": [0, 6, 8, 12], "string": [0, 4, 5, 6, 8, 12], "7a1db742": 0, "remov": [0, 6, 8], "from": [0, 2, 5, 6, 7, 8, 12], "workflow": [0, 4], "aaabc1b5": 0, "bump": 0, "patho": 0, "unbreak": 0, "gitlab": 0, "bce45d8a": 0, "disabl": [0, 2], "mkdoc": 0, "8540f880": 0, "reorder": 0, "step": [0, 13], "74379d53": 0, "increas": 0, "verbos": [0, 5, 6, 13], "max": 0, "integ": 0, "task": [0, 1, 6], "b6625d31": 0, "privat": 0, "when": [0, 4, 5, 6, 7, 8, 12], "fetch": [0, 12, 13], "represent": [0, 5, 8, 12], "d83aa666": 0, "preserv": 0, "workload": [0, 4, 8, 12], "order": [0, 4, 5, 12], "filter": [0, 8, 12], "3648dd5e": 0, "ani": [0, 1, 5, 6, 7, 8, 12, 13], "pygit2": 0, "b09d9248": 0, "unus": 0, "code": [0, 12], "0d1c890d": 0, "pin": 0, "sqlalchemi": 0, "86d45043": 0, "do": [0, 4, 5, 6, 12], "overwrit": 0, "config": [0, 5, 6], "option": [0, 3, 5, 6, 8, 12], "i": [0, 1, 3, 4, 5, 6, 7, 8, 12], "b1a095c1": 0, "improv": 0, "error": [0, 4, 8, 13], "handl": 0, "result": [0, 4, 6], "fbb69502": 0, "slurm": [0, 13], "contain": [0, 5, 7, 12, 13], "runroot": 0, "root": [0, 4, 5, 6, 8], "avail": [0, 5, 6, 8, 12, 13], "custom": [0, 6, 12, 13], "616a4c69": 0, "528": 0, "sourc": [0, 1, 4, 5, 6, 7, 8, 13], "sure": [0, 5, 6, 12], "we": [0, 4, 5, 6, 7, 8, 12], "manag": [0, 1, 3, 6, 7], "archiv": [0, 6, 12], "symlink": [0, 7], "properli": [0, 6], "7687f0e3": 0, "http": [0, 8, 13], "untar": 0, "84f90e75": 0, "miss": 0, "log": [0, 4, 12], "import": [0, 6, 7, 8], "aad1b287": 0, "err": 0, "19c5983c": 0, "notifi": 0, "user": [0, 5, 6, 7, 8], "fail": [0, 4], "78b890af": 0, "project": [0, 4, 6, 12, 13], "should": [0, 1, 4, 5, 6, 7, 12], "onli": [0, 1, 4, 5, 6, 7, 8, 12], "consid": [0, 6, 7, 12], "expand": [0, 4, 12, 13], "3d546314": 0, "sort": [0, 8, 12, 13], "revis": [0, 4, 8, 12, 13], "ca973ff0": 0, "project_cl": [0, 12, 13], "enumerate_revis": [0, 12, 13], "interfac": [0, 6, 12], "awar": [0, 12], "singleversionfilt": 0, "print": [0, 4, 6], "free": [0, 12], "public": 0, "api": [0, 6, 12], "introduc": 0, "type": [0, 4, 5, 6, 8, 12], "skeleton": 0, "prototyp": 0, "enumer": [0, 6, 12], "replac": [0, 8, 13], "stepclass": 0, "metaclass": 0, "init_subclass": 0, "mark": [0, 4], "stepti": 0, "covari": [0, 4], "stepabl": 0, "protocol": [0, 8, 12], "bound": [0, 4], "accept": 0, "vararg": 0, "call": [0, 2, 5, 6, 8], "implement": [0, 4, 6, 8, 12], "exactli": 0, "linter": 0, "warn": [0, 5], "debug": 0, "util": [0, 4, 8, 13], "variant": [0, 4, 12, 13], "repair": 0, "after": [0, 4, 6, 8, 12], "variantcontext": 0, "runtime_check": 0, "decor": 0, "class": [0, 4, 5, 6, 8, 12], "object": [0, 4, 5, 6, 7, 8, 12], "return": [0, 4, 5, 6, 8, 12], "sequenc": [0, 6, 8, 12], "nestedvari": 0, "clean": [0, 13], "up": [0, 1, 6, 8], "renam": 0, "stepty_co": [0, 4], "notify_step_begin_end": 0, "reduc": 0, "mypi": 0, "mutabl": 0, "gener": [0, 3, 4, 5, 7, 8], "baseversiongroup": 0, "expandableandfetchablesourc": 0, "multistep": [0, 4, 13], "render": [0, 8, 13], "unrender": 0, "pathtoken": [0, 8, 13], "explicit": 0, "safeguard": 0, "prune": [0, 8], "backup": [0, 8], "enable_rollback": 0, "creat": [0, 4, 5, 6, 8, 12, 13], "consum": [0, 8, 13], "properti": [0, 1, 4, 5, 6, 8, 12], "switch": 0, "workloadset": [0, 8, 13], "kwarg": [0, 6, 8, 12, 13], "exampl": [0, 4, 8], "onlyin": [0, 8, 13], "strictli": 0, "less": [0, 6], "than": [0, 3, 6, 12], "9": [0, 5, 7], "_is_relative_to": 0, "where": [0, 1, 3, 6, 12], "need": [0, 4, 5, 6, 7, 12], "guard": 0, "is_relative_to": 0, "els": [0, 6, 12], "depend": [0, 1, 6, 7, 12], "path": [0, 5, 6, 8, 12, 13], "python3": [0, 6], "happi": 0, "callabl": [0, 4, 6], "callback": [0, 8], "function": [0, 5, 8, 12], "getitem": 0, "constructor": 0, "wrong": 0, "self": [0, 4], "_label": 0, "str": [0, 4, 5, 6, 8, 12], "assign": [0, 4, 5, 8], "attribut": [0, 4, 6, 8, 12], "missing_ok": 0, "unlink": 0, "test_command": 0, "pickl": 0, "abl": [0, 6, 7], "pytest": 0, "git": [0, 8, 13], "might": [0, 3], "none": [0, 4, 5, 6, 8, 12], "access": [0, 3, 5, 8, 12], "cach": [0, 12], "builddir": [0, 6, 8, 12, 13], "supportsunwrap": [0, 8, 13], "cleanup": [0, 4, 8, 13], "nullrender": 0, "rootrender": [0, 8, 13], "token": [0, 12, 13], "logic": 0, "convert": [0, 5, 6, 8, 12], "scimark2": 0, "migrat": [0, 5], "clear": 0, "tracker": 0, "fresh": 0, "projectenviron": [0, 13], "avoid": [0, 5, 6, 12], "same": [0, 5, 6, 12], "twice": [0, 4], "job": [0, 5, 8], "runjob": 0, "anywher": [0, 12], "part": [0, 12], "pass": [0, 6, 8], "plumbum": [0, 8], "arg": [0, 6, 8, 12, 13], "declar": [0, 4, 8, 12, 13], "wip": 0, "fetchablesourc": [0, 12, 13], "deriv": 0, "tag": [0, 5, 6], "accessor": 0, "xz": 0, "must": 0, "x264": 0, "broken": 0, "check": [0, 4, 5, 6, 7, 12], "exist": [0, 1, 3, 5, 6, 8, 12, 13], "target": [0, 6, 13], "compil": [0, 1, 5, 8, 13], "run_test": 0, "definit": [0, 8, 13], "typing_extens": 0, "protocl": 0, "provid": [0, 1, 3, 4, 5, 6, 7, 8, 12], "map": [0, 5, 6, 8], "strip": 0, "previou": 0, "draft": 0, "workaround": 0, "correct": 0, "sprefix": 0, "stepresult": [0, 4, 13], "store": [0, 5, 6, 8, 12, 13], "tupl": [0, 4, 5, 6, 8, 12], "bzip2": 0, "marker": 0, "statu": [0, 4, 13], "experi": [0, 3, 6, 8, 13], "initi": [0, 4, 5, 6], "cleanextra": [0, 13], "correctli": 0, "oci_compli": 0, "list": [0, 5, 6, 8, 12], "scalar": [0, 5], "convers": 0, "lower": [0, 6], "case": [0, 3, 6, 13], "unnecessari": 0, "ellipsi": 0, "instanc": [0, 8], "descriptor": [0, 8], "new": [0, 1, 4, 5, 6, 8, 12], "impl": 0, "simpl": [0, 5, 12], "intersect": [0, 8], "chang": [0, 3, 4, 6], "registr": 0, "style": 0, "abstract": [0, 6, 8, 12], "method": [0, 6], "gzip": 0, "enter": 0, "interact": [0, 6, 12], "mode": 0, "typo": 0, "undo": 0, "obj": 0, "rebas": 0, "useless": 0, "throw": 0, "revisionstr": [0, 12, 13], "match": [0, 4, 8, 12], "explor": [0, 12, 13], "partial": 0, "setprojectvers": [0, 13], "context_from_revis": 0, "an": [0, 3, 4, 5, 6, 7, 8, 12, 13], "easi": 0, "wai": [0, 4, 6, 8, 12], "adapt": 0, "argument": [0, 6, 8, 12], "runprojectcontain": [0, 6, 13], "track": 0, "active_vari": 0, "multivers": 0, "mixin": 0, "activ": [0, 7], "link": [0, 12], "locat": [0, 6, 8, 12], "addprojectvers": 0, "obsolet": [0, 7], "paramet": [0, 4, 5, 6, 8, 12], "attr": 0, "ey": 0, "break": 0, "align": 0, "entrypoint": [0, 6, 13], "suppli": 0, "dedic": [0, 7], "subcommand": [0, 6], "factori": 0, "directori": [0, 4, 5, 6, 8, 12, 13], "obviou": 0, "pylint": 0, "almost": 0, "abc": [0, 6], "unbuff": [0, 2], "watch": [0, 2], "remot": [0, 6, 8, 12, 13], "434": 0, "force_tti": 0, "control": [0, 1, 6], "richhandl": 0, "435": 0, "schema": [0, 4], "silenc": 0, "sawarn": 0, "about": [0, 1, 6, 12], "428": 0, "format": [0, 8], "427": 0, "rich": 0, "stderr": 0, "415": 0, "bb_env": 0, "ignor": [0, 6], "load": [0, 3, 5, 6, 13], "414": 0, "consist": [0, 5], "behavior": [0, 4, 8, 12], "creation": [0, 6], "just": [0, 4, 6], "messag": [0, 4, 6, 13], "too": 0, "long": [0, 1], "libpod": 0, "number": [0, 5, 12], "tune": 0, "down": 0, "build": [0, 4, 6, 8, 12], "more": [0, 3, 4, 6, 12], "output": [0, 2, 4, 5, 6, 8, 12, 13], "through": [0, 4, 8], "rmi": 0, "delet": [0, 8], "stand": 0, "out": [0, 4, 6, 8], "clearli": 0, "g": [0, 4, 6, 8, 12], "split": 0, "image_exist": 0, "entiti": 0, "basic": [0, 6, 13], "emit": 0, "layer": [0, 6, 13], "event": [0, 6, 13], "construct": [0, 5, 6, 8], "progress": 0, "hashabl": [0, 6], "wise": 0, "repositori": [0, 6, 12], "unit": 0, "work": [0, 6], "each": [0, 4, 5, 6, 8, 12], "customiz": [0, 8], "templat": [0, 13], "detail": 0, "view": 0, "singl": [0, 4, 12], "condens": 0, "export": [0, 3, 6], "flag": [0, 6], "unshallow": 0, "clone": [0, 12], "befor": [0, 4, 6, 8], "dissoci": 0, "left": [0, 8, 13], "podman": [0, 7, 13], "reus": [0, 6], "bar": 0, "structur": [0, 5, 6], "other": [0, 6, 8, 12], "annot": 0, "turpl": 0, "baild": 0, "rework": 0, "handler": 0, "copi": [0, 3, 6], "sy": 0, "maybecontain": 0, "modifi": [0, 3, 5, 6], "slurm_node_dir": 0, "deal": [0, 12], "multi": 0, "line": [0, 8], "id": 0, "spawn": [0, 6], "fromlay": [0, 6, 13], "print_lay": 0, "neutral": 0, "element": 0, "multipl": [0, 4, 12], "group": [0, 13], "explicitli": 0, "state": 0, "registri": [0, 6], "conffigur": 0, "local": [0, 8, 12, 13], "lookup": 0, "possibl": [0, 5, 8], "unbound": 0, "cli_process": 0, "rmeov": 0, "some": [0, 4, 12], "functool": 0, "closur": 0, "unsplit": 0, "enviro": 0, "count": 0, "document": [0, 6], "print_project": 0, "set_limit": 0, "limit": [0, 8, 12], "better": 0, "layout": 0, "inform": [0, 1, 6, 12], "field": 0, "plugin": 0, "spam": 0, "higher": 0, "level": [0, 3], "open": 1, "toolkit": 1, "help": [1, 2], "softwar": [1, 7], "driven": 1, "empir": 1, "wa": 1, "specif": [1, 12], "defin": [1, 4, 5, 6, 8, 12], "reusabl": 1, "between": [1, 8], "differ": [1, 4, 6, 12], "It": [1, 7, 12], "mainli": 1, "assist": [1, 6, 7], "follow": [1, 4, 5, 6, 7, 8, 12], "standard": [1, 6, 8], "found": [1, 6, 8, 12], "bodi": 1, "main": [1, 6, 12, 13], "mind": 1, "If": [1, 3, 4, 5, 6, 7, 8, 12], "you": [1, 3, 4, 5, 6, 7, 8, 12], "never": 1, "have": [1, 3, 4, 6, 7, 8, 12], "reli": [1, 12], "background": 1, "ar": [1, 4, 5, 6, 7, 8, 12], "concern": 1, "execut": [1, 4, 6, 8], "dure": [1, 4], "time": [1, 4, 5], "what": [1, 8], "can": [1, 2, 3, 4, 5, 6, 7, 8, 12], "intercept": 1, "ad": [1, 6, 8], "knowledg": [1, 6], "take": [1, 4, 5, 12], "care": [1, 4], "process": [1, 6], "procedur": [1, 7], "given": [1, 5, 6, 8, 12], "thi": [1, 2, 3, 4, 5, 6, 7, 8, 12], "being": 1, "done": [1, 3, 4, 6, 8], "extens": [1, 4, 8], "point": [1, 3, 6, 8, 12], "3": [1, 4, 5, 7, 13], "7": [1, 5, 7, 13], "8": [1, 5, 6, 7, 13], "develop": 1, "focus": 1, "effort": 1, "made": 1, "distribut": 1, "like": [1, 5, 12], "debian": 1, "linux": 1, "ship": 1, "see": [1, 3, 6], "instal": [1, 6, 13], "guid": 1, "quickli": 1, "buffer": 2, "tool": [2, 6, 7], "high": 3, "integr": 3, "cluster": [3, 7], "resourc": [3, 5], "bash": [3, 6], "script": [3, 7], "assum": [3, 6, 12], "configur": [3, 4, 8, 13], "benchbuid": 3, "sbatch": [3, 7], "your": [3, 4, 6, 7, 8, 12], "todo": [3, 4, 10, 11], "recommend": 3, "howev": [3, 6, 8, 12], "situat": 3, "complic": 3, "misc": 3, "sh": 3, "inc": 3, "The": [3, 4, 5, 6, 7, 8, 12], "bb_slurm_templ": 3, "detect": 3, "filesystem": [3, 6, 12], "No": [3, 5], "valid": [3, 5, 6, 12, 13], "risk": 3, "suit": 4, "most": 4, "A": [4, 5, 6, 8, 12, 13], "per": 4, "those": 4, "whenev": [4, 5, 12], "expeir": 4, "def": 4, "actions_for_project": 4, "usual": [4, 6, 8], "box": 4, "insid": [4, 6, 12, 13], "determin": [4, 6], "sometim": [4, 6], "comparison": 4, "achiev": 4, "usag": [4, 13], "happen": 4, "souc": 4, "exact": 4, "again": 4, "is_expand": [4, 12, 13], "enhanc": 4, "oper": 4, "put": 4, "descript": [4, 12, 13], "classvar": 4, "question": 4, "ask": 4, "check_empti": 4, "fals": [4, 5, 8], "projectstep": [4, 13], "tp": [4, 6], "static": [4, 5, 12], "clean_mountpoint": [4, 13], "unmount": 4, "remain": [4, 8], "mountpoint": [4, 6], "under": 4, "unionf": [4, 7], "extra": 4, "transact": 4, "begin_transact": [4, 13], "end_transact": [4, 13], "session": 4, "mkdir": 4, "one": [4, 5, 6, 8, 12], "e": [4, 5, 6, 7, 8, 12], "everyth": [4, 12], "regardless": 4, "upon": 4, "first": [4, 6, 12], "mutablesequ": 4, "typevar": [4, 12], "true": [4, 5, 6, 7, 8, 12], "onerror": [4, 13], "doe": [4, 6], "noth": [4, 6], "prepar": [4, 6], "stopiter": 4, "encapsul": [4, 8], "substep": 4, "child": 4, "succe": 4, "runworkload": [4, 13], "workload_ref": [4, 13], "run_onli": 4, "revision_str": 4, "checkout": [4, 6], "intenum": 4, "can_continu": [4, 13], "2": [4, 5, 6, 7, 8, 12, 13], "ok": [4, 13], "1": [4, 5, 6, 7, 8, 12, 13], "unset": [4, 13], "0": [4, 5, 7, 8, 12, 13], "log_before_aft": [4, 13], "desc": 4, "func": [4, 6, 13], "prepend_statu": [4, 13], "prepend": [4, 6, 13], "run_any_child": [4, 13], "step_has_fail": [4, 13], "error_statu": 4, "bool": [4, 5, 6, 8, 12], "dictionari": [5, 6, 12], "via": [5, 7, 12], "encod": [5, 8, 12], "tree": 5, "inner": 5, "node": 5, "leaf": 5, "repres": [5, 6], "kei": [5, 6, 7, 8, 12, 13], "configdump": [5, 13], "stream": 5, "default_styl": 5, "default_flow_styl": 5, "canon": 5, "indent": 5, "width": 5, "allow_unicod": 5, "line_break": 5, "explicit_start": 5, "explicit_end": 5, "sort_kei": 5, "safedump": 5, "pollut": 5, "yaml": 5, "namespac": [5, 6], "our": [5, 6, 8], "modif": 5, "yaml_implicit_resolv": [5, 13], "org": 5, "2002": 5, "null": 5, "n": 5, "float": 5, "9_": 5, "ee": 5, "5": [5, 13], "int": 5, "0b": 5, "1_": 5, "7_": 5, "0x": 5, "9a": 5, "fa": 5, "f_": 5, "timestamp": 5, "tt": 5, "t": [5, 12, 13], "4": [5, 13], "6": [5, 6, 7, 13], "merg": 5, "f": [5, 8], "ye": 5, "NO": 5, "On": 5, "ON": 5, "off": [5, 6], "o": 5, "y": 5, "uuid": 5, "b": 5, "f0": 5, "12": [5, 13], "yaml_represent": [5, 13], "nonetyp": 5, "saferepresent": 5, "represent_non": 5, "configpath": [5, 13], "path_represent": [5, 13], "represent_bool": 5, "byte": 5, "represent_binari": 5, "datetim": 5, "date": 5, "represent_d": 5, "represent_datetim": 5, "dict": [5, 6, 12], "represent_dict": 5, "represent_float": 5, "represent_int": 5, "represent_list": 5, "represent_set": 5, "represent_str": 5, "uuid_represent": [5, 13], "represent_undefin": 5, "configload": [5, 13], "csafeload": 5, "yaml_constructor": [5, 13], "path_constructor": [5, 13], "uuid_constructor": [5, 13], "safeconstructor": 5, "construct_yaml_binari": 5, "construct_yaml_bool": 5, "construct_yaml_float": 5, "construct_yaml_int": 5, "construct_yaml_map": 5, "construct_yaml_nul": 5, "omap": 5, "construct_yaml_omap": 5, "pair": [5, 6], "construct_yaml_pair": 5, "seq": 5, "construct_yaml_seq": 5, "construct_yaml_set": 5, "construct_yaml_str": 5, "construct_yaml_timestamp": 5, "construct_undefin": 5, "compon": [5, 6, 8, 12], "wrapper": [5, 8, 12], "around": [5, 12], "path_to_str": [5, 13], "parent_kei": 5, "parent": 5, "init": 5, "index": [5, 8, 12, 13], "data": 5, "serv": [5, 12], "throughout": 5, "subtre": 5, "automat": [5, 6, 8], "cfg": [5, 6], "build_dir": [5, 6, 13], "becom": 5, "bb_build_dir": 5, "llvm": 5, "dir": [5, 12], "bb_llvm_dir": 5, "filter_export": [5, 13], "has_default": [5, 13], "has_valu": [5, 13], "init_from_env": [5, 13], "comput": 5, "otherwis": [5, 6], "children": 5, "is_leaf": [5, 13], "_from": 5, "config_fil": 5, "to_env_dict": [5, 13], "flat": 5, "invalidconfigkei": [5, 13], "runtimewarn": 5, "non": 5, "available_cpu_count": [5, 13], "get": [5, 6, 7, 13], "cpu": 5, "virtual": [5, 6, 7, 12], "physic": 5, "system": [5, 6, 7, 12], "real": 5, "optim": 5, "scale": 5, "userspac": 5, "program": [5, 12], "avaial": 5, "convert_compon": [5, 13], "current_available_thread": [5, 13], "current": [5, 6, 8, 12], "thread": 5, "bb": 5, "escape_yaml": [5, 13], "raw_str": 5, "shell": [5, 6, 13], "escap": 5, "input": [5, 6, 12], "unescap": 5, "find_config": [5, 13], "test_fil": 5, "look": [5, 8, 12], "start": [5, 6, 13], "recurs": 5, "until": 5, "absolut": [5, 6, 8], "anyth": [5, 6], "localpath": [5, 12], "get_number_of_job": [5, 13], "is_yaml": [5, 13], "cfg_file": 5, "loader": 5, "form": [5, 12], "dumper": 5, "setup_config": [5, 13], "config_filenam": 5, "env_var_nam": 5, "_not_": 5, "preced": 5, "right": [5, 7, 8, 13], "now": [5, 6, 7, 8], "refus": 5, "alreadi": [5, 6], "filenam": [5, 6], "hold": [5, 8], "to_env_var": [5, 13], "env_var": 5, "compat": [5, 8], "to_yaml": [5, 13], "update_env": [5, 6, 13], "upgrad": [5, 13], "forward": [5, 8], "uuid_add_implicit_resolv": [5, 13], "attach": 5, "implicit": [5, 12], "pattern": 5, "resolv": [5, 8], "want": [6, 7], "simpli": 6, "select": [6, 12], "raw": 6, "linpack": 6, "stage": 6, "necessari": [6, 7, 12], "know": [6, 13], "how": 6, "few": [6, 7], "These": [6, 8], "bring": 6, "For": [6, 8], "relev": 6, "rebuild": 6, "uncondition": 6, "bb_container_export": 6, "By": 6, "Will": 6, "bb_container_import": 6, "bb_container_from_sourc": 6, "pip": [6, 7], "bb_container_root": 6, "subuid": 6, "gid": 6, "nf": 6, "lib": 6, "bb_container_runroot": 6, "temporari": 6, "restrict": 6, "bb_container_runtim": 6, "oci": [6, 7], "launch": 6, "crun": 6, "been": [6, 8, 12], "usr": 6, "bin": [6, 7, 8], "bb_container_mount": 6, "With": 6, "arbitrari": [6, 12], "containerimag": [6, 13], "testproject": 6, "from_": [6, 13], "dockerfil": 6, "beforehand": 6, "formul": 6, "backend": 6, "19": 6, "hand": 6, "rootless": 6, "daemon": 6, "subordin": 6, "uid": 6, "permiss": 6, "pleas": 6, "refer": [6, 8, 12], "uchroot": [6, 7], "strategi": [6, 8, 13], "appli": 6, "them": 6, "fix": [6, 13], "space": [6, 7], "bashstrategi": [6, 13], "containerstrategi": [6, 13], "applic": 6, "tmpdir": 6, "input_fil": [6, 13], "_contain": 6, "me": 6, "super": 6, "mount": [6, 13], "user_mount": 6, "save": 6, "output_fil": [6, 13], "write": 6, "chroot": 6, "custom_shel": 6, "containerbootstrap": [6, 13], "install_cmake_and_exit": [6, 13], "tell": 6, "cmake": 6, "abort": 6, "containercr": [6, 13], "predefin": 6, "offer": [6, 8, 12], "varieti": 6, "polici": 6, "leav": [6, 8], "extract": 6, "exit": 6, "pack": 6, "containerlist": [6, 13], "known": [6, 8], "containerrun": [6, 13], "commannd": 6, "prebuilt": 6, "chosen": 6, "mockobj": [6, 13], "setuppolyjitgentoostrategi": [6, 13], "gentoo": 6, "suitabl": 6, "polyjit": 6, "clean_directori": [6, 13], "in_dir": 6, "out_dir": 6, "confirm": 6, "find_hash": [6, 13], "container_db": 6, "entri": 6, "pack_contain": [6, 13], "in_contain": 6, "out_fil": 6, "tar": [6, 12], "bz2": 6, "run_in_contain": [6, 13], "container_dir": 6, "tri": [6, 7], "set_input_contain": [6, 13], "setup_bash_in_contain": [6, 13], "outfil": 6, "which": [6, 7], "also": 6, "afterward": 6, "setup_contain": [6, 13], "setup_directori": [6, 13], "container": 6, "give": 6, "full": 6, "concept": 6, "mai": [6, 12], "apk": 6, "iter": [6, 12], "tgt": 6, "syntax": 6, "cmd": [6, 8, 12], "artifact": [6, 8], "copy_": [6, 13], "base_imag": 6, "specifi": [6, 8, 12], "addit": [6, 8], "workingdir": [6, 13], "cwd": 6, "add_benchbuild_lay": [6, 13], "depen": 6, "either": 6, "mirror": 6, "complet": [6, 12], "bind": 6, "addlay": [6, 13], "destin": [6, 13], "container_id": [6, 13], "_noth": 6, "contextlay": [6, 13], "copylay": [6, 13], "layer_index": [6, 13], "append": [6, 13], "is_complet": [6, 13], "is_pres": [6, 13], "layerst": [6, 13], "present": [6, 13], "sens": [6, 12], "thei": [6, 7], "lead": 6, "statement": 6, "enum": 6, "absent": [6, 13], "runlay": [6, 13], "setcommand": [6, 13], "updateenv": [6, 13], "workingdirectori": [6, 13], "immutable_kwarg": [6, 13], "createbenchbuildbas": [6, 13], "createimag": [6, 13], "deleteimag": [6, 13], "exportimag": [6, 13], "out_nam": [6, 13], "importimag": [6, 13], "in_path": [6, 13], "fs_compliant_nam": [6, 13], "oci_compliant_nam": [6, 13], "compliant": 6, "foo": [6, 8], "instruct": 7, "against": 7, "ubuntu": 7, "20": 7, "04": [7, 13], "particular": 7, "below": 7, "alwai": [7, 8], "mandatori": 7, "minimum": 7, "note": 7, "libpq": 7, "psycopg2": 7, "libfus": 7, "llnl": 7, "18": 7, "08": [7, 13], "librari": 7, "becaus": 7, "featur": [7, 8, 13], "intern": 7, "plan": 7, "rid": 7, "futur": 7, "often": 7, "conjunct": 7, "legaci": 7, "soon": 7, "stabl": 7, "As": 7, "altern": 7, "machin": 7, "srun": 7, "signal": 7, "expect": 7, "batch": 7, "releas": 7, "isol": 7, "rest": 7, "virtualenv": 7, "ppython3": 7, "venv_path": 7, "pip3": 7, "carri": [8, 12], "paramt": 8, "dynam": 8, "besid": 8, "behav": 8, "ident": 8, "let": 8, "sourceroot": [8, 13], "myproject": 8, "com": 8, "refspec": [8, 12], "head": [8, 12], "compress": [8, 12], "myprj": 8, "here": [8, 12], "belong": 8, "concret": 8, "One": 8, "abov": 8, "author": 8, "argsrenderstrategi": [8, 13], "unrend": [8, 13], "argstoken": [8, 13], "classmethod": 8, "make_token": [8, 13], "pathlib": 8, "pathrenderstrategi": [8, 13], "backupfn": [8, 13], "builddirrender": [8, 13], "logg": 8, "output_param": [8, 13], "includ": 8, "base_c": 8, "env_c": 8, "bb_env_test": 8, "args_c": 8, "arg1": 8, "arg2": 8, "tmp": 8, "as_plumbum": [8, 13], "boundenvcommand": 8, "dirnam": [8, 13], "rendered_arg": [8, 13], "conststrrender": [8, 13], "constant": 8, "rev_rang": [8, 13], "workload_set": [8, 13], "fill": 8, "rang": 8, "unwrap": [8, 13], "iff": 8, "revisionrang": 8, "substitut": 8, "similar": 8, "projectcommand": [8, 13], "associ": [8, 12], "runtim": [8, 13], "subdirectori": 8, "rel": 8, "try": 8, "confin": 8, "runtime_extens": 8, "projectroot": [8, 13], "prunefn": [8, 13], "restorefn": [8, 13], "restor": 8, "local_nam": 8, "sourcerootrender": [8, 12, 13], "concaten": 8, "ensur": 8, "immut": 8, "usabl": 8, "composit": [8, 12], "union": 8, "therefor": 8, "compar": 8, "insert": 8, "project_command": 8, "_default_backup": 8, "_default_restor": 8, "_default_prun": 8, "contextmanag": 8, "back": [8, 12], "filter_workload_index": [8, 13], "yield": 8, "project_root": [8, 13], "source_root": [8, 12, 13], "empti": 8, "boolean": 8, "evalu": [8, 12], "mutablemap": 8, "download": 12, "basesourc": [12, 13], "contextawaresourc": [12, 13], "is_context_fre": [12, 13], "versions_with_context": [12, 13], "ctx": 12, "augment": 12, "everi": 12, "contextenumeratorfn": [12, 13], "contextfreemixin": [12, 13], "enumeratorfn": [12, 13], "expans": 12, "treat": 12, "would": 12, "fetchabl": [12, 13], "identif": 12, "guarante": 12, "uniqu": 12, "among": 12, "while": 12, "further": 12, "assumpt": 12, "good": 12, "candid": 12, "subclass": 12, "block": 12, "opt": 12, "anywai": 12, "target_dir": 12, "request": 12, "place": 12, "nosourc": [12, 13], "_primari": 12, "captur": 12, "submodul": 12, "extend": [12, 13], "has_vari": [12, 13], "primari": [12, 13], "source_by_nam": [12, 13], "keyerror": 12, "variant_by_nam": [12, 13], "owner": [12, 13], "somewher": 12, "In": 12, "term": 12, "semant": 12, "origin": 12, "configuraiton": 12, "context_free_enumer": 12, "_default_enumer": 12, "context_aware_enumer": 12, "_default_caw_enumer": 12, "two": 12, "phase": 12, "sourcet": 12, "product": [12, 13], "cross": 12, "revision_from_str": [12, 13], "rev": 12, "equival": 12, "hash": 12, "secondari": [12, 13], "complement": 12, "sources_as_dict": [12, 13], "target_prefix": [12, 13], "prefix": 12, "to_str": [12, 13], "join": 12, "10": [12, 13], "shallow": 12, "version_filt": 12, "lambda": 12, "worktre": 12, "live": 12, "desir": 12, "gitsubmodul": [12, 13], "particip": 12, "clone_need": [12, 13], "repo_loc": 12, "maybe_shallow": [12, 13], "condition": 12, "doesn": [12, 13], "fetch_vers": [12, 13], "pull": 12, "httpmultipl": [12, 13], "httpuntar": [12, 13], "unpack": 12, "gnu": 12, "rtype": 12, "gz": 12, "content": 12, "download_requir": [12, 13], "target_path": 12, "download_single_vers": [12, 13], "url": 12, "normalize_remot": [12, 13], "versioned_target_nam": [12, 13], "target_nam": 12, "design": 13, "philosophi": 13, "studi": 13, "postgresql": 13, "fuse": 13, "bootstrap": 13, "domain": 13, "model": 13, "makebuilddir": 13, "echo": 13, "requireal": 13, "rsync": 13, "2023": 13, "09": 13, "bug": 13, "changelog": 13, "03": 13, "16": 13, "06": 13, "01": 13, "2022": 13, "11": 13, "feat": 13, "refactor": 13, "21": 13, "02": 13, "2021": 13, "15": 13, "26": 13, "07": 13, "29": 13, "05": 13, "2020": 13, "search": 13, "page": 13}, "objects": {"benchbuild": [[8, 0, 0, "-", "command"], [6, 0, 0, "-", "container"], [5, 0, 0, "-", "settings"], [12, 0, 0, "-", "source"]], "benchbuild.command": [[8, 1, 1, "", "ArgsRenderStrategy"], [8, 1, 1, "", "ArgsToken"], [8, 1, 1, "", "BackupFn"], [8, 1, 1, "", "BuilddirRenderer"], [8, 1, 1, "", "Command"], [8, 1, 1, "", "ConstStrRenderer"], [8, 1, 1, "", "OnlyIn"], [8, 1, 1, "", "PathRenderStrategy"], [8, 1, 1, "", "PathToken"], [8, 1, 1, "", "ProjectCommand"], [8, 5, 1, "", "ProjectRoot"], [8, 1, 1, "", "PruneFn"], [8, 1, 1, "", "RestoreFn"], [8, 1, 1, "", "RootRenderer"], [8, 5, 1, "", "SourceRoot"], [8, 1, 1, "", "SourceRootRenderer"], [8, 1, 1, "", "SupportsUnwrap"], [8, 1, 1, "", "WorkloadSet"], [8, 5, 1, "", "cleanup"], [8, 5, 1, "", "filter_workload_index"], [8, 5, 1, "", "project_root"], [8, 5, 1, "", "source_root"], [8, 5, 1, "", "unwrap"]], "benchbuild.command.ArgsRenderStrategy": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.ArgsToken": [[8, 2, 1, "", "make_token"], [8, 2, 1, "", "render"], [8, 4, 1, "", "renderer"]], "benchbuild.command.BuilddirRenderer": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.Command": [[8, 2, 1, "", "as_plumbum"], [8, 3, 1, "id0", "consumes"], [8, 3, 1, "id1", "creates"], [8, 3, 1, "", "dirname"], [8, 2, 1, "", "env"], [8, 3, 1, "id2", "label"], [8, 3, 1, "", "name"], [8, 3, 1, "id3", "output"], [8, 4, 1, "", "output_param"], [8, 3, 1, "id4", "path"], [8, 2, 1, "", "rendered_args"]], "benchbuild.command.ConstStrRenderer": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"], [8, 4, 1, "", "value"]], "benchbuild.command.OnlyIn": [[8, 4, 1, "", "rev_range"], [8, 2, 1, "", "unwrap"], [8, 4, 1, "", "workload_set"]], "benchbuild.command.PathRenderStrategy": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.PathToken": [[8, 3, 1, "", "dirname"], [8, 2, 1, "", "exists"], [8, 4, 1, "", "left"], [8, 2, 1, "", "make_token"], [8, 3, 1, "", "name"], [8, 2, 1, "", "render"], [8, 4, 1, "", "renderer"], [8, 4, 1, "", "right"]], "benchbuild.command.ProjectCommand": [[8, 4, 1, "", "command"], [8, 3, 1, "", "path"], [8, 4, 1, "", "project"]], "benchbuild.command.RootRenderer": [[8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.SourceRootRenderer": [[8, 4, 1, "", "local"], [8, 2, 1, "", "rendered"], [8, 3, 1, "", "unrendered"]], "benchbuild.command.SupportsUnwrap": [[8, 2, 1, "", "unwrap"]], "benchbuild.command.WorkloadSet": [[8, 2, 1, "", "unwrap"]], "benchbuild.container": [[6, 1, 1, "", "BashStrategy"], [6, 1, 1, "", "Container"], [6, 1, 1, "", "ContainerBootstrap"], [6, 1, 1, "", "ContainerCreate"], [6, 1, 1, "", "ContainerList"], [6, 1, 1, "", "ContainerRun"], [6, 1, 1, "", "ContainerStrategy"], [6, 1, 1, "", "MockObj"], [6, 1, 1, "", "SetupPolyJITGentooStrategy"], [6, 5, 1, "", "clean_directories"], [6, 5, 1, "", "find_hash"], [6, 5, 1, "", "main"], [6, 5, 1, "", "pack_container"], [6, 5, 1, "", "run_in_container"], [6, 5, 1, "", "set_input_container"], [6, 5, 1, "", "setup_bash_in_container"], [6, 5, 1, "", "setup_container"], [6, 5, 1, "", "setup_directories"]], "benchbuild.container.BashStrategy": [[6, 2, 1, "", "run"]], "benchbuild.container.Container": [[6, 4, 1, "", "VERSION"], [6, 2, 1, "", "builddir"], [6, 2, 1, "", "input_file"], [6, 2, 1, "", "main"], [6, 2, 1, "", "mounts"], [6, 2, 1, "", "output_file"], [6, 2, 1, "", "shell"], [6, 4, 1, "", "verbosity"]], "benchbuild.container.ContainerBootstrap": [[6, 2, 1, "", "install_cmake_and_exit"], [6, 2, 1, "", "main"]], "benchbuild.container.ContainerCreate": [[6, 2, 1, "", "main"], [6, 2, 1, "", "strategy"]], "benchbuild.container.ContainerList": [[6, 2, 1, "", "main"]], "benchbuild.container.ContainerRun": [[6, 2, 1, "", "main"]], "benchbuild.container.ContainerStrategy": [[6, 2, 1, "", "run"]], "benchbuild.container.SetupPolyJITGentooStrategy": [[6, 2, 1, "", "run"]], "benchbuild.environments.domain": [[6, 0, 0, "-", "commands"], [6, 0, 0, "-", "declarative"], [6, 0, 0, "-", "model"]], "benchbuild.environments.domain.commands": [[6, 1, 1, "", "CreateBenchbuildBase"], [6, 1, 1, "", "CreateImage"], [6, 1, 1, "", "DeleteImage"], [6, 1, 1, "", "ExportImage"], [6, 1, 1, "", "ImportImage"], [6, 1, 1, "", "RunProjectContainer"], [6, 5, 1, "", "fs_compliant_name"], [6, 5, 1, "", "oci_compliant_name"]], "benchbuild.environments.domain.commands.CreateBenchbuildBase": [[6, 4, 1, "", "layers"], [6, 4, 1, "", "name"]], "benchbuild.environments.domain.commands.CreateImage": [[6, 4, 1, "", "layers"], [6, 4, 1, "", "name"]], "benchbuild.environments.domain.commands.DeleteImage": [[6, 4, 1, "", "name"]], "benchbuild.environments.domain.commands.ExportImage": [[6, 4, 1, "", "image"], [6, 4, 1, "", "out_name"]], "benchbuild.environments.domain.commands.ImportImage": [[6, 4, 1, "", "image"], [6, 4, 1, "", "in_path"]], "benchbuild.environments.domain.commands.RunProjectContainer": [[6, 4, 1, "", "args"], [6, 4, 1, "", "build_dir"], [6, 4, 1, "", "image"], [6, 4, 1, "", "name"]], "benchbuild.environments.domain.declarative": [[6, 1, 1, "", "ContainerImage"], [6, 5, 1, "", "add_benchbuild_layers"]], "benchbuild.environments.domain.declarative.ContainerImage": [[6, 2, 1, "", "add"], [6, 3, 1, "", "base"], [6, 2, 1, "", "command"], [6, 2, 1, "", "context"], [6, 2, 1, "", "copy_"], [6, 2, 1, "", "entrypoint"], [6, 2, 1, "", "env"], [6, 2, 1, "", "from_"], [6, 2, 1, "", "run"], [6, 2, 1, "", "workingdir"]], "benchbuild.environments.domain.model": [[6, 1, 1, "", "AddLayer"], [6, 1, 1, "", "Command"], [6, 1, 1, "", "Container"], [6, 1, 1, "", "ContextLayer"], [6, 1, 1, "", "CopyLayer"], [6, 1, 1, "", "EntryPoint"], [6, 1, 1, "", "Event"], [6, 1, 1, "", "FromLayer"], [6, 1, 1, "", "Image"], [6, 1, 1, "", "Layer"], [6, 1, 1, "", "LayerState"], [6, 1, 1, "", "Message"], [6, 1, 1, "", "Mount"], [6, 1, 1, "", "RunLayer"], [6, 1, 1, "", "SetCommand"], [6, 1, 1, "", "UpdateEnv"], [6, 1, 1, "", "WorkingDirectory"], [6, 5, 1, "", "immutable_kwargs"]], "benchbuild.environments.domain.model.AddLayer": [[6, 4, 1, "", "destination"], [6, 4, 1, "", "sources"]], "benchbuild.environments.domain.model.Container": [[6, 4, 1, "", "container_id"], [6, 4, 1, "", "context"], [6, 4, 1, "", "events"], [6, 4, 1, "", "image"], [6, 4, 1, "", "name"]], "benchbuild.environments.domain.model.ContextLayer": [[6, 4, 1, "", "func"]], "benchbuild.environments.domain.model.CopyLayer": [[6, 4, 1, "", "destination"], [6, 4, 1, "", "sources"]], "benchbuild.environments.domain.model.EntryPoint": [[6, 4, 1, "", "command"]], "benchbuild.environments.domain.model.FromLayer": [[6, 4, 1, "", "base"]], "benchbuild.environments.domain.model.Image": [[6, 2, 1, "", "append"], [6, 4, 1, "", "env"], [6, 4, 1, "", "events"], [6, 4, 1, "", "from_"], [6, 2, 1, "", "is_complete"], [6, 2, 1, "", "is_present"], [6, 4, 1, "", "layer_index"], [6, 4, 1, "", "layers"], [6, 4, 1, "", "mounts"], [6, 4, 1, "", "name"], [6, 2, 1, "", "prepend"], [6, 2, 1, "", "present"], [6, 2, 1, "", "update_env"]], "benchbuild.environments.domain.model.LayerState": [[6, 4, 1, "", "ABSENT"], [6, 4, 1, "", "PRESENT"]], "benchbuild.environments.domain.model.Mount": [[6, 4, 1, "", "source"], [6, 4, 1, "", "target"]], "benchbuild.environments.domain.model.RunLayer": [[6, 4, 1, "", "args"], [6, 4, 1, "", "command"], [6, 4, 1, "", "kwargs"]], "benchbuild.environments.domain.model.SetCommand": [[6, 4, 1, "", "command"]], "benchbuild.environments.domain.model.UpdateEnv": [[6, 4, 1, "", "env"]], "benchbuild.environments.domain.model.WorkingDirectory": [[6, 4, 1, "", "directory"]], "benchbuild.source": [[12, 0, 0, "-", "base"], [12, 0, 0, "-", "git"], [12, 0, 0, "-", "http"], [12, 0, 0, "-", "rsync"]], "benchbuild.source.base": [[12, 1, 1, "", "BaseSource"], [12, 1, 1, "", "ContextAwareSource"], [12, 1, 1, "", "ContextEnumeratorFn"], [12, 1, 1, "", "ContextFreeMixin"], [12, 1, 1, "", "EnumeratorFn"], [12, 1, 1, "", "Expandable"], [12, 1, 1, "", "Fetchable"], [12, 1, 1, "", "FetchableSource"], [12, 1, 1, "", "NoSource"], [12, 1, 1, "", "Revision"], [12, 1, 1, "", "RevisionStr"], [12, 1, 1, "", "Variant"], [12, 1, 1, "", "Versioned"], [12, 5, 1, "", "enumerate_revisions"], [12, 5, 1, "", "nosource"], [12, 5, 1, "", "primary"], [12, 5, 1, "", "product"], [12, 5, 1, "", "revision_from_str"], [12, 5, 1, "", "secondaries"], [12, 5, 1, "", "sources_as_dict"], [12, 5, 1, "", "target_prefix"], [12, 5, 1, "", "to_str"]], "benchbuild.source.base.ContextAwareSource": [[12, 2, 1, "", "is_context_free"], [12, 2, 1, "", "versions_with_context"]], "benchbuild.source.base.ContextFreeMixin": [[12, 2, 1, "", "is_context_free"], [12, 2, 1, "", "versions_with_context"]], "benchbuild.source.base.Expandable": [[12, 3, 1, "", "is_expandable"], [12, 2, 1, "", "versions"]], "benchbuild.source.base.Fetchable": [[12, 2, 1, "", "fetch"], [12, 3, 1, "", "key"], [12, 3, 1, "", "local"], [12, 3, 1, "", "remote"]], "benchbuild.source.base.FetchableSource": [[12, 3, 1, "", "default"], [12, 2, 1, "", "explore"], [12, 2, 1, "", "fetch"], [12, 3, 1, "", "is_expandable"], [12, 3, 1, "", "key"], [12, 3, 1, "", "local"], [12, 3, 1, "", "remote"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.base.NoSource": [[12, 3, 1, "", "default"], [12, 2, 1, "", "fetch"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.base.Revision": [[12, 2, 1, "", "extend"], [12, 2, 1, "", "has_variant"], [12, 3, 1, "", "primary"], [12, 4, 1, "", "project_cls"], [12, 2, 1, "", "sorted"], [12, 2, 1, "", "source_by_name"], [12, 2, 1, "", "update"], [12, 2, 1, "", "variant_by_name"], [12, 4, 1, "", "variants"]], "benchbuild.source.base.RevisionStr": [[12, 4, 1, "", "value"]], "benchbuild.source.base.Variant": [[12, 2, 1, "", "name"], [12, 4, 1, "", "owner"], [12, 2, 1, "", "source"], [12, 4, 1, "", "version"]], "benchbuild.source.base.Versioned": [[12, 3, 1, "", "default"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.git": [[12, 1, 1, "", "Git"], [12, 1, 1, "", "GitSubmodule"], [12, 5, 1, "", "clone_needed"], [12, 5, 1, "", "maybe_shallow"]], "benchbuild.source.git.Git": [[12, 3, 1, "", "default"], [12, 2, 1, "", "fetch"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.git.GitSubmodule": [[12, 3, 1, "", "is_expandable"]], "benchbuild.source.http": [[12, 1, 1, "", "HTTP"], [12, 1, 1, "", "HTTPMultiple"], [12, 1, 1, "", "HTTPUntar"], [12, 5, 1, "", "download_required"], [12, 5, 1, "", "download_single_version"], [12, 5, 1, "", "normalize_remotes"], [12, 5, 1, "", "versioned_target_name"]], "benchbuild.source.http.HTTP": [[12, 3, 1, "", "default"], [12, 2, 1, "", "fetch"], [12, 2, 1, "", "fetch_version"], [12, 2, 1, "", "version"], [12, 2, 1, "", "versions"]], "benchbuild.source.http.HTTPMultiple": [[12, 2, 1, "", "fetch_version"]], "benchbuild.source.http.HTTPUntar": [[12, 2, 1, "", "version"]], "benchbuild.utils": [[4, 0, 0, "-", "actions"], [5, 0, 0, "-", "settings"]], "benchbuild.utils.actions": [[4, 1, 1, "", "Any"], [4, 1, 1, "", "Clean"], [4, 1, 1, "", "CleanExtra"], [4, 1, 1, "", "Compile"], [4, 1, 1, "", "Echo"], [4, 1, 1, "", "Experiment"], [4, 1, 1, "", "MakeBuildDir"], [4, 1, 1, "", "MultiStep"], [4, 1, 1, "", "ProjectEnvironment"], [4, 1, 1, "", "ProjectStep"], [4, 1, 1, "", "RequireAll"], [4, 1, 1, "", "Run"], [4, 1, 1, "", "RunWorkload"], [4, 1, 1, "", "RunWorkloads"], [4, 1, 1, "", "SetProjectVersion"], [4, 1, 1, "", "Step"], [4, 1, 1, "", "StepResult"], [4, 5, 1, "", "log_before_after"], [4, 5, 1, "", "prepend_status"], [4, 5, 1, "", "run_any_child"], [4, 5, 1, "", "step_has_failed"]], "benchbuild.utils.actions.Any": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.Clean": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 2, 1, "", "clean_mountpoints"]], "benchbuild.utils.actions.CleanExtra": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.Compile": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.Echo": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "message"]], "benchbuild.utils.actions.Experiment": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 2, 1, "", "begin_transaction"], [4, 2, 1, "", "end_transaction"], [4, 4, 1, "", "experiment"]], "benchbuild.utils.actions.MakeBuildDir": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.MultiStep": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "actions"], [4, 2, 1, "", "onerror"]], "benchbuild.utils.actions.ProjectEnvironment": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.ProjectStep": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 2, 1, "", "onerror"], [4, 4, 1, "", "project"]], "benchbuild.utils.actions.RequireAll": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"]], "benchbuild.utils.actions.Run": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "experiment"]], "benchbuild.utils.actions.RunWorkload": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 3, 1, "", "workload_ref"]], "benchbuild.utils.actions.RunWorkloads": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "experiment"], [4, 4, 1, "", "project"]], "benchbuild.utils.actions.SetProjectVersion": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 4, 1, "", "revision"]], "benchbuild.utils.actions.Step": [[4, 4, 1, "", "DESCRIPTION"], [4, 4, 1, "", "NAME"], [4, 2, 1, "", "onerror"], [4, 4, 1, "", "status"]], "benchbuild.utils.actions.StepResult": [[4, 4, 1, "", "CAN_CONTINUE"], [4, 4, 1, "", "ERROR"], [4, 4, 1, "", "OK"], [4, 4, 1, "", "UNSET"]], "benchbuild.utils.settings": [[5, 1, 1, "", "ConfigDumper"], [5, 1, 1, "", "ConfigLoader"], [5, 1, 1, "", "ConfigPath"], [5, 1, 1, "", "Configuration"], [5, 1, 1, "", "Indexable"], [5, 6, 1, "", "InvalidConfigKey"], [5, 5, 1, "", "available_cpu_count"], [5, 5, 1, "", "convert_components"], [5, 5, 1, "", "current_available_threads"], [5, 5, 1, "", "escape_yaml"], [5, 5, 1, "", "find_config"], [5, 5, 1, "", "get_number_of_jobs"], [5, 5, 1, "", "is_yaml"], [5, 5, 1, "", "path_constructor"], [5, 5, 1, "", "path_representer"], [5, 5, 1, "", "setup_config"], [5, 5, 1, "", "to_env_var"], [5, 5, 1, "", "to_yaml"], [5, 5, 1, "", "update_env"], [5, 5, 1, "", "upgrade"], [5, 5, 1, "", "uuid_add_implicit_resolver"], [5, 5, 1, "", "uuid_constructor"], [5, 5, 1, "", "uuid_representer"]], "benchbuild.utils.settings.ConfigDumper": [[5, 4, 1, "", "yaml_implicit_resolvers"], [5, 4, 1, "", "yaml_representers"]], "benchbuild.utils.settings.ConfigLoader": [[5, 4, 1, "", "yaml_constructors"], [5, 4, 1, "", "yaml_implicit_resolvers"]], "benchbuild.utils.settings.ConfigPath": [[5, 2, 1, "", "path_to_str"], [5, 2, 1, "", "validate"]], "benchbuild.utils.settings.Configuration": [[5, 2, 1, "", "filter_exports"], [5, 2, 1, "", "has_default"], [5, 2, 1, "", "has_value"], [5, 2, 1, "", "init_from_env"], [5, 2, 1, "", "is_leaf"], [5, 2, 1, "", "load"], [5, 2, 1, "", "store"], [5, 2, 1, "", "to_env_dict"], [5, 3, 1, "", "value"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:property", "4": "py:attribute", "5": "py:function", "6": "py:exception"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "property", "Python property"], "4": ["py", "attribute", "Python attribute"], "5": ["py", "function", "Python function"], "6": ["py", "exception", "Python exception"]}, "titleterms": {"6": 0, "8": 0, "2023": 0, "10": 0, "09": 0, "featur": 0, "bug": 0, "fix": 0, "7": 0, "04": 0, "changelog": 0, "4": 0, "03": 0, "16": 0, "3": 0, "06": 0, "2": 0, "1": 0, "01": 0, "5": 0, "2022": 0, "11": 0, "feat": 0, "refactor": 0, "21": 0, "08": 0, "02": 0, "2021": 0, "15": 0, "26": 0, "07": 0, "29": 0, "05": 0, "0": 0, "2020": 0, "12": 0, "benchbuild": [1, 6, 7], "document": [1, 13], "design": 1, "philosophi": 1, "A": 1, "case": 1, "studi": 1, "doesn": 1, "t": 1, "know": 1, "its": 1, "experi": [1, 4, 10], "an": 1, "support": 1, "python": 1, "version": 1, "get": 1, "start": 1, "cli": 2, "slurm": [3, 7], "basic": 3, "templat": 3, "custom": [3, 4], "action": 4, "avail": 4, "step": 4, "base": [4, 12], "clean": 4, "makebuilddir": 4, "compil": 4, "run": 4, "echo": 4, "ani": 4, "group": 4, "requireal": 4, "cleanextra": 4, "projectenviron": 4, "setprojectvers": 4, "configur": [5, 6], "modul": [5, 6, 8, 12], "set": 5, "util": 5, "contain": 6, "usag": [6, 8], "replac": 6, "imag": 6, "definit": 6, "runtim": 6, "requir": [6, 7], "buildah": 6, "podman": 6, "environ": [6, 9], "domain": 6, "declar": 6, "model": 6, "exampl": [6, 12], "command": [6, 8], "instal": 7, "postgresql": 7, "fuse": 7, "bootstrap": 7, "insid": 8, "project": [8, 11], "token": 8, "sourc": 12, "git": 12, "http": 12, "rsync": 12, "welcom": 13, "bencbuild": 13, "": 13, "content": 13, "indic": 13, "tabl": 13}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1, "sphinx": 60}, "alltitles": {"6.8 (2023-10-09)": [[0, "id1"]], "Features": [[0, "features"], [0, "id3"], [0, "id10"]], "Bug Fixes": [[0, "bug-fixes"], [0, "id4"], [0, "id8"], [0, "id11"]], "6.7 (2023-04-04)": [[0, "id2"]], "Changelog": [[0, "changelog"]], "6.6.4 (2023-03-16)": [[0, "id5"]], "6.6.3 (2023-03-06)": [[0, "id6"]], "6.6.2 (2023-03-06)": [[0, "id7"]], "6.6.1 (2023-01-10)": [[0, "id9"]], "6.5 (2022-11-03)": [[0, "id12"]], "Feat": [[0, "feat"], [0, "id14"], [0, "id18"], [0, "id22"], [0, "id26"], [0, "id33"], [0, "id39"], [0, "id46"]], "Fix": [[0, "fix"], [0, "id15"], [0, "id19"], [0, "id23"], [0, "id27"], [0, "id31"], [0, "id36"], [0, "id40"], [0, "id42"], [0, "id44"], [0, "id47"], [0, "id50"]], "Refactor": [[0, "refactor"], [0, "id16"], [0, "id20"], [0, "id24"], [0, "id28"], [0, "id48"]], "6.4 (2022-09-21)": [[0, "id13"]], "6.3.2 (2022-08-21)": [[0, "id17"]], "6.3.1 (2022-03-01)": [[0, "id21"]], "6.3 (2022-02-03)": [[0, "id25"]], "6.2.7 (2021-09-21)": [[0, "id29"]], "6.2.6 (2021-09-16)": [[0, "id30"]], "6.2.5 (2021-09-15)": [[0, "id32"]], "6.2.4 (2021-09-03)": [[0, "id34"]], "6.2.3 (2021-08-26)": [[0, "id35"]], "6.2.2 (2021-07-29)": [[0, "id37"]], "6.2.1 (2021-07-06)": [[0, "id38"]], "6.2 (2021-06-02)": [[0, "id41"]], "6.1.1 (2021-05-11)": [[0, "id43"]], "6.1 (2021-05-11)": [[0, "id45"]], "6.0.1 (2020-12-29)": [[0, "id49"]], "BenchBuild Documentation": [[1, "benchbuild-documentation"]], "Design Philosophy": [[1, "design-philosophy"]], "A case-study doesn\u2019t know its experiment": [[1, "a-case-study-doesn-t-know-its-experiment"]], "An experiment doesn\u2019t know its case-studies": [[1, "an-experiment-doesn-t-know-its-case-studies"]], "Supported Python Versions": [[1, "supported-python-versions"]], "Getting started": [[1, "getting-started"]], "CLI": [[2, "cli"]], "SLURM": [[3, "slurm"], [7, "slurm"]], "Basics": [[3, "basics"]], "Template customization": [[3, "template-customization"]], "Actions": [[4, "actions"]], "Customize actions": [[4, "customize-actions"]], "Available Actions": [[4, "available-actions"]], "Step (Base)": [[4, "step-base"]], "Clean": [[4, "clean"]], "MakeBuildDir": [[4, "makebuilddir"]], "Compile": [[4, "compile"]], "Run": [[4, "run"]], "Echo": [[4, "echo"]], "Any (Group)": [[4, "any-group"]], "Experiment (Any, Group)": [[4, "experiment-any-group"]], "RequireAll (Group)": [[4, "requireall-group"]], "CleanExtra": [[4, "cleanextra"]], "ProjectEnvironment": [[4, "projectenvironment"]], "SetProjectVersion": [[4, "setprojectversion"]], "Configure": [[5, "configure"]], "Module: settings": [[5, "module-benchbuild.settings"]], "Module: utils.settings": [[5, "module-benchbuild.utils.settings"]], "Containers": [[6, "containers"]], "Usage": [[6, "usage"]], "Replace Images": [[6, "replace-images"]], "Configuration": [[6, "configuration"]], "Definition": [[6, "definition"]], "Runtime requirements": [[6, "runtime-requirements"]], "Buildah": [[6, "buildah"]], "Podman": [[6, "podman"]], "Module: benchbuild.container": [[6, "module-benchbuild.container"]], "Module: benchbuild.environments.domain.declarative": [[6, "module-benchbuild.environments.domain.declarative"]], "Module: benchbuild.environments.domain.model": [[6, "module-benchbuild.environments.domain.model"]], "Examples": [[6, null], [6, null]], "Module: benchbuild.environments.domain.commands": [[6, "module-benchbuild.environments.domain.commands"]], "Installation": [[7, "installation"]], "Requirements": [[7, "requirements"]], "PostgreSQL": [[7, "postgresql"]], "FUSE": [[7, "fuse"]], "Benchbuild": [[7, "benchbuild"]], "Bootstrapping": [[7, "bootstrapping"]], "Commands": [[8, "commands"]], "Usage inside Projects": [[8, "usage-inside-projects"]], "Tokens": [[8, "tokens"]], "Module: command": [[8, "module-benchbuild.command"]], "Environment": [[9, "environment"]], "Experiment": [[10, "experiment"]], "Project": [[11, "project"]], "Source": [[12, "source"]], "Base": [[12, "module-benchbuild.source.base"]], "Git": [[12, "module-benchbuild.source.git"]], "HTTP": [[12, "module-benchbuild.source.http"]], "Example": [[12, null]], "RSync": [[12, "module-benchbuild.source.rsync"]], "Module: source": [[12, "module-benchbuild.source"]], "Welcome to bencbuild\u2019s documentation!": [[13, "welcome-to-bencbuild-s-documentation"]], "Contents:": [[13, null]], "Indices and tables": [[13, "indices-and-tables"]]}, "indexentries": {"any (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Any"]], "can_continue (benchbuild.utils.actions.stepresult attribute)": [[4, "benchbuild.utils.actions.StepResult.CAN_CONTINUE"]], "clean (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Clean"]], "cleanextra (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.CleanExtra"]], "compile (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Compile"]], "description (benchbuild.utils.actions.any attribute)": [[4, "benchbuild.utils.actions.Any.DESCRIPTION"]], "description (benchbuild.utils.actions.clean attribute)": [[4, "benchbuild.utils.actions.Clean.DESCRIPTION"]], "description (benchbuild.utils.actions.cleanextra attribute)": [[4, "benchbuild.utils.actions.CleanExtra.DESCRIPTION"]], "description (benchbuild.utils.actions.compile attribute)": [[4, "benchbuild.utils.actions.Compile.DESCRIPTION"]], "description (benchbuild.utils.actions.echo attribute)": [[4, "benchbuild.utils.actions.Echo.DESCRIPTION"]], "description (benchbuild.utils.actions.experiment attribute)": [[4, "benchbuild.utils.actions.Experiment.DESCRIPTION"]], "description (benchbuild.utils.actions.makebuilddir attribute)": [[4, "benchbuild.utils.actions.MakeBuildDir.DESCRIPTION"]], "description (benchbuild.utils.actions.multistep attribute)": [[4, "benchbuild.utils.actions.MultiStep.DESCRIPTION"]], "description (benchbuild.utils.actions.projectenvironment attribute)": [[4, "benchbuild.utils.actions.ProjectEnvironment.DESCRIPTION"]], "description (benchbuild.utils.actions.projectstep attribute)": [[4, "benchbuild.utils.actions.ProjectStep.DESCRIPTION"]], "description (benchbuild.utils.actions.requireall attribute)": [[4, "benchbuild.utils.actions.RequireAll.DESCRIPTION"]], "description (benchbuild.utils.actions.run attribute)": [[4, "benchbuild.utils.actions.Run.DESCRIPTION"]], "description (benchbuild.utils.actions.runworkload attribute)": [[4, "benchbuild.utils.actions.RunWorkload.DESCRIPTION"]], "description (benchbuild.utils.actions.runworkloads attribute)": [[4, "benchbuild.utils.actions.RunWorkloads.DESCRIPTION"]], "description (benchbuild.utils.actions.setprojectversion attribute)": [[4, "benchbuild.utils.actions.SetProjectVersion.DESCRIPTION"]], "description (benchbuild.utils.actions.step attribute)": [[4, "benchbuild.utils.actions.Step.DESCRIPTION"]], "error (benchbuild.utils.actions.stepresult attribute)": [[4, "benchbuild.utils.actions.StepResult.ERROR"]], "echo (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Echo"]], "experiment (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Experiment"]], "makebuilddir (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.MakeBuildDir"]], "multistep (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.MultiStep"]], "name (benchbuild.utils.actions.any attribute)": [[4, "benchbuild.utils.actions.Any.NAME"]], "name (benchbuild.utils.actions.clean attribute)": [[4, "benchbuild.utils.actions.Clean.NAME"]], "name (benchbuild.utils.actions.cleanextra attribute)": [[4, "benchbuild.utils.actions.CleanExtra.NAME"]], "name (benchbuild.utils.actions.compile attribute)": [[4, "benchbuild.utils.actions.Compile.NAME"]], "name (benchbuild.utils.actions.echo attribute)": [[4, "benchbuild.utils.actions.Echo.NAME"]], "name (benchbuild.utils.actions.experiment attribute)": [[4, "benchbuild.utils.actions.Experiment.NAME"]], "name (benchbuild.utils.actions.makebuilddir attribute)": [[4, "benchbuild.utils.actions.MakeBuildDir.NAME"]], "name (benchbuild.utils.actions.multistep attribute)": [[4, "benchbuild.utils.actions.MultiStep.NAME"]], "name (benchbuild.utils.actions.projectenvironment attribute)": [[4, "benchbuild.utils.actions.ProjectEnvironment.NAME"]], "name (benchbuild.utils.actions.projectstep attribute)": [[4, "benchbuild.utils.actions.ProjectStep.NAME"]], "name (benchbuild.utils.actions.requireall attribute)": [[4, "benchbuild.utils.actions.RequireAll.NAME"]], "name (benchbuild.utils.actions.run attribute)": [[4, "benchbuild.utils.actions.Run.NAME"]], "name (benchbuild.utils.actions.runworkload attribute)": [[4, "benchbuild.utils.actions.RunWorkload.NAME"]], "name (benchbuild.utils.actions.runworkloads attribute)": [[4, "benchbuild.utils.actions.RunWorkloads.NAME"]], "name (benchbuild.utils.actions.setprojectversion attribute)": [[4, "benchbuild.utils.actions.SetProjectVersion.NAME"]], "name (benchbuild.utils.actions.step attribute)": [[4, "benchbuild.utils.actions.Step.NAME"]], "ok (benchbuild.utils.actions.stepresult attribute)": [[4, "benchbuild.utils.actions.StepResult.OK"]], "projectenvironment (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.ProjectEnvironment"]], "projectstep (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.ProjectStep"]], "requireall (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.RequireAll"]], "run (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Run"]], "runworkload (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.RunWorkload"]], "runworkloads (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.RunWorkloads"]], "setprojectversion (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.SetProjectVersion"]], "step (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.Step"]], "stepresult (class in benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.StepResult"]], "unset (benchbuild.utils.actions.stepresult attribute)": [[4, "benchbuild.utils.actions.StepResult.UNSET"]], "actions (benchbuild.utils.actions.multistep attribute)": [[4, "benchbuild.utils.actions.MultiStep.actions"]], "begin_transaction() (benchbuild.utils.actions.experiment method)": [[4, "benchbuild.utils.actions.Experiment.begin_transaction"]], "benchbuild.utils.actions": [[4, "module-benchbuild.utils.actions"]], "clean_mountpoints() (benchbuild.utils.actions.clean static method)": [[4, "benchbuild.utils.actions.Clean.clean_mountpoints"]], "end_transaction() (benchbuild.utils.actions.experiment static method)": [[4, "benchbuild.utils.actions.Experiment.end_transaction"]], "experiment (benchbuild.utils.actions.experiment attribute)": [[4, "benchbuild.utils.actions.Experiment.experiment"]], "experiment (benchbuild.utils.actions.run attribute)": [[4, "benchbuild.utils.actions.Run.experiment"]], "experiment (benchbuild.utils.actions.runworkloads attribute)": [[4, "benchbuild.utils.actions.RunWorkloads.experiment"]], "log_before_after() (in module benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.log_before_after"]], "message (benchbuild.utils.actions.echo attribute)": [[4, "benchbuild.utils.actions.Echo.message"]], "module": [[4, "module-benchbuild.utils.actions"], [5, "module-benchbuild.settings"], [5, "module-benchbuild.utils.settings"], [6, "module-benchbuild.container"], [6, "module-benchbuild.environments.domain.commands"], [6, "module-benchbuild.environments.domain.declarative"], [6, "module-benchbuild.environments.domain.model"], [8, "module-benchbuild.command"], [12, "module-benchbuild.source"], [12, "module-benchbuild.source.base"], [12, "module-benchbuild.source.git"], [12, "module-benchbuild.source.http"], [12, "module-benchbuild.source.rsync"]], "onerror() (benchbuild.utils.actions.multistep method)": [[4, "benchbuild.utils.actions.MultiStep.onerror"]], "onerror() (benchbuild.utils.actions.projectstep method)": [[4, "benchbuild.utils.actions.ProjectStep.onerror"]], "onerror() (benchbuild.utils.actions.step method)": [[4, "benchbuild.utils.actions.Step.onerror"]], "prepend_status() (in module benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.prepend_status"]], "project (benchbuild.utils.actions.projectstep attribute)": [[4, "benchbuild.utils.actions.ProjectStep.project"]], "project (benchbuild.utils.actions.runworkloads attribute)": [[4, "benchbuild.utils.actions.RunWorkloads.project"]], "revision (benchbuild.utils.actions.setprojectversion attribute)": [[4, "benchbuild.utils.actions.SetProjectVersion.revision"]], "run_any_child() (in module benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.run_any_child"]], "status (benchbuild.utils.actions.step attribute)": [[4, "benchbuild.utils.actions.Step.status"]], "step_has_failed() (in module benchbuild.utils.actions)": [[4, "benchbuild.utils.actions.step_has_failed"]], "workload_ref (benchbuild.utils.actions.runworkload property)": [[4, "benchbuild.utils.actions.RunWorkload.workload_ref"]], "configdumper (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.ConfigDumper"]], "configloader (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.ConfigLoader"]], "configpath (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.ConfigPath"]], "configuration (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.Configuration"]], "indexable (class in benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.Indexable"]], "invalidconfigkey": [[5, "benchbuild.utils.settings.InvalidConfigKey"]], "available_cpu_count() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.available_cpu_count"]], "benchbuild.settings": [[5, "module-benchbuild.settings"]], "benchbuild.utils.settings": [[5, "module-benchbuild.utils.settings"]], "convert_components() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.convert_components"]], "current_available_threads() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.current_available_threads"]], "escape_yaml() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.escape_yaml"]], "filter_exports() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.filter_exports"]], "find_config() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.find_config"]], "get_number_of_jobs() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.get_number_of_jobs"]], "has_default() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.has_default"]], "has_value() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.has_value"]], "init_from_env() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.init_from_env"]], "is_leaf() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.is_leaf"]], "is_yaml() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.is_yaml"]], "load() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.load"]], "path_constructor() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.path_constructor"]], "path_representer() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.path_representer"]], "path_to_str() (benchbuild.utils.settings.configpath static method)": [[5, "benchbuild.utils.settings.ConfigPath.path_to_str"]], "setup_config() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.setup_config"]], "store() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.store"]], "to_env_dict() (benchbuild.utils.settings.configuration method)": [[5, "benchbuild.utils.settings.Configuration.to_env_dict"]], "to_env_var() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.to_env_var"]], "to_yaml() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.to_yaml"]], "update_env() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.update_env"]], "upgrade() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.upgrade"]], "uuid_add_implicit_resolver() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.uuid_add_implicit_resolver"]], "uuid_constructor() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.uuid_constructor"]], "uuid_representer() (in module benchbuild.utils.settings)": [[5, "benchbuild.utils.settings.uuid_representer"]], "validate() (benchbuild.utils.settings.configpath method)": [[5, "benchbuild.utils.settings.ConfigPath.validate"]], "value (benchbuild.utils.settings.configuration property)": [[5, "benchbuild.utils.settings.Configuration.value"]], "yaml_constructors (benchbuild.utils.settings.configloader attribute)": [[5, "benchbuild.utils.settings.ConfigLoader.yaml_constructors"]], "yaml_implicit_resolvers (benchbuild.utils.settings.configdumper attribute)": [[5, "benchbuild.utils.settings.ConfigDumper.yaml_implicit_resolvers"]], "yaml_implicit_resolvers (benchbuild.utils.settings.configloader attribute)": [[5, "benchbuild.utils.settings.ConfigLoader.yaml_implicit_resolvers"]], "yaml_representers (benchbuild.utils.settings.configdumper attribute)": [[5, "benchbuild.utils.settings.ConfigDumper.yaml_representers"]], "absent (benchbuild.environments.domain.model.layerstate attribute)": [[6, "benchbuild.environments.domain.model.LayerState.ABSENT"]], "addlayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.AddLayer"]], "bashstrategy (class in benchbuild.container)": [[6, "benchbuild.container.BashStrategy"]], "command (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Command"]], "container (class in benchbuild.container)": [[6, "benchbuild.container.Container"]], "container (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Container"]], "containerbootstrap (class in benchbuild.container)": [[6, "benchbuild.container.ContainerBootstrap"]], "containercreate (class in benchbuild.container)": [[6, "benchbuild.container.ContainerCreate"]], "containerimage (class in benchbuild.environments.domain.declarative)": [[6, "benchbuild.environments.domain.declarative.ContainerImage"]], "containerlist (class in benchbuild.container)": [[6, "benchbuild.container.ContainerList"]], "containerrun (class in benchbuild.container)": [[6, "benchbuild.container.ContainerRun"]], "containerstrategy (class in benchbuild.container)": [[6, "benchbuild.container.ContainerStrategy"]], "contextlayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.ContextLayer"]], "copylayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.CopyLayer"]], "createbenchbuildbase (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.CreateBenchbuildBase"]], "createimage (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.CreateImage"]], "deleteimage (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.DeleteImage"]], "entrypoint (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.EntryPoint"]], "event (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Event"]], "exportimage (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.ExportImage"]], "fromlayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.FromLayer"]], "image (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Image"]], "importimage (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.ImportImage"]], "layer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Layer"]], "layerstate (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.LayerState"]], "message (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Message"]], "mockobj (class in benchbuild.container)": [[6, "benchbuild.container.MockObj"]], "mount (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.Mount"]], "present (benchbuild.environments.domain.model.layerstate attribute)": [[6, "benchbuild.environments.domain.model.LayerState.PRESENT"]], "runlayer (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.RunLayer"]], "runprojectcontainer (class in benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer"]], "setcommand (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.SetCommand"]], "setuppolyjitgentoostrategy (class in benchbuild.container)": [[6, "benchbuild.container.SetupPolyJITGentooStrategy"]], "updateenv (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.UpdateEnv"]], "version (benchbuild.container.container attribute)": [[6, "benchbuild.container.Container.VERSION"]], "workingdirectory (class in benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.WorkingDirectory"]], "add() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.add"]], "add_benchbuild_layers() (in module benchbuild.environments.domain.declarative)": [[6, "benchbuild.environments.domain.declarative.add_benchbuild_layers"]], "append() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.append"]], "args (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.args"]], "args (benchbuild.environments.domain.model.runlayer attribute)": [[6, "benchbuild.environments.domain.model.RunLayer.args"]], "base (benchbuild.environments.domain.declarative.containerimage property)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.base"]], "base (benchbuild.environments.domain.model.fromlayer attribute)": [[6, "benchbuild.environments.domain.model.FromLayer.base"]], "benchbuild.container": [[6, "module-benchbuild.container"]], "benchbuild.environments.domain.commands": [[6, "module-benchbuild.environments.domain.commands"]], "benchbuild.environments.domain.declarative": [[6, "module-benchbuild.environments.domain.declarative"]], "benchbuild.environments.domain.model": [[6, "module-benchbuild.environments.domain.model"]], "build_dir (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.build_dir"]], "builddir() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.builddir"]], "clean_directories() (in module benchbuild.container)": [[6, "benchbuild.container.clean_directories"]], "command (benchbuild.environments.domain.model.entrypoint attribute)": [[6, "benchbuild.environments.domain.model.EntryPoint.command"]], "command (benchbuild.environments.domain.model.runlayer attribute)": [[6, "benchbuild.environments.domain.model.RunLayer.command"]], "command (benchbuild.environments.domain.model.setcommand attribute)": [[6, "benchbuild.environments.domain.model.SetCommand.command"]], "command() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.command"]], "container_id (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.container_id"]], "context (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.context"]], "context() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.context"]], "copy_() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.copy_"]], "destination (benchbuild.environments.domain.model.addlayer attribute)": [[6, "benchbuild.environments.domain.model.AddLayer.destination"]], "destination (benchbuild.environments.domain.model.copylayer attribute)": [[6, "benchbuild.environments.domain.model.CopyLayer.destination"]], "directory (benchbuild.environments.domain.model.workingdirectory attribute)": [[6, "benchbuild.environments.domain.model.WorkingDirectory.directory"]], "entrypoint() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.entrypoint"]], "env (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.env"]], "env (benchbuild.environments.domain.model.updateenv attribute)": [[6, "benchbuild.environments.domain.model.UpdateEnv.env"]], "env() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.env"]], "events (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.events"]], "events (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.events"]], "find_hash() (in module benchbuild.container)": [[6, "benchbuild.container.find_hash"]], "from_ (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.from_"]], "from_() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.from_"]], "fs_compliant_name() (in module benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.fs_compliant_name"]], "func (benchbuild.environments.domain.model.contextlayer attribute)": [[6, "benchbuild.environments.domain.model.ContextLayer.func"]], "image (benchbuild.environments.domain.commands.exportimage attribute)": [[6, "benchbuild.environments.domain.commands.ExportImage.image"]], "image (benchbuild.environments.domain.commands.importimage attribute)": [[6, "benchbuild.environments.domain.commands.ImportImage.image"]], "image (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.image"]], "image (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.image"]], "immutable_kwargs() (in module benchbuild.environments.domain.model)": [[6, "benchbuild.environments.domain.model.immutable_kwargs"]], "in_path (benchbuild.environments.domain.commands.importimage attribute)": [[6, "benchbuild.environments.domain.commands.ImportImage.in_path"]], "input_file() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.input_file"]], "install_cmake_and_exit() (benchbuild.container.containerbootstrap method)": [[6, "benchbuild.container.ContainerBootstrap.install_cmake_and_exit"]], "is_complete() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.is_complete"]], "is_present() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.is_present"]], "kwargs (benchbuild.environments.domain.model.runlayer attribute)": [[6, "benchbuild.environments.domain.model.RunLayer.kwargs"]], "layer_index (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.layer_index"]], "layers (benchbuild.environments.domain.commands.createbenchbuildbase attribute)": [[6, "benchbuild.environments.domain.commands.CreateBenchbuildBase.layers"]], "layers (benchbuild.environments.domain.commands.createimage attribute)": [[6, "benchbuild.environments.domain.commands.CreateImage.layers"]], "layers (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.layers"]], "main() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.main"]], "main() (benchbuild.container.containerbootstrap method)": [[6, "benchbuild.container.ContainerBootstrap.main"]], "main() (benchbuild.container.containercreate method)": [[6, "benchbuild.container.ContainerCreate.main"]], "main() (benchbuild.container.containerlist method)": [[6, "benchbuild.container.ContainerList.main"]], "main() (benchbuild.container.containerrun method)": [[6, "benchbuild.container.ContainerRun.main"]], "main() (in module benchbuild.container)": [[6, "benchbuild.container.main"]], "mounts (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.mounts"]], "mounts() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.mounts"]], "name (benchbuild.environments.domain.commands.createbenchbuildbase attribute)": [[6, "benchbuild.environments.domain.commands.CreateBenchbuildBase.name"]], "name (benchbuild.environments.domain.commands.createimage attribute)": [[6, "benchbuild.environments.domain.commands.CreateImage.name"]], "name (benchbuild.environments.domain.commands.deleteimage attribute)": [[6, "benchbuild.environments.domain.commands.DeleteImage.name"]], "name (benchbuild.environments.domain.commands.runprojectcontainer attribute)": [[6, "benchbuild.environments.domain.commands.RunProjectContainer.name"]], "name (benchbuild.environments.domain.model.container attribute)": [[6, "benchbuild.environments.domain.model.Container.name"]], "name (benchbuild.environments.domain.model.image attribute)": [[6, "benchbuild.environments.domain.model.Image.name"]], "oci_compliant_name() (in module benchbuild.environments.domain.commands)": [[6, "benchbuild.environments.domain.commands.oci_compliant_name"]], "out_name (benchbuild.environments.domain.commands.exportimage attribute)": [[6, "benchbuild.environments.domain.commands.ExportImage.out_name"]], "output_file() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.output_file"]], "pack_container() (in module benchbuild.container)": [[6, "benchbuild.container.pack_container"]], "prepend() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.prepend"]], "present() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.present"]], "run() (benchbuild.container.bashstrategy method)": [[6, "benchbuild.container.BashStrategy.run"]], "run() (benchbuild.container.containerstrategy method)": [[6, "benchbuild.container.ContainerStrategy.run"]], "run() (benchbuild.container.setuppolyjitgentoostrategy method)": [[6, "benchbuild.container.SetupPolyJITGentooStrategy.run"]], "run() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.run"]], "run_in_container() (in module benchbuild.container)": [[6, "benchbuild.container.run_in_container"]], "set_input_container() (in module benchbuild.container)": [[6, "benchbuild.container.set_input_container"]], "setup_bash_in_container() (in module benchbuild.container)": [[6, "benchbuild.container.setup_bash_in_container"]], "setup_container() (in module benchbuild.container)": [[6, "benchbuild.container.setup_container"]], "setup_directories() (in module benchbuild.container)": [[6, "benchbuild.container.setup_directories"]], "shell() (benchbuild.container.container method)": [[6, "benchbuild.container.Container.shell"]], "source (benchbuild.environments.domain.model.mount attribute)": [[6, "benchbuild.environments.domain.model.Mount.source"]], "sources (benchbuild.environments.domain.model.addlayer attribute)": [[6, "benchbuild.environments.domain.model.AddLayer.sources"]], "sources (benchbuild.environments.domain.model.copylayer attribute)": [[6, "benchbuild.environments.domain.model.CopyLayer.sources"]], "strategy() (benchbuild.container.containercreate method)": [[6, "benchbuild.container.ContainerCreate.strategy"]], "target (benchbuild.environments.domain.model.mount attribute)": [[6, "benchbuild.environments.domain.model.Mount.target"]], "update_env() (benchbuild.environments.domain.model.image method)": [[6, "benchbuild.environments.domain.model.Image.update_env"]], "verbosity (benchbuild.container.container attribute)": [[6, "benchbuild.container.Container.verbosity"]], "workingdir() (benchbuild.environments.domain.declarative.containerimage method)": [[6, "benchbuild.environments.domain.declarative.ContainerImage.workingdir"]], "argsrenderstrategy (class in benchbuild.command)": [[8, "benchbuild.command.ArgsRenderStrategy"]], "argstoken (class in benchbuild.command)": [[8, "benchbuild.command.ArgsToken"]], "backupfn (class in benchbuild.command)": [[8, "benchbuild.command.BackupFn"]], "builddirrenderer (class in benchbuild.command)": [[8, "benchbuild.command.BuilddirRenderer"]], "command (class in benchbuild.command)": [[8, "benchbuild.command.Command"]], "conststrrenderer (class in benchbuild.command)": [[8, "benchbuild.command.ConstStrRenderer"]], "onlyin (class in benchbuild.command)": [[8, "benchbuild.command.OnlyIn"]], "pathrenderstrategy (class in benchbuild.command)": [[8, "benchbuild.command.PathRenderStrategy"]], "pathtoken (class in benchbuild.command)": [[8, "benchbuild.command.PathToken"]], "projectcommand (class in benchbuild.command)": [[8, "benchbuild.command.ProjectCommand"]], "projectroot() (in module benchbuild.command)": [[8, "benchbuild.command.ProjectRoot"]], "prunefn (class in benchbuild.command)": [[8, "benchbuild.command.PruneFn"]], "restorefn (class in benchbuild.command)": [[8, "benchbuild.command.RestoreFn"]], "rootrenderer (class in benchbuild.command)": [[8, "benchbuild.command.RootRenderer"]], "sourceroot() (in module benchbuild.command)": [[8, "benchbuild.command.SourceRoot"]], "sourcerootrenderer (class in benchbuild.command)": [[8, "benchbuild.command.SourceRootRenderer"]], "supportsunwrap (class in benchbuild.command)": [[8, "benchbuild.command.SupportsUnwrap"]], "workloadset (class in benchbuild.command)": [[8, "benchbuild.command.WorkloadSet"]], "as_plumbum() (benchbuild.command.command method)": [[8, "benchbuild.command.Command.as_plumbum"]], "benchbuild.command": [[8, "module-benchbuild.command"]], "cleanup() (in module benchbuild.command)": [[8, "benchbuild.command.cleanup"]], "command (benchbuild.command.projectcommand attribute)": [[8, "benchbuild.command.ProjectCommand.command"]], "consumes (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.consumes"]], "consumes (benchbuild.command.command property)": [[8, "id0"]], "creates (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.creates"]], "creates (benchbuild.command.command property)": [[8, "id1"]], "dirname (benchbuild.command.command property)": [[8, "benchbuild.command.Command.dirname"]], "dirname (benchbuild.command.pathtoken property)": [[8, "benchbuild.command.PathToken.dirname"]], "env() (benchbuild.command.command method)": [[8, "benchbuild.command.Command.env"]], "exists() (benchbuild.command.pathtoken method)": [[8, "benchbuild.command.PathToken.exists"]], "filter_workload_index() (in module benchbuild.command)": [[8, "benchbuild.command.filter_workload_index"]], "label (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.label"]], "label (benchbuild.command.command property)": [[8, "id2"]], "left (benchbuild.command.pathtoken attribute)": [[8, "benchbuild.command.PathToken.left"]], "local (benchbuild.command.sourcerootrenderer attribute)": [[8, "benchbuild.command.SourceRootRenderer.local"]], "make_token() (benchbuild.command.argstoken class method)": [[8, "benchbuild.command.ArgsToken.make_token"]], "make_token() (benchbuild.command.pathtoken class method)": [[8, "benchbuild.command.PathToken.make_token"]], "name (benchbuild.command.command property)": [[8, "benchbuild.command.Command.name"]], "name (benchbuild.command.pathtoken property)": [[8, "benchbuild.command.PathToken.name"]], "output (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.output"]], "output (benchbuild.command.command property)": [[8, "id3"]], "output_param (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.output_param"]], "path (benchbuild.command.command attribute)": [[8, "benchbuild.command.Command.path"]], "path (benchbuild.command.command property)": [[8, "id4"]], "path (benchbuild.command.projectcommand property)": [[8, "benchbuild.command.ProjectCommand.path"]], "project (benchbuild.command.projectcommand attribute)": [[8, "benchbuild.command.ProjectCommand.project"]], "project_root() (in module benchbuild.command)": [[8, "benchbuild.command.project_root"]], "render() (benchbuild.command.argstoken method)": [[8, "benchbuild.command.ArgsToken.render"]], "render() (benchbuild.command.pathtoken method)": [[8, "benchbuild.command.PathToken.render"]], "rendered() (benchbuild.command.argsrenderstrategy method)": [[8, "benchbuild.command.ArgsRenderStrategy.rendered"]], "rendered() (benchbuild.command.builddirrenderer method)": [[8, "benchbuild.command.BuilddirRenderer.rendered"]], "rendered() (benchbuild.command.conststrrenderer method)": [[8, "benchbuild.command.ConstStrRenderer.rendered"]], "rendered() (benchbuild.command.pathrenderstrategy method)": [[8, "benchbuild.command.PathRenderStrategy.rendered"]], "rendered() (benchbuild.command.rootrenderer method)": [[8, "benchbuild.command.RootRenderer.rendered"]], "rendered() (benchbuild.command.sourcerootrenderer method)": [[8, "benchbuild.command.SourceRootRenderer.rendered"]], "rendered_args() (benchbuild.command.command method)": [[8, "benchbuild.command.Command.rendered_args"]], "renderer (benchbuild.command.argstoken attribute)": [[8, "benchbuild.command.ArgsToken.renderer"]], "renderer (benchbuild.command.pathtoken attribute)": [[8, "benchbuild.command.PathToken.renderer"]], "rev_range (benchbuild.command.onlyin attribute)": [[8, "benchbuild.command.OnlyIn.rev_range"]], "right (benchbuild.command.pathtoken attribute)": [[8, "benchbuild.command.PathToken.right"]], "source_root() (in module benchbuild.command)": [[8, "benchbuild.command.source_root"]], "unrendered (benchbuild.command.argsrenderstrategy property)": [[8, "benchbuild.command.ArgsRenderStrategy.unrendered"]], "unrendered (benchbuild.command.builddirrenderer property)": [[8, "benchbuild.command.BuilddirRenderer.unrendered"]], "unrendered (benchbuild.command.conststrrenderer property)": [[8, "benchbuild.command.ConstStrRenderer.unrendered"]], "unrendered (benchbuild.command.pathrenderstrategy property)": [[8, "benchbuild.command.PathRenderStrategy.unrendered"]], "unrendered (benchbuild.command.rootrenderer property)": [[8, "benchbuild.command.RootRenderer.unrendered"]], "unrendered (benchbuild.command.sourcerootrenderer property)": [[8, "benchbuild.command.SourceRootRenderer.unrendered"]], "unwrap() (benchbuild.command.onlyin method)": [[8, "benchbuild.command.OnlyIn.unwrap"]], "unwrap() (benchbuild.command.supportsunwrap method)": [[8, "benchbuild.command.SupportsUnwrap.unwrap"]], "unwrap() (benchbuild.command.workloadset method)": [[8, "benchbuild.command.WorkloadSet.unwrap"]], "unwrap() (in module benchbuild.command)": [[8, "benchbuild.command.unwrap"]], "value (benchbuild.command.conststrrenderer attribute)": [[8, "benchbuild.command.ConstStrRenderer.value"]], "workload_set (benchbuild.command.onlyin attribute)": [[8, "benchbuild.command.OnlyIn.workload_set"]], "basesource (class in benchbuild.source.base)": [[12, "benchbuild.source.base.BaseSource"]], "contextawaresource (class in benchbuild.source.base)": [[12, "benchbuild.source.base.ContextAwareSource"]], "contextenumeratorfn (class in benchbuild.source.base)": [[12, "benchbuild.source.base.ContextEnumeratorFn"]], "contextfreemixin (class in benchbuild.source.base)": [[12, "benchbuild.source.base.ContextFreeMixin"]], "enumeratorfn (class in benchbuild.source.base)": [[12, "benchbuild.source.base.EnumeratorFn"]], "expandable (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Expandable"]], "fetchable (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Fetchable"]], "fetchablesource (class in benchbuild.source.base)": [[12, "benchbuild.source.base.FetchableSource"]], "git (class in benchbuild.source.git)": [[12, "benchbuild.source.git.Git"]], "gitsubmodule (class in benchbuild.source.git)": [[12, "benchbuild.source.git.GitSubmodule"]], "http (class in benchbuild.source.http)": [[12, "benchbuild.source.http.HTTP"]], "httpmultiple (class in benchbuild.source.http)": [[12, "benchbuild.source.http.HTTPMultiple"]], "httpuntar (class in benchbuild.source.http)": [[12, "benchbuild.source.http.HTTPUntar"]], "nosource (class in benchbuild.source.base)": [[12, "benchbuild.source.base.NoSource"]], "revision (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Revision"]], "revisionstr (class in benchbuild.source.base)": [[12, "benchbuild.source.base.RevisionStr"]], "variant (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Variant"]], "versioned (class in benchbuild.source.base)": [[12, "benchbuild.source.base.Versioned"]], "benchbuild.source": [[12, "module-benchbuild.source"]], "benchbuild.source.base": [[12, "module-benchbuild.source.base"]], "benchbuild.source.git": [[12, "module-benchbuild.source.git"]], "benchbuild.source.http": [[12, "module-benchbuild.source.http"]], "benchbuild.source.rsync": [[12, "module-benchbuild.source.rsync"]], "clone_needed() (in module benchbuild.source.git)": [[12, "benchbuild.source.git.clone_needed"]], "default (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.default"]], "default (benchbuild.source.base.nosource property)": [[12, "benchbuild.source.base.NoSource.default"]], "default (benchbuild.source.base.versioned property)": [[12, "benchbuild.source.base.Versioned.default"]], "default (benchbuild.source.git.git property)": [[12, "benchbuild.source.git.Git.default"]], "default (benchbuild.source.http.http property)": [[12, "benchbuild.source.http.HTTP.default"]], "download_required() (in module benchbuild.source.http)": [[12, "benchbuild.source.http.download_required"]], "download_single_version() (in module benchbuild.source.http)": [[12, "benchbuild.source.http.download_single_version"]], "enumerate_revisions() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.enumerate_revisions"]], "explore() (benchbuild.source.base.fetchablesource method)": [[12, "benchbuild.source.base.FetchableSource.explore"]], "extend() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.extend"]], "fetch() (benchbuild.source.base.fetchable method)": [[12, "benchbuild.source.base.Fetchable.fetch"]], "fetch() (benchbuild.source.base.fetchablesource method)": [[12, "benchbuild.source.base.FetchableSource.fetch"]], "fetch() (benchbuild.source.base.nosource method)": [[12, "benchbuild.source.base.NoSource.fetch"]], "fetch() (benchbuild.source.git.git method)": [[12, "benchbuild.source.git.Git.fetch"]], "fetch() (benchbuild.source.http.http method)": [[12, "benchbuild.source.http.HTTP.fetch"]], "fetch_version() (benchbuild.source.http.http method)": [[12, "benchbuild.source.http.HTTP.fetch_version"]], "fetch_version() (benchbuild.source.http.httpmultiple method)": [[12, "benchbuild.source.http.HTTPMultiple.fetch_version"]], "has_variant() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.has_variant"]], "is_context_free() (benchbuild.source.base.contextawaresource method)": [[12, "benchbuild.source.base.ContextAwareSource.is_context_free"]], "is_context_free() (benchbuild.source.base.contextfreemixin method)": [[12, "benchbuild.source.base.ContextFreeMixin.is_context_free"]], "is_expandable (benchbuild.source.base.expandable property)": [[12, "benchbuild.source.base.Expandable.is_expandable"]], "is_expandable (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.is_expandable"]], "is_expandable (benchbuild.source.git.gitsubmodule property)": [[12, "benchbuild.source.git.GitSubmodule.is_expandable"]], "key (benchbuild.source.base.fetchable property)": [[12, "benchbuild.source.base.Fetchable.key"]], "key (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.key"]], "local (benchbuild.source.base.fetchable property)": [[12, "benchbuild.source.base.Fetchable.local"]], "local (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.local"]], "maybe_shallow() (in module benchbuild.source.git)": [[12, "benchbuild.source.git.maybe_shallow"]], "name() (benchbuild.source.base.variant method)": [[12, "benchbuild.source.base.Variant.name"]], "normalize_remotes() (in module benchbuild.source.http)": [[12, "benchbuild.source.http.normalize_remotes"]], "nosource() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.nosource"]], "owner (benchbuild.source.base.variant attribute)": [[12, "benchbuild.source.base.Variant.owner"]], "primary (benchbuild.source.base.revision property)": [[12, "benchbuild.source.base.Revision.primary"]], "primary() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.primary"]], "product() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.product"]], "project_cls (benchbuild.source.base.revision attribute)": [[12, "benchbuild.source.base.Revision.project_cls"]], "remote (benchbuild.source.base.fetchable property)": [[12, "benchbuild.source.base.Fetchable.remote"]], "remote (benchbuild.source.base.fetchablesource property)": [[12, "benchbuild.source.base.FetchableSource.remote"]], "revision_from_str() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.revision_from_str"]], "secondaries() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.secondaries"]], "sorted() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.sorted"]], "source() (benchbuild.source.base.variant method)": [[12, "benchbuild.source.base.Variant.source"]], "source_by_name() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.source_by_name"]], "sources_as_dict() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.sources_as_dict"]], "target_prefix() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.target_prefix"]], "to_str() (in module benchbuild.source.base)": [[12, "benchbuild.source.base.to_str"]], "update() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.update"]], "value (benchbuild.source.base.revisionstr attribute)": [[12, "benchbuild.source.base.RevisionStr.value"]], "variant_by_name() (benchbuild.source.base.revision method)": [[12, "benchbuild.source.base.Revision.variant_by_name"]], "variants (benchbuild.source.base.revision attribute)": [[12, "benchbuild.source.base.Revision.variants"]], "version (benchbuild.source.base.variant attribute)": [[12, "benchbuild.source.base.Variant.version"]], "version() (benchbuild.source.base.fetchablesource method)": [[12, "benchbuild.source.base.FetchableSource.version"]], "version() (benchbuild.source.base.nosource method)": [[12, "benchbuild.source.base.NoSource.version"]], "version() (benchbuild.source.base.versioned method)": [[12, "benchbuild.source.base.Versioned.version"]], "version() (benchbuild.source.git.git method)": [[12, "benchbuild.source.git.Git.version"]], "version() (benchbuild.source.http.http method)": [[12, "benchbuild.source.http.HTTP.version"]], "version() (benchbuild.source.http.httpuntar method)": [[12, "benchbuild.source.http.HTTPUntar.version"]], "versioned_target_name() (in module benchbuild.source.http)": [[12, "benchbuild.source.http.versioned_target_name"]], "versions() (benchbuild.source.base.expandable method)": [[12, "benchbuild.source.base.Expandable.versions"]], "versions() (benchbuild.source.base.fetchablesource method)": [[12, "benchbuild.source.base.FetchableSource.versions"]], "versions() (benchbuild.source.base.nosource method)": [[12, "benchbuild.source.base.NoSource.versions"]], "versions() (benchbuild.source.base.versioned method)": [[12, "benchbuild.source.base.Versioned.versions"]], "versions() (benchbuild.source.git.git method)": [[12, "benchbuild.source.git.Git.versions"]], "versions() (benchbuild.source.http.http method)": [[12, "benchbuild.source.http.HTTP.versions"]], "versions_with_context() (benchbuild.source.base.contextawaresource method)": [[12, "benchbuild.source.base.ContextAwareSource.versions_with_context"]], "versions_with_context() (benchbuild.source.base.contextfreemixin method)": [[12, "benchbuild.source.base.ContextFreeMixin.versions_with_context"]]}}) \ No newline at end of file