create.py 6.38 KB
Newer Older
André Anjos's avatar
André Anjos committed
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import logging
logger = logging.getLogger(__name__)

import pkg_resources
import click
11
import yaml
André Anjos's avatar
André Anjos committed
12
13
14

from . import bdt
from ..log import verbosity_option
15
16
17
18
from ..build import parse_dependencies, conda_create, make_conda_config
from ..constants import BASE_CONDARC, CONDA_BUILD_CONFIG, \
    CONDA_RECIPE_APPEND, SERVER
from ..bootstrap import set_environment, get_channels
André Anjos's avatar
André Anjos committed
19
20
21
22
23
24
25
26
27


@click.command(epilog='''
Examples:

  1. Creates an environment called `myenv' for developing the currently checked-out package (N.B.: first activate the base environment):

\b
     $ cd bob.package.foo
André Anjos's avatar
DRY    
André Anjos committed
28
     $ bdt create -vv myenv
André Anjos's avatar
André Anjos committed
29
30
31
32
33
34
35
36

     The above command assumes the directory `conda' exists on the current directory and that it contains a file called `meta.yaml' containing the recipe for the package you want to create a development environment for.

     If you get things right by default, the above form is the typical usage scenario of this app. Read-on to tweak special flags and settings.


  2. By default, we use the native python version of your conda installation as the default python version to use for the newly created environment. You may select a different one with `--python=X.Y':

André Anjos's avatar
DRY    
André Anjos committed
37
     $ bdt create -vv --python=3.6 myenv
André Anjos's avatar
André Anjos committed
38
39
40
41


  3. By default, we use our own condarc and `conda_build_config.yaml` files that are used in creating packages for our CI/CD system. If you wish to use your own, specify them on the command line:

André Anjos's avatar
DRY    
André Anjos committed
42
     $ bdt create -vv --python=3.6 --config=config.yaml --condarc=~/.condarc myenv
André Anjos's avatar
André Anjos committed
43
44
45
46
47
48
49
50
51
52

     Notice the condarc file **must** end in `condarc', or conda will complain.


  4. You can use the option `--dry-run' to simulate what would be installed
  instead of actually creating a new environment.  Combine with `-vvv` to
  enable debug printing.  Equivalent conda commands you can execute on the
  shell will be printed:


André Anjos's avatar
DRY    
André Anjos committed
53
     $ bdt create -vvv --dry-run myenv
André Anjos's avatar
André Anjos committed
54
55
56
57
58
59
60
61
62
63
64
''')
@click.argument('name')
@click.argument('recipe-dir', required=False, type=click.Path(file_okay=False,
  dir_okay=True, exists=True))
@click.option('-p', '--python', default=('%d.%d' % sys.version_info[:2]),
    show_default=True, help='Version of python to build the ' \
        'environment for [default: %(default)s]')
@click.option('-o', '--overwrite/--no-overwrite', default=False,
      help='If set and an environment with the same name exists, ' \
          'deletes it first before creating the new environment',
          show_default=True)
65
66
67
68
@click.option('-r', '--condarc',
    help='Use custom conda configuration file instead of our own',)
@click.option('-l', '--use-local', default=False,
    help='Allow the use of local channels for package retrieval')
André Anjos's avatar
André Anjos committed
69
@click.option('-m', '--config', '--variant-config-files', show_default=True,
70
      default=CONDA_BUILD_CONFIG, help='overwrites the path leading to ' \
André Anjos's avatar
André Anjos committed
71
          'variant configuration file to use')
72
@click.option('-a', '--append-file', show_default=True,
73
      default=CONDA_RECIPE_APPEND, help='overwrites the path leading to ' \
74
          'appended configuration file to use')
75
76
77
78
79
80
81
82
83
84
85
@click.option('-S', '--server', show_default=True,
    default='https://www.idiap.ch/software/bob', help='Server used for ' \
    'downloading conda packages and documentation indexes of required packages')
@click.option('-P', '--private/--no-private', default=False,
    help='Set this to **include** private channels on your build - ' \
        'you **must** be at Idiap to execute this build in this case - ' \
        'you **must** also use the correct server name through --server - ' \
        'notice this option has no effect if you also pass --condarc')
@click.option('-X', '--stable/--no-stable', default=False,
    help='Set this to **exclude** beta channels from your build - ' \
        'notice this option has no effect if you also pass --condarc')
André Anjos's avatar
André Anjos committed
86
87
88
89
90
91
@click.option('-d', '--dry-run/--no-dry-run', default=False,
    help='Only goes through the actions, but does not execute them ' \
        '(combine with the verbosity flags - e.g. ``-vvv``) to enable ' \
        'printing to help you understand what will be done')
@verbosity_option()
@bdt.raise_on_error
92
93
def create(name, recipe_dir, python, overwrite, condarc, use_local, config,
    append_file, server, private, stable, dry_run):
94
  """Creates a development environment for a recipe
André Anjos's avatar
André Anjos committed
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

  It uses the conda render API to render a recipe and install an environment
  containing all build/host, run and test dependencies of a package. It does
  **not** build the package itself, just install dependencies so you can build
  the package by hand, possibly using buildout or similar. If you'd like to
  conda-build your package, just use `conda build` instead.

  Once the environment is created, a copy of the used `condarc' file is placed
  on the root of the environment. Installing or updating packages on the newly
  created environment should be possible without further configuration. Notice
  that beta packages quickly get outdated and upgrading may no longer be
  possible for aging development environments. You're advised to always re-use
  this app and use the flag `--overwrite` to re-create from scratch the
  development environment.
  """

  recipe_dir = recipe_dir or os.path.join(os.path.realpath('.'), 'conda')

  if not os.path.exists(recipe_dir):
    raise RuntimeError("The directory %s does not exist" % recipe_dir)

116
  # this is not used to conda-build, just to create the final environment
André Anjos's avatar
André Anjos committed
117
118
119
120
121
122
  conda = os.environ.get('CONDA_EXE')
  if conda is None:
    raise RuntimeError("Cannot find `conda' executable (${CONDA_EXEC}) - " \
        "have you activated the build environment containing bob.devtools " \
        "properly?")

123
  # set some environment variables before continuing
124
  set_environment('DOCSERVER', server, os.environ)
125

126
127
128
129
130
131
132
133
134
135
136
137
  if condarc is not None:
    logger.info('Loading CONDARC file from %s...', condarc)
    with open(condarc, 'rb') as f:
      condarc_options = yaml.load(f)
  else:
    # use default and add channels
    condarc_options = yaml.load(BASE_CONDARC)  #n.b.: no channels
    channels = get_channels(public=(not private), stable=stable, server=server,
        intranet=private)
    condarc_options['channels'] = channels + ['defaults']

  conda_config = make_conda_config(config, python, append_file, condarc_options)
138
  deps = parse_dependencies(recipe_dir, conda_config)
139
140
  status = conda_create(conda, name, overwrite, condarc_options, deps,
      dry_run, use_local)
André Anjos's avatar
André Anjos committed
141
  click.echo('Execute on your shell: "conda activate %s"' % name)