Skip to content

Commit

Permalink
Support environments without names (eg, don't require dev/prod)
Browse files Browse the repository at this point in the history
  • Loading branch information
nathan-muir committed May 26, 2017
1 parent ebae7c0 commit d439a7f
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 33 deletions.
20 changes: 10 additions & 10 deletions nv/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import click

from .core import create, remove, launch_shell
from .core import create, remove, launch_shell, _valid_environment_name

logging.basicConfig()
logger = logging.getLogger(__name__)
Expand All @@ -15,11 +15,11 @@ def main():


@main.command('create')
@click.argument('environment_name', default='dev')
@click.argument('environment_name', default='', type=_valid_environment_name)
@click.option('--project-name', '-p', default=None,
help='''Your project name (defaults to current directory name)''')
@click.option('--project-dir', '-d', default='.',
type=click.Path(file_okay=False, dir_okay=True, exists=True, resolve_path=True),
type=click.Path(file_okay=False, dir_okay=True, exists=True),
help='''Path to the project project (defaults to current directory)''')
@click.option('use_pew', '--pew', is_flag=True, default=False,
help='''Activate a python virtualenv via pew''')
Expand All @@ -34,7 +34,7 @@ def cmd_create(environment_name, project_name, project_dir, use_pew, aws_profile
if wants_password:
password = click.prompt('Password', hide_input=True)

nv_dir = create(environment_name, project_dir, project_name=project_name, use_pew=use_pew, aws_profile=aws_profile,
nv_dir = create(project_dir, environment_name, project_name=project_name, use_pew=use_pew, aws_profile=aws_profile,
environment_vars=dict(environment_vars), password=password, use_keyring=use_keyring)
rel_dir = os.path.relpath(nv_dir, os.getcwd())
click.echo("""
Expand All @@ -47,20 +47,20 @@ def cmd_create(environment_name, project_name, project_dir, use_pew, aws_profile


@main.command('rm')
@click.argument('environment_name', default='dev')
@click.argument('environment_name', default='', type=_valid_environment_name)
@click.option('--project-dir', '-d', default='.',
type=click.Path(file_okay=False, dir_okay=True, exists=True, resolve_path=True),
type=click.Path(file_okay=False, dir_okay=True, exists=True),
help='''Path to the project project (defaults to current directory)''')
def cmd_remove(environment_name, project_dir):
"""Remove an environment."""
click.echo("Removing {0} in {1}".format(environment_name, project_dir))
remove(environment_name, project_dir)
remove(project_dir, environment_name)


@main.command('shell')
@click.argument('environment_name', default='dev')
@click.argument('environment_name', default='', type=_valid_environment_name)
@click.option('--project-dir', '-d', default='.',
type=click.Path(file_okay=False, dir_okay=True, exists=True, resolve_path=True),
type=click.Path(file_okay=False, dir_okay=True, exists=True),
help='''Path to the project project (defaults to current directory)''')
@click.option('wants_password', '-P', default=False, is_flag=True)
@click.option('update_keyring', '-K', default=False, is_flag=True)
Expand All @@ -71,5 +71,5 @@ def cmd_shell(environment_name, project_dir, wants_password, update_keyring):
if wants_password:
password = click.prompt('Password', hide_input=True)

launch_shell(environment_name, project_dir, password, update_keyring)
launch_shell(project_dir, environment_name, password, update_keyring)
click.echo('Environment closed.')
70 changes: 47 additions & 23 deletions nv/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import json
import logging
import os
import re
import shutil
from os import mkdir
from os.path import exists, join, basename
from os.path import exists, join, basename, dirname, realpath

import boto3
import sh
Expand All @@ -16,14 +17,13 @@
logger = logging.getLogger(__name__)


def create(environment_name, project_dir, project_name=None, use_pew=False, aws_profile=None,
def create(project_dir, environment_name='', project_name=None, use_pew=False, aws_profile=None,
environment_vars=None, password=None, use_keyring=False):
# TODO check that environment_name contains only [a-z0-9_]
# TODO check that project_dir is fully resolved

nv_dir = join(project_dir, '.nv-{0}'.format(environment_name))
project_dir = realpath(project_dir)
_valid_environment_name(environment_name)
nv_dir = join(project_dir, _folder_name(environment_name))
if exists(nv_dir):
raise RuntimeError("Environment exists at '{0}'".format(nv_dir))
raise RuntimeError("Environment already exists at '{0}'".format(nv_dir))

if environment_vars:
if not isinstance(environment_vars, dict):
Expand All @@ -50,7 +50,10 @@ def create(environment_name, project_dir, project_name=None, use_pew=False, aws_
}

if use_pew:
pew_env = "{0}-{1}".format(project_name, environment_name)
if environment_name:
pew_env = "{0}-{1}".format(project_name, environment_name)
else:
pew_env = project_name
logger.info('Setting up a virtual environment... ({0})'.format(pew_env))
# "-d" flag causes environment _not_ to activate when created
sh.pew('new', '-d', '-a', project_dir, pew_env, _fg=True)
Expand All @@ -68,12 +71,8 @@ def create(environment_name, project_dir, project_name=None, use_pew=False, aws_
return nv_dir


def remove(environment_name, project_dir):
nv_dir = join(project_dir, '.nv-{0}'.format(environment_name))
if not exists(nv_dir):
raise RuntimeError("Not found: '{0}'".format(nv_dir))
with open(join(nv_dir, 'nv.json'), 'rb') as fp:
nv_conf = json.load(fp)
def remove(project_dir, environment_name=''):
nv_dir, nv_conf = _load_nv(project_dir, environment_name)
pew_env = nv_conf.get('pew')
if pew_env:
try:
Expand All @@ -83,13 +82,8 @@ def remove(environment_name, project_dir):
shutil.rmtree(nv_dir)


def launch_shell(environment_name, project_dir, password=None, update_keyring=False):
nv_dir = join(project_dir, '.nv-{0}'.format(environment_name))
if not exists(nv_dir):
raise RuntimeError("Not found: '{0}'".format(nv_dir))
with open(join(nv_dir, 'nv.json'), 'rb') as fp:
nv_conf = json.load(fp)

def launch_shell(project_dir, environment_name='', password=None, update_keyring=False):
nv_dir, nv_conf = _load_nv(project_dir, environment_name)
if password and update_keyring:
keyring_store(nv_dir, password)
elif not password:
Expand All @@ -104,14 +98,18 @@ def launch_shell(environment_name, project_dir, password=None, update_keyring=Fa
new_env = os.environ.copy()
new_env.update({
'NV_PROJECT': nv_conf['project_name'],
'NV_PROJECT_DIR': project_dir,
'NV_PROJECT_DIR': dirname(nv_dir),
'NV_ENVIRONMENT': nv_conf['environment_name'],
'NV_ENVIRONMENT_DIR': nv_dir,
})
if 'PS1' in os.environ:
if nv_conf['environment_name']:
nickname = '{0[project_name]}:{0[environment_name]}'.format(nv_conf)
else:
nickname = '{0[project_name]}'.format(nv_conf)
new_env.update({
# specify non-printing sequences (e.g. color codes) as non-printing, using \[...\]
'PS1': r'\[\e[01m\]{0[project_name]}:{0[environment_name]}\[\e[0m\] {1}'.format(nv_conf, os.environ['PS1']),
'PS1': r'\[\e[01m\]{nickname}\[\e[0m\] {ps1}'.format(nickname=nickname, ps1=os.environ['PS1']),
})
aws_profile = nv_conf.get('aws_profile')
if aws_profile:
Expand Down Expand Up @@ -144,3 +142,29 @@ def launch_shell(environment_name, project_dir, password=None, update_keyring=Fa
except sh.ErrorReturnCode:
pass


def _valid_environment_name(environment_name):
if not isinstance(environment_name, six.string_types):
raise TypeError('Expected string got: {0}'.format(type(environment_name)))

if not environment_name or re.match(r'^[a-z][a-z0-9]*(-[a-z0-9]+)*$', environment_name):
return environment_name
raise ValueError()


def _folder_name(environment_name=''):
if environment_name:
return '.nv-{}'.format(environment_name)
else:
return '.nv'


def _load_nv(project_dir, environment_name):
project_dir = realpath(project_dir)
_valid_environment_name(environment_name)
nv_dir = join(project_dir, _folder_name(environment_name))
if not exists(nv_dir):
raise RuntimeError("Not found: '{0}'".format(nv_dir))
with open(join(nv_dir, 'nv.json'), 'rb') as fp:
nv_conf = json.load(fp)
return nv_dir, nv_conf

0 comments on commit d439a7f

Please sign in to comment.