From c0f597864179991033efce416ee9e440be8815ec Mon Sep 17 00:00:00 2001 From: aliciaaevans Date: Tue, 14 Nov 2023 18:01:51 -0500 Subject: [PATCH 01/41] add aarch64 to support --- source/developer/repodata_patching.rst | 4 +++- source/faqs.rst | 2 +- source/index.rst | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/source/developer/repodata_patching.rst b/source/developer/repodata_patching.rst index b54502b..061c0fa 100644 --- a/source/developer/repodata_patching.rst +++ b/source/developer/repodata_patching.rst @@ -16,7 +16,7 @@ What is repodata? ----------------- Repodata is a JSON file that contains a variety of information for each package -in Bioconda. There is one for each architecture (linux-64, osx-64, noarch, etc.) +in Bioconda. There is one for each architecture (linux-64, linux-aarch64, osx-64, noarch, etc.) and they're hosted by bioconda. For example, the noarch repodata.json file `is available here `_. Let's take a look at the what sorts of things are stored within this file for a @@ -77,6 +77,8 @@ each architecture:: │   └── patch_instructions.json └── osx-64 └── patch_instructions.json +.. + TODO: update when bioconda-repodata-patches is updated with linux-aarch64 For an individual package, the json file will contain the updated dependencies. For the `nanoqc` example above, that would look like:: diff --git a/source/faqs.rst b/source/faqs.rst index aa30381..6d512f3 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -80,7 +80,7 @@ What versions are supported? Operating Systems ~~~~~~~~~~~~~~~~~ -Bioconda only supports 64-bit Linux and macOS. ARM is not currently supported. +Bioconda only supports Linux (64-bit and AArch64) and macOS (64-bit). ARM is not currently supported for macOS. Python ~~~~~~ diff --git a/source/index.rst b/source/index.rst index 7d5ffbc..a232406 100644 --- a/source/index.rst +++ b/source/index.rst @@ -18,7 +18,7 @@ **Bioconda** lets you install thousands of software packages related to biomedical research using the `conda `_ package manager. -**NOTE**: *Bioconda supports only 64-bit Linux and macOS* +**NOTE**: *Bioconda supports only Linux (64-bit and AArch64) and macOS (64-bit)* Usage ===== From d3a18abe81e53cf86cfe64a5802ce3c05e99228e Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:05:07 -0500 Subject: [PATCH 02/41] add new datechanged directive --- source/_ext/datechanged_ext.py | 19 +++++++++++++++++++ source/conf.py | 1 + 2 files changed, 20 insertions(+) create mode 100644 source/_ext/datechanged_ext.py diff --git a/source/_ext/datechanged_ext.py b/source/_ext/datechanged_ext.py new file mode 100644 index 0000000..f7ac257 --- /dev/null +++ b/source/_ext/datechanged_ext.py @@ -0,0 +1,19 @@ +""" +Slight modification of the .. versionchanged:: directive that prints "changed +on" rather than "changed in version". +""" + +from sphinx.domains import changeset +from sphinx.locale import _ + +changeset.versionlabels['datechanged'] = _("Changed on %s") +changeset.versionlabel_classes['datechanged'] = 'changed' + +def setup(app): + app.add_directive('datechanged', changeset.VersionChange) + return { + 'version': 'builtin', + 'env_version': 1, + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/source/conf.py b/source/conf.py index aa15c86..bb72a08 100644 --- a/source/conf.py +++ b/source/conf.py @@ -26,6 +26,7 @@ def setup(app): extensions = [ "bioconda_sphinx_ext", "details_ext", + "datechanged_ext", "sphinx.ext.intersphinx", "sphinx.ext.todo", "sphinx.ext.mathjax", From ee47a8257a5ed7aeb49348758c79b7b7fdffd566 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:05:22 -0500 Subject: [PATCH 03/41] add section on platform nomenclature --- source/contributor/faqs.rst | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/source/contributor/faqs.rst b/source/contributor/faqs.rst index cde479b..b8a938a 100644 --- a/source/contributor/faqs.rst +++ b/source/contributor/faqs.rst @@ -169,3 +169,67 @@ which elements and values can appear in ``meta.yaml``. Conda has this information available `here `_. Please check that you are looking at the correct version of the documentation for the current conda version used by bioconda. + + +.. _platform-nomenclature-faq: + +Understanding platform nomenclature +----------------------------------- + +Different CPU chips use different architecture, so programs are written +fundamentally differently for them. Why do we care about this for conda +packages? Because a package with compiled dependencies must have +platform-specific dependencies. + +New Apple Silicon + +There is a lot of confusing nomenclature surrounding them. Here is an attempt +at clearing them up, or at least providing enough context that you can look up +more details on your own: + +**instruction set, CISC, RISC, RISC-V**: The *instruction set* is the assembly +code commands that are possible for the chip. *CISC* is "complex instruction set +computer", prioritizing flexibility; *RISC* is "reduced instruction set +computer", prioritizing power consumption (oversimplification, but that's the +general idea). Instruction sets can be proprietary. ARM is a company that +licenses a widely-used proprietary reduced instruction set. RISC-V is an open +(non-proprietary) reduced instruction set. + +**ARM vs ARM RISC:** ARM is a company. They make chips (for example, the ones +used in Raspberry Pi computers). They also license the proprietary RISC (for +example, they license it to Apple to run on their M-series chips). + +``x86_64``, ``amd64``: These are synonyms for the original Intel/AMD +architecture. + +``linux/x86_64``, ``linux/arm64``, ``darwin/amd64``: These are the platform +designators when using Docker (see `multi-platform images +`_ in the Docker +documentation). + +``linux-64``, ``linux-aarch64``, ``osx-64``, ``osx-arm64``: These are the +platform designators used by conda in channels hosted by Anaconda. + +``linux-64``, ``linux-aarch64``, ``osx-64``, ``osx-arm64``: These are the +labels the conda ecosystem gives to packages. + +``aarch64``, ``arm64``: These are synonyms for ARM 64-bit architecture. + +**M1, M2, M3, Apple Silicon**: These are chips made by Apple and used in Macs. +Apple licenses the ARM RISC, so they are considered aarch64 or arm64. + +Here is a summary table: + +.. list-table:: + + * - Linux machines from past few decades + - ``x86_64``, ``amd64``, ``linux/x86_64``, ``linux-64``. + + * - Newer Linux machines + - ``aarch64``, ``arm64``, ``linux-aarch64``, ``linux/arm64`` + + * - Newer Macs + - ``M1``, ``M2``, ``M3``, ``osx-arm64``, ``aarch64``, ``arm64``, ``darwin/amd64`` + + * - Older Macs + - ``osx-64`` From 72005641c69075ea819491012cc1544bc248e933 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:07:07 -0500 Subject: [PATCH 04/41] update supported python version info --- source/contributor/guidelines.rst | 2 +- source/faqs.rst | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/source/contributor/guidelines.rst b/source/contributor/guidelines.rst index f519e49..d8f19f3 100644 --- a/source/contributor/guidelines.rst +++ b/source/contributor/guidelines.rst @@ -215,7 +215,7 @@ a command-line tool, in which case that should be tested as well. By default, Python recipes (those that have ``python`` listed as a dependency) -must be successfully built and tested on Python 2.7, 3.6, and 3.7 in order to +must be successfully built and tested on all supported Python versions in order to pass. However, many Python packages are not fully compatible across all Python versions. Use the `preprocessing selectors ` in the meta.yaml file along with the ``build/skip`` entry to indicate that diff --git a/source/faqs.rst b/source/faqs.rst index 6d512f3..7956056 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -85,7 +85,17 @@ Bioconda only supports Linux (64-bit and AArch64) and macOS (64-bit). ARM is not Python ~~~~~~ -Bioconda only supports python 2.7, 3.6, 3.7, 3.8 and 3.9. +.. datechanged:: 2022-09-01 + Python 3.10 support started in Aug 2022 + +.. datechanged:: 2023-05-01 + Python 2.7, 3.6, 3.7 support were dropped for new recipes in May 2023. + +Bioconda currently supports Python 3.8, 3.9, and 3.10 (see :ref:`Pinned +packages` for where this is configured). + +There are still packages in the Bioconda channel for earlier versions of +Python (2.7, 3.6, and 3.7). The exception to this is Bioconda packages which declare `noarch: python` and only depend on such packages - those packages can be installed in an From 628dc0c63e40ff2e7dcf929dfc85de3673e8145a Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:07:28 -0500 Subject: [PATCH 05/41] minor tweaks to guidelines --- source/contributor/guidelines.rst | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/source/contributor/guidelines.rst b/source/contributor/guidelines.rst index d8f19f3..49cd350 100644 --- a/source/contributor/guidelines.rst +++ b/source/contributor/guidelines.rst @@ -159,10 +159,13 @@ runs the tests listed in the ``test`` section of the recipe's ``meta.yaml`` file in an environment which does not have the dependencies listed in the ``test: requires:`` section. Because of this, all tests in that section must only rely on runtime dependencies or the build will fail. -Tests that rely on the test-time dependencies listed in ``test: requires:`` should be put in -the ``run_test.sh`` file in the same directory as the ``meta.yaml`` file. This file is -picked up and run by the standard build that occurs before the ``mulled-build``, but is -not passed on to and run by the ``mulled-build``. + +If you do want to run tests that rely on dependencies listed in ``test: +requires:``, those tests should not be written directly in the ``meta.yaml`` +file but instead put in a ``run_test.sh`` file in the same directory as the +``meta.yaml`` file. This file is picked up and run by the standard conda build +test that occurs before the ``mulled-build``, but is not passed on to and run +by the ``mulled-build``. .. _patching: @@ -378,6 +381,12 @@ Use ``conda skeleton cpan `` to build a recipe for Perl and place the recipe in the ``recipes`` dir. The recipe will have the ``perl-`` prefix. +.. note:: + + Historically, before conda-forge hosted Perl packages, many + non-bioinformatics-related Perl packages were hosted on Bioconda. These are + slowly being migrated to conda-forge. + An example of such a package is `perl-module-build `_. From fab702718bce38fe3772473b8a6ec01df5cb87f7 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:08:11 -0500 Subject: [PATCH 06/41] fix typos --- source/developer/bulk.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/developer/bulk.rst b/source/developer/bulk.rst index ed32645..d72f098 100644 --- a/source/developer/bulk.rst +++ b/source/developer/bulk.rst @@ -97,7 +97,7 @@ example is updating pinnings to support Python 3.10. 6. Then, **bulk-commit** and push the changes. -7. Once the CI run has finished, inspect all build failures (see :ref:`handling-build-failues`). +7. Once the CI run has finished, inspect all build failures (see :ref:`handling-build-failures`). For each failure, decide whether the recipe shall be skiplisted or whether you would like to fix it. In general it is advisable to fix all libraries on which many recipes depend and anything else that is obvious and easy. For the rest, mark the recipes as skiplisted in the build failure file. @@ -131,7 +131,7 @@ Handling build failures Build failures are stored in a file ``build_failure..yaml`` next to each failing recipe. You can list all build failures stored in the current branch of bioconda-recipes via the command -``bioconda-utils list-build-failures recipes config.yaml``. The presented table will be sorted by +``bioconda-utils list-build-failures recipes config.yml``. The presented table on stdout will be sorted by the number of dependencies and package downloads, which should help for prioritizing the fixing work. This file can look e.g. like this: @@ -153,7 +153,7 @@ Check out all possibilities in the corresponding help message: .. code-block:: bash - bioconda-utils annotate-build-failure --help + bioconda-utils annotate-build-failures --help Skiplisted recipes from the master branch are automatically displayed in a `wiki page `_, so that others can pick them up for providing a fix. From 684368ec14b593a3c79ac919a9f7a8f3d14bcbdc Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:08:19 -0500 Subject: [PATCH 07/41] minor cleanup on bulk.rst --- source/developer/bulk.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/developer/bulk.rst b/source/developer/bulk.rst index d72f098..87d95dc 100644 --- a/source/developer/bulk.rst +++ b/source/developer/bulk.rst @@ -29,8 +29,9 @@ decides whether it will run its jobs or not. * If any of the pushed commit messages contains the substring ``[ci run]`` the CI jobs are executed. * If not, no CI jobs are executed. -The reason for this behavior is that we want to avoid race conditions caused by multiple CI jobs -spawned from different commits to be exectuted at the same time. +The reason for this behavior is that we want to avoid race conditions caused by +multiple CI jobs spawned from different commits, possibly from different +people, to be exectuted at the same time. In order to simplify interactions with the bulk CI, bioconda-utils offers therefore some dedicated subcommands: @@ -109,8 +110,7 @@ example is updating pinnings to support Python 3.10. step 6-7 again. If the run has finished without any build failure and did not time out before checking all recipes, you can go on with step 7. -9. Once all the packages have either been successfully built or skiplisted, merge in the master branch - (after doing a git pull on it). +9. Once all the packages have either been successfully built or skiplisted, pull the master branch and merge it into bulk. Usually, conflicts can occur here due to build-numbers having been increased in the master branch while you did your changes in bulk. For such cases (which should be not so many) you can just increase the build number to ``max(build_number_master, build_number_bulk)`` and **bulk-commit** all of those in a row. From 636d1e74645999a78280bcb83240cc83d71ac0d9 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:08:51 -0500 Subject: [PATCH 08/41] clarification on repodata patching --- source/developer/repodata_patching.rst | 32 +++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/source/developer/repodata_patching.rst b/source/developer/repodata_patching.rst index 061c0fa..8e4d01d 100644 --- a/source/developer/repodata_patching.rst +++ b/source/developer/repodata_patching.rst @@ -7,17 +7,22 @@ That wouldn't be a problem, except nanoqc doesn't restrict the range of `bokeh` that can be installed. Thus, you and everyone else in the world, will constantly get non-functional installs whenever creating new environments with nanoqc. Sure you can get around this with `conda create -n nanoqc nanoqc bokeh=2.4.3`, -but that still leaves things broken for everyone else in the world. Wouldn't it -be nice if you could just fix the nanoqc package, in place, such that it -magically contains a restriction on the version of bokeh that it depends on? It -turns out you **CAN** do this with repodata patching. +but that still leaves things broken for everyone else in the world. Another +option would be to update the nanoqc recipe in bioconda-recipes, and this +should also be done if the latest version is problematic, but this would not +solve all other existing, earlier versions of nanoqc packages that also do not +restrict bokeh. + +Wouldn't it be nice if you could just fix the nanoqc package, in place, such +that it magically contains a restriction on the version of bokeh that it +depends on? It turns out you **CAN** do this with repodata patching. What is repodata? ----------------- Repodata is a JSON file that contains a variety of information for each package in Bioconda. There is one for each architecture (linux-64, linux-aarch64, osx-64, noarch, etc.) -and they're hosted by bioconda. For example, the noarch repodata.json file `is +and they're hosted in the bioconda channel. For example, the noarch repodata.json file `is available here `_. Let's take a look at the what sorts of things are stored within this file for a single package: @@ -60,9 +65,10 @@ This is what's used by `conda` and `mamba` for determining what packages exist and their dependencies. Note that the exact fields have changed over time, with older packages lacking things like the `timestamp` value. -In order to add/remove/update a dependency, we need to modify the `depends` list -in each package that should be modified. We can't directly modify these files, -instead we need to patch them with the bioconda-repodata-patches package. +In order to add/remove/update a dependency (like restricting the bokeh +version), we need to modify the `depends` list in each package that should be +modified. We can't directly modify these files, instead we need to patch them +with the bioconda-repodata-patches package. The bioconda-repodata-patches package ------------------------------------- @@ -80,8 +86,8 @@ each architecture:: .. TODO: update when bioconda-repodata-patches is updated with linux-aarch64 -For an individual package, the json file will contain the updated dependencies. -For the `nanoqc` example above, that would look like:: +For an individual package, the json file will eventually contain the updated dependencies. +For the `nanoqc` example above, that will eventually look like:: "nanoqc-0.9.4-py_0.tar.bz2": { "depends": [ @@ -94,11 +100,15 @@ For the `nanoqc` example above, that would look like:: Thankfully, you do not need to manually update each package and in fact if you do your changes will almost certainly be lost over time. Instead, within the -`bioconda-repodata-patches` recipe, edit and run the `gen_patch_json.py` script. +`bioconda-repodata-patches` recipe, edit and run the `gen_patch_json.py` script +as described below. Modifying gen_patch_json.py --------------------------- +We will be working in the `bioconda-repodate-patches recipe +`_. + The `gen_patch_json.py` file is borrowed from conda-forge and has one function that should typically be modified: `_gen_new_index`. Within this function, each record in repodata.json is iterated over and changes that should be made to it From 6dbbb3020c4eba25901b20a415994759b88be07e Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:10:23 -0500 Subject: [PATCH 09/41] add Alicia to core team --- source/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/source/index.rst b/source/index.rst index a232406..85985ab 100644 --- a/source/index.rst +++ b/source/index.rst @@ -279,6 +279,7 @@ Core * `Elmar Pruesse `_ * `Robert A. Petit III `_ * `Christian Brueffer `_ +* `Alicia Evans `_ Former core members ~~~~~~~~~~~~~~~~~~~ From 627984c80059a2bb86533c566ca26b51207a946f Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:10:34 -0500 Subject: [PATCH 10/41] update notes on building docs --- source/index.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/index.rst b/source/index.rst index 85985ab..f286261 100644 --- a/source/index.rst +++ b/source/index.rst @@ -3,9 +3,11 @@ To build the documentation locally, first create an environment using bioconda_utils/bioconda_utils-requirements.txt. - Then activate the env and run: + mamba create -p ./env --file https://raw.githubusercontent.com/bioconda/bioconda-utils/master/bioconda_utils/bioconda_utils-requirements.txt -y - make -C docs/ BIOCONDA_FILTER_RECIPES=2 SPHINXOPTS="-E" html + With that env activated, run: + + make BIOCONDA_FILTER_RECIPES=2 SPHINXOPTS="-E" html This will only build 2 of the recipes pages, dramatically speeding up the build process. From 0c1b1ff14592ddba6ee253dcd25975ac086023df Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:10:52 -0500 Subject: [PATCH 11/41] css on datechanged directives --- source/static/style.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/static/style.css b/source/static/style.css index c76fb1b..69844ce 100644 --- a/source/static/style.css +++ b/source/static/style.css @@ -168,3 +168,13 @@ details a.headerlink { color: #ccc; visibility: visible; } + +div.datechanged { + font-style: italic; + font-size: 0.9em; +} + +.versionmodified { + color: #3eb049; +} + From fecf0077ba550e163d0b2f73bdea42b14a935376 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:11:41 -0500 Subject: [PATCH 12/41] overhaul and update CI inventory page --- source/developer/ci-inventory.rst | 393 ++++++++++++++++++------------ source/static/style.css | 4 + 2 files changed, 238 insertions(+), 159 deletions(-) diff --git a/source/developer/ci-inventory.rst b/source/developer/ci-inventory.rst index a129f36..e5dc9d6 100644 --- a/source/developer/ci-inventory.rst +++ b/source/developer/ci-inventory.rst @@ -1,166 +1,241 @@ CI Inventory ============ -This page documents the various moving parts that, together, make Bioconda -work. We rely on a mixture of free services to spread the workload and to -maintain flexibility over the long term in case a service becomes unusable. - -Autobump bot ------------- - -Checks upstream repository for version updates, if so, creates a new -bioconda-recipes recipe with the updated version and an updated hash, and opens -a new pull request with various templated info and with the "autobump" label -applied. - -:runs on: CircleCI -:controlled from: bioconda-utils -:trigger: hourly -:code references: `config.yml `_ -:OS: Linux - -Documentation -------------- - -Build sphinx documentation (including updated READMEs for every recipe) and -pushes the changes to -[bioconda.github.io](https://github.com/bioconda/bioconda.github.io). - -:runs on: GitHub Actions -:controlled from: bioconda-docs -:trigger: daily, or on push -:code references: `docs.yml `_ -:OS: Linux - -bioconda-utils tests --------------------- - -Unit tests and functional tests for bioconda-utils - -:runs on: GitHub Actions -:controlled from: bioconda-utils -:trigger: on push -:code references: `GithubActionTests.yml `_ -:OS: Linux, macOS - -Test building bioconda-utils docker image ------------------------------------------ - -Ensures that bioconda-utils can run inside a newly-built container. - -:runs on: GitHub Actions -:controlled from: bioconda-utils -:trigger: on push -:code references: `build-image.yml `_, `Dockerfile `_ - -Ensure Biocontainers are public -------------------------------- - -Checks quay.io to see if any containers are mistakenly private; if so makes them public - -:runs on: GitHub Actions -:controlled from: bioconda-utils -:triggered: manually -:code references: `changevisibility.yml `_ - -conventional PRs ----------------- - -Enforces "conventional commit" tags in the title of PRs, like "docs:", "fix:", "ci:", and so on. - -:runs on: GitHub Actions -:controlled from: bioconda-utils -:trigger: PR open/reopen/edit/sync -:code references: `conventional-prs.yml `_ -:OS: Linux - -release-please --------------- +.. datechanged:: 2023-05-02 + Use `mergify `_ instead of AutoMerge.yml GitHub Action -Collects PRs that have been merged to master since the last release into -a separate, special PR. Merging that special PR triggers a new release. +.. datechanged:: 2023-06-06 + Start using build-failures workflow -:runs on: GitHub Actions -:controlled from: bioconda-utils -:trigger: push to master on bioconda-utils -:code references: `release-please.yml `_ -:OS: Linux +.. datechanged:: 2023-11-18 + Start using ``linux-aarch64`` in bulk and recipe tests -Recipe tests ------------- - -Runs linting and tests for pull requests to bioconda-recipes. - -:runs on: Azure Pipelines -:controlled from: bioconda-recipes -:trigger: on push -:code references: `azure-pipeline.yml `_ -:OS: Linux, macOS - -master branch tests -------------------- - -Runs the same tests as for PRs, but on the master branch. Note that when the -bot merges, it uses [ci skip] in the commit comment and works with the -already-built artifacts, so this doesn't typically run. - -:runs on: Azure Pipelines -:controlled from: bioconda-recipes -:trigger: push to master -:code references: `azure-pipeline-master.yml `_ -:OS: Linux, macOS - - -nightly maintenance -------------------- -Various maintenance tasks: - -- build and upload the bioconda-repodata-patches package -- try to build and upload any remaining packages (runs bioconda-utils build on *all* recipes) - -:runs on: Azure Pipelines -:controlled from: bioconda-recipes -:trigger: daily -:code references: `azure-pipeline-nightly.yml `_ -:OS: Linux, macOS - - -automerge, automerge trigger ----------------------------- - -This is intended to automatically merge PRs when all checks pass (including the -review step). It will only be triggered if the AutoMergeTrigger workflow runs -successfully. If a PR's review is submitted or dismissed, or a PR is labeled -with "automerge", then this workflow fires, and needs to complete before the -AutoMerge workflow will run. - -:runs on: GitHub Actions -:controlled from: bioconda-recipes -:trigger: completed check suite -:code references: `AutoMerge.yml `_, `AutoMergeTrigger.yml `_ - - -Bulk ----- -If pushing to the special ``bulk`` branch, this workflow will run. It uses -special bioconda-utils functionality to split the full DAG into sub-DAGs and -submits them to independent parallel jobs. When recipes sucessfully build, they -are *immediately* uploaded. Use with caution. Typically used when migrating -(e.g., bioconductor updates, pinning updates) - -:runs on: GitHub Actions -:controlled from: bioconda-recipes -:trigger: push to ``bulk`` branch of bioconda-utils -:code references: `Bulk.yml `_ -:OS: Linux, macOS - -comment responder ------------------ - -Runs the bioconda-bot container (quay.io/bioconda/bot) with different image tags (merge, comment, update, repost) in response to comments. +This page documents the various moving parts that, together, make Bioconda +work. We rely on a mixture of free services to spread the workload and to +maintain flexibility over the long term in case a service becomes unusable. -:runs on: GitHub Actions -:controlled from: bioconda-recipes -:trigger: @bioconda-bot mentions -:code references: `CommentResponder.yml `_ -:OS: Linux +.. note:: + + For the platform column, we use the conda designations when conda packages + are built. Otherwise we use operating system. + See :ref:`platform-nomenclature-faq` for more info on this. + +.. + When updating this documentation in the future, go through all the existing + yaml files you can find across all the bioconda repos and make sure they are + represented here. + + bioconda-recipes: + - azure-pipeline-master.yml + - azure-pipeline-nightly.yml + - azure-pipeline.yml + - .circleci/config.yml + - .github/workflows/Bulk.yml + - .github/workflows/CommentResponder.yml + - .github/workflows/PR.yml <-------- appears to be manually disabled? + - .github/workflows/build-failures.yml + - .github/workflows/master.yml + - .github/workflows/nightly.yml <------- appears to be manually disabled? + + bioconda-utils: + - .circleci/config.yml + - .github/workfows/GithubActionTests.yml + - .github/workfows/build-image.yml + - .github/workfows/changevisibility.yml + - .github/workfows/conventional-prs.yml + - .github/workfows/release-please.yml + + bioconda-plots: + - .github/workfows/generate-plots.yml + + + +.. list-table:: + :header-rows: 1 + :class: inventory + + * - Name + - Runs on + - Controlled from + - Trigger + - Code references + - Platform + - Description + + + * - Recipe tests + - Azure Pipelines, CircleCI + - ``bioconda-recipes`` + - on push + - `azure-pipeline.yml `_ (``linux-64``, ``osx-64``); + `config.yml `_ (``linux-aarch64``) + - ``linux-64``, ``osx-64`` + - These are the most-run tests: these are what run on every change on + pull requests to bioconda-recipes, and they must pass before the recipe + is merged into the master branch. + + + * - Comment responder + - GitHub Actions + - ``bioconda-recipes`` + - @BiocondaBot mentions + - `CommentResponder.yml `_ + - Linux + - Runs the bioconda-bot container (quay.io/bioconda/bot) with different + image tags (merge, comment, update, repost) in response to comments. + This allows fast response time (rather than, say, restoring a cache + each time). + + + * - Master branch tests + - Azure Pipelines + - ``bioconda-recipes`` + - push to master (bioconda-recipes) + - `azure-pipeline-master.yml `_ + - ``linux-64``, ``osx-64``, ``linux-aarch64`` + - Runs the same tests as for PRs, but on the master branch. Note that + when the bot is doing the merge, it adds ``[ci skip]`` in the commit + comment, and works with the already-built artifacts from the PR. + + + * - Mergify + - `mergify `_ + - ``bioconda-recipes`` + - Successful tests on an autobumped recipe + - `.mergify.yml `_ + - Linux + - If a recipe was autobumped, the tests passed, and it's been more than + 3 days, then automatically merge the updated recipe. + + + * - Autobump bot + - CircleCI + - ``bioconda-utils`` + - hourly + - `config.yml `_ + - Linux + - Checks upstream repository for version updates, if so, creates a new + bioconda-recipes recipe with the updated version and an updated hash, + and opens a new pull request with various templated info and with the + "autobump" label applied. + + + * - Build failures + - GitHub Actions + - ``bioconda-recipes`` + - daily + - `build-failures.yaml `_ + - Linux + - Runs ``bioconda-utils list-build-failures`` to generate and publish + a `wiki page listing prioritized failures + `_. + + + * - Docs + - GitHub Actions + - ``bioconda-docs`` + - daily, or on push + - `docs.yml `_ + - Linux + - Build sphinx documentation (including updated READMEs for every recipe) + and pushes the changes to + [bioconda.github.io](https://github.com/bioconda/bioconda.github.io). + + + * - bioconda-utils tests + - GitHub Actions + - ``bioconda-utils`` + - on push + - `GithubActionTests.yml `_ + - ``linux-64``, ``osx-64`` + - Unit tests and functional tests for bioconda-utils. + + + * - Docker image test + - GitHub Actions + - ``bioconda-utils`` + - on push + - `build-image.yml `_, + `Dockerfile `_ + - Linux + - Ensures that bioconda-utils can run inside a newly-built container. + + + * - Check public containers + - GitHub Actions + - ``bioconda-utils`` + - manually + - `changevisibility.yml `_ + - Linux + - Checks quay.io to see if any containers are mistakenly private; if so + makes them public + + + * - Conventional PRs + - GitHub Actions + - ``bioconda-utils`` + - bioconda-utils PR open/reopen/edit/sync + - `conventional-prs.yml `_ + - Linux + - Enforces "conventional commit" tags in the title of PRs, like "docs:", + "fix:", "ci:", and so on in bioconda-utils. This enables better + automation of releases. + + + * - Release-please + - GitHub Actions + - ``bioconda-utils`` + - push to master on bioconda-utils + - `release-please.yml `_ + - Linux + - Collects PRs that have been merged to master since the last release + into a separate, special PR. Merging that special PR is what triggers + a new release. + + + * - Nightly maintenance + - Azure Pipelines + - ``bioconda-recipes`` + - daily + - `azure-pipeline-nightly.yml `_ + - Linux, macOS + - Various maintenance tasks: build and upload the + bioconda-repodata-patches package; try to build and upload any + remaining packages (runs bioconda-utils build on *all* recipes) + + + * - Bulk + - GitHub Actions + - ``bioconda-recipes`` + - push to ``bulk`` branch of bioconda-utils + - `Bulk.yml `_ (``linux-64``, ``osx-64``); + `config.yml `_ (``linux-aarch64``) + - ``linux-64``, ``osx-64``, ``linux-aarch64`` + - If pushing to the special ``bulk`` branch, this workflow will run. It + uses special bioconda-utils functionality to split the full DAG into + sub-DAGs and submits them to independent parallel jobs. When recipes + sucessfully build, they are *immediately* uploaded. Use with caution. + Typically used when migrating (e.g., bioconductor updates, pinning + updates) + + + * - Compile stats for plots + - GitHub Actions + - ``bioconda-stats`` + - several times a day + - `packages-anaconda-org.yml `_ + - Linux + - Builds a zip file containing TSVs for each package, which are inspected + and compiled into json files in ``bioconda-plots``. + + + * - Generate plots + - GitHub Actions + - ``bioconda-plots`` + - daily + - `generate-plots.yml `_; + `test-plots.yml `_ runs minor tests on the plot-generating code. + - Linux + - Using stats compiled in ``bioconda-stats``, builds json files for each + package that are used by plotting code on bioconda.github.io recipe + pages. diff --git a/source/static/style.css b/source/static/style.css index 69844ce..10191d6 100644 --- a/source/static/style.css +++ b/source/static/style.css @@ -178,3 +178,7 @@ div.datechanged { color: #3eb049; } +table.inventory { + overflow-x: scroll; + font-size: 0.8em; +} From ef5a87df46cd45c35d16aac35d2c8a3003023861 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 15:19:21 -0500 Subject: [PATCH 13/41] consolidate all FAQs together into top-level --- source/contributor/faqs.rst | 235 ----------------------------------- source/contributor/index.rst | 1 - source/faqs.rst | 119 +++++++++++++++++- 3 files changed, 118 insertions(+), 237 deletions(-) delete mode 100644 source/contributor/faqs.rst diff --git a/source/contributor/faqs.rst b/source/contributor/faqs.rst deleted file mode 100644 index b8a938a..0000000 --- a/source/contributor/faqs.rst +++ /dev/null @@ -1,235 +0,0 @@ -FAQs -==== -This section is to help contributors get up to speed on various topics related -to building and testing conda packages. - -.. _conda-anaconda-minconda: - -What's the difference between Anaconda, conda, and Miniconda? -------------------------------------------------------------- - -The `Anaconda Python distribution `_ -started out as a bundle of scientific Python packages that were otherwise -difficult to install. It was created by `ContinuumIO -`_ and remains the easiest way to install the full -scientific Python stack. - -Many packaging problems had to be solved in order to provide a cross-platform -bundle, and one of the tools that came out of that work was the conda package -manager. So conda is part of Anaconda. But conda ended up being very useful on -its own and for things other than Python, so ContinuumIO spun it out into its -own separate `open-source package `_. - -However, conda is not just for Python, it is not "pip-installable" and rather -needs to be installed in a language-agnostic manner. The conda installer is -called Miniconda, to differentiate it from the full-size Anaconda. - -So: conda is a package manager, Miniconda is the conda installer, and Anaconda -is a scientific Python distribution that also includes conda. - -Recipe vs package ------------------ - -A *recipe* is a directory containing small set of files that defines name, -version, dependencies, and URL for source code. A recipe typically contains -a ``meta.yaml`` file that defines these settings and a ``build.sh`` script that -builds the software. A recipe is converted into a *package* by running -`conda-build` on the recipe. A package is a bgzipped tar file (``.tar.bz2``) that -contains the built software. Packages are uploaded to anaconda.org so that -users can install them with ``conda install``. - -.. seealso:: - - The `conda-build:resources/package-spec` has details on exactly - what a package contains and how it is installed into an - environment. - -Continuous integration (Circle CI) ----------------------------------- -We use the Circle CI continuous integration service. Continuous integration -tests each small incremental change to code to ensure that everything is -up-to-date and correct. Circle CI graciously provides this service for free to -open-source projects. It is connected to GitHub such that each time a pull -request or merge occurs, a new Circle CI build is created. For bioconda, -a "build" means identifying any recipes that need to built, running -`conda-build` on them, and testing to make sure they work. - -How is Circle CI set up and configured? ---------------------------------------- - -- ``.circleci/config.yml`` is read by the Circle CI worker. - -- The worker runs ``.circleci/setup.sh``. This installs conda, adds - channels, and installs :doc:`../developer/bioconda-utils` - -- The worker runs tests defined in ``.circleci/config.yml``. - -A local version of the Circle CI tests can be executed via the -:ref:`Circle CI client `. Note that this version lacks some -additional tests that are executed in the online version. Thus, it can be that -a local test passes while the online test fails. -Nevertheless, the local test should capture most problems, such that it is highly -encouraged to first run a local test in order to save quota on Circle CI. - -How are dependencies pinned to particular versions? ---------------------------------------------------- - -In some cases a recipe may need to pin the version of a dependency. -A global set of default versions to pin against is shared with conda-forge and -can be found `here `_. -For new dependencies that are contained in conda-forge and not yet in this list, -please update the list via a pull request. -Local pinnings can be achieved by adding a file ``conda_build_config.yaml`` next -to your ``meta.yaml``. - -To find out against which version you can pin a package, e.g. x.y.* or x.* please use `ABI-Laboratory `_. - -What's the lifecycle of a bioconda package? -------------------------------------------- - -- Submit a pull request with a new recipe or an updated recipe -- Circle CI automatically builds and tests the changed recipe[s] using - conda-build. Test results are shown on the PR. -- If tests fail, push changes to PR until they pass. -- Once tests pass, merge into master branch -- Circle CI tests again, but this time after testing the built packages are - uploaded to the bioconda channel on anaconda.org. -- Users can now install the package just like any other conda package with - ``conda install``. - -Once uploaded to anaconda.org, it is our intention to never delete any old -packages. Even if a recipe in the bioconda repo is updated to a new version, -the old version will remain on anaconda.org. ContinuumIO has graciously agreed -to sponsor the storage required by the bioconda channel. -Nevertheless, it can sometimes happen that we have to mark packages as broken -in order to avoid that they are accidentally pulled by the conda solver. -In such a case it is only possible to install them by specifically considering -the ``broken`` label, i.e., - -.. code-block:: bash - - conda install -c conda-forge -c bioconda -c defaults -c bioconda/label/broken my-package= - - -.. _circlecimacos: - -CircleCI macOS plans --------------------- -In the past we had recommended enabling CircleCI for your fork to help conserve -the bioconda team's build time quota. However this did not work very well: -macOS builds on CircleCI require an extra macOS plan, which is not free to -users. The result was that contributors' pull requests would fail tests simply -due to not having a paid macOS plan. Luckily, CircleCI has generously provided -macOS builds to the bioconda team. - -To ensure that CircleCI uses the bioconda team account, please **disable** -CircleCI on your fork (look for the big red "Stop Building" button at -https://circleci.com/dashboard under the settings for your fork). - -Testing ``bioconda-utils`` locally ----------------------------------- - -Follow the instructions at :ref:`bootstrap` to create a separate Miniconda -installation using the ``bootstrap.py`` script in the ``bioconda-recipes`` repo. - -Then, in the activated environment, install the bioconda-utils test -requirements, from the top-level directory of the ``bioconda-utils`` repo. -While the bootstrap script installs bioconda-utils dependencies, if there are -any changes in ``requirements.txt`` you will want to install them as well. - -The bootstrap script already installed bioconda-utils, but we want to install -it in develop mode so we can make local changes and they will be immediately -picked up. So we need to uninstall and then reinstall bioconda-utils. - -Finally, run the tests using ``pytest``. - -In summary: - -.. code-block:: bash - - # activate env - source ~/.config/bioconda/activate - - # install dependencies - conda install --file test-requirements.txt --file bioconda_utils/bioconda_utils-requirements.txt - - # uninstall and then reinstall - pip uninstall bioconda_utils - python setup.py develop - - # run tests - pytest test -vv - -Where can I find more info on ``meta.yaml``? --------------------------------------------- - -The ``meta.yaml`` file is conda's metadata definition file for recipes. -If you are developing a new recipe or are trying to update or improve an existing one, it can be helpful to know -which elements and values can appear in ``meta.yaml``. - -Conda has this information available `here `_. -Please check that you are looking at the correct version of the documentation for the current conda version used by bioconda. - - -.. _platform-nomenclature-faq: - -Understanding platform nomenclature ------------------------------------ - -Different CPU chips use different architecture, so programs are written -fundamentally differently for them. Why do we care about this for conda -packages? Because a package with compiled dependencies must have -platform-specific dependencies. - -New Apple Silicon - -There is a lot of confusing nomenclature surrounding them. Here is an attempt -at clearing them up, or at least providing enough context that you can look up -more details on your own: - -**instruction set, CISC, RISC, RISC-V**: The *instruction set* is the assembly -code commands that are possible for the chip. *CISC* is "complex instruction set -computer", prioritizing flexibility; *RISC* is "reduced instruction set -computer", prioritizing power consumption (oversimplification, but that's the -general idea). Instruction sets can be proprietary. ARM is a company that -licenses a widely-used proprietary reduced instruction set. RISC-V is an open -(non-proprietary) reduced instruction set. - -**ARM vs ARM RISC:** ARM is a company. They make chips (for example, the ones -used in Raspberry Pi computers). They also license the proprietary RISC (for -example, they license it to Apple to run on their M-series chips). - -``x86_64``, ``amd64``: These are synonyms for the original Intel/AMD -architecture. - -``linux/x86_64``, ``linux/arm64``, ``darwin/amd64``: These are the platform -designators when using Docker (see `multi-platform images -`_ in the Docker -documentation). - -``linux-64``, ``linux-aarch64``, ``osx-64``, ``osx-arm64``: These are the -platform designators used by conda in channels hosted by Anaconda. - -``linux-64``, ``linux-aarch64``, ``osx-64``, ``osx-arm64``: These are the -labels the conda ecosystem gives to packages. - -``aarch64``, ``arm64``: These are synonyms for ARM 64-bit architecture. - -**M1, M2, M3, Apple Silicon**: These are chips made by Apple and used in Macs. -Apple licenses the ARM RISC, so they are considered aarch64 or arm64. - -Here is a summary table: - -.. list-table:: - - * - Linux machines from past few decades - - ``x86_64``, ``amd64``, ``linux/x86_64``, ``linux-64``. - - * - Newer Linux machines - - ``aarch64``, ``arm64``, ``linux-aarch64``, ``linux/arm64`` - - * - Newer Macs - - ``M1``, ``M2``, ``M3``, ``osx-arm64``, ``aarch64``, ``arm64``, ``darwin/amd64`` - - * - Older Macs - - ``osx-64`` diff --git a/source/contributor/index.rst b/source/contributor/index.rst index 93b5d74..2c40cdb 100644 --- a/source/contributor/index.rst +++ b/source/contributor/index.rst @@ -40,7 +40,6 @@ challenging to package. The topics below provide more details. guidelines linting - faqs updating cb3 diff --git a/source/faqs.rst b/source/faqs.rst index 7956056..e62e90c 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -80,7 +80,8 @@ What versions are supported? Operating Systems ~~~~~~~~~~~~~~~~~ -Bioconda only supports Linux (64-bit and AArch64) and macOS (64-bit). ARM is not currently supported for macOS. +Bioconda supports Linux (x86_64 and aarch64/arm64) and macOS (64-bit). ARM +is not currently supported for macOS. Windows is not supported. Python ~~~~~~ @@ -163,6 +164,10 @@ maintain) the same environment. What's the difference between Anaconda, conda, Miniconda, and mamba? -------------------------------------------------------------------- +This `blog post from Anaconda `_ +gives a lot of context on the Anaconda/conda ecosystem. + + - conda is the name of the package manager, which is what runs when you call, e.g., ``conda install``. - mamba is a drop-in replacement for conda (see above for details) @@ -383,3 +388,115 @@ The ``--no-builds`` argument completely removes the build number from the output, avoiding future errors when trying to rebuild the environment, and allowing the conda solver to identify the packages that can co-exist in the same environment. + +How are dependencies pinned to particular versions? +--------------------------------------------------- + +In some cases a recipe may need to pin the version of a dependency. +A global set of default versions to pin against is shared with conda-forge and +can be found `here `_. +For new dependencies that are contained in conda-forge and not yet in this list, +please update the list via a pull request. +Local pinnings can be achieved by adding a file ``conda_build_config.yaml`` next +to your ``meta.yaml``. + +To find out against which version you can pin a package, e.g. x.y.* or x.* please use `ABI-Laboratory `_. + +What's the lifecycle of a bioconda package? +------------------------------------------- + +- Submit a pull request with a new recipe or an updated recipe +- Circle CI automatically builds and tests the changed recipe[s] using + conda-build. Test results are shown on the PR. +- If tests fail, push changes to PR until they pass. +- Once tests pass, merge into master branch +- Circle CI tests again, but this time after testing the built packages are + uploaded to the bioconda channel on anaconda.org. +- Users can now install the package just like any other conda package with + ``conda install``. + +Once uploaded to anaconda.org, it is our intention to never delete any old +packages. Even if a recipe in the bioconda repo is updated to a new version, +the old version will remain on anaconda.org. ContinuumIO has graciously agreed +to sponsor the storage required by the bioconda channel. +Nevertheless, it can sometimes happen that we have to mark packages as broken +in order to avoid that they are accidentally pulled by the conda solver. +In such a case it is only possible to install them by specifically considering +the ``broken`` label, i.e., + +.. code-block:: bash + + conda install -c conda-forge -c bioconda -c defaults -c bioconda/label/broken my-package= + +Where can I find more info on ``meta.yaml``? +-------------------------------------------- + +The ``meta.yaml`` file is conda's metadata definition file for recipes. +If you are developing a new recipe or are trying to update or improve an existing one, it can be helpful to know +which elements and values can appear in ``meta.yaml``. + +Conda has this information available `here `_. +Please check that you are looking at the correct version of the documentation for the current conda version used by bioconda. + +.. _platform-nomenclature-faq: + +Understanding platform nomenclature +----------------------------------- + +Different CPU chips use different architecture, so programs are written +fundamentally differently for them. Why do we care about this for conda +packages? Because a package with compiled dependencies must have +platform-specific dependencies. + +New Apple Silicon + +There is a lot of confusing nomenclature surrounding them. Here is an attempt +at clearing them up, or at least providing enough context that you can look up +more details on your own: + +**instruction set, CISC, RISC, RISC-V**: The *instruction set* is the assembly +code commands that are possible for the chip. *CISC* is "complex instruction set +computer", prioritizing flexibility; *RISC* is "reduced instruction set +computer", prioritizing power consumption (oversimplification, but that's the +general idea). Instruction sets can be proprietary. ARM is a company that +licenses a widely-used proprietary reduced instruction set. RISC-V is an open +(non-proprietary) reduced instruction set. + +**ARM vs ARM RISC:** ARM is a company. They make chips (for example, the ones +used in Raspberry Pi computers). They also license the proprietary RISC (for +example, they license it to Apple to run on their M-series chips). + +``x86_64``, ``amd64``: These are synonyms for the original Intel/AMD +architecture. + +``linux/x86_64``, ``linux/arm64``, ``darwin/amd64``: These are the platform +designators when using Docker (see `multi-platform images +`_ in the Docker +documentation). + +``linux-64``, ``linux-aarch64``, ``osx-64``, ``osx-arm64``: These are the +platform designators used by conda in channels hosted by Anaconda. + +``linux-64``, ``linux-aarch64``, ``osx-64``, ``osx-arm64``: These are the +labels the conda ecosystem gives to packages. + +``aarch64``, ``arm64``: These are synonyms for ARM 64-bit architecture. + +**M1, M2, M3, Apple Silicon**: These are chips made by Apple and used in Macs. +Apple licenses the ARM RISC, so they are considered aarch64 or arm64. + +Here is a summary table: + +.. list-table:: + + * - Linux machines from past few decades + - ``x86_64``, ``amd64``, ``linux/x86_64``, ``linux-64``. + + * - Newer Linux machines + - ``aarch64``, ``arm64``, ``linux-aarch64``, ``linux/arm64`` + + * - Newer Macs + - ``M1``, ``M2``, ``M3``, ``osx-arm64``, ``aarch64``, ``arm64``, ``darwin/amd64`` + + * - Older Macs + - ``osx-64`` From 4c2c62a74480635d492fd44a7643abfd72cd0fb3 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 17:46:00 -0500 Subject: [PATCH 14/41] consolidate cb3.rst into top-level faqs --- source/contributor/cb3.rst | 264 ----------------------------------- source/contributor/index.rst | 3 - source/faqs.rst | 178 +++++++++++++++++------ 3 files changed, 132 insertions(+), 313 deletions(-) delete mode 100644 source/contributor/cb3.rst diff --git a/source/contributor/cb3.rst b/source/contributor/cb3.rst deleted file mode 100644 index daecce3..0000000 --- a/source/contributor/cb3.rst +++ /dev/null @@ -1,264 +0,0 @@ -.. _cb3-main: - -Conda build v3 --------------- - -Conda build version 3 has lots of nice features that will make managing -packages in Bioconda much easier. However there are some changes that you will -need to be aware of, especially if you're used to making recipes using the old -conda-build v2 way. - -This page documents each change and is intended to serve as a reference for the -transition. - -.. _host-section: - -The new ``host`` section -~~~~~~~~~~~~~~~~~~~~~~~~ - -**Summary:** - -- Previously, build-time dependencies were listed in the ``requirements:build:`` section. -- Conda-build 3 now has an additional ``requirements:host:`` section. It is required if - using compilers; otherwise old recipes can remain as-is and can be gradually - ported over. New recipes should use the new ``host`` section as described - below. - -Due to the improved way compilers are now being handled (see -:ref:`compiler-tools`), the old build section is now split into two sections, -``build`` and ``host``. This change is largely to support cross-compiling, -which we are not doing yet. However if a recipe uses one of the new ``{{ -compiler() }}`` methods described in :ref:`compiler-tools`, the ``host`` -section is **required**. - -The new ``build`` section should have things like compilers, ``git``, -``automake``, ``make``, ``cmake``, and other build tools. If there are no -compilers or other build tools, there should be no ``build:`` section. - -The new ``host`` section should have everything else. - -There are many existing recipes that only have a ``build:`` section. They will -work for now; they just won't work if we ever try to cross-compile them. -However **new** recipes should have the ``host:`` section. - -The ``run`` section remains the same. - -Before: - -.. code-block:: yaml - - package: - name: example - version: 0.1 - requirements: - build: - - python - run: - - python - -After: - -.. code-block:: yaml - - package: - name: example - version: 0.1 - requirements: - host: - - python - run: - - python - -.. seealso:: - - See the `requirements section ` of the - conda docs for more info. - - -.. _compiler-tools: - -Compiler tools -~~~~~~~~~~~~~~ -**Summary:** - -- Previously we used ``- gcc #[linux]`` and ``- llvm # [osx]`` for compilers -- Instead, we should use the syntax ``{{ compiler('c') }}``, ``{{ - compiler('cxx') }}``, and/or ``{{ compiler('fortran') }}``. These should go - in the ``build`` section, and all other build dependencies should go in the - ``host`` section. - -Anaconda now provides platform-specific compilers that are automatically -determined. The string ``{{ compiler('c') }}`` will resolve to ``gcc`` on -Linux, but ``clang`` on macOS. This should greatly simplify recipes, as we no -longer need to have separate lines for linux and osx. - -Note that previously we typically would also add ``- libgcc #[linux]`` as a run -dependency, but this is now taken care of by the compiler tools (see the global -pinning section below for more on this). - -Conda-build 3 also now has the ability to cross-compile, making it now possible -to compile packages for macOS while running on Linux. To support this, recipes -must now make a distinction between dependencies that should be specific to the -building machine and dependencies that should be specific to the running -machine. - -Dependencies specific to the building machine go in ``build``; -dependencies specific to the running machine go in ``host`` (see -:ref:`host-section`). - - -Before: - -.. code-block:: yaml - - package: - name: example - version: 0.1 - requirements: - build: - - python - - gcc # [linux] - - llvm # [osx] - run: - - python - - libgcc # [linux] - -After: - -.. code-block:: yaml - - package: - name: example - version: 0.1 - requirements: - build: - - {{ compiler('c') }} - host: - - python - run: - - python - -.. seealso:: - - - The `compiler tools ` section of the - conda docs has much more info. - - - The default compiler options are defined by conda-build in the - `variants.DEFAULT_COMPILERS - `_ - variable. - - - More details on "strong" and "weak" exports (using examples of - libpng and libgcc) can be found in the `export runtime - requirements ` conda documentation. - - -.. warning:: - - These compilers are only available in the ``defaults`` channel. Until now - we have not had this channel as a dependency, so be sure to add the channel - when setting up bioconda (see :ref:`set-up-channels`). - -.. _global-pinning: - -Global pinning -~~~~~~~~~~~~~~ - -**Summary:** - -- Previously we pinned packages using the syntax ``- zlib {{ CONDA_ZLIB }}*`` - in both the ``build`` and ``run`` dependencies. -- Instead, we should now specify only package names in the ``host`` and ``run`` - sections e.g., as simply ``zlib``. They are pinned automatically. - -Global pinning is the idea of making sure all recipes use the same versions of -common libraries. Problems arise when the build-time version does not match -the install-time version. Furthermore, all packages installed into the same -environment should have been built using the same version so that they can -co-exist. For example, many bioinformatics tools have ``zlib`` as a dependency. -The version of ``zlib`` used when building the package should be the same as the -version used when installing the package into a new environment. This implies -that we need to specify the ``zlib`` version in one place and have all recipes -use that version. - -Previously we maintained a global, bioconda-specific pinning file (see -`scripts/env_matrix.yaml -`_). -For ``zlib``, that file defined the variable ``CONDA_ZLIB`` and that variable -was made available to the recipes as a jinja2 variable. One problem with this -is that we did not often synchronize our pinned versions with conda-forge's -pinned versions, and this disconnect could cause problems. - -There are two major advances in conda-build 3 to address these problems. First -is the concept of "variants". Variants are a generalized way of specifying one -or more specific versions, and they come with many weird and wonderful ways to -specify constraints. Specifying variants generally takes the form of writing -a YAML file. We have adopted the variants defined by conda-forge by installing -their `conda-forge-pinning` conda package in our build environment. -Technically, that package unpacks the config YAML into our conda environment so -that it can be used for building all recipes. You can see this file at -`conda_build_config.yaml -`_. - -The second major advance in conda-build 3 is the the concept of "run exports". -The idea here is to specify that any time a dependency (``zlib``, in our running example) -is used as a build dependency, it should also be automatically be installed as -a run dependency without having to explicitly add it as such in the recipe. -This specification is done in the ``zlib`` recipe itself (which is hosted by -conda-forge), so in general bioconda collaborators can just add ``zlib`` as -a build dependency. - -Note that we don't have to specify the version of ``zlib`` in the recipe -- it -is pinned in that ``conda_build_config.yaml`` file we share with conda-forge. - -In a similar fashion, the reason that we no longer have to specify ``libgcc`` -as a run dependency (as described above in the compilers section) is that ``{{ -compiler('c') }}`` automatically export ``libgcc`` as a run dependency. - -Before: - -.. code-block:: yaml - - package: - name: example - version: 0.1 - requirements: - build: - - python - - gcc # [linux] - - llvm # [osx] - - zlib {{ CONDA_ZLIB }}* - run: - - python - - libgcc # [linux] - - zlib {{ CONDA_ZLIB }}* - -After: - -.. code-block:: yaml - - package: - name: example - version: 0.1 - requirements: - build: - - {{ compiler('c') }} - host: - - python - - zlib - run: - - python - - zlib - - -.. seealso:: - - The `conda-build:resources/variants` section of the conda docs has - much more information. - - We share the packages pinned by conda-forge, which can be found in their - `conda_build_config.yaml - `_ - - Bio-specific packages additionally pinned by bioconda can be found at - ``bioconda_utils-conda_build_config.yaml`` in the bioconda-utils source. diff --git a/source/contributor/index.rst b/source/contributor/index.rst index 2c40cdb..a0610c2 100644 --- a/source/contributor/index.rst +++ b/source/contributor/index.rst @@ -41,6 +41,3 @@ challenging to package. The topics below provide more details. linting updating - cb3 - - diff --git a/source/faqs.rst b/source/faqs.rst index e62e90c..eda2777 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -15,6 +15,7 @@ How do I speed up package installation? Speedup option 1: use ``mamba`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `mamba `_ is a drop-in replacement for conda that uses a faster dependency solving library and parts reimplemented in C++ for speed. Install it just into the base environment so that it's always @@ -39,6 +40,7 @@ channels. Speedup option 2: use environments strategically ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Here are several ways you can use environments to minimize the time spent on solving dependencies, which typically is what takes the longest amount of time: @@ -77,21 +79,12 @@ solving dependencies, which typically is what takes the longest amount of time: What versions are supported? ---------------------------- -Operating Systems -~~~~~~~~~~~~~~~~~ - -Bioconda supports Linux (x86_64 and aarch64/arm64) and macOS (64-bit). ARM -is not currently supported for macOS. Windows is not supported. - -Python -~~~~~~ - -.. datechanged:: 2022-09-01 - Python 3.10 support started in Aug 2022 - -.. datechanged:: 2023-05-01 - Python 2.7, 3.6, 3.7 support were dropped for new recipes in May 2023. +**Operating Systems:** +Bioconda supports Linux (x86_64 and aarch64/arm64) and +macOS (64-bit). ARM is not currently supported for macOS. Windows is not +supported. +**Python:** Bioconda currently supports Python 3.8, 3.9, and 3.10 (see :ref:`Pinned packages` for where this is configured). @@ -104,10 +97,13 @@ environment with any version of python they say they can support. However many python packages in Bioconda depend on other Bioconda packages with architecture specific builds, such as `pysam`, and so do not meet this criteria. +.. datechanged:: 2022-09-01 + Python 3.10 support started in Aug 2022 -Pinned packages -~~~~~~~~~~~~~~~ +.. datechanged:: 2023-05-01 + Python 2.7, 3.6, 3.7 support were dropped for new recipes in May 2023. +**Pinned packages:** Some packages require `ABI `_ compatibility with underlying libraries. To ensure that packages can work together, there are @@ -125,9 +121,7 @@ This is *in addition to* the conda-forge specified versions, `_ which pins versions of base dependencies like boost, zlib, and many others. -Unsupported versions -~~~~~~~~~~~~~~~~~~~~ - +**Unsupported versions:** If there is a version of a dependency you wish to build against that Bioconda does not currently support, please reach out to the `Bioconda Gitter `_ for more information about if supporting @@ -161,20 +155,28 @@ maintain) the same environment. .. _conda-anaconda-minconda: -What's the difference between Anaconda, conda, Miniconda, and mamba? --------------------------------------------------------------------- +What's the difference between Anaconda, conda, Miniconda, mamba, Mambaforge, micromamba? +---------------------------------------------------------------------------------------- This `blog post from Anaconda `_ gives a lot of context on the Anaconda/conda ecosystem. -- conda is the name of the package manager, which is what runs when you call, +- **conda** is the name of the package manager, which is what runs when you call, e.g., ``conda install``. -- mamba is a drop-in replacement for conda (see above for details) -- Anaconda is a large installation including Python, conda, and a large number +- **mamba** is a drop-in replacement for conda +- **Anaconda** is a large installation including Python, conda, and a large number of packages. -- Miniconda just has conda and its dependencies (in contrast to the larger - Anaconda distribution). +- **Miniconda** just has conda and its dependencies (in contrast to the larger + Anaconda distribution) +- **Miniforge** is like miniconda, but with the conda-forge channel + preconfigured and all packages coming from the conda-forge and *not* the + ``defaults`` channel. +- **Mambaforge** is like miniforge, but has mamba installed into the base environment. +- **Micromamba** is not a conda distribution. Rather, it is a minimal binary + that has roughly the same commands as mamba, so that a single executable + (rather than an entire Python installation required for conda itself) can be + used to create environments. Micromamba is currently still experimental. The `Anaconda Python distribution `_ started out as a bundle of scientific Python packages that were otherwise @@ -196,8 +198,15 @@ This installs only what you need to run conda itself, which can then be used to create other environments. So the "mini" in Miniconda means that it's a fraction of the size of the full Anaconda installation. -So: conda is a package manager, Miniconda is the conda installer, and Anaconda -is a scientific Python distribution that also includes conda. +Then the conda-forge channel gained popularity. Miniforge was developed to +quickly and easily get a conda-forge-ready conda installation. Then as mamba +gained popularity, the Mambaforge variant was created. + +Even with those easier methods, sometimes the entire base Python installation that comes with conda/mamba was too much overhead. Micromamba has a single binary that is very fast to install, and is perfect for CI environments. + +So: conda is a package manager, Anaconda is a scientific Python distribution +that also includes conda, and the rest are other flavors of getting +a conda/mamba installation. What's the difference between a recipe and a package? ----------------------------------------------------- @@ -224,22 +233,6 @@ with ``conda install``. what a package contains and how it is installed into an environment. -What's the difference between miniconda, miniforge, mambaforge, micromamba? ---------------------------------------------------------------------------- - -**Miniconda** is the slimmed-down version of the Anaconda distribution; -miniconda only has conda and its dependencies. - -**Miniforge** is like miniconda, but with the conda-forge channel preconfigured -and all packages coming from the conda-forge and *not* the ``defaults`` -channel. - -**Mambaforge** is like miniforge, but has mamba installed into the base environment. - -**Micromamba** is not a conda distribution. Rather, it is a minimal binary that -has roughly the same commands as mamba, so that a single executable (rather -than an entire Python installation required for conda itself) can be used to -create environments. Micromamba is currently still experimental. Why are Bioconductor data packages failing to install? ------------------------------------------------------ @@ -438,18 +431,110 @@ which elements and values can appear in ``meta.yaml``. Conda has this information available `here `_. Please check that you are looking at the correct version of the documentation for the current conda version used by bioconda. +What are the ``host`` and ``build`` sections of a recipe? +--------------------------------------------------------- + +The ``requirements:build`` section of a meta.yaml file is used to specify the +tools for *building* the package, but not necessarily for *running* it. This is +where compilers should go. The build section might also include tools like +``make``, ``automake``, ``cmake``, or ``git``. If there are no compilers or +other build tools, there should be no ``build:`` section. + +The ``requirements::host`` section of a meta.yaml is used to specify the +*runtime* dependencies of the package. + +.. seealso:: + + See the `requirements section ` of the + conda docs for more info. + + +.. _compiler-tools: + +Compiler tools +-------------- + +Use the syntax ``{{ compiler('c') }}``, ``{{ compiler('cxx') }}``, and/or ``{{ +compiler('fortran') }}``. These should go in the ``build`` section, and all +other build dependencies should go in the ``host`` section. + +Anaconda provides platform-specific compilers that are automatically +determined. The string ``{{ compiler('c') }}`` will resolve to ``gcc`` on +Linux, but ``clang`` on macOS (osx-64). + + +.. seealso:: + + - The `compiler tools ` section of the + conda docs has much more info. + + - The default compiler options are defined by conda-build in the + `variants.DEFAULT_COMPILERS + `_ + variable. + + - More details on "strong" and "weak" exports (using examples of + libpng and libgcc) can be found in the `export runtime + requirements ` conda documentation. + + +.. _global-pinning: + +How does global pinning work? +----------------------------- + +Global pinning is the idea of making sure all recipes use the same versions of +common libraries. Otherwise, problems arise when the build-time version does not match +the install-time version. Furthermore, all packages installed into the same +environment should have been built using the same version so that they can +co-exist. + +For example, many bioinformatics tools have ``zlib`` as a dependency. +The version of ``zlib`` used when building the package should be the same as the +version used when installing the package into a new environment. This implies +that we need to specify the ``zlib`` version in one place and have *all recipes +intended to coexist in the same environment** use that version. + +This is handled with special build config files. Since we rely heavily on the +conda-forge channel, the bioconda build system installs the conda-forge +`conda_build_config.yaml +`_ +into our build environment so that it can be used for building all recipes. +This is then combined with the bioconda-specific +`bioconda-Utils-conda_build_config.yaml +`_. +Note that in some cases the bioconda config may override some of the +conda-forge configs. For example, historically, we did this when we wanted to +support older Python versions. + +The idea here is to specify that any time a dependency (``zlib``, in our +running example) is used as a build dependency, it should also be automatically +be installed as a run dependency without having to explicitly add it as such in +the recipe. This specification is done in the ``zlib`` recipe itself (which is +hosted by conda-forge), so in general bioconda collaborators can just add +``zlib`` as a build dependency. + +Note that we don't have to specify the version of ``zlib`` in the recipe -- it +is pinned in that ``conda_build_config.yaml`` file we share with conda-forge. + +In a similar fashion, the reason that we don't have to specify ``libgcc`` as +a *run* dependency is that ``{{ compiler('c') }}`` automatically exports +``libgcc`` as a run dependency of any package that uses the C compiler to +build. + .. _platform-nomenclature-faq: Understanding platform nomenclature ----------------------------------- +.. datechanged:: 2023-11-18 + Added section + Different CPU chips use different architecture, so programs are written fundamentally differently for them. Why do we care about this for conda packages? Because a package with compiled dependencies must have platform-specific dependencies. -New Apple Silicon - There is a lot of confusing nomenclature surrounding them. Here is an attempt at clearing them up, or at least providing enough context that you can look up more details on your own: @@ -500,3 +585,4 @@ Here is a summary table: * - Older Macs - ``osx-64`` + From c777929637b878eaac1904a73d2c6ab95ba5a728 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 21:47:16 -0500 Subject: [PATCH 15/41] overheaul build-system.rst Made it more general so it's accurate across multiple CI platforms --- source/contributor/build-system.rst | 177 +++++++++------------------- 1 file changed, 57 insertions(+), 120 deletions(-) diff --git a/source/contributor/build-system.rst b/source/contributor/build-system.rst index 9caa4a0..bcdf19f 100644 --- a/source/contributor/build-system.rst +++ b/source/contributor/build-system.rst @@ -1,32 +1,40 @@ Build system ============ +.. datechanged:: 2023-11-14 + Made descriptions more generalized to reflect multiple CI systems in use + The build system for Bioconda takes recipes and converts them into conda packages that are uploaded to anaconda.org as well as Docker containers that -are uploaded to quay.io as part of the Biocontainers project. All of this happens in a transparent way, with all -build logs available for inspection. The code for the build system can be found -in `bioconda-utils `_, but parts -are also with the ``bioconda-recipes`` repo. This document serves as -a high-level overview; the code remains the authoritative source on exactly -what happens during a build. +are uploaded to quay.io as part of the Biocontainers project. All of this +happens in a transparent way, with all build logs available for inspection. The +code for the build system can be found in `bioconda-utils +`_, but parts are also with the +``bioconda-recipes`` repo. This document serves as a high-level overview; the +code remains the authoritative source on exactly what happens during a build. Why so complicated? We have to work within the constraints of conda-build, -Docker, and Azure, while simultaneously supporting the same build system on -a local machine so contributors can test. We also have isolated bioconda-utils -from bioconda-recipes to better facilitate testing of the infrastructure, and -to (one day!) make it general enough that others can use the framework for -their own specific channels. So there are a lot of moving parts that have to be -coordinated, resulting in a complex system. That said, we do have some room to -simplify, and do so where we can. +Docker, CircleCI, GitHub Actions, and Azure DevOps . . . while simultaneously +supporting the same build system on a local machine so contributors can test. +We also have isolated bioconda-utils from bioconda-recipes to better facilitate +testing of the infrastructure, and to (one day!) make it general enough that +others can use the framework for their own specific channels. So there are +a lot of moving parts that have to be coordinated, resulting in a complex +system. That said, we do have some room to simplify, and do so where we can. + +This page gives a high-level overview of the most relevant parts to building +recipes. See :ref:`ci-inventory` for *all* of the moving parts throughout the +bioconda ecosystem. Stages of a bioconda build -------------------------- + A GitHub pull request, or any pushed changes to a GitHub pull request, triggers -a new build on Azure DevOps. One build can contain mulitple recipes, limited only -by the time limit imposed by Azure. -Each build on Azure starts with a fresh VM, so we -need to create the entire bioconda-build system environment from scratch for -each build. +a new build on CI/CD platforms. One build can contain mulitple recipes, limited +only by the time limit imposed by each CI platform. Typically, each build +starts with a fresh VM, so we need to create the entire bioconda-build system +environment from scratch for each build. When possible, we take advantage of +caching offered by the CI platform. When testing locally, we use the ``quay.io/bioconda/bioconda-utils-build-env-cos7`` Docker container to avoid changing the @@ -34,120 +42,49 @@ local system. This container is defined by `this Dockerfile `_. -Otherwise, when running on Azure, a new Linux or MacOS VM is created for -each build. - -The steps are orchestrated by the `Azure config file `_. - -Configure the environment -~~~~~~~~~~~~~~~~~~~~~~~~~ +Build steps +~~~~~~~~~~~ -N.B., due to transitioning to Azure, the remainder of this section is no longer relevant and requires rewritting. +Once the environment is configured in the first step, the rest of the steps are +orchestrated by bioconda-utils. -- Configure the CI environment: - - ``bioconda-recipes: .circleci/config.yml`` is the primary configuration - file for the steps that are run. See https://circleci.com/docs/2.0/ for - the configuration documentation. - - ``bioconda-common: common.sh`` defines the versions of Miniconda and - bioconda-utils to use. - - ``bioconda-recipes: .circleci/setup.sh`` installs Miniconda and - bioconda-utils, sets the correct channel order -- Run linting on changed recipes - - This is triggered by the ``bioconda-recipes: .circleci/config.yml`` "lint" - job, which runs ``bioconda-utils: bioconda_utils/cli.py`` and - ``bioconda_utils/linting.py`` +- **Configure the environment.** The `bioconda-common + `_ repo has scripts for + configuring a working conda environment with `bioconda-utils + `_ installed. This is used across + the various CI systems to minimize maintenance burden. -- Build recipes - - Triggered by the ``bioconda-recipes: .circleci/config.yaml`` "test-linux" - job, which runs ``bioconda-utils build``. This performs the next steps. +- **Lint.** This step checks for common errors, formatting, and consistency. -- Filter recipes to only focus on recipes that satisfy the following criteria: - - changed recently (we use a ``git diff`` command to identify these - recipes; see ``bioconda-utils: bioconda_utils/build.py`` - - not on any blacklists listed in ``config.yaml`` +- **Build recipes.** Recipes to be built sastify the following criteria: + - changed in this pull request + - not on the `build-fail-blacklist` + - does not have a build-failure yaml file in the recipe with a hash + matching this version - package with that version number and build number does not exist in - bioconda channel (we check the channel for each of the changed recipes) - -- Download the configured Docker container (currently based on CentOS 7) - - default configured in ``bioconda-utils: docker_utils.py`` - -- Build a new, temporary Docker container - - Dockerfile configured in ``bioconda-utils: docker_utils.py``; we hope to - move to simply pulling from DockerHub now that our build dependencies are - not changing as often) - -- Topologically sort changed recipes, and build them one-by-one in the Docker - container. This runs ``conda-build`` on the recipe while also specifying the - correct environment variables. - - - The conda-build directory is exported to the docker container to a temp - file and added as a channel. This way, packages built by one container - will be visible to containers building subsequent packages in the same - Travis-CI build. - - ``bioconda-utils: docker_utils.py`` specifies the build script that is - run in the container. - - At the end of the build, the build script copies the package to the - exported conda-bld directory - - A whitelist of env vars is exported. The whitelist is configured in - ``bioconda-utils: utils.py``. - -- Upon successfully building and testing via ``conda-build``, the built package - is added to a minimal BusyBox container using ``mulled-build`` (maintained in - `galaxy-lib `_). This acts as - a more stringent test than ``conda-build`` alone. The BusyBox container + bioconda channel + +- **Isolated test.** Upon successfully building and testing via + ``conda-build``, the built package is added to a minimal BusyBox container + using ``mulled-build`` (maintained in `galaxy-lib + `_). This acts as a more + stringent test than ``conda-build`` alone, because the BusyBox container purposefully is missing many system libraries (like libgcc) that may be present in the CentOS 7 container. Note that it is common for a package to build in the CentOS 7 container but fail in the BusyBox container. When this happens, it is often because a dependency needs to be added to the recipe. -- Upon successfully testing the package in the BusyBox container, we have a branch point: - - - if we are on a pull request: - - report the successful test back to the GitHub PR, at which time it - can be merged into the master branch - - if we are on the master branch: - - upload the built conda package to anaconda.org, with an optional label - - upload the BusyBox container to quay.io - -As soon as the package is uploaded to anaconda.org, it is available for -installing via ``conda``. As soon as the BusyBox container is uploaded to -quay.io, it is available for use via ``docker pull``. - -The ``bulk`` branch -------------------- - -Periodically, large-scale maintenance needs to be done on the channel. For -example, when a new version of Bioconductor comes out, we need to update all -``bioconductor-*`` packages and rebuild them. Or if we change the version of -a pinned package in ``scripts/env.yaml``, then all packages depending -on that package need to be rebuilt. While our build infrastructure will build -recipes in the correct toplogically sorted order, if there are too many recipes -then Travis-CI will timeout and the build will fail. - -Our solution to avoiding builds failing due to timeouts is the special ``bulk`` -branch. This branch is used by the bioconda core team for maintenance and -behaves much like the ``master`` branch in that packages, once successfully -built and tested, are immediately uploaded to anaconda.org. The major -difference is that ``bulk`` does not go through the pull-request-and-review -process in order for packages to be built and uploaded to the channel. As such, -only bioconda core members are able to push to the ``bulk`` branch. - -The workflow is to first merge the latest master into ``bulk`` branch and -resolve any conflicts. Then push (often a large number of) changes to the -branch, without opening a PR. Unlike the ``master`` branch, which uses -the shortcut of only checking for recipes in the channel if they have been changed -according to ``git``, the ``bulk`` branch is configured to do the exhaustive -check against the channel (which can take some time). Any existing recipe that -does not exist in the channel will therefore be re-built. As packages build, -they are uploaded; as they fail, the testing moves on to the next package. The -``bulk`` branch runs up until the Travis-CI timeout, at which time the entire -build fails. But since individual packages were uploaded as they are -successfully built, our work is saved and we can start the next build where we -left off. Failing tests are fixed in another round of commits, and these -changes are then pushed to ``bulk`` and the process repeats. Once ``bulk`` is -fully successful, a PR is opened to merge the changes into master. +- **Report.** If we are on a pull request, report the successful test back to + the GitHub PR, at which time it can be merged into the master branch + +- **Upload.** If we are on the master branch, then upload the built conda + package to anaconda.org, and upload the BusyBox container to quay.io + +- **Use!** As soon as the package is uploaded to anaconda.org, it is available + for installing via ``conda``. As soon as the BusyBox container is uploaded to + quay.io, it is available for use via ``docker pull``. Labels ------ From 4a7e86df725d9a6cd3c9d6bf95cfeadc262d9eb0 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 21:47:53 -0500 Subject: [PATCH 16/41] minor updates to bulk --- source/developer/bulk.rst | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/source/developer/bulk.rst b/source/developer/bulk.rst index 87d95dc..d25f2ad 100644 --- a/source/developer/bulk.rst +++ b/source/developer/bulk.rst @@ -129,10 +129,12 @@ example is updating pinnings to support Python 3.10. Handling build failures ~~~~~~~~~~~~~~~~~~~~~~~ -Build failures are stored in a file ``build_failure..yaml`` next to each failing recipe. -You can list all build failures stored in the current branch of bioconda-recipes via the command -``bioconda-utils list-build-failures recipes config.yml``. The presented table on stdout will be sorted by -the number of dependencies and package downloads, which should help for prioritizing the fixing work. +Build failures are stored in a file ``build_failure..yaml`` next to each +failing recipe. You can list all build failures stored in the current branch of +bioconda-recipes via the command ``bioconda-utils list-build-failures recipes +config.yml``. This reads the yaml files from failing recipes, and prints +a table on stdout that will be sorted by the number of dependencies and package +downloads, which should help for prioritizing the fixing work. This file can look e.g. like this: @@ -230,5 +232,7 @@ Some unordered notes on working with the bulk branch: that don't need to be rebuilt, but that work needs to be done simply to figure out if a rebuild is needed, and so this is expected. -- The bulk runs take place on GitHub Actions, and the configuration is in - :file:`.github/workflows/Bulk.yml`. +- For ``linux-64`` and ``osx-64``, the bulk runs take place on GitHub Actions, + and the configuration is in :file:`.github/workflows/Bulk.yml`. For + ``linux-aarch64``, the builds take place on CircleCI and the configuration is + in :file:`.circleci/config.yml`. From d733189d5d94647ee59823c2863834aa36794acb Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 21:48:42 -0500 Subject: [PATCH 17/41] add new aarch64 page --- source/developer/aarch64.rst | 25 +++++++++++++++++++++++++ source/developer/ci-inventory.rst | 2 ++ source/developer/index.rst | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 source/developer/aarch64.rst diff --git a/source/developer/aarch64.rst b/source/developer/aarch64.rst new file mode 100644 index 0000000..482da51 --- /dev/null +++ b/source/developer/aarch64.rst @@ -0,0 +1,25 @@ +``aarch64`` builds +================== + +.. datechanged:: 2023-11-18 + Added this section as initial linux-aarch64 builds are starting + +While we do not yet have builds for ``osx-arm64`` (see +:ref:`platform-nomenclature-faq`), we are starting to roll out +``linux-aarch64`` builds. These run on CircleCI, which offers the +infrastructure for this (in contrast to GitHub Actions). + +This is being initially approached as an opt-in process as we make sure +all the moving parts are working correctly. A recipe can be flagged for +building on ``linux-aarch64`` by adding the following to the +:file:`meta.yaml` file: + +.. code-block:: yaml + + extra: + additional-platforms: + - linux-aarch64 + +The current CircleCI config will only run if at least one recipe in the +commit range (typically for the PR) includes the above additional +platform. diff --git a/source/developer/ci-inventory.rst b/source/developer/ci-inventory.rst index e5dc9d6..0d1e784 100644 --- a/source/developer/ci-inventory.rst +++ b/source/developer/ci-inventory.rst @@ -1,3 +1,5 @@ +.. _ci-inventory: + CI Inventory ============ diff --git a/source/developer/index.rst b/source/developer/index.rst index d8fa3c5..cc88506 100644 --- a/source/developer/index.rst +++ b/source/developer/index.rst @@ -9,4 +9,4 @@ Developer Docs bulk repodata_patching ci-inventory - + aarch64 From 84fe3ce74a6761eb069736a9d4ceffa0b4d09631 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 21:56:13 -0500 Subject: [PATCH 18/41] update number of contributors --- source/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/index.rst b/source/index.rst index f286261..d7bbde7 100644 --- a/source/index.rst +++ b/source/index.rst @@ -144,7 +144,7 @@ system consists of the components illustrated in the diagram below. **Legend** (starting from the bottom): -:circlednumber:`①` Over 1400 contributors who add, +:circlednumber:`①` Over 1800 contributors who add, modify, update, and maintain recipes and packages .. details:: Details @@ -294,7 +294,7 @@ Team ~~~~ Bioconda would not exist without the continuous hard work and support of the -wonderful community which includes over 1400 (as of 2022) `contributors +wonderful community which includes over 1800 (as of 2023) `contributors `_. From bec930c855fdb61a6b7c31274ccc5c642ac28309 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 21:56:24 -0500 Subject: [PATCH 19/41] make CI platforms more general --- source/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/index.rst b/source/index.rst index d7bbde7..5aa918b 100644 --- a/source/index.rst +++ b/source/index.rst @@ -187,9 +187,9 @@ package and a Docker container the process repeats until all tests pass. Our `build system`_, `bioconda-utils`, orchestrates the various building - and testing steps on Azure Pipelines. The output consists of both a `conda - package`_ and a `Biocontainer`_ that can be inspected before merging the - pull request. + and testing steps on CI infrastructure like CircleCI, Azure Pipelines, and + GitHub Actions. The output consists of both a `conda package`_ and + a `Biocontainer`_ that can be inspected before merging the pull request. :circlednumber:`④` A repository of packages and a registry of containers From c5e8956f8f2291d4b19c18fed616ef6339bd8cbc Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 21:58:27 -0500 Subject: [PATCH 20/41] minor formatting --- source/faqs.rst | 13 +++++++------ source/index.rst | 2 -- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/source/faqs.rst b/source/faqs.rst index eda2777..8cedf10 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -44,7 +44,7 @@ Speedup option 2: use environments strategically Here are several ways you can use environments to minimize the time spent on solving dependencies, which typically is what takes the longest amount of time: -1. Keep the ``base`` environment small. +1. **Keep the base environment small.** If you install everything into the same environment (e.g. the ``base`` environment, which is used any time you don't otherwise specify an @@ -52,29 +52,30 @@ solving dependencies, which typically is what takes the longest amount of time: to do a lot of work to make sure all of the many packages are mutually compatible with each other. -2. Use smaller environments. +2. **Use smaller environments.** Fewer packages means less work for the solver. Try to use environments only containing what you need for a particular project or task. -3. Pin dependencies. +3. **Pin dependencies.** Sometimes pinning dependencies to a specific version can speed up the solving, since it reduces the search space for the solver. In some cases this may backfire though. For example, you can't pin an older version of R and also use newer R packages that don't support that version of R. -4. Create an environment from a file with all dependencies. +4. **Create an environment from a file with all dependencies.** Creating an environment with all dependencies at once can be faster than incrementally adding packages to an existing environment. For example ``conda create -n myenv --file requirements.txt``, or ``conda env create --file env.yaml``. -5. Use strict channel priority. +5. **Use strict channel priority.** Ensure that you've run ``conda config --set channel_priority strict`` to - respect the configured channel order. This can also speed up the solving. + respect the configured channel order, as recommended in the setup + instructions. This can also speed up the solving. What versions are supported? ---------------------------- diff --git a/source/index.rst b/source/index.rst index 5aa918b..80dae6e 100644 --- a/source/index.rst +++ b/source/index.rst @@ -298,8 +298,6 @@ wonderful community which includes over 1800 (as of 2023) `contributors `_. - - Table of contents ================= From caa2685a4d429cf305d9ea379b7c060bdddc5c44 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sat, 18 Nov 2023 22:16:39 -0500 Subject: [PATCH 21/41] clarifications in faqs --- source/faqs.rst | 91 +++++++++++++++++++------------------------------ 1 file changed, 35 insertions(+), 56 deletions(-) diff --git a/source/faqs.rst b/source/faqs.rst index 8cedf10..22f0dcc 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -86,17 +86,16 @@ macOS (64-bit). ARM is not currently supported for macOS. Windows is not supported. **Python:** -Bioconda currently supports Python 3.8, 3.9, and 3.10 (see :ref:`Pinned -packages` for where this is configured). +Bioconda currently supports Python 3.8, 3.9, and 3.10 (see "pinned packages" +below for where this is configured). There are still packages in the Bioconda +channel for earlier versions of Python (2.7, 3.6, and 3.7), but new packages +are not built for these versions. -There are still packages in the Bioconda channel for earlier versions of -Python (2.7, 3.6, and 3.7). - -The exception to this is Bioconda packages which declare `noarch: python` and -only depend on such packages - those packages can be installed in an -environment with any version of python they say they can support. However many -python packages in Bioconda depend on other Bioconda packages with architecture -specific builds, such as `pysam`, and so do not meet this criteria. +Packages which declare `noarch: python` and only depend on packages that also +declare `noarch: python` can be installed in an environment with any version of +Python they say they can support. However many Python packages in Bioconda +depend on other Bioconda packages with architecture specific builds, such as +`pysam`, and so do not meet this criteria. .. datechanged:: 2022-09-01 Python 3.10 support started in Aug 2022 @@ -104,23 +103,7 @@ specific builds, such as `pysam`, and so do not meet this criteria. .. datechanged:: 2023-05-01 Python 2.7, 3.6, 3.7 support were dropped for new recipes in May 2023. -**Pinned packages:** -Some packages require `ABI -`_ compatibility -with underlying libraries. To ensure that packages can work together, there are -some libraries that need to be *pinned*, or fixed to a particular version. -Other packages are then built with that specific version (and therefore that -specific ABI) to ensure they can all work together. - -The authoritative source for which packages are pinned and to which versions -can be found in the `bioconda_utils-conda_build_config.yaml -`_ -file. - -This is *in addition to* the conda-forge specified versions, -`conda_build_config.yaml -`_ -which pins versions of base dependencies like boost, zlib, and many others. +**Globally-pinned versions:** See :ref:`global-pinning` for details. **Unsupported versions:** If there is a version of a dependency you wish to build against that Bioconda @@ -139,7 +122,7 @@ You can view your created environments with ``conda env list``. Note that if keeping track of different environment names becomes a burden, you can create an environment in the same directory as -a project with the ``-p`` argument, e.g., +a project with the ``-p`` argument, e.g., .. code-block:: bash @@ -172,7 +155,7 @@ gives a lot of context on the Anaconda/conda ecosystem. Anaconda distribution) - **Miniforge** is like miniconda, but with the conda-forge channel preconfigured and all packages coming from the conda-forge and *not* the - ``defaults`` channel. + ``defaults`` channel. - **Mambaforge** is like miniforge, but has mamba installed into the base environment. - **Micromamba** is not a conda distribution. Rather, it is a minimal binary that has roughly the same commands as mamba, so that a single executable @@ -350,7 +333,7 @@ everywhere in conda-forge and Bioconda to maintain ABI compatibility conda-forge pinnings `here `_, and the bioconda-specific ones `here -`_. +`_. In the case of samtools, that hash ``h1170115`` incorporates the packages and versions of all of its dependencies that are pinned. That includes gcc, zlib, @@ -425,12 +408,12 @@ the ``broken`` label, i.e., Where can I find more info on ``meta.yaml``? -------------------------------------------- -The ``meta.yaml`` file is conda's metadata definition file for recipes. -If you are developing a new recipe or are trying to update or improve an existing one, it can be helpful to know +The ``meta.yaml`` file is conda's metadata definition file for recipes. +If you are developing a new recipe or are trying to update or improve an existing one, it can be helpful to know which elements and values can appear in ``meta.yaml``. Conda has this information available `here `_. -Please check that you are looking at the correct version of the documentation for the current conda version used by bioconda. +Please check that you are looking at the correct version of the documentation for the current conda version used by bioconda. What are the ``host`` and ``build`` sections of a recipe? --------------------------------------------------------- @@ -484,20 +467,21 @@ Linux, but ``clang`` on macOS (osx-64). How does global pinning work? ----------------------------- -Global pinning is the idea of making sure all recipes use the same versions of -common libraries. Otherwise, problems arise when the build-time version does not match -the install-time version. Furthermore, all packages installed into the same -environment should have been built using the same version so that they can -co-exist. +We can have conflicts when the version of a common library used when the +package is originally *built* differs from the version when the package is +*installed*. All packages intending to be installed into the same environment +should be built using the same versions of common libraries so that they can +co-exist. **Global pinning** is the idea of making sure all recipes use the +same versions of common libraries. For example, many bioinformatics tools have ``zlib`` as a dependency. The version of ``zlib`` used when building the package should be the same as the version used when installing the package into a new environment. This implies that we need to specify the ``zlib`` version in one place and have *all recipes -intended to coexist in the same environment** use that version. +intended to coexist in the same environment* use that version. -This is handled with special build config files. Since we rely heavily on the -conda-forge channel, the bioconda build system installs the conda-forge +This is configured with special build config files. Since we rely heavily on +the conda-forge channel, the bioconda build system installs the conda-forge `conda_build_config.yaml `_ into our build environment so that it can be used for building all recipes. @@ -532,25 +516,24 @@ Understanding platform nomenclature Added section Different CPU chips use different architecture, so programs are written -fundamentally differently for them. Why do we care about this for conda -packages? Because a package with compiled dependencies must have -platform-specific dependencies. +fundamentally differently for them. A package with compiled dependencies must +therefore use platform-specific dependencies. There is a lot of confusing nomenclature surrounding them. Here is an attempt at clearing them up, or at least providing enough context that you can look up more details on your own: **instruction set, CISC, RISC, RISC-V**: The *instruction set* is the assembly -code commands that are possible for the chip. *CISC* is "complex instruction set -computer", prioritizing flexibility; *RISC* is "reduced instruction set -computer", prioritizing power consumption (oversimplification, but that's the -general idea). Instruction sets can be proprietary. ARM is a company that -licenses a widely-used proprietary reduced instruction set. RISC-V is an open -(non-proprietary) reduced instruction set. +code commands that are possible for the chip. *CISC* is "complex instruction +set computer" which prioritizes flexibility. *RISC* is "reduced instruction set +computer" which prioritizing power consumption (this oversimplification, but +that's the general idea). Instruction sets can be proprietary. ARM is a company +that licenses a widely-used proprietary reduced instruction set. RISC-V is an +open (non-proprietary) reduced instruction set. **ARM vs ARM RISC:** ARM is a company. They make chips (for example, the ones -used in Raspberry Pi computers). They also license the proprietary RISC (for -example, they license it to Apple to run on their M-series chips). +used in Raspberry Pi computers). They also license the proprietary instruction +set (for example, they license it to Apple to run on their M-series chips). ``x86_64``, ``amd64``: These are synonyms for the original Intel/AMD architecture. @@ -563,9 +546,6 @@ documentation). ``linux-64``, ``linux-aarch64``, ``osx-64``, ``osx-arm64``: These are the platform designators used by conda in channels hosted by Anaconda. -``linux-64``, ``linux-aarch64``, ``osx-64``, ``osx-arm64``: These are the -labels the conda ecosystem gives to packages. - ``aarch64``, ``arm64``: These are synonyms for ARM 64-bit architecture. **M1, M2, M3, Apple Silicon**: These are chips made by Apple and used in Macs. @@ -586,4 +566,3 @@ Here is a summary table: * - Older Macs - ``osx-64`` - From e98d181c9b6c11034a17ed3153063df12965f559 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sun, 19 Nov 2023 10:40:43 -0500 Subject: [PATCH 22/41] update link to galaxy's mulled-build docs --- source/contributor/build-system.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/contributor/build-system.rst b/source/contributor/build-system.rst index bcdf19f..485b45c 100644 --- a/source/contributor/build-system.rst +++ b/source/contributor/build-system.rst @@ -68,8 +68,8 @@ orchestrated by bioconda-utils. - **Isolated test.** Upon successfully building and testing via ``conda-build``, the built package is added to a minimal BusyBox container - using ``mulled-build`` (maintained in `galaxy-lib - `_). This acts as a more + using ``mulled-build`` (maintained in `galaxy-tool-util + `_). This acts as a more stringent test than ``conda-build`` alone, because the BusyBox container purposefully is missing many system libraries (like libgcc) that may be present in the CentOS 7 container. Note that it is common for a package to From 15c6b33de65f2e5ac777458753a95378b8e789ea Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sun, 19 Nov 2023 10:41:45 -0500 Subject: [PATCH 23/41] clarifications and updates --- source/faqs.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/source/faqs.rst b/source/faqs.rst index 22f0dcc..0b5f5aa 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -82,7 +82,7 @@ What versions are supported? **Operating Systems:** Bioconda supports Linux (x86_64 and aarch64/arm64) and -macOS (64-bit). ARM is not currently supported for macOS. Windows is not +macOS (x86_64). ARM is not currently supported for macOS. Windows is not supported. **Python:** @@ -155,8 +155,9 @@ gives a lot of context on the Anaconda/conda ecosystem. Anaconda distribution) - **Miniforge** is like miniconda, but with the conda-forge channel preconfigured and all packages coming from the conda-forge and *not* the - ``defaults`` channel. -- **Mambaforge** is like miniforge, but has mamba installed into the base environment. + ``defaults`` channel. It also now has mamba and libmamba included. +- **Mambaforge** is like miniforge, but has mamba installed into the base + environment. It is currently deprecated. - **Micromamba** is not a conda distribution. Rather, it is a minimal binary that has roughly the same commands as mamba, so that a single executable (rather than an entire Python installation required for conda itself) can be @@ -412,8 +413,10 @@ The ``meta.yaml`` file is conda's metadata definition file for recipes. If you are developing a new recipe or are trying to update or improve an existing one, it can be helpful to know which elements and values can appear in ``meta.yaml``. -Conda has this information available `here `_. -Please check that you are looking at the correct version of the documentation for the current conda version used by bioconda. +Conda has this information available `here +`_. +Please check that you are looking at the correct version of the documentation +for the current conda version used by bioconda. What are the ``host`` and ``build`` sections of a recipe? --------------------------------------------------------- From 3849bcc8b897db32a3e2f726705cdf0a1373d408 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sun, 19 Nov 2023 10:42:02 -0500 Subject: [PATCH 24/41] fix build/host/run details --- source/faqs.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/source/faqs.rst b/source/faqs.rst index 0b5f5aa..8695305 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -427,7 +427,20 @@ where compilers should go. The build section might also include tools like ``make``, ``automake``, ``cmake``, or ``git``. If there are no compilers or other build tools, there should be no ``build:`` section. -The ``requirements::host`` section of a meta.yaml is used to specify the +The ``requirements:host`` section is used to specify *shared libraries*. It was +originally introduced to support cross-compiling (e.g., build on linux-64 but +output a package to be used on linux-aarch64) and the shared libraries here are +what's needed on the target (e.g. linux-aarch64 in this example). In practice, +this is where the base interpreter ``python`` or ``r-base`` should go for +Python and R packages. ``pip`` is usually here as well, and ``setuptools`` if +it is required for the build process. ``cython`` would go here. If a package +`builds against numpy +`_, +then ``numpy`` should go here (otherwise, it should go in the ``run:`` +requirements). Shared libraries like ``zlib``, ``hdf5``, ``libcurl``, and +``htslib`` should go here in ``requirements:host``. + +The ``requirements:run`` section of a meta.yaml is used to specify the *runtime* dependencies of the package. .. seealso:: From 5c7ded50ca17a6ada71b1c0c1f267481dbf6ebea Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sun, 19 Nov 2023 10:42:18 -0500 Subject: [PATCH 25/41] Arm/ARM clarification --- source/faqs.rst | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/source/faqs.rst b/source/faqs.rst index 8695305..a9b034d 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -542,14 +542,19 @@ more details on your own: **instruction set, CISC, RISC, RISC-V**: The *instruction set* is the assembly code commands that are possible for the chip. *CISC* is "complex instruction set computer" which prioritizes flexibility. *RISC* is "reduced instruction set -computer" which prioritizing power consumption (this oversimplification, but -that's the general idea). Instruction sets can be proprietary. ARM is a company -that licenses a widely-used proprietary reduced instruction set. RISC-V is an -open (non-proprietary) reduced instruction set. - -**ARM vs ARM RISC:** ARM is a company. They make chips (for example, the ones -used in Raspberry Pi computers). They also license the proprietary instruction -set (for example, they license it to Apple to run on their M-series chips). +computer" which prioritizing power consumption (this is an oversimplification, +but that's the general idea). Instruction sets can be proprietary. `Arm +`_ is a company that licenses a widely-used +proprietary reduced instruction set. RISC-V is an open (non-proprietary) +reduced instruction set. + +**Arm vs ARM:** Arm is the company that licenses the proprietary instruction +set For example, they license it to Apple to run on their M-series chips. ARM +(in all caps) refers to the family of RISC instruction sets, and by extension +chips that use the instruction sets. It is also an acronym for Advanced RISC +Machines and the eariler Acorn RISC Machine). This `blog post +`_ goes +into lots more detail. ``x86_64``, ``amd64``: These are synonyms for the original Intel/AMD architecture. From e425b40770383321d7cb9ce791ce430753c8426c Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sun, 19 Nov 2023 10:44:11 -0500 Subject: [PATCH 26/41] correct arch for supported mac --- source/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/index.rst b/source/index.rst index 80dae6e..991416a 100644 --- a/source/index.rst +++ b/source/index.rst @@ -20,7 +20,7 @@ **Bioconda** lets you install thousands of software packages related to biomedical research using the `conda `_ package manager. -**NOTE**: *Bioconda supports only Linux (64-bit and AArch64) and macOS (64-bit)* +**NOTE**: *Bioconda supports only Linux (64-bit and AArch64) and macOS (x86_64)* Usage ===== From a8fc0eef9e06a9862a9c33eedde80123ef1282e3 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sun, 19 Nov 2023 12:34:16 -0500 Subject: [PATCH 27/41] rm "summary" table --- source/faqs.rst | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/source/faqs.rst b/source/faqs.rst index a9b034d..5305787 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -571,19 +571,3 @@ platform designators used by conda in channels hosted by Anaconda. **M1, M2, M3, Apple Silicon**: These are chips made by Apple and used in Macs. Apple licenses the ARM RISC, so they are considered aarch64 or arm64. - -Here is a summary table: - -.. list-table:: - - * - Linux machines from past few decades - - ``x86_64``, ``amd64``, ``linux/x86_64``, ``linux-64``. - - * - Newer Linux machines - - ``aarch64``, ``arm64``, ``linux-aarch64``, ``linux/arm64`` - - * - Newer Macs - - ``M1``, ``M2``, ``M3``, ``osx-arm64``, ``aarch64``, ``arm64``, ``darwin/amd64`` - - * - Older Macs - - ``osx-64`` From a324f6e91253a8d4ab96786317bdfab57dc5d10e Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Sun, 19 Nov 2023 12:38:20 -0500 Subject: [PATCH 28/41] make miniforge statement more accurate and add link --- source/faqs.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/faqs.rst b/source/faqs.rst index 5305787..7221db9 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -157,7 +157,8 @@ gives a lot of context on the Anaconda/conda ecosystem. preconfigured and all packages coming from the conda-forge and *not* the ``defaults`` channel. It also now has mamba and libmamba included. - **Mambaforge** is like miniforge, but has mamba installed into the base - environment. It is currently deprecated. + environment. While not strictly deprecated, its use is discouraged as of + Sept 2023 (see `miniforge README `_)> - **Micromamba** is not a conda distribution. Rather, it is a minimal binary that has roughly the same commands as mamba, so that a single executable (rather than an entire Python installation required for conda itself) can be From 81f6bce039d9709f86e2c567115e3bed07c735d1 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 20 Nov 2023 09:03:41 -0500 Subject: [PATCH 29/41] Update source/developer/aarch64.rst Co-authored-by: Martin Grigorov --- source/developer/aarch64.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/developer/aarch64.rst b/source/developer/aarch64.rst index 482da51..950dedc 100644 --- a/source/developer/aarch64.rst +++ b/source/developer/aarch64.rst @@ -7,7 +7,7 @@ While we do not yet have builds for ``osx-arm64`` (see :ref:`platform-nomenclature-faq`), we are starting to roll out ``linux-aarch64`` builds. These run on CircleCI, which offers the -infrastructure for this (in contrast to GitHub Actions). +infrastructure for this (in contrast to GitHub Actions, which does not support Linux ARM64 at the moment (Nov 2023)). This is being initially approached as an opt-in process as we make sure all the moving parts are working correctly. A recipe can be flagged for From d302e374a02082ecb5aee9358b1c533811aa6917 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 20 Nov 2023 09:04:05 -0500 Subject: [PATCH 30/41] Update source/faqs.rst Co-authored-by: Martin Grigorov --- source/faqs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/faqs.rst b/source/faqs.rst index 7221db9..3320797 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -550,7 +550,7 @@ proprietary reduced instruction set. RISC-V is an open (non-proprietary) reduced instruction set. **Arm vs ARM:** Arm is the company that licenses the proprietary instruction -set For example, they license it to Apple to run on their M-series chips. ARM +set. For example, they license it to Apple to run on their M-series chips. ARM (in all caps) refers to the family of RISC instruction sets, and by extension chips that use the instruction sets. It is also an acronym for Advanced RISC Machines and the eariler Acorn RISC Machine). This `blog post From f104c60bea035f45866bd61df4e2980f30f8881b Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 20 Nov 2023 10:00:46 -0500 Subject: [PATCH 31/41] note about linux-aarch64 containers --- source/developer/aarch64.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/developer/aarch64.rst b/source/developer/aarch64.rst index 950dedc..f86a1ba 100644 --- a/source/developer/aarch64.rst +++ b/source/developer/aarch64.rst @@ -23,3 +23,6 @@ building on ``linux-aarch64`` by adding the following to the The current CircleCI config will only run if at least one recipe in the commit range (typically for the PR) includes the above additional platform. + +Support for building and uploading containers for ``linux-aarch64`` is planned +but not yet implemented (Nov 2023). From 7ff4680fac15c39e1b6f5c18935e97a166d5b452 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Fri, 24 Nov 2023 09:26:36 -0500 Subject: [PATCH 32/41] add inventory of repos --- source/developer/index.rst | 1 + source/developer/repo-inventory.rst | 55 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 source/developer/repo-inventory.rst diff --git a/source/developer/index.rst b/source/developer/index.rst index cc88506..ea76ebf 100644 --- a/source/developer/index.rst +++ b/source/developer/index.rst @@ -9,4 +9,5 @@ Developer Docs bulk repodata_patching ci-inventory + repo-inventory aarch64 diff --git a/source/developer/repo-inventory.rst b/source/developer/repo-inventory.rst new file mode 100644 index 0000000..a07e55c --- /dev/null +++ b/source/developer/repo-inventory.rst @@ -0,0 +1,55 @@ +Repository inventory +==================== + +.. list-table:: + :header-rows: 1 + :class: inventory + + * - repo + - description + + * - `bioconda-recipes `_ + - Recipes that are automatically built + + * - `bioconda-utils `_ + - The build system that orchestrates everything + + * - `bioconda-docs `_ + - Home of the documentation + + * - `bioconda-common `_ + - Centralized location for installation/config + + * - `bioconda-containers `_ + - Dockerfiles and CI config for building :ref:`bioconda containers `_ + + * - `bioconda.github.io `_ + - Docs built by bioconda-docs are pushed here for hosting by GitHub + + * - `bioconda-stats `_ + - Gathers and stores statistics from the conda channel + + * - `bioconda-plots `_ + - Converts data from bioconda-stats into plots used by the docs + + * - `bioconda-paper `_ + - Code and data for generating the figures in https://doi.org/10.1038/s41592-018-0046-7 + + * - `bioconda-tests `_ + - Intended to trigger periodic tests of all packages + + * - `bioconda-outreach `_ + - Presentations and training materials + + * - `bioconda-actions `_ + - DEPRECATED, previously used for factoring out GitHub Actions + + * - `bioconda-repodata-patches `_ + - DEPRECATED, this is now moved to the corresponding `recipe `_ + + * - `bioconda-extended-base-image `_ + - DEPRECATED, this is now handled in `bioconda-containers `_ + + * - `quay.io/organization/bioconda `_ + - Docker containers + From c69024f49e59744807d74bdb164630768b9a2a71 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Fri, 24 Nov 2023 09:27:20 -0500 Subject: [PATCH 33/41] add inventory of dockerfiles/images --- source/developer/dockerfile-inventory.rst | 167 +++ source/developer/index.rst | 1 + source/images/bioconda-containers.excalidraw | 1318 ++++++++++++++++++ source/images/bioconda-containers.png | Bin 0 -> 47033 bytes source/images/bioconda-containers.svg | 21 + 5 files changed, 1507 insertions(+) create mode 100644 source/developer/dockerfile-inventory.rst create mode 100644 source/images/bioconda-containers.excalidraw create mode 100644 source/images/bioconda-containers.png create mode 100644 source/images/bioconda-containers.svg diff --git a/source/developer/dockerfile-inventory.rst b/source/developer/dockerfile-inventory.rst new file mode 100644 index 0000000..1629e20 --- /dev/null +++ b/source/developer/dockerfile-inventory.rst @@ -0,0 +1,167 @@ +Dockerfile inventory +==================== + +Docker containers are used in multiple ways by bioconda-utils. Broadly, we can +divide them into containers used for *building* packages and containers used +for the bot. + +Overview of containers used in building +--------------------------------------- + +Bioconda builds not only conda packages but also Docker containers with the +package installed. Here's how it works. + + +.. figure:: ../images/bioconda-containers.png + + Sketch of how containers and packages interact with :command:`bioconda-utils + build --docker --mulled-test`. See below for details. [:download:`excalidraw + <../images/bioconda-containers.excalidraw>`] [:download:`SVG + <../images/bioconda-containers.svg>`] + +If we run :command:`bioconda-utils build` without the :command:`--docker` +argument, it will build a conda package using the conda-build in the local +environment and the built package will appear in the host's :file:`conda-bld` +directory, ready for uploading to the channel. + +However, the host may have libraries or packages installed that are not defined +in the recipe. If a package uses any of these, then even if tests pass on this +host they may fail on another machine that is missing those undeclared +dependencies, resulting in a broken package. Since we use multiple CI providers +(CircleCI, GitHub Actions, Azure DevOps), and since any one of these providers +may install or update libraries on their hosts at any time, there is a risk of +creating packages that work when building but are broken on other systems. + +To guard against this, we run :command:`bioconda-utils build` with the +:command:`--docker` argument. This runs conda-build inside a Docker container, +isolating it from the host and preventing any host libraries from being used. +As before, the resulting package is found in the host's :file:`conda-bld` +directory. + +When we additionally use the :command:`--mulled-test` argument, +:program:`bioconda-utils` will run :program:`mulled-build` from the `galaxy-lib +`_ package. +:program:`mulled-build` is a tool to convert conda packages into Docker images. +It uses `involucro `_ to make a final, +minimal image with a dramatically reduced file size. + +This process uses two images: an image containing conda, and a minimal base +image. First, a container with conda installed is used to :command:`conda +install` the package built in the previous step into the container. This +installs the package's dependencies as well. The test commands are extracted +from the package, and run to test this newly-installed package. Next, *just the +conda environment directory* is extracted from the conda container and layered +onto the base image using :program:`involucro`. + +The base image has very little else, not even conda. So the end result is +a minimal Docker image with nothing but the installed package and its +dependencies (and therefore a small size), ready to be uploaded to +a repository. + + +Details of containers using in building +--------------------------------------- + +The **build image** is used for *building* a package, isolated from the host. +The built package appears back on the host's local channel. + +The **conda image** is used by mulled-build for *installing* the conda package +in such a way that the resulting conda env can be easily copied out by +involucro + +The **base image** is used by involucro as a starting image into which it will +copy the conda env created by mulled-build in the conda image + +The **extended base image** is used in rare cases where very minimal base image +is *too* minimal. In this case, recipe authors can specify +``container:extended-base:true`` in the meta.yaml file, and the extended image +will be used as the base instead. + +Here are the images, their respective Dockerfiles, and where they are built. + +.. list-table:: + :header-rows: 1 + :class: inventory + + * - description + - image + - maintained in + - dockerfile + - built by + + * - build image + - ``quay.io/bioconda/bioconda-utils-build-env-cos7`` + - bioconda-utils + - `Dockerfile `_ + - `GitHub Action workflow `_ + + * - conda image + - ``quay.io/bioconda/create-env:latest`` + - bioconda-containers + - `Dockerfile `_ + - `GitHub Action workflow `_ + + * - base image + - ``quay.io/bioconda/base-glibc-busybox-bash:3.0`` + - bioconda-containers + - `Dockerfile `_ + - `GitHub Action workflow `_ + + * - extended base image + - ``quay.io/bioconda/base-glibc-debian-bash:3.0`` + - bioconda-containers + - `Dockerfile `_ + - `GitHub Action workflow `_ + +As of Nov 2023, each of these is configured to be built on both amd64 and arm64 +(a.k.a x86_64 and aarch64) architectures. + +In the actual :program:`bioconda-utils` code, the containers are specified in +several ways. Note that the links to code below point to specific commits in +order to highlight a line, so these may not be the most up-to-date code. But it +can give you a starting point for where to look. + +- The build image is configured in `bioconda_utils/cli `_. + +- mulled-build pays attention to `env vars + `_ + that define what images to use. + +- `bioconda_utils.pkg_test.test_package() + `_ + sets DEST_BASE_IMAGE to the `base_image` arg, which in turn is set in + `bioconda_utils.build.build() + `_. + This can take one of two hard-coded values, depending on if the recipe needed + an extended image or not. + +- mulled-build also needs a conda image to use. This is set by bioconda-utils + in `pkg_test.py + `_ + which is then passed to `build.build + `_. + + +The bot +------- + +The BiocondaBot responds to comments on PRs an interacts with some artifacts +created by package builds. In order to have rapid response times, the bot is +implemented as a set of tagged Docker containers. + +The bot actions largely consist of relatively simple HTTP requests. The code +for these actions if maintained in the `src/bioconda_bot +`_ +Python package, within the bioconda-containers repo. There are different tagged +images for the different behaviors of the bot, which are built and pushed in +the `bot.yaml +`_ +GitHub Action workflow in the bioconda-containers repo. For example, the +comment behavior on bioconda-recipes is defined `here +`_, +which uses the ``quay.io/bioconda/bot:comment`` container, sets some env +variables that GitHub Actions has access to, and runs :command:`bioconda-bot +comment` in the container. This container was created `here +`_, +when the `matrix.tag was set to "comment" +`_. diff --git a/source/developer/index.rst b/source/developer/index.rst index ea76ebf..37f721a 100644 --- a/source/developer/index.rst +++ b/source/developer/index.rst @@ -9,5 +9,6 @@ Developer Docs bulk repodata_patching ci-inventory + dockerfile-inventory repo-inventory aarch64 diff --git a/source/images/bioconda-containers.excalidraw b/source/images/bioconda-containers.excalidraw new file mode 100644 index 0000000..a311012 --- /dev/null +++ b/source/images/bioconda-containers.excalidraw @@ -0,0 +1,1318 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "Ry0HXcfp2TtDCwDgRSN05", + "type": "rectangle", + "x": 315.244140625, + "y": 439.88203125, + "width": 641.97265625, + "height": 29.2, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffd43b", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 591301005, + "version": 427, + "versionNonce": 861916067, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "92AKwAgt4H6S0AAjrQu_3" + } + ], + "updated": 1700758646509, + "link": null, + "locked": false + }, + { + "id": "92AKwAgt4H6S0AAjrQu_3", + "type": "text", + "x": 570.60546875, + "y": 444.88203125, + "width": 131.25, + "height": 19.2, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1410176237, + "version": 491, + "versionNonce": 1498177347, + "isDeleted": false, + "boundElements": null, + "updated": 1700758646509, + "link": null, + "locked": false, + "text": "bioconda-utils", + "fontSize": 16, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 15, + "containerId": "Ry0HXcfp2TtDCwDgRSN05", + "originalText": "bioconda-utils", + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 493, + "versionNonce": 424045965, + "isDeleted": false, + "id": "DMfgmgWEVMH6fhFuNgxVr", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 504.8535156250001, + "y": 479.989453125, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "width": 446.31640624999983, + "height": 29.2, + "seed": 129562083, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "ebIoI_c0AL2Mect1VXg5P" + } + ], + "updated": 1700758642591, + "link": null, + "locked": false + }, + { + "id": "ebIoI_c0AL2Mect1VXg5P", + "type": "text", + "x": 671.76171875, + "y": 484.989453125, + "width": 112.5, + "height": 19.2, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1102745517, + "version": 453, + "versionNonce": 1587229677, + "isDeleted": false, + "boundElements": null, + "updated": 1700758642592, + "link": null, + "locked": false, + "text": "mulled-build", + "fontSize": 16, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 15, + "containerId": "DMfgmgWEVMH6fhFuNgxVr", + "originalText": "mulled-build", + "lineHeight": 1.2 + }, + { + "type": "rectangle", + "version": 663, + "versionNonce": 429563373, + "isDeleted": false, + "id": "abSQmI8Tl4VEY2QBVppey", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 733.376953125, + "y": 517.59375, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff9db", + "width": 216.76171874999997, + "height": 29.2, + "seed": 1468203427, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "QDHZi5ciBJh_S7srIu1IG" + } + ], + "updated": 1700758628960, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 652, + "versionNonce": 969562189, + "isDeleted": false, + "id": "QDHZi5ciBJh_S7srIu1IG", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 799.5703125, + "y": 522.59375, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 84.375, + "height": 19.2, + "seed": 1066980675, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1700758628961, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "involucro", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "abSQmI8Tl4VEY2QBVppey", + "originalText": "involucro", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "id": "cCiUDhdHKsMRPLATOl74B", + "type": "line", + "x": 152.51953125, + "y": 686.49609375, + "width": 766.21484375, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 2081779939, + "version": 218, + "versionNonce": 1974850285, + "isDeleted": false, + "boundElements": null, + "updated": 1700758620397, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 766.21484375, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "lzBDka8XJXnQKztZ11Dxh", + "type": "text", + "x": 278.33984375, + "y": 748.20078125, + "width": 150, + "height": 19.2, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 507070019, + "version": 215, + "versionNonce": 1198972515, + "isDeleted": false, + "boundElements": [ + { + "id": "YBQpyBT_TcIo47RBV5WZP", + "type": "arrow" + } + ], + "updated": 1700758620397, + "link": null, + "locked": false, + "text": "recipes/pkgname/", + "fontSize": 16, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 15, + "containerId": null, + "originalText": "recipes/pkgname/", + "lineHeight": 1.2 + }, + { + "id": "uD7PB-jAZk41aqxRuaISt", + "type": "text", + "x": 469.8046875, + "y": 748.18125, + "width": 234.375, + "height": 19.2, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 797833347, + "version": 179, + "versionNonce": 1718819331, + "isDeleted": false, + "boundElements": [ + { + "id": "Wv4FKPgKrMaF6iDzDn0Lx", + "type": "arrow" + }, + { + "id": "z2WjdCLrgR50gxx-9Mp6i", + "type": "arrow" + } + ], + "updated": 1700758620397, + "link": null, + "locked": false, + "text": "conda-bld/pkgname.tar.bz2", + "fontSize": 16, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 15, + "containerId": null, + "originalText": "conda-bld/pkgname.tar.bz2", + "lineHeight": 1.2 + }, + { + "id": "YBQpyBT_TcIo47RBV5WZP", + "type": "arrow", + "x": 323.4322857790941, + "y": 736.7515625, + "width": 21.145419762216193, + "height": 55.58479406392064, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 2043726947, + "version": 1315, + "versionNonce": 626341837, + "isDeleted": false, + "boundElements": null, + "updated": 1700758665077, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 21.145419762216193, + -55.58479406392064 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "lzBDka8XJXnQKztZ11Dxh", + "gap": 11.44921875, + "focus": -0.4822151595925682 + }, + "endBinding": { + "elementId": "ZSPG8ACP4jq3ssZMYNzQW", + "gap": 13.940205936079337, + "focus": 0.20174636147394562 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "Wv4FKPgKrMaF6iDzDn0Lx", + "type": "arrow", + "x": 503.05232956876023, + "y": 676.0541109444912, + "width": 34.33759363829097, + "height": 63.46698280550879, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1479936387, + "version": 1349, + "versionNonce": 461362957, + "isDeleted": false, + "boundElements": null, + "updated": 1700758665076, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 34.33759363829097, + 63.46698280550879 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "ZSPG8ACP4jq3ssZMYNzQW", + "gap": 9.063868781165752, + "focus": -0.32741834502722905 + }, + "endBinding": { + "elementId": "uD7PB-jAZk41aqxRuaISt", + "gap": 8.66015625, + "focus": -0.32458329747209613 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "z2WjdCLrgR50gxx-9Mp6i", + "type": "arrow", + "x": 578.3213788819246, + "y": 739.74765625, + "width": 33.700690869569144, + "height": 83.9816591883033, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 2070448685, + "version": 915, + "versionNonce": 1083999011, + "isDeleted": false, + "boundElements": null, + "updated": 1700759043553, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 33.700690869569144, + -83.9816591883033 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "uD7PB-jAZk41aqxRuaISt", + "focus": -0.13192007287625357, + "gap": 8.43359375 + }, + "endBinding": { + "elementId": "Mp4CB3RLFFYLjwBEjjBCf", + "focus": 0.4992174931088646, + "gap": 1.4331845616966348 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "rectangle", + "version": 704, + "versionNonce": 221470413, + "isDeleted": false, + "id": "YagLhsW7rU9oRtGDs3MVQ", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 815.67578125, + "y": 567.35546875, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 140.07812499999994, + "height": 93.99609375, + "seed": 471524227, + "groupIds": [ + "qxo2_x0gTN9YPhOX7abNO" + ], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "UOwu-SVo7CcdghHvhRNoO" + } + ], + "updated": 1700758620397, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 734, + "versionNonce": 424706179, + "isDeleted": false, + "id": "UOwu-SVo7CcdghHvhRNoO", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 844.5771484375, + "y": 572.35546875, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 82.275390625, + "height": 46, + "seed": 1318681379, + "groupIds": [ + "qxo2_x0gTN9YPhOX7abNO" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1700758620397, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 2, + "text": "base \ncontainer", + "textAlign": "center", + "verticalAlign": "top", + "containerId": "YagLhsW7rU9oRtGDs3MVQ", + "originalText": "base container", + "lineHeight": 1.15, + "baseline": 41 + }, + { + "type": "rectangle", + "version": 775, + "versionNonce": 1113062701, + "isDeleted": false, + "id": "90jJda8XDVExXoLSysirR", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 823.23828125, + "y": 623.15234375, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 129.57031250000003, + "height": 29.2, + "seed": 1352933059, + "groupIds": [ + "qxo2_x0gTN9YPhOX7abNO" + ], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "HBYY_8kDzFZ8A95N1D3Xr" + }, + { + "id": "NixZifivTH-xD1rNFKj8g", + "type": "arrow" + } + ], + "updated": 1700758620397, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 866, + "versionNonce": 756250659, + "isDeleted": false, + "id": "HBYY_8kDzFZ8A95N1D3Xr", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 841.1484375, + "y": 628.15234375, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 93.75, + "height": 19.2, + "seed": 1826180707, + "groupIds": [ + "qxo2_x0gTN9YPhOX7abNO" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1700758620397, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "/usr/local", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "90jJda8XDVExXoLSysirR", + "originalText": "/usr/local", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "id": "NixZifivTH-xD1rNFKj8g", + "type": "arrow", + "x": 729.40234375, + "y": 642.2313583849638, + "width": 85.6875, + "height": 1.5641890104180902, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 359479811, + "version": 537, + "versionNonce": 1874482787, + "isDeleted": false, + "boundElements": null, + "updated": 1700759043553, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 85.6875, + 1.5641890104180902 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "Mp4CB3RLFFYLjwBEjjBCf", + "focus": 0.07085274746293091, + "gap": 10.89453125 + }, + "endBinding": { + "elementId": "90jJda8XDVExXoLSysirR", + "focus": -0.46725910481659183, + "gap": 8.1484375 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "type": "rectangle", + "version": 527, + "versionNonce": 685145027, + "isDeleted": false, + "id": "y8aZgYOatYLM0Fa3dOUuj", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 586.07421875, + "y": 525, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 140.07812499999994, + "height": 136.27343750000003, + "seed": 2095935789, + "groupIds": [ + "EBigXOisoe8W1KUQ3lS5K" + ], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "Gr5IokqxpJqxRSfCPzEZl" + } + ], + "updated": 1700758620397, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 543, + "versionNonce": 1387419117, + "isDeleted": false, + "id": "Gr5IokqxpJqxRSfCPzEZl", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 614.9755859375, + "y": 530, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 82.275390625, + "height": 46, + "seed": 702595981, + "groupIds": [ + "EBigXOisoe8W1KUQ3lS5K" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1700758620397, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 2, + "text": "conda \ncontainer", + "textAlign": "center", + "verticalAlign": "top", + "containerId": "y8aZgYOatYLM0Fa3dOUuj", + "originalText": "conda container", + "lineHeight": 1.15, + "baseline": 41 + }, + { + "type": "rectangle", + "version": 610, + "versionNonce": 1541267523, + "isDeleted": false, + "id": "Mp4CB3RLFFYLjwBEjjBCf", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 588.9375, + "y": 625.1328125, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 129.57031250000003, + "height": 29.2, + "seed": 1275482339, + "groupIds": [ + "EBigXOisoe8W1KUQ3lS5K" + ], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "-3ke31NdzuocXVw_hkILy" + }, + { + "id": "z2WjdCLrgR50gxx-9Mp6i", + "type": "arrow" + }, + { + "id": "NixZifivTH-xD1rNFKj8g", + "type": "arrow" + } + ], + "updated": 1700759043553, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 693, + "versionNonce": 1580266435, + "isDeleted": false, + "id": "-3ke31NdzuocXVw_hkILy", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 634.97265625, + "y": 630.1328125, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 37.5, + "height": 19.2, + "seed": 1030765699, + "groupIds": [ + "EBigXOisoe8W1KUQ3lS5K" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1700759051498, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "env/", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Mp4CB3RLFFYLjwBEjjBCf", + "originalText": "env/", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "type": "rectangle", + "version": 613, + "versionNonce": 1090955011, + "isDeleted": false, + "id": "HZ-rnkXnVkb89LtWcmhUZ", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 590.48046875, + "y": 590.4585937500001, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 129.57031250000003, + "height": 29.2, + "seed": 180706349, + "groupIds": [ + "EBigXOisoe8W1KUQ3lS5K" + ], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "x4SHbu6J53EOkI86YBWpP" + } + ], + "updated": 1700758620397, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 698, + "versionNonce": 895319725, + "isDeleted": false, + "id": "x4SHbu6J53EOkI86YBWpP", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 631.828125, + "y": 595.4585937500001, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 46.875, + "height": 19.2, + "seed": 730025613, + "groupIds": [ + "EBigXOisoe8W1KUQ3lS5K" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1700758620397, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "conda", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "HZ-rnkXnVkb89LtWcmhUZ", + "originalText": "conda", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "id": "T80XglCa2EMVp9kTzyUad", + "type": "text", + "x": 176.8662109375, + "y": 592.29921875, + "width": 88.689453125, + "height": 32.199999999999996, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1326686243, + "version": 176, + "versionNonce": 2017513123, + "isDeleted": false, + "boundElements": null, + "updated": 1700758620397, + "link": null, + "locked": false, + "text": "Docker", + "fontSize": 28, + "fontFamily": 2, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 26, + "containerId": null, + "originalText": "Docker", + "lineHeight": 1.15 + }, + { + "type": "text", + "version": 214, + "versionNonce": 1140007181, + "isDeleted": false, + "id": "8U-iTgt9HlDYzlNCGtoI9", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 176.8662109375, + "y": 717.353125, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "width": 57.572265625, + "height": 32.199999999999996, + "seed": 1374987693, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1700758620397, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 2, + "text": "Host", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Host", + "lineHeight": 1.15, + "baseline": 26 + }, + { + "id": "ZSPG8ACP4jq3ssZMYNzQW", + "type": "rectangle", + "x": 313.4609375, + "y": 499.1015625, + "width": 187.53515625, + "height": 168.12499999999997, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "VKry84j3vgFdUIVvIcZot" + ], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 2141807747, + "version": 559, + "versionNonce": 1041120301, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "RSmIGjVVf1qi-P26cGPBy" + }, + { + "id": "Wv4FKPgKrMaF6iDzDn0Lx", + "type": "arrow" + }, + { + "id": "YBQpyBT_TcIo47RBV5WZP", + "type": "arrow" + } + ], + "updated": 1700758679592, + "link": null, + "locked": false + }, + { + "id": "RSmIGjVVf1qi-P26cGPBy", + "type": "text", + "x": 342.1845703125, + "y": 504.1015625, + "width": 130.087890625, + "height": 23, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "VKry84j3vgFdUIVvIcZot" + ], + "frameId": null, + "roundness": null, + "seed": 1033868227, + "version": 618, + "versionNonce": 505719075, + "isDeleted": false, + "boundElements": null, + "updated": 1700758679592, + "link": null, + "locked": false, + "text": "build container", + "fontSize": 20, + "fontFamily": 2, + "textAlign": "center", + "verticalAlign": "top", + "baseline": 18, + "containerId": "ZSPG8ACP4jq3ssZMYNzQW", + "originalText": "build container", + "lineHeight": 1.15 + }, + { + "type": "rectangle", + "version": 772, + "versionNonce": 1118842509, + "isDeleted": false, + "id": "COs0yi5IlmMD9jBPtDSYv", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 327.6875, + "y": 620.153125, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 159.08203125000003, + "height": 29.2, + "seed": 1481006691, + "groupIds": [ + "VKry84j3vgFdUIVvIcZot" + ], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "9lNvtWk4-OHSmBA-xig0m" + } + ], + "updated": 1700758679592, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1064, + "versionNonce": 580488387, + "isDeleted": false, + "id": "9lNvtWk4-OHSmBA-xig0m", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 341.603515625, + "y": 625.153125, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 131.25, + "height": 19.2, + "seed": 827496963, + "groupIds": [ + "VKry84j3vgFdUIVvIcZot" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1700758679592, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "bioconda-utils", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "COs0yi5IlmMD9jBPtDSYv", + "originalText": "bioconda-utils", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "type": "rectangle", + "version": 644, + "versionNonce": 388289773, + "isDeleted": false, + "id": "wBcYIwBjFolSi4vZE0mDW", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 342.443359375, + "y": 549.6968750000001, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 129.57031250000003, + "height": 29.2, + "seed": 741604525, + "groupIds": [ + "VKry84j3vgFdUIVvIcZot" + ], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "Xiop5TihDc0Y2uoKalufe" + } + ], + "updated": 1700758679592, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 729, + "versionNonce": 2045836387, + "isDeleted": false, + "id": "Xiop5TihDc0Y2uoKalufe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 383.791015625, + "y": 554.6968750000001, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 46.875, + "height": 19.2, + "seed": 1464459021, + "groupIds": [ + "VKry84j3vgFdUIVvIcZot" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1700758679592, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "conda", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "wBcYIwBjFolSi4vZE0mDW", + "originalText": "conda", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "type": "rectangle", + "version": 665, + "versionNonce": 385199949, + "isDeleted": false, + "id": "uL7UDVECJInJJUMUqODvN", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 342.443359375, + "y": 584.2242187500001, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 129.57031250000003, + "height": 29.2, + "seed": 686579213, + "groupIds": [ + "VKry84j3vgFdUIVvIcZot" + ], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "Q1r1idMiMOx9hFfsS5wvt" + } + ], + "updated": 1700758679592, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 776, + "versionNonce": 1073313795, + "isDeleted": false, + "id": "Q1r1idMiMOx9hFfsS5wvt", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 355.666015625, + "y": 589.2242187500001, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 103.125, + "height": 19.2, + "seed": 1897534787, + "groupIds": [ + "VKry84j3vgFdUIVvIcZot" + ], + "frameId": null, + "roundness": null, + "boundElements": null, + "updated": 1700758679592, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "conda-build", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "uL7UDVECJInJJUMUqODvN", + "originalText": "conda-build", + "lineHeight": 1.2, + "baseline": 15 + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/source/images/bioconda-containers.png b/source/images/bioconda-containers.png new file mode 100644 index 0000000000000000000000000000000000000000..ff3e569ae179d2e303ebb527e555ee9a8d36b2a1 GIT binary patch literal 47033 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 C+eT>s literal 0 HcmV?d00001 diff --git a/source/images/bioconda-containers.svg b/source/images/bioconda-containers.svg new file mode 100644 index 0000000..66108b6 --- /dev/null +++ b/source/images/bioconda-containers.svg @@ -0,0 +1,21 @@ + + + + + + + + bioconda-utilsmulled-buildinvolucrorecipes/pkgname/conda-bld/pkgname.tar.bz2base container/usr/localconda containerenv/condaDockerHostbuild containerbioconda-utilscondaconda-build \ No newline at end of file From 9726db0a2a43dbe9af8cf180fb1341d82f4bf32c Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Fri, 1 Dec 2023 15:19:48 -0500 Subject: [PATCH 34/41] Update source/faqs.rst --- source/faqs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/faqs.rst b/source/faqs.rst index 3320797..772b846 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -553,7 +553,7 @@ reduced instruction set. set. For example, they license it to Apple to run on their M-series chips. ARM (in all caps) refers to the family of RISC instruction sets, and by extension chips that use the instruction sets. It is also an acronym for Advanced RISC -Machines and the eariler Acorn RISC Machine). This `blog post +Machines and the eariler Acorn RISC Machine. This `blog post `_ goes into lots more detail. From 22a39f5e4007e75f49b057d8f66ff703eeccfd95 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Fri, 24 Nov 2023 22:02:58 -0500 Subject: [PATCH 35/41] typo --- source/developer/repodata_patching.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/developer/repodata_patching.rst b/source/developer/repodata_patching.rst index 8e4d01d..539a05a 100644 --- a/source/developer/repodata_patching.rst +++ b/source/developer/repodata_patching.rst @@ -106,7 +106,7 @@ as described below. Modifying gen_patch_json.py --------------------------- -We will be working in the `bioconda-repodate-patches recipe +We will be working in the `bioconda-repodata-patches recipe `_. The `gen_patch_json.py` file is borrowed from conda-forge and has one function From 2fc9c8c64729ea1fafd56cef652439586120af87 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Fri, 24 Nov 2023 22:03:04 -0500 Subject: [PATCH 36/41] css update --- source/static/style.css | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/source/static/style.css b/source/static/style.css index 10191d6..014bfca 100644 --- a/source/static/style.css +++ b/source/static/style.css @@ -152,6 +152,7 @@ details div.details { font-style: italic; } +/* Used on the front page to describe the workflow diagram */ .circlednumber { font-size: 150%; font-weight: bold; @@ -164,21 +165,64 @@ details div.details { margin-top: -15px; } +/* If a details section includes an anchor, this styles the "¶" symbol */ details a.headerlink { color: #ccc; visibility: visible; } +/* when using .. datechanged:: directive, makes the whole thing italic and +* a little smaller */ div.datechanged { font-style: italic; font-size: 0.9em; } +/* "conda green" for the .. datechanged:: label */ .versionmodified { color: #3eb049; } + +/* make the inventory tables (for ci and docker) fit a little better on screen */ table.inventory { overflow-x: scroll; font-size: 0.8em; } + +table.inventory th, td { + min-width: 100px; +} + +code.xref { + font-weight: normal; +} + +/* for :program:`program-name` roles */ +.program { + font-weight: normal; + font-style: italic; + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} +/* for :command:`cmd here` roles */ +.command { + font-weight: normal; + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +/* for :file:`path` roles */ +.file { + font-weight: normal; + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; + background-color: transparent; +} + +/* Text under figures */ +.caption-text { + font-style: italic; + font-size: 0.9em; +} + From 0e07cade26c23b5a9f929f129fcfa004c6033b8e Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 4 Mar 2024 15:41:43 -0500 Subject: [PATCH 37/41] minor changes --- source/contributor/build-system.rst | 4 ++-- source/developer/aarch64.rst | 8 ++++---- source/developer/ci-inventory.rst | 2 +- source/developer/repo-inventory.rst | 2 +- source/faqs.rst | 2 +- source/static/style.css | 7 +++++++ 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/source/contributor/build-system.rst b/source/contributor/build-system.rst index 485b45c..b71f283 100644 --- a/source/contributor/build-system.rst +++ b/source/contributor/build-system.rst @@ -1,8 +1,8 @@ Build system ============ -.. datechanged:: 2023-11-14 - Made descriptions more generalized to reflect multiple CI systems in use +.. datechanged:: 2024-03-02 + Generalized descriptions to reflect multiple CI systems in use The build system for Bioconda takes recipes and converts them into conda packages that are uploaded to anaconda.org as well as Docker containers that diff --git a/source/developer/aarch64.rst b/source/developer/aarch64.rst index f86a1ba..499c802 100644 --- a/source/developer/aarch64.rst +++ b/source/developer/aarch64.rst @@ -1,13 +1,13 @@ ``aarch64`` builds ================== -.. datechanged:: 2023-11-18 +.. datechanged:: 2024-03-02 Added this section as initial linux-aarch64 builds are starting While we do not yet have builds for ``osx-arm64`` (see :ref:`platform-nomenclature-faq`), we are starting to roll out ``linux-aarch64`` builds. These run on CircleCI, which offers the -infrastructure for this (in contrast to GitHub Actions, which does not support Linux ARM64 at the moment (Nov 2023)). +infrastructure for this. This is being initially approached as an opt-in process as we make sure all the moving parts are working correctly. A recipe can be flagged for @@ -24,5 +24,5 @@ The current CircleCI config will only run if at least one recipe in the commit range (typically for the PR) includes the above additional platform. -Support for building and uploading containers for ``linux-aarch64`` is planned -but not yet implemented (Nov 2023). +Support for building and uploading ``linux-aarch64`` containers is planned but +not yet implemented (as of March 2023). diff --git a/source/developer/ci-inventory.rst b/source/developer/ci-inventory.rst index 0d1e784..72b82a4 100644 --- a/source/developer/ci-inventory.rst +++ b/source/developer/ci-inventory.rst @@ -9,7 +9,7 @@ CI Inventory .. datechanged:: 2023-06-06 Start using build-failures workflow -.. datechanged:: 2023-11-18 +.. datechanged:: 2024-03-02 Start using ``linux-aarch64`` in bulk and recipe tests This page documents the various moving parts that, together, make Bioconda diff --git a/source/developer/repo-inventory.rst b/source/developer/repo-inventory.rst index a07e55c..1d9cf34 100644 --- a/source/developer/repo-inventory.rst +++ b/source/developer/repo-inventory.rst @@ -21,7 +21,7 @@ Repository inventory - Centralized location for installation/config * - `bioconda-containers `_ - - Dockerfiles and CI config for building :ref:`bioconda containers `_ + - Dockerfiles and CI config for building :ref:`bioconda containers ` * - `bioconda.github.io `_ - Docs built by bioconda-docs are pushed here for hosting by GitHub diff --git a/source/faqs.rst b/source/faqs.rst index 772b846..eb59800 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -529,7 +529,7 @@ build. Understanding platform nomenclature ----------------------------------- -.. datechanged:: 2023-11-18 +.. datechanged:: 2024-03-02 Added section Different CPU chips use different architecture, so programs are written diff --git a/source/static/style.css b/source/static/style.css index 014bfca..f6ee1a1 100644 --- a/source/static/style.css +++ b/source/static/style.css @@ -226,3 +226,10 @@ code.xref { font-size: 0.9em; } +/* add more space to lists */ +ol.simple p { + margin-bottom: 1em; +} +ul.simple p { + margin-bottom: 1em; +} From 38b0e0e8f85cb6c630714064135b63892ba1fc61 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 4 Mar 2024 15:43:08 -0500 Subject: [PATCH 38/41] update images page --- source/developer/dockerfile-inventory.rst | 140 ++- source/images/bioconda-containers.excalidraw | 1100 ++++++++++++------ source/images/bioconda-containers.png | Bin 47033 -> 50474 bytes source/images/bioconda-containers.svg | 2 +- 4 files changed, 818 insertions(+), 424 deletions(-) diff --git a/source/developer/dockerfile-inventory.rst b/source/developer/dockerfile-inventory.rst index 1629e20..e9a8537 100644 --- a/source/developer/dockerfile-inventory.rst +++ b/source/developer/dockerfile-inventory.rst @@ -1,16 +1,38 @@ +.. _dockerfile-inventory: + Dockerfile inventory ==================== -Docker containers are used in multiple ways by bioconda-utils. Broadly, we can -divide them into containers used for *building* packages and containers used -for the bot. +.. datechanged:: 2024-03-02 + Added section + +Containers are used in multiple ways by bioconda-utils. Broadly, we can +divide them into containers used for *building* packages, containers for +*running* packages, and containers used for the bot. + +.. details:: Containers vs images + + An image is like a static snapshot, while a container is a running instance + of an image. A single image can be used to start multiple containers. Changes + made to a container are not saved back to the original image used to start the + container, but it is possible to make a *new* image from the latest state + of a container . . . which can later be used image to start yet more + containers that start from that latest state. + +.. details:: Docker, podman, buildah, OCI + + Open Container Initiative (OCI) specification defines the format of images. + Buildah is a tool for creating OCI images, and podman is a tool for running + them. Docker is a tool for both creating OCI images and running containers + made from them. + Overview of containers used in building --------------------------------------- -Bioconda builds not only conda packages but also Docker containers with the -package installed. Here's how it works. - +For every recipe, Bioconda builds not only conda packages for mulitple +architectures like osx, linux/amd64, linux/arm64, but also OCI images +(linux/amd64, linux/arm64) with the package installed. Here's how it works. .. figure:: ../images/bioconda-containers.png @@ -19,55 +41,80 @@ package installed. Here's how it works. <../images/bioconda-containers.excalidraw>`] [:download:`SVG <../images/bioconda-containers.svg>`] -If we run :command:`bioconda-utils build` without the :command:`--docker` -argument, it will build a conda package using the conda-build in the local -environment and the built package will appear in the host's :file:`conda-bld` -directory, ready for uploading to the channel. - -However, the host may have libraries or packages installed that are not defined -in the recipe. If a package uses any of these, then even if tests pass on this -host they may fail on another machine that is missing those undeclared -dependencies, resulting in a broken package. Since we use multiple CI providers -(CircleCI, GitHub Actions, Azure DevOps), and since any one of these providers -may install or update libraries on their hosts at any time, there is a risk of -creating packages that work when building but are broken on other systems. - -To guard against this, we run :command:`bioconda-utils build` with the -:command:`--docker` argument. This runs conda-build inside a Docker container, -isolating it from the host and preventing any host libraries from being used. -As before, the resulting package is found in the host's :file:`conda-bld` -directory. +**Description of steps:** + +These steps are all coordinated with running :command:`bioconda-utils build +pkgname` in the bioconda-recipes repo. + + +1. Recipe on the host is mounted as a volume in the build container. + The host's conda-bld directory is also mounted in the container. We call this + the *build-env* container. +2. The build-env container uses conda-build to build a conda package from the + mounted recipe. +3. The newly-built conda package is saved in the conda-bld directory mounted from the + host. The build-env container exits. +4. The new conda package is mounted into a minimal container that has + conda installed (but *not* conda-build or bioconda-utils or any other + dependencies). This is the *create-env* container. +5. The package is installed (with :command:`conda install`) into create-env's + conda environment. This of course includes all dependencies specified in the recipe. + The recipe's test commands are also extracted. +6. Only the contents of the :file:`env/` directory in the *create-env* + container are copied over into the :file:`/usr/local` dir of a minimal *base + container* (which does not even include conda). The extracted tests are run + in the container as a final check (see notes below on + :command:`--mulled-test`), and then the container is ready to upload to + a container registry. + +Why do we do it this way? The short answer is to ensure that all dependencies +are accurately captured in the recipe. + +More details on this rationale: + +We build on multiple CI providers (CircleCI, GitHub Actions, Azure DevOps). Any +one of these providers may install or update libraries on their hosts at any +time. If we didn't use containers for isolation when building packages, +a package could silently depend on those system libraries when building. While +the build might work on CI that already has those libraries, it will be broken +on ar machine without those libraries. + +So :command:`bioconda-utils build --docker` runs conda-build inside a Docker +container, isolating it from the host and preventing any host libraries from +being used. As with a normal :command:`conda build` command, the resulting +package is found in the host's :file:`conda-bld` directory. This is illustrated +in steps 1-3 above. When we additionally use the :command:`--mulled-test` argument, :program:`bioconda-utils` will run :program:`mulled-build` from the `galaxy-lib `_ package. :program:`mulled-build` is a tool to convert conda packages into Docker images. It uses `involucro `_ to make a final, -minimal image with a dramatically reduced file size. - -This process uses two images: an image containing conda, and a minimal base -image. First, a container with conda installed is used to :command:`conda -install` the package built in the previous step into the container. This -installs the package's dependencies as well. The test commands are extracted -from the package, and run to test this newly-installed package. Next, *just the -conda environment directory* is extracted from the conda container and layered -onto the base image using :program:`involucro`. +minimal image with a dramatically reduced file size. This is illustrated in +steps 4-6 above. The base image has very little else, not even conda. So the end result is -a minimal Docker image with nothing but the installed package and its -dependencies (and therefore a small size), ready to be uploaded to +a fully-isolated, minimal Docker image with nothing but the installed package +and its dependencies (and therefore a small size), ready to be uploaded to a repository. +Note that :command:`--mulled-test` runs the tests extracted from the recipe in +the minimal container. Since the container only contains the package and its +dependencies, any tests must use only these. Even if the recipe specifies +additional test dependencies or additional test data (which is supported by +standard conda-build), these are not copied over to the final image and tests +with additional dependencies will therefore fail. Details of containers using in building --------------------------------------- -The **build image** is used for *building* a package, isolated from the host. -The built package appears back on the host's local channel. +The **build-env image** is used for *building* a package in a manner that is +isolated from the host. The built package appears back on the host's local +channel. -The **conda image** is used by mulled-build for *installing* the conda package -in such a way that the resulting conda env can be easily copied out by -involucro +The **create-env image** is used by mulled-build for creating a conda +environment with the package and dependencies installed in such a way that the +resulting conda env can be easily copied out by involucro. The **base image** is used by involucro as a starting image into which it will copy the conda env created by mulled-build in the conda image @@ -77,7 +124,16 @@ is *too* minimal. In this case, recipe authors can specify ``container:extended-base:true`` in the meta.yaml file, and the extended image will be used as the base instead. -Here are the images, their respective Dockerfiles, and where they are built. +Here are the images, their respective Dockerfiles, and their quay.io repository +names. All images are built in the `bioconda-utils build-images GitHub Action +workflow +`_. + +The base image and extended base image have major.minor.patch versions (e.g., +``1.2.3``) as their tags. The build-env image and the create-env image have +both the bioconda-utils version as well as the base image version (e.g., +``2.11.1-base1.2.3``). This is because the images loosely depend on each other +for things like locale, and exact version of conda/mamba. .. list-table:: :header-rows: 1 @@ -150,7 +206,7 @@ created by package builds. In order to have rapid response times, the bot is implemented as a set of tagged Docker containers. The bot actions largely consist of relatively simple HTTP requests. The code -for these actions if maintained in the `src/bioconda_bot +for these actions is maintained in the `src/bioconda_bot `_ Python package, within the bioconda-containers repo. There are different tagged images for the different behaviors of the bot, which are built and pushed in diff --git a/source/images/bioconda-containers.excalidraw b/source/images/bioconda-containers.excalidraw index a311012..5791dcb 100644 --- a/source/images/bioconda-containers.excalidraw +++ b/source/images/bioconda-containers.excalidraw @@ -4,79 +4,79 @@ "source": "https://excalidraw.com", "elements": [ { - "id": "Ry0HXcfp2TtDCwDgRSN05", "type": "rectangle", - "x": 315.244140625, - "y": 439.88203125, - "width": 641.97265625, - "height": 29.2, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffd43b", + "version": 428, + "versionNonce": 1274662954, + "isDeleted": false, + "id": "Ry0HXcfp2TtDCwDgRSN05", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 315.244140625, + "y": 439.88203125, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffd43b", + "width": 641.97265625, + "height": 29.2, + "seed": 591301005, "groupIds": [], "frameId": null, "roundness": { "type": 3 }, - "seed": 591301005, - "version": 427, - "versionNonce": 861916067, - "isDeleted": false, "boundElements": [ { "type": "text", "id": "92AKwAgt4H6S0AAjrQu_3" } ], - "updated": 1700758646509, + "updated": 1705337711919, "link": null, "locked": false }, { - "id": "92AKwAgt4H6S0AAjrQu_3", "type": "text", - "x": 570.60546875, - "y": 444.88203125, - "width": 131.25, - "height": 19.2, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 492, + "versionNonce": 1701453686, + "isDeleted": false, + "id": "92AKwAgt4H6S0AAjrQu_3", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 570.60546875, + "y": 444.88203125, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 131.25, + "height": 19.2, + "seed": 1410176237, "groupIds": [], "frameId": null, "roundness": null, - "seed": 1410176237, - "version": 491, - "versionNonce": 1498177347, - "isDeleted": false, - "boundElements": null, - "updated": 1700758646509, + "boundElements": [], + "updated": 1705337711919, "link": null, "locked": false, - "text": "bioconda-utils", "fontSize": 16, "fontFamily": 3, + "text": "bioconda-utils", "textAlign": "center", "verticalAlign": "middle", - "baseline": 15, "containerId": "Ry0HXcfp2TtDCwDgRSN05", "originalText": "bioconda-utils", - "lineHeight": 1.2 + "lineHeight": 1.2, + "baseline": 15 }, { "type": "rectangle", - "version": 493, - "versionNonce": 424045965, + "version": 494, + "versionNonce": 358759146, "isDeleted": false, "id": "DMfgmgWEVMH6fhFuNgxVr", "fillStyle": "solid", @@ -103,50 +103,50 @@ "id": "ebIoI_c0AL2Mect1VXg5P" } ], - "updated": 1700758642591, + "updated": 1705337711919, "link": null, "locked": false }, { - "id": "ebIoI_c0AL2Mect1VXg5P", "type": "text", - "x": 671.76171875, - "y": 484.989453125, - "width": 112.5, - "height": 19.2, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 454, + "versionNonce": 354599094, + "isDeleted": false, + "id": "ebIoI_c0AL2Mect1VXg5P", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 671.76171875, + "y": 484.989453125, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 112.5, + "height": 19.2, + "seed": 1102745517, "groupIds": [], "frameId": null, "roundness": null, - "seed": 1102745517, - "version": 453, - "versionNonce": 1587229677, - "isDeleted": false, - "boundElements": null, - "updated": 1700758642592, + "boundElements": [], + "updated": 1705337711919, "link": null, "locked": false, - "text": "mulled-build", "fontSize": 16, "fontFamily": 3, + "text": "mulled-build", "textAlign": "center", "verticalAlign": "middle", - "baseline": 15, "containerId": "DMfgmgWEVMH6fhFuNgxVr", "originalText": "mulled-build", - "lineHeight": 1.2 + "lineHeight": 1.2, + "baseline": 15 }, { "type": "rectangle", - "version": 663, - "versionNonce": 429563373, + "version": 664, + "versionNonce": 1408191914, "isDeleted": false, "id": "abSQmI8Tl4VEY2QBVppey", "fillStyle": "solid", @@ -173,14 +173,14 @@ "id": "QDHZi5ciBJh_S7srIu1IG" } ], - "updated": 1700758628960, + "updated": 1705337711919, "link": null, "locked": false }, { "type": "text", - "version": 652, - "versionNonce": 969562189, + "version": 653, + "versionNonce": 531970550, "isDeleted": false, "id": "QDHZi5ciBJh_S7srIu1IG", "fillStyle": "solid", @@ -200,7 +200,7 @@ "frameId": null, "roundness": null, "boundElements": [], - "updated": 1700758628961, + "updated": 1705337711919, "link": null, "locked": false, "fontSize": 16, @@ -214,33 +214,38 @@ "baseline": 15 }, { - "id": "cCiUDhdHKsMRPLATOl74B", "type": "line", - "x": 152.51953125, - "y": 686.49609375, - "width": 766.21484375, - "height": 0, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 219, + "versionNonce": 1288439914, + "isDeleted": false, + "id": "cCiUDhdHKsMRPLATOl74B", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 152.51953125, + "y": 686.49609375, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 766.21484375, + "height": 0, + "seed": 2081779939, "groupIds": [], "frameId": null, "roundness": { "type": 2 }, - "seed": 2081779939, - "version": 218, - "versionNonce": 1974850285, - "isDeleted": false, - "boundElements": null, - "updated": 1700758620397, + "boundElements": [], + "updated": 1705337711919, "link": null, "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, "points": [ [ 0, @@ -250,76 +255,71 @@ 766.21484375, 0 ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null, - "startArrowhead": null, - "endArrowhead": null + ] }, { - "id": "lzBDka8XJXnQKztZ11Dxh", "type": "text", - "x": 278.33984375, - "y": 748.20078125, - "width": 150, - "height": 19.2, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 217, + "versionNonce": 2099417936, + "isDeleted": false, + "id": "lzBDka8XJXnQKztZ11Dxh", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 278.33984375, + "y": 748.20078125, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 150, + "height": 19.2, + "seed": 507070019, "groupIds": [], "frameId": null, "roundness": null, - "seed": 507070019, - "version": 215, - "versionNonce": 1198972515, - "isDeleted": false, "boundElements": [ { "id": "YBQpyBT_TcIo47RBV5WZP", "type": "arrow" } ], - "updated": 1700758620397, + "updated": 1708529841161, "link": null, "locked": false, - "text": "recipes/pkgname/", "fontSize": 16, "fontFamily": 3, + "text": "recipes/pkgname/", "textAlign": "left", "verticalAlign": "top", - "baseline": 15, "containerId": null, "originalText": "recipes/pkgname/", - "lineHeight": 1.2 + "lineHeight": 1.2, + "baseline": 15 }, { - "id": "uD7PB-jAZk41aqxRuaISt", "type": "text", - "x": 469.8046875, - "y": 748.18125, - "width": 234.375, - "height": 19.2, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 181, + "versionNonce": 1249839536, + "isDeleted": false, + "id": "uD7PB-jAZk41aqxRuaISt", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 469.8046875, + "y": 748.18125, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 234.375, + "height": 19.2, + "seed": 797833347, "groupIds": [], "frameId": null, "roundness": null, - "seed": 797833347, - "version": 179, - "versionNonce": 1718819331, - "isDeleted": false, "boundElements": [ { "id": "Wv4FKPgKrMaF6iDzDn0Lx", @@ -330,58 +330,47 @@ "type": "arrow" } ], - "updated": 1700758620397, + "updated": 1708529841161, "link": null, "locked": false, - "text": "conda-bld/pkgname.tar.bz2", "fontSize": 16, "fontFamily": 3, + "text": "conda-bld/pkgname.tar.bz2", "textAlign": "left", "verticalAlign": "top", - "baseline": 15, "containerId": null, "originalText": "conda-bld/pkgname.tar.bz2", - "lineHeight": 1.2 + "lineHeight": 1.2, + "baseline": 15 }, { - "id": "YBQpyBT_TcIo47RBV5WZP", "type": "arrow", - "x": 323.4322857790941, - "y": 736.7515625, - "width": 21.145419762216193, - "height": 55.58479406392064, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 1346, + "versionNonce": 1821449109, + "isDeleted": false, + "id": "YBQpyBT_TcIo47RBV5WZP", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 323.61229028882474, + "y": 736.7515625, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 19.372450779387577, + "height": 50.2429816377379, + "seed": 2043726947, "groupIds": [], "frameId": null, "roundness": { "type": 2 }, - "seed": 2043726947, - "version": 1315, - "versionNonce": 626341837, - "isDeleted": false, - "boundElements": null, - "updated": 1700758665077, + "boundElements": [], + "updated": 1709584334242, "link": null, "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 21.145419762216193, - -55.58479406392064 - ] - ], - "lastCommittedPoint": null, "startBinding": { "elementId": "lzBDka8XJXnQKztZ11Dxh", "gap": 11.44921875, @@ -392,48 +381,48 @@ "gap": 13.940205936079337, "focus": 0.20174636147394562 }, + "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow" + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 19.372450779387577, + -50.2429816377379 + ] + ] }, { - "id": "Wv4FKPgKrMaF6iDzDn0Lx", "type": "arrow", - "x": 503.05232956876023, - "y": 676.0541109444912, - "width": 34.33759363829097, - "height": 63.46698280550879, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 1380, + "versionNonce": 2032700629, + "isDeleted": false, + "id": "Wv4FKPgKrMaF6iDzDn0Lx", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 504.06124691603935, + "y": 680.6695012070668, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 32.93216823870722, + "height": 58.85159254293319, + "seed": 1479936387, "groupIds": [], "frameId": null, "roundness": { "type": 2 }, - "seed": 1479936387, - "version": 1349, - "versionNonce": 461362957, - "isDeleted": false, - "boundElements": null, - "updated": 1700758665076, + "boundElements": [], + "updated": 1709584334241, "link": null, "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 34.33759363829097, - 63.46698280550879 - ] - ], - "lastCommittedPoint": null, "startBinding": { "elementId": "ZSPG8ACP4jq3ssZMYNzQW", "gap": 9.063868781165752, @@ -444,48 +433,48 @@ "gap": 8.66015625, "focus": -0.32458329747209613 }, + "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow" + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 32.93216823870722, + 58.85159254293319 + ] + ] }, { - "id": "z2WjdCLrgR50gxx-9Mp6i", "type": "arrow", - "x": 578.3213788819246, - "y": 739.74765625, - "width": 33.700690869569144, - "height": 83.9816591883033, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 916, + "versionNonce": 1335473590, + "isDeleted": false, + "id": "z2WjdCLrgR50gxx-9Mp6i", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 578.3213788819246, + "y": 739.74765625, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 33.700690869569144, + "height": 83.9816591883033, + "seed": 2070448685, "groupIds": [], "frameId": null, "roundness": { "type": 2 }, - "seed": 2070448685, - "version": 915, - "versionNonce": 1083999011, - "isDeleted": false, - "boundElements": null, - "updated": 1700759043553, + "boundElements": [], + "updated": 1705337711919, "link": null, "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 33.700690869569144, - -83.9816591883033 - ] - ], - "lastCommittedPoint": null, "startBinding": { "elementId": "uD7PB-jAZk41aqxRuaISt", "focus": -0.13192007287625357, @@ -496,13 +485,24 @@ "focus": 0.4992174931088646, "gap": 1.4331845616966348 }, + "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow" + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 33.700690869569144, + -83.9816591883033 + ] + ] }, { "type": "rectangle", - "version": 704, - "versionNonce": 221470413, + "version": 705, + "versionNonce": 1481517226, "isDeleted": false, "id": "YagLhsW7rU9oRtGDs3MVQ", "fillStyle": "solid", @@ -531,14 +531,14 @@ "id": "UOwu-SVo7CcdghHvhRNoO" } ], - "updated": 1700758620397, + "updated": 1705337711919, "link": null, "locked": false }, { "type": "text", - "version": 734, - "versionNonce": 424706179, + "version": 735, + "versionNonce": 965054198, "isDeleted": false, "id": "UOwu-SVo7CcdghHvhRNoO", "fillStyle": "solid", @@ -560,7 +560,7 @@ "frameId": null, "roundness": null, "boundElements": [], - "updated": 1700758620397, + "updated": 1705337711919, "link": null, "locked": false, "fontSize": 20, @@ -571,12 +571,12 @@ "containerId": "YagLhsW7rU9oRtGDs3MVQ", "originalText": "base container", "lineHeight": 1.15, - "baseline": 41 + "baseline": 42 }, { "type": "rectangle", - "version": 775, - "versionNonce": 1113062701, + "version": 776, + "versionNonce": 915899242, "isDeleted": false, "id": "90jJda8XDVExXoLSysirR", "fillStyle": "solid", @@ -609,14 +609,14 @@ "type": "arrow" } ], - "updated": 1700758620397, + "updated": 1705337711919, "link": null, "locked": false }, { "type": "text", - "version": 866, - "versionNonce": 756250659, + "version": 867, + "versionNonce": 1126449206, "isDeleted": false, "id": "HBYY_8kDzFZ8A95N1D3Xr", "fillStyle": "solid", @@ -638,7 +638,7 @@ "frameId": null, "roundness": null, "boundElements": [], - "updated": 1700758620397, + "updated": 1705337711919, "link": null, "locked": false, "fontSize": 16, @@ -652,61 +652,57 @@ "baseline": 15 }, { - "id": "NixZifivTH-xD1rNFKj8g", "type": "arrow", - "x": 729.40234375, - "y": 642.2313583849638, - "width": 85.6875, - "height": 1.5641890104180902, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 618, + "versionNonce": 1071442971, + "isDeleted": false, + "id": "NixZifivTH-xD1rNFKj8g", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 697.4339676060858, + "y": 643.6608595218478, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 117.65587614391416, + "height": 0.13468787353406242, + "seed": 359479811, "groupIds": [], "frameId": null, "roundness": { "type": 2 }, - "seed": 359479811, - "version": 537, - "versionNonce": 1874482787, - "isDeleted": false, - "boundElements": null, - "updated": 1700759043553, + "boundElements": [], + "updated": 1709584345826, "link": null, "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "90jJda8XDVExXoLSysirR", + "focus": -0.4175158043271526, + "gap": 8.1484375 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", "points": [ [ 0, 0 ], [ - 85.6875, - 1.5641890104180902 + 117.65587614391416, + 0.13468787353406242 ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "Mp4CB3RLFFYLjwBEjjBCf", - "focus": 0.07085274746293091, - "gap": 10.89453125 - }, - "endBinding": { - "elementId": "90jJda8XDVExXoLSysirR", - "focus": -0.46725910481659183, - "gap": 8.1484375 - }, - "startArrowhead": null, - "endArrowhead": "arrow" + ] }, { "type": "rectangle", - "version": 527, - "versionNonce": 685145027, + "version": 528, + "versionNonce": 542820726, "isDeleted": false, "id": "y8aZgYOatYLM0Fa3dOUuj", "fillStyle": "solid", @@ -735,14 +731,14 @@ "id": "Gr5IokqxpJqxRSfCPzEZl" } ], - "updated": 1700758620397, + "updated": 1705337711919, "link": null, "locked": false }, { "type": "text", - "version": 543, - "versionNonce": 1387419117, + "version": 554, + "versionNonce": 1459001845, "isDeleted": false, "id": "Gr5IokqxpJqxRSfCPzEZl", "fillStyle": "solid", @@ -751,11 +747,11 @@ "roughness": 1, "opacity": 100, "angle": 0, - "x": 614.9755859375, + "x": 606.0888671875, "y": 530, "strokeColor": "#1e1e1e", "backgroundColor": "transparent", - "width": 82.275390625, + "width": 100.048828125, "height": 46, "seed": 702595981, "groupIds": [ @@ -764,23 +760,23 @@ "frameId": null, "roundness": null, "boundElements": [], - "updated": 1700758620397, + "updated": 1709584311047, "link": null, "locked": false, "fontSize": 20, "fontFamily": 2, - "text": "conda \ncontainer", + "text": "create-env \ncontainer", "textAlign": "center", "verticalAlign": "top", "containerId": "y8aZgYOatYLM0Fa3dOUuj", - "originalText": "conda container", + "originalText": "create-env container", "lineHeight": 1.15, - "baseline": 41 + "baseline": 42 }, { "type": "rectangle", - "version": 610, - "versionNonce": 1541267523, + "version": 612, + "versionNonce": 1064768379, "isDeleted": false, "id": "Mp4CB3RLFFYLjwBEjjBCf", "fillStyle": "solid", @@ -811,20 +807,16 @@ { "id": "z2WjdCLrgR50gxx-9Mp6i", "type": "arrow" - }, - { - "id": "NixZifivTH-xD1rNFKj8g", - "type": "arrow" } ], - "updated": 1700759043553, + "updated": 1709584345825, "link": null, "locked": false }, { "type": "text", - "version": 693, - "versionNonce": 1580266435, + "version": 694, + "versionNonce": 1692894122, "isDeleted": false, "id": "-3ke31NdzuocXVw_hkILy", "fillStyle": "solid", @@ -846,7 +838,7 @@ "frameId": null, "roundness": null, "boundElements": [], - "updated": 1700759051498, + "updated": 1705337711919, "link": null, "locked": false, "fontSize": 16, @@ -861,8 +853,8 @@ }, { "type": "rectangle", - "version": 613, - "versionNonce": 1090955011, + "version": 614, + "versionNonce": 1644389366, "isDeleted": false, "id": "HZ-rnkXnVkb89LtWcmhUZ", "fillStyle": "solid", @@ -891,14 +883,14 @@ "id": "x4SHbu6J53EOkI86YBWpP" } ], - "updated": 1700758620397, + "updated": 1705337711919, "link": null, "locked": false }, { "type": "text", - "version": 698, - "versionNonce": 895319725, + "version": 699, + "versionNonce": 1028488810, "isDeleted": false, "id": "x4SHbu6J53EOkI86YBWpP", "fillStyle": "solid", @@ -920,7 +912,7 @@ "frameId": null, "roundness": null, "boundElements": [], - "updated": 1700758620397, + "updated": 1705337711919, "link": null, "locked": false, "fontSize": 16, @@ -934,45 +926,45 @@ "baseline": 15 }, { - "id": "T80XglCa2EMVp9kTzyUad", "type": "text", - "x": 176.8662109375, - "y": 592.29921875, - "width": 88.689453125, - "height": 32.199999999999996, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", + "version": 177, + "versionNonce": 656373046, + "isDeleted": false, + "id": "T80XglCa2EMVp9kTzyUad", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 0, "opacity": 100, + "angle": 0, + "x": 176.8662109375, + "y": 592.29921875, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "width": 88.689453125, + "height": 32.199999999999996, + "seed": 1326686243, "groupIds": [], "frameId": null, "roundness": null, - "seed": 1326686243, - "version": 176, - "versionNonce": 2017513123, - "isDeleted": false, - "boundElements": null, - "updated": 1700758620397, + "boundElements": [], + "updated": 1705337711919, "link": null, "locked": false, - "text": "Docker", "fontSize": 28, "fontFamily": 2, + "text": "Docker", "textAlign": "left", "verticalAlign": "top", - "baseline": 26, "containerId": null, "originalText": "Docker", - "lineHeight": 1.15 + "lineHeight": 1.15, + "baseline": 26 }, { "type": "text", - "version": 214, - "versionNonce": 1140007181, + "version": 215, + "versionNonce": 1957044522, "isDeleted": false, "id": "8U-iTgt9HlDYzlNCGtoI9", "fillStyle": "solid", @@ -992,7 +984,7 @@ "frameId": null, "roundness": null, "boundElements": [], - "updated": 1700758620397, + "updated": 1705337711919, "link": null, "locked": false, "fontSize": 28, @@ -1006,20 +998,24 @@ "baseline": 26 }, { - "id": "ZSPG8ACP4jq3ssZMYNzQW", "type": "rectangle", - "x": 313.4609375, - "y": 499.1015625, - "width": 187.53515625, - "height": 168.12499999999997, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 575, + "versionNonce": 906972693, + "isDeleted": false, + "id": "ZSPG8ACP4jq3ssZMYNzQW", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 312.4609375, + "y": 504.44337492618274, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 187.53515625, + "height": 168.12499999999997, + "seed": 2141807747, "groupIds": [ "VKry84j3vgFdUIVvIcZot" ], @@ -1027,10 +1023,6 @@ "roundness": { "type": 3 }, - "seed": 2141807747, - "version": 559, - "versionNonce": 1041120301, - "isDeleted": false, "boundElements": [ { "type": "text", @@ -1045,67 +1037,67 @@ "type": "arrow" } ], - "updated": 1700758679592, + "updated": 1709584334240, "link": null, "locked": false }, { - "id": "RSmIGjVVf1qi-P26cGPBy", "type": "text", - "x": 342.1845703125, - "y": 504.1015625, - "width": 130.087890625, - "height": 23, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", + "version": 639, + "versionNonce": 1735581941, + "isDeleted": false, + "id": "RSmIGjVVf1qi-P26cGPBy", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "angle": 0, + "x": 362.3125, + "y": 509.44337492618274, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 87.83203125, + "height": 46, + "seed": 1033868227, "groupIds": [ "VKry84j3vgFdUIVvIcZot" ], "frameId": null, "roundness": null, - "seed": 1033868227, - "version": 618, - "versionNonce": 505719075, - "isDeleted": false, - "boundElements": null, - "updated": 1700758679592, + "boundElements": [], + "updated": 1709584334242, "link": null, "locked": false, - "text": "build container", "fontSize": 20, "fontFamily": 2, + "text": "build-env\n container", "textAlign": "center", "verticalAlign": "top", - "baseline": 18, "containerId": "ZSPG8ACP4jq3ssZMYNzQW", - "originalText": "build container", - "lineHeight": 1.15 + "originalText": "build-env\n container", + "lineHeight": 1.15, + "baseline": 42 }, { "type": "rectangle", - "version": 772, - "versionNonce": 1118842509, + "version": 699, + "versionNonce": 118079509, "isDeleted": false, - "id": "COs0yi5IlmMD9jBPtDSYv", + "id": "wBcYIwBjFolSi4vZE0mDW", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 327.6875, - "y": 620.153125, + "x": 342.443359375, + "y": 573.2676711402182, "strokeColor": "#1e1e1e", "backgroundColor": "transparent", - "width": 159.08203125000003, + "width": 129.57031250000003, "height": 29.2, - "seed": 1481006691, + "seed": 741604525, "groupIds": [ "VKry84j3vgFdUIVvIcZot" ], @@ -1116,70 +1108,70 @@ "boundElements": [ { "type": "text", - "id": "9lNvtWk4-OHSmBA-xig0m" + "id": "Xiop5TihDc0Y2uoKalufe" } ], - "updated": 1700758679592, + "updated": 1709584327997, "link": null, "locked": false }, { "type": "text", - "version": 1064, - "versionNonce": 580488387, + "version": 784, + "versionNonce": 1684206965, "isDeleted": false, - "id": "9lNvtWk4-OHSmBA-xig0m", + "id": "Xiop5TihDc0Y2uoKalufe", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 341.603515625, - "y": 625.153125, + "x": 383.791015625, + "y": 578.2676711402182, "strokeColor": "#1e1e1e", "backgroundColor": "transparent", - "width": 131.25, + "width": 46.875, "height": 19.2, - "seed": 827496963, + "seed": 1464459021, "groupIds": [ "VKry84j3vgFdUIVvIcZot" ], "frameId": null, "roundness": null, "boundElements": [], - "updated": 1700758679592, + "updated": 1709584327997, "link": null, "locked": false, "fontSize": 16, "fontFamily": 3, - "text": "bioconda-utils", + "text": "conda", "textAlign": "center", "verticalAlign": "middle", - "containerId": "COs0yi5IlmMD9jBPtDSYv", - "originalText": "bioconda-utils", + "containerId": "wBcYIwBjFolSi4vZE0mDW", + "originalText": "conda", "lineHeight": 1.2, "baseline": 15 }, { "type": "rectangle", - "version": 644, - "versionNonce": 388289773, + "version": 714, + "versionNonce": 531529429, "isDeleted": false, - "id": "wBcYIwBjFolSi4vZE0mDW", + "id": "uL7UDVECJInJJUMUqODvN", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 342.443359375, - "y": 549.6968750000001, + "x": 342.7518848002268, + "y": 613.9595617836726, "strokeColor": "#1e1e1e", "backgroundColor": "transparent", "width": 129.57031250000003, "height": 29.2, - "seed": 741604525, + "seed": 686579213, "groupIds": [ "VKry84j3vgFdUIVvIcZot" ], @@ -1190,123 +1182,469 @@ "boundElements": [ { "type": "text", - "id": "Xiop5TihDc0Y2uoKalufe" + "id": "Q1r1idMiMOx9hFfsS5wvt" } ], - "updated": 1700758679592, + "updated": 1709584327997, "link": null, "locked": false }, { "type": "text", - "version": 729, - "versionNonce": 2045836387, + "version": 825, + "versionNonce": 1870781493, "isDeleted": false, - "id": "Xiop5TihDc0Y2uoKalufe", + "id": "Q1r1idMiMOx9hFfsS5wvt", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", "roughness": 1, "opacity": 100, "angle": 0, - "x": 383.791015625, - "y": 554.6968750000001, + "x": 355.9745410502268, + "y": 618.9595617836726, "strokeColor": "#1e1e1e", "backgroundColor": "transparent", - "width": 46.875, + "width": 103.125, "height": 19.2, - "seed": 1464459021, + "seed": 1897534787, "groupIds": [ "VKry84j3vgFdUIVvIcZot" ], "frameId": null, "roundness": null, "boundElements": [], - "updated": 1700758679592, + "updated": 1709584327997, "link": null, "locked": false, "fontSize": 16, "fontFamily": 3, - "text": "conda", + "text": "conda-build", "textAlign": "center", "verticalAlign": "middle", - "containerId": "wBcYIwBjFolSi4vZE0mDW", - "originalText": "conda", + "containerId": "uL7UDVECJInJJUMUqODvN", + "originalText": "conda-build", "lineHeight": 1.2, "baseline": 15 }, { - "type": "rectangle", - "version": 665, - "versionNonce": 385199949, + "type": "ellipse", + "version": 568, + "versionNonce": 1095690806, "isDeleted": false, - "id": "uL7UDVECJInJJUMUqODvN", + "id": "Y8CtHy2gv3zxdPojUf7L3", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 272.8351696995087, + "y": 694.64140625, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "width": 41, + "height": 41, + "seed": 2006391094, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "N6KMnt43uVIlLK3Z4KOso" + } + ], + "updated": 1705337790340, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 412, + "versionNonce": 396374902, + "isDeleted": false, + "id": "N6KMnt43uVIlLK3Z4KOso", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", - "roughness": 1, + "roughness": 0, "opacity": 100, "angle": 0, - "x": 342.443359375, - "y": 584.2242187500001, - "strokeColor": "#1e1e1e", + "x": 288.88948087591933, + "y": 705.9457172356758, + "strokeColor": "#1971c2", "backgroundColor": "transparent", - "width": 129.57031250000003, - "height": 29.2, - "seed": 686579213, - "groupIds": [ - "VKry84j3vgFdUIVvIcZot" + "width": 8.899999618530273, + "height": 18.4, + "seed": 1980335350, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1705337790340, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "1", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Y8CtHy2gv3zxdPojUf7L3", + "originalText": "1", + "lineHeight": 1.15, + "baseline": 15 + }, + { + "type": "ellipse", + "version": 610, + "versionNonce": 1803370154, + "isDeleted": false, + "id": "IJM7hd-nLRds4mMsxy8C6", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 288.8351696995087, + "y": 490.64140625000005, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "width": 41, + "height": 41, + "seed": 994929398, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "ZkNf9fJytMEUCiohoP48a" + } ], + "updated": 1705337781507, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 454, + "versionNonce": 1008356330, + "isDeleted": false, + "id": "ZkNf9fJytMEUCiohoP48a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 304.88948087591933, + "y": 501.94571723567583, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "width": 8.899999618530273, + "height": 18.4, + "seed": 2060150634, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1705337776025, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "2", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "IJM7hd-nLRds4mMsxy8C6", + "originalText": "2", + "lineHeight": 1.15, + "baseline": 15 + }, + { + "type": "ellipse", + "version": 679, + "versionNonce": 200183722, + "isDeleted": false, + "id": "clU19FQCAD7zyXa4A3uEp", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 465.8351696995087, + "y": 694.64140625, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "width": 41, + "height": 41, + "seed": 1651920374, + "groupIds": [], "frameId": null, "roundness": { - "type": 3 + "type": 2 }, "boundElements": [ { "type": "text", - "id": "Q1r1idMiMOx9hFfsS5wvt" + "id": "8LnDOKQq4T22dg3EYMuaq" } ], - "updated": 1700758679592, + "updated": 1705337795712, "link": null, "locked": false }, { "type": "text", - "version": 776, - "versionNonce": 1073313795, + "version": 523, + "versionNonce": 496790186, "isDeleted": false, - "id": "Q1r1idMiMOx9hFfsS5wvt", + "id": "8LnDOKQq4T22dg3EYMuaq", "fillStyle": "solid", "strokeWidth": 2, "strokeStyle": "solid", - "roughness": 1, + "roughness": 0, "opacity": 100, "angle": 0, - "x": 355.666015625, - "y": 589.2242187500001, - "strokeColor": "#1e1e1e", + "x": 481.88948087591933, + "y": 705.9457172356758, + "strokeColor": "#1971c2", "backgroundColor": "transparent", - "width": 103.125, - "height": 19.2, - "seed": 1897534787, - "groupIds": [ - "VKry84j3vgFdUIVvIcZot" + "width": 8.899999618530273, + "height": 18.4, + "seed": 1633039466, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1705337797947, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "3", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "clU19FQCAD7zyXa4A3uEp", + "originalText": "3", + "lineHeight": 1.15, + "baseline": 15 + }, + { + "type": "ellipse", + "version": 1001, + "versionNonce": 1660453034, + "isDeleted": false, + "id": "kPtMFuoLB5CW-Vw395RG3", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 600.8351696995087, + "y": 697.64140625, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "width": 41, + "height": 41, + "seed": 1955416106, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "CDjph4pnXE_2D7g2BCAUY" + } ], + "updated": 1705337819537, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 845, + "versionNonce": 708238186, + "isDeleted": false, + "id": "CDjph4pnXE_2D7g2BCAUY", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 616.8894808759194, + "y": 708.9457172356758, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "width": 8.899999618530273, + "height": 18.4, + "seed": 1542072182, + "groupIds": [], "frameId": null, "roundness": null, - "boundElements": null, - "updated": 1700758679592, + "boundElements": [], + "updated": 1705337819537, "link": null, "locked": false, "fontSize": 16, - "fontFamily": 3, - "text": "conda-build", + "fontFamily": 2, + "text": "4", "textAlign": "center", "verticalAlign": "middle", - "containerId": "uL7UDVECJInJJUMUqODvN", - "originalText": "conda-build", - "lineHeight": 1.2, + "containerId": "kPtMFuoLB5CW-Vw395RG3", + "originalText": "4", + "lineHeight": 1.15, + "baseline": 15 + }, + { + "type": "ellipse", + "version": 1063, + "versionNonce": 1345914282, + "isDeleted": false, + "id": "r4dTiBdf_M1Zge8gYzVTq", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 560.8351696995087, + "y": 516.64140625, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "width": 41, + "height": 41, + "seed": 1954017654, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "6GqtRDsMkX9IH1jFZ9eQ4" + } + ], + "updated": 1705337822598, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 907, + "versionNonce": 1711005866, + "isDeleted": false, + "id": "6GqtRDsMkX9IH1jFZ9eQ4", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 576.8894808759194, + "y": 527.9457172356758, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "width": 8.899999618530273, + "height": 18.4, + "seed": 609388778, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1705337825109, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "5", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "r4dTiBdf_M1Zge8gYzVTq", + "originalText": "5", + "lineHeight": 1.15, + "baseline": 15 + }, + { + "type": "ellipse", + "version": 1133, + "versionNonce": 1452724650, + "isDeleted": false, + "id": "tj4xtVc1Oj1bcmtp_1RGq", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 792.8351696995087, + "y": 559.64140625, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "width": 41, + "height": 41, + "seed": 1571983734, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "YOochIApNbIqGsJ-8vmWA" + } + ], + "updated": 1705337831322, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 977, + "versionNonce": 1494461610, + "isDeleted": false, + "id": "YOochIApNbIqGsJ-8vmWA", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 808.8894808759194, + "y": 570.9457172356758, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "width": 8.899999618530273, + "height": 18.4, + "seed": 2039605482, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1705337833141, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "6", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "tj4xtVc1Oj1bcmtp_1RGq", + "originalText": "6", + "lineHeight": 1.15, "baseline": 15 } ], diff --git a/source/images/bioconda-containers.png b/source/images/bioconda-containers.png index ff3e569ae179d2e303ebb527e555ee9a8d36b2a1..42e56e537277435352b7d107b498b69f6f56435e 100644 GIT binary patch literal 50474 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%0DjP-&ymr;}X}A)NPNST6G*- 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 C+eT>s diff --git a/source/images/bioconda-containers.svg b/source/images/bioconda-containers.svg index 66108b6..1e74110 100644 --- a/source/images/bioconda-containers.svg +++ b/source/images/bioconda-containers.svg @@ -18,4 +18,4 @@ - bioconda-utilsmulled-buildinvolucrorecipes/pkgname/conda-bld/pkgname.tar.bz2base container/usr/localconda containerenv/condaDockerHostbuild containerbioconda-utilscondaconda-build \ No newline at end of file + bioconda-utilsmulled-buildinvolucrorecipes/pkgname/conda-bld/pkgname.tar.bz2base container/usr/localcreate-env containerenv/condaDockerHostbuild-env containercondaconda-build123456 \ No newline at end of file From 9c795b943399643783053c86ebccce6b2f732984 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 4 Mar 2024 16:45:25 -0500 Subject: [PATCH 39/41] Update source/contributor/build-system.rst Co-authored-by: Martin Grigorov --- source/contributor/build-system.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/contributor/build-system.rst b/source/contributor/build-system.rst index b71f283..7ece08f 100644 --- a/source/contributor/build-system.rst +++ b/source/contributor/build-system.rst @@ -58,7 +58,7 @@ orchestrated by bioconda-utils. - **Lint.** This step checks for common errors, formatting, and consistency. -- **Build recipes.** Recipes to be built sastify the following criteria: +- **Build recipes.** Recipes to be built satisfy the following criteria: - changed in this pull request - not on the `build-fail-blacklist` - does not have a build-failure yaml file in the recipe with a hash From 6846aa8a955d4e5f5cdaf93891813e9825a6b4c2 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 4 Mar 2024 16:48:07 -0500 Subject: [PATCH 40/41] update datechanged --- source/contributor/build-system.rst | 2 +- source/developer/aarch64.rst | 2 +- source/developer/ci-inventory.rst | 2 +- source/developer/dockerfile-inventory.rst | 2 +- source/faqs.rst | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/contributor/build-system.rst b/source/contributor/build-system.rst index 7ece08f..914084c 100644 --- a/source/contributor/build-system.rst +++ b/source/contributor/build-system.rst @@ -1,7 +1,7 @@ Build system ============ -.. datechanged:: 2024-03-02 +.. datechanged:: 2024-03-04 Generalized descriptions to reflect multiple CI systems in use The build system for Bioconda takes recipes and converts them into conda diff --git a/source/developer/aarch64.rst b/source/developer/aarch64.rst index 499c802..73ca2bb 100644 --- a/source/developer/aarch64.rst +++ b/source/developer/aarch64.rst @@ -1,7 +1,7 @@ ``aarch64`` builds ================== -.. datechanged:: 2024-03-02 +.. datechanged:: 2024-03-04 Added this section as initial linux-aarch64 builds are starting While we do not yet have builds for ``osx-arm64`` (see diff --git a/source/developer/ci-inventory.rst b/source/developer/ci-inventory.rst index 72b82a4..75ddc29 100644 --- a/source/developer/ci-inventory.rst +++ b/source/developer/ci-inventory.rst @@ -9,7 +9,7 @@ CI Inventory .. datechanged:: 2023-06-06 Start using build-failures workflow -.. datechanged:: 2024-03-02 +.. datechanged:: 2024-03-04 Start using ``linux-aarch64`` in bulk and recipe tests This page documents the various moving parts that, together, make Bioconda diff --git a/source/developer/dockerfile-inventory.rst b/source/developer/dockerfile-inventory.rst index e9a8537..b7278ae 100644 --- a/source/developer/dockerfile-inventory.rst +++ b/source/developer/dockerfile-inventory.rst @@ -3,7 +3,7 @@ Dockerfile inventory ==================== -.. datechanged:: 2024-03-02 +.. datechanged:: 2024-03-04 Added section Containers are used in multiple ways by bioconda-utils. Broadly, we can diff --git a/source/faqs.rst b/source/faqs.rst index 7c46cd8..5edf411 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -530,7 +530,7 @@ build. Understanding platform nomenclature ----------------------------------- -.. datechanged:: 2024-03-02 +.. datechanged:: 2024-03-04 Added section Different CPU chips use different architecture, so programs are written From 26f99c57b6ea98dae0df1ed59e2fee0c61f5a02e Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 4 Mar 2024 16:55:17 -0500 Subject: [PATCH 41/41] address various review comments --- source/developer/ci-inventory.rst | 4 ++-- source/developer/dockerfile-inventory.rst | 8 ++++---- source/developer/repo-inventory.rst | 2 +- source/faqs.rst | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/developer/ci-inventory.rst b/source/developer/ci-inventory.rst index 75ddc29..e0b883e 100644 --- a/source/developer/ci-inventory.rst +++ b/source/developer/ci-inventory.rst @@ -71,7 +71,7 @@ maintain flexibility over the long term in case a service becomes unusable. - on push - `azure-pipeline.yml `_ (``linux-64``, ``osx-64``); `config.yml `_ (``linux-aarch64``) - - ``linux-64``, ``osx-64`` + - ``linux-64``, ``osx-64``, ``linux-aarch`` - These are the most-run tests: these are what run on every change on pull requests to bioconda-recipes, and they must pass before the recipe is merged into the master branch. @@ -114,7 +114,7 @@ maintain flexibility over the long term in case a service becomes unusable. - CircleCI - ``bioconda-utils`` - hourly - - `config.yml `_ + - `config.yml `_ - Linux - Checks upstream repository for version updates, if so, creates a new bioconda-recipes recipe with the updated version and an updated hash, diff --git a/source/developer/dockerfile-inventory.rst b/source/developer/dockerfile-inventory.rst index b7278ae..2a31a8c 100644 --- a/source/developer/dockerfile-inventory.rst +++ b/source/developer/dockerfile-inventory.rst @@ -93,10 +93,10 @@ It uses `involucro `_ to make a final, minimal image with a dramatically reduced file size. This is illustrated in steps 4-6 above. -The base image has very little else, not even conda. So the end result is -a fully-isolated, minimal Docker image with nothing but the installed package -and its dependencies (and therefore a small size), ready to be uploaded to -a repository. +The base image has very few packages or libraries installed -- not even conda. +So the end result is a fully-isolated, minimal Docker image with nothing but +the installed package and its dependencies (and therefore a small size), ready +to be uploaded to a repository. Note that :command:`--mulled-test` runs the tests extracted from the recipe in the minimal container. Since the container only contains the package and its diff --git a/source/developer/repo-inventory.rst b/source/developer/repo-inventory.rst index 1d9cf34..8976444 100644 --- a/source/developer/repo-inventory.rst +++ b/source/developer/repo-inventory.rst @@ -27,7 +27,7 @@ Repository inventory - Docs built by bioconda-docs are pushed here for hosting by GitHub * - `bioconda-stats `_ - - Gathers and stores statistics from the conda channel + - Gathers and stores statistics from the bioconda channel * - `bioconda-plots `_ - Converts data from bioconda-stats into plots used by the docs diff --git a/source/faqs.rst b/source/faqs.rst index 5edf411..e0f3d31 100644 --- a/source/faqs.rst +++ b/source/faqs.rst @@ -386,11 +386,11 @@ What's the lifecycle of a bioconda package? ------------------------------------------- - Submit a pull request with a new recipe or an updated recipe -- Circle CI automatically builds and tests the changed recipe[s] using - conda-build. Test results are shown on the PR. +- CI (see :ref:`ci-inventory`) automatically builds and tests the changed + recipe[s] using conda-build. Test results are shown on the PR. - If tests fail, push changes to PR until they pass. - Once tests pass, merge into master branch -- Circle CI tests again, but this time after testing the built packages are +- CI tests again, but this time after testing the built packages are uploaded to the bioconda channel on anaconda.org. - Users can now install the package just like any other conda package with ``conda install``. @@ -541,7 +541,7 @@ There is a lot of confusing nomenclature surrounding them. Here is an attempt at clearing them up, or at least providing enough context that you can look up more details on your own: -**instruction set, CISC, RISC, RISC-V**: The *instruction set* is the assembly +**ISA, instruction set, CISC, RISC, RISC-V**: The *instruction set* is the assembly code commands that are possible for the chip. *CISC* is "complex instruction set computer" which prioritizes flexibility. *RISC* is "reduced instruction set computer" which prioritizing power consumption (this is an oversimplification,