diff --git a/.gitignore b/.gitignore index 0117b7c35d7db5aa24e245317a384e465d8f26ec..ac2f3277d9129aa2caf76606814f1457007f8c9f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ *.swp _ci/ src/ -dist/ -build-prefix/ +miniconda.sh +miniconda/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ccd8867baf5c3f89d87df6f38c466f76d943280e..c0ffa4c3b4b18e537214253480d45c814e2e4811 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,24 +1,57 @@ -stages: - - core - - extra - variables: + CONDA_ROOT: "${CI_PROJECT_DIR}/miniconda" + BOB_PACKAGE_VERSION: "unknown" PYTHONUNBUFFERED: 1 -core_build: - stage: core +stages: + - build + +.build_template: &build_job + stage: build + before_script: + - mkdir _ci + - curl --silent "https://gitlab.idiap.ch/bob/bob.admin/raw/master/gitlab/install.sh" > _ci/install.sh + - chmod 755 _ci/install.sh + - ./_ci/install.sh _ci master #installs ci support scripts + - ./_ci/before_build.sh script: - - pip install --upgrade python-gitlab - - python build.py core.txt 1 - image: python + - ./scripts/build.sh + after_script: + - ./_ci/after_build.sh + cache: &build_caches + key: "$CI_BUILD_NAME" + paths: + - miniconda.sh + - ${CONDA_ROOT}/pkgs/*.tar.bz2 + - ${CONDA_ROOT}/pkgs/urls.txt + - ${CONDA_ROOT}/conda-bld/src_cache + +linux_27: + <<: *build_job + variables: + PYTHON_VERSION: "2.7" tags: - docker + image: continuumio/conda-concourse-ci -extra_build: - stage: extra - script: - - pip install --upgrade python-gitlab - - python build.py extra.txt 0 - image: python +linux_36: + <<: *build_job + variables: + PYTHON_VERSION: "3.6" tags: - docker + image: continuumio/conda-concourse-ci + +macosx_27: + <<: *build_job + variables: + PYTHON_VERSION: "2.7" + tags: + - macosx + +macosx_36: + <<: *build_job + variables: + PYTHON_VERSION: "3.6" + tags: + - macosx diff --git a/README.rst b/README.rst index 5bd03847af4563683299ff4db52b2743e10d1a3c..75e0679f1189711b4712174abade0b690a12d3d4 100644 --- a/README.rst +++ b/README.rst @@ -1,6 +1,6 @@ .. vim: set fileencoding=utf-8 : .. Andre Anjos <andre.anjos@idiap.ch> -.. Thu 22 Dec 2016 08:47:14 CET +.. Sat Feb 17 14:26:47 2018 CET .. image:: https://gitlab.idiap.ch/bob/bob.nightlies/badges/master/build.svg :target: https://gitlab.idiap.ch/bob/bob.nightlies/commits/master @@ -18,20 +18,14 @@ latest environment and tested together under that light. Installation ------------ -This package can be built starting from a base development environment, as -provided by our `from-scratch.sh`_ script. First run it to create a conda-based -environment for development. Once the environment is ready, follow the -instructions on the ``.gitlab-ci.yml`` file to complete the development cycle. +This package can be built completely from scratch by following the instructions +on the ``.gitlab-ci.yml`` file. The script ``build.sh`` will try to execute the steps from the CI in the right order and can be used to locally test your modifications **before** pushing a branch into the nightlies, which will trigger a complete set of builds in multiple platforms. -The script ``build.sh`` takes several parameters (run it for a help print out):: - - $ ./build.sh - Updating a Package ------------------ @@ -40,7 +34,7 @@ Updating a Package Before adding a package to this prototype, please ensure that the package contains all standard components of a Bob_ package (README, unit tests, CI - integration and documentation among others). + integration, documentation and conda build recipe among others). If you don't know how to do this, ask for information on our `mailing list`_. @@ -55,8 +49,8 @@ The new package sits in one of two categories: to the order in which packages should be compiled. Once the file is modified, commit the changes to a **new branch**, with a -suggestive name. Push the branch and, once it is green, you may merge it to the -master (or ask it to be merged), via a standard merge request. +suggestive name. Push the branch and merge it to the master (or ask it to be +merged), via a standard merge request. Contact diff --git a/build.py b/build.py deleted file mode 100644 index 7791109d781bc870c0172ef7457c2fe335632632..0000000000000000000000000000000000000000 --- a/build.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -import os -import gitlab -import time -from datetime import datetime - - -def wait_for_pipeline(project, pipeline): - time.sleep(15) - pipeline = project.pipelines.get(pipeline.id) - while pipeline.status in ('pending', 'running'): - time.sleep(15) - pipeline = project.pipelines.get(pipeline.id) - return pipeline - - -def main(pkg_list_file, fail=True): - - private_token = os.environ['GITLAB_API_TOKEN'] - gl = gitlab.Gitlab('https://gitlab.idiap.ch', - private_token=private_token, api_version=4) - any_failed = False - with open(pkg_list_file) as f: - for line in f: - line = line.strip() - if not line or line.startswith('#'): - continue - pkg = line.split('#')[0] - project = gl.projects.get('bob/{}'.format(pkg)) - pipeline = project.pipelines.create({'ref': 'master'}) - message = ("{date} Triggered pipeline: " + - "https://gitlab.idiap.ch/bob/{pkg}/pipelines/{id}") - print(message.format(date=datetime.now(), pkg=pkg, id=pipeline.id)) - - pipeline = wait_for_pipeline(project, pipeline) - - # re-try once if the pipeline fails - if pipeline.status != 'success': - print("Retrying the pipeline.") - pipeline.retry() - pipeline = wait_for_pipeline(project, pipeline) - - if pipeline.status != 'success': - any_failed = True - message = ("Pipeline: https://gitlab.idiap.ch/bob/{pkg}/" + - "pipelines/{id} failed with status {status}") - message = message.format( - id=pipeline.id, pkg=pkg, status=pipeline.status) - if fail: - raise RuntimeError(message) - else: - print(message) - if any_failed: - raise RuntimeError("Failed to build some of the packages.") - - -if __name__ == '__main__': - import sys - pkg_list_file = sys.argv[1] - fail = bool(int(sys.argv[2])) - main(pkg_list_file, fail) diff --git a/buildout.cfg.template b/buildout.cfg.template deleted file mode 100644 index 5925fda712bd453b15d87d56998b4e1b30a2bf1d..0000000000000000000000000000000000000000 --- a/buildout.cfg.template +++ /dev/null @@ -1,18 +0,0 @@ -[buildout] -parts = scripts -extensions = bob.buildout - mr.developer -auto-checkout = * -debug = true -newest = false -verbose = true -eggs = {eggs} - -develop = {develop} - -[scripts] -recipe = bob.buildout:scripts -dependent-scripts = true - -[sources] -{sources} diff --git a/core.txt b/core.txt deleted file mode 100644 index 1f64da0418a07a2af9302edf877c40c14343c5c5..0000000000000000000000000000000000000000 --- a/core.txt +++ /dev/null @@ -1,33 +0,0 @@ -bob.buildout -bob.extension -bob.blitz -bob.core -bob.io.base -bob.math -bob.measure -bob.io.image -bob.db.base -bob.io.video -bob.io.matlab -bob.io.audio -bob.sp -bob.ap -bob.ip.base -bob.ip.color -bob.ip.draw -bob.ip.gabor -bob.learn.activation -bob.learn.libsvm -bob.learn.linear -bob.learn.mlp -bob.learn.boosting -bob.db.iris -bob.learn.em -bob.db.wine -bob.db.mnist -bob.db.atnt -bob.ip.facedetect -bob.ip.optflow.hornschunck -bob.ip.optflow.liu -bob.ip.flandmark -bob diff --git a/generate_buildout_config b/generate_buildout_config deleted file mode 100755 index 3a836703f36ce6b5e97f14a289a579d59cec2a9c..0000000000000000000000000000000000000000 --- a/generate_buildout_config +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -"""Generates a buildout configuration file based on the list of the packages - -Usage: - %(prog)s <package_list>... - %(prog)s --help - -Arguments: - <package_list> The files containing the package list. Each line should - contain only the name of one package. Empty lines and - comments starting with # are allowed. - -Options: - -h --help Show this help message and exit -""" - - -def format_list(package_list, prepend, left_fill): - text = prepend + package_list[0] + '\n' - package_list = package_list[1:] - for pkg in package_list: - text += ' ' * left_fill + prepend + pkg + '\n' - return text - - -def main(argv=None): - from docopt import docopt - import sys - import os - docs = __doc__ % {'prog': os.path.basename(sys.argv[0])} - args = docopt(docs, argv=argv) - package_list_files = args['<package_list>'] - package_list = [] - for path in package_list_files: - for line in open(path): - line = line.partition('#')[0].strip() - if not line: - continue - package_list.append(line) - print(package_list) - # read the buildout config template - with open("buildout.cfg.template") as f: - template = f.read() - # eggs - eggs = format_list(package_list, '', 7) - develop = format_list(package_list, 'src/', 10) - source_list = ['{0} = git git@gitlab.idiap.ch:bob/{0}'.format(p) - for p in package_list] - sources = format_list(source_list, '', 0) - with open('buildout.cfg', 'wt') as f: - f.write(template.format(eggs=eggs, develop=develop, sources=sources)) - - -if __name__ == '__main__': - main() diff --git a/extra.txt b/order.txt similarity index 69% rename from extra.txt rename to order.txt index b586a988e7e9e0eb28e4445a0d06393c83fd2473..c90c37360a721a9a47cb41f704ecedd2d670d82d 100644 --- a/extra.txt +++ b/order.txt @@ -1,3 +1,36 @@ +bob.buildout +bob.extension +bob.blitz +bob.core +bob.io.base +bob.math +bob.measure +bob.io.image +bob.db.base +bob.io.video +bob.io.matlab +bob.io.audio +bob.sp +bob.ap +bob.ip.base +bob.ip.color +bob.ip.draw +bob.ip.gabor +bob.learn.activation +bob.learn.libsvm +bob.learn.linear +bob.learn.mlp +bob.learn.boosting +bob.db.iris +bob.learn.em +bob.db.wine +bob.db.mnist +bob.db.atnt +bob.ip.facedetect +bob.ip.optflow.hornschunck +bob.ip.optflow.liu +bob.ip.flandmark +bob gridtk bob.ip.qualitymeasure bob.ip.skincolorfilter diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..f75fc1a6bd459febbba5a931734dce2b08976dcc --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# Thu 15 Feb 15:36:30 2018 CET + +export PYTHON_VERSION="${PYTHON_VERSION:-${1}}" +if [ -z "${PYTHON_VERSION}" ]; then + echo "usage: $0 <python-version>" + exit 1 +fi + +scriptdir="$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)" +basedir=`pwd` + +# These should be set by the CI - resetting in case of running from cmdline +export CONDA_ROOT="${CONDA_ROOT:-${basedir}/miniconda}" +export BOB_PACKAGE_VERSION="${BOB_PACKAGE_VERSION:-unknown}" +export PYTHONUNBUFFERED="${PYTHONUNBUFFERED:-1}" +export CI_PROJECT_URL="${CI_PROJECT_URL:-https://gitlab.idiap.ch/bob/bob.nightlies}" + +# This should be installed by CI, but installing it here in case running from +# cmdline +if [ ! -d "_ci" ]; then + mkdir _ci + curl --silent "https://gitlab.idiap.ch/bob/bob.admin/raw/master/gitlab/install.sh" > _ci/install.sh + chmod 755 _ci/install.sh + ./_ci/install.sh _ci master #installs ci support scripts +fi + +# If not running on the CI, set docserver +if [ -z "${DOCPASS}" ]; then + export DOCSERVER=https://www.idiap.ch + export CONDA_CHANNEL=https://www.idiap.ch/software/bob/conda/label/main + export CONDA_BETA_CHANNEL=http://beatubulatest.lab.idiap.ch/private/conda +fi + +if [ ! -d "${CONDA_ROOT}" ]; then + ./_ci/before_build.sh +fi + +source ${basedir}/_ci/functions.sh + +PACKAGES=($(sed -e "/^\s*#.*/d;/^\s*$/d" ${basedir}/order.txt)) + +current=0 + +for f in "${PACKAGES[@]}"; do + + ((current++)) + + echo ""; + log_debug " =========================================================="; + log_debug " Checking ${f} (${current}/${#PACKAGES[@]})..."; + log_debug " =========================================================="; + echo ""; + + # First checks if all package tests pass + export BOB_TEST_ONLY="true" + ${scriptdir}/rebuild.sh ${CONDA_ROOT} ${PYTHON_VERSION} ${f} + unset BOB_TEST_ONLY + + if [ $? -ne 0 ]; then + log_warn "Package ${f} check FAILED - rebuilding it..." + echo ""; + log_info " =========================================================="; + log_info " Building ${f} (${current}/${#PACKAGES[@]})..."; + log_info " =========================================================="; + echo ""; + ${scriptdir}/rebuild.sh ${CONDA_ROOT} ${PYTHON_VERSION} ${f} + else + log_info "Package ${f} check SUCCESS - skipping rebuild" + fi + +done diff --git a/scripts/rebuild.sh b/scripts/rebuild.sh new file mode 100755 index 0000000000000000000000000000000000000000..a5ff6e4c47231b425726236dd16d0b67f011693a --- /dev/null +++ b/scripts/rebuild.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env bash +# Mon 19 Feb 10:42:26 2018 CET + +if [ $# -ne 3 ]; then + echo "Completely rebuilds the given package" + echo "usage: $0 <conda> <python-version> <package-name>" + echo "example: $0 \$\{CONDA_ROOT\} 2.7 bob.blitz" + exit 1 +fi + +CONDA_ROOT=${1} +PYTHON_VERSION=${2} +CI_PROJECT_NAME=${3} + +# Defines some required defaults, if they are not set by the CI (these allow +# local builds) +basedir=`pwd` +CI_PROJECT_NAMESPACE="${CI_PROJECT_NAMESPACE:-bob}" +CI_PROJECT_PATH=${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME} +CI_PROJECT_DIR=${basedir}/src/${CI_PROJECT_NAME} +CI_PROJECT_URL="https://gitlab.idiap.ch/${CI_PROJECT_PATH}" +CI_COMMIT_REF="${CI_COMMIT_REF:-12345678}" +CI_COMMIT_REF_NAME="${CI_COMMIT_REF_NAME:-@local}" + +# The way to clone the repositories for this build +GITLAB_CHECKOUT_STRATEGY="git@gitlab.idiap.ch:" + +# Overrides some stuff +if [ "${CI_COMMIT_REF_NAME}" == "@local" ]; then + BOB_PACKAGE_VERSION="unknown" + PYTHONUNBUFFERED=1 +fi + +source ${basedir}/_ci/functions.sh +unset BOB_PACKAGE_VERSION + +# Setup project variables +export_env CI_PROJECT_DIR +export_env CI_PROJECT_NAME +export_env CI_PROJECT_NAMESPACE +export_env CI_PROJECT_PATH +export_env CI_COMMIT_REF +export_env CI_COMMIT_REF_NAME +export_env CI_PROJECT_URL +export_env CONDA_ROOT +export_env PYTHONUNBUFFERED +export_env PYTHON_VERSION + +export_env CI_PROJECT_DIR +export_env CI_PROJECT_PATH +export_env CI_PROJECT_NAME + +if [ -d "${CI_PROJECT_DIR}" ]; then + run_cmd git -C ${CI_PROJECT_DIR} pull #updates + run_cmd git -C ${CI_PROJECT_DIR} clean -ffdx #rebuilds +else + if [ ! -d ${basedir}/src ]; then + run_cmd mkdir -p ${basedir}/src + fi + run_cmd git clone --depth 1 ${GITLAB_CHECKOUT_STRATEGY}${CI_PROJECT_PATH} ${CI_PROJECT_DIR} +fi + +# Gets the latest stable version of a given package or returns the empty string +# $1: work directory for the package checkout +latest_stable () { + git -C $1 fetch --tags + echo `git -C $1 tag --sort='v:refname' | grep -e 'v[0-9]*\.[0-9]*\.[0-9]*$' | tail -n 1` +} + +if [ -n "${STABLE}" ]; then + CI_COMMIT_TAG=`latest_stable ${CI_PROJECT_DIR}` + if [ -z "${CI_COMMIT_TAG}" ]; then + echo ""; + log_debug " =========================================================="; + log_debug " Skipping $f (${current}/${total}). No stable release"; + log_debug " =========================================================="; + echo ""; + continue; + fi + export_env CI_COMMIT_TAG + run_cmd git -C ${CI_PROJECT_DIR} checkout ${CI_COMMIT_TAG} +fi + +run_cmd cd ${CI_PROJECT_DIR} +run_cmd ln -s ${basedir}/_ci . + +# Calculates package version +if [ ! -r "version.txt" ]; then + log_error "./version.txt does not exist - cannot figure out version number" + exit 1 +fi +BOB_PACKAGE_VERSION=`cat version.txt | tr -d '\n'`; +export_env BOB_PACKAGE_VERSION + +# Calculates the current build-number available if in test-only mode +if [ -n "${BOB_TEST_ONLY}" ]; then + run_cmd mkdir -p ./_ci/${OS_SLUG}/${PYTHON_VERSION} + if [ -z "${CI_COMMIT_TAG}" ]; then + run_cmd ${CONDA_ROOT}/bin/python _ci/channel_support.py ${CONDA_BETA_CHANNEL} ${CI_PROJECT_NAME} ${BOB_PACKAGE_VERSION} ${PYTHON_VERSION} -u --log ./_ci/${OS_SLUG}/${PYTHON_VERSION}/build_number.txt + else + run_cmd ${CONDA_ROOT}/bin/python _ci/channel_support.py ${CONDA_CHANNEL} ${CI_PROJECT_NAME} ${BOB_PACKAGE_VERSION} ${PYTHON_VERSION} -u --log ./_ci/${OS_SLUG}/${PYTHON_VERSION}/build_number.txt + fi + + BOB_BUILD_NUMBER=`head -n 1 ./_ci/${OS_SLUG}/${PYTHON_VERSION}/build_number.txt | tr -d '\n'` + ((BOB_BUILD_NUMBER--)) #uses the latest available + export_env BOB_BUILD_NUMBER +fi + +run_cmd ./_ci/build.sh + +if [ -n "${BOB_TEST_ONLY}" ]; then + # we don't keep stuff while testing only + run_cmd ${CONDA_ROOT}/bin/conda build purge +else + # consider uploading... + if [[ "${IS_MASTER}" == "true" ]]; then + # Uploads all the built packages + for os in "osx-64" "noarch" "linux-64"; do + for f in ${CONDA_ROOT}/conda-bld/${os}/*.tar.bz2; do + if [[ -f $f ]]; then + dav_check_upload "${f}" "public-upload/conda/label/main/${os}/" + fi + done + done + else + log_info 'Skipping package upload (not on master branch)' + fi +fi