Skip to content

Commit

Permalink
Merge pull request conda#1038 from conda/feature/instructions
Browse files Browse the repository at this point in the history
Updated plan to use an instruction mapping instead of an if statement
  • Loading branch information
tswicegood committed Dec 18, 2014
2 parents 942b2a6 + b085f13 commit 75001d2
Show file tree
Hide file tree
Showing 9 changed files with 399 additions and 240 deletions.
33 changes: 17 additions & 16 deletions conda/cli/main_remove.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,22 @@
def configure_parser(sub_parsers, name='remove'):
p = sub_parsers.add_parser(
name,
formatter_class = RawDescriptionHelpFormatter,
description = descr % name,
help = help % name,
epilog = example % name,
formatter_class=RawDescriptionHelpFormatter,
description=descr % name,
help=help % name,
epilog=example % name,
)
common.add_parser_yes(p)
common.add_parser_json(p)
p.add_argument(
"--all",
action = "store_true",
help = "%s all packages, i.e. the entire environment" % name,
action="store_true",
help="%s all packages, i.e. the entire environment" % name,
)
p.add_argument(
"--features",
action = "store_true",
help = "%s features (instead of packages)" % name,
action="store_true",
help="%s features (instead of packages)" % name,
)
common.add_parser_no_pin(p)
common.add_parser_channels(p)
Expand All @@ -57,16 +57,16 @@ def configure_parser(sub_parsers, name='remove'):
common.add_parser_offline(p)
p.add_argument(
"--force-pscheck",
action = "store_true",
help = ("force removal (when package process is running)"
action="store_true",
help=("force removal (when package process is running)"
if config.platform == 'win' else argparse.SUPPRESS)
)
p.add_argument(
'package_names',
metavar = 'package_name',
action = "store",
nargs = '*',
help = "package names to %s from environment" % name,
metavar='package_name',
action="store",
nargs='*',
help="package names to %s from environment" % name,
)
p.set_defaults(func=execute)

Expand All @@ -75,6 +75,7 @@ def execute(args, parser):
import sys

import conda.plan as plan
import conda.instructions as inst
from conda.cli import pscheck
from conda.install import rm_rf, linked
from conda import config
Expand Down Expand Up @@ -127,8 +128,8 @@ def execute(args, parser):
json=args.json,
error_type="CantRemoveRoot")

actions = {plan.PREFIX: prefix,
plan.UNLINK: sorted(linked(prefix))}
actions = {inst.PREFIX: prefix,
inst.UNLINK: sorted(linked(prefix))}

else:
specs = common.specs_from_args(args.package_names)
Expand Down
8 changes: 8 additions & 0 deletions conda/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class CondaException(Exception):
pass


class InvalidInstruction(CondaException):
def __init__(self, instruction, *args, **kwargs):
msg = "No handler for instruction: %r" % instruction
super(InvalidInstruction, self).__init__(msg, *args, **kwargs)
147 changes: 147 additions & 0 deletions conda/instructions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
from logging import getLogger
import re

from conda import config
from conda import install
from conda.exceptions import InvalidInstruction
from conda.fetch import fetch_pkg


log = getLogger(__name__)

# op codes
FETCH = 'FETCH'
EXTRACT = 'EXTRACT'
UNLINK = 'UNLINK'
LINK = 'LINK'
RM_EXTRACTED = 'RM_EXTRACTED'
RM_FETCHED = 'RM_FETCHED'
PREFIX = 'PREFIX'
PRINT = 'PRINT'
PROGRESS = 'PROGRESS'
SYMLINK_CONDA = 'SYMLINK_CONDA'


progress_cmds = set([EXTRACT, RM_EXTRACTED, LINK, UNLINK])
action_codes = (FETCH, EXTRACT, UNLINK, LINK, SYMLINK_CONDA, RM_EXTRACTED,
RM_FETCHED)


def PREFIX_CMD(state, arg):
state['prefix'] = arg


def PRINT_CMD(state, arg):
getLogger('print').info(arg)


def fetch(index, dist):
assert index is not None
fn = dist + '.tar.bz2'
fetch_pkg(index[fn])


def FETCH_CMD(state, arg):
fetch(state['index'], arg)


def PROGRESS_CMD(state, arg):
state['i'] = 0
state['maxval'] = int(arg)
getLogger('progress.start').info(state['maxval'])


def EXTRACT_CMD(state, arg):
install.extract(config.pkgs_dirs[0], arg)


def RM_EXTRACTED_CMD(state, arg):
install.rm_extracted(config.pkgs_dirs[0], arg)


def RM_FETCHED_CMD(state, arg):
install.rm_fetched(config.pkgs_dirs[0], arg)


def split_linkarg(arg):
"Return tuple(dist, pkgs_dir, linktype)"
pat = re.compile(r'\s*(\S+)(?:\s+(.+?)\s+(\d+))?\s*$')
m = pat.match(arg)
dist, pkgs_dir, linktype = m.groups()
if pkgs_dir is None:
pkgs_dir = config.pkgs_dirs[0]
if linktype is None:
linktype = install.LINK_HARD
return dist, pkgs_dir, int(linktype)


def link(prefix, arg, index=None):
dist, pkgs_dir, lt = split_linkarg(arg)
install.link(pkgs_dir, prefix, dist, lt, index=index)


def LINK_CMD(state, arg):
link(state['prefix'], arg, index=state['index'])


def UNLINK_CMD(state, arg):
install.unlink(state['prefix'], arg)


def SYMLINK_CONDA_CMD(state, arg):
install.symlink_conda(state['prefix'], arg)

# Map instruction to command (a python function)
commands = {
PREFIX: PREFIX_CMD,
PRINT: PRINT_CMD,
FETCH: FETCH_CMD,
PROGRESS: PROGRESS_CMD,
EXTRACT: EXTRACT_CMD,
RM_EXTRACTED: RM_EXTRACTED_CMD,
RM_FETCHED: RM_FETCHED_CMD,
LINK: LINK_CMD,
UNLINK: UNLINK_CMD,
SYMLINK_CONDA: SYMLINK_CONDA_CMD,
}


def execute_instructions(plan, index=None, verbose=False, _commands=None):
"""
Execute the instructions in the plan
:param plan: A list of (instruction, arg) tuples
:param index: The meta-data index
:param verbose: verbose output
:param _commands: (For testing only) dict mapping an instruction to executable if None
then the default commands will be used
"""
if _commands is None:
_commands = commands

if verbose:
from conda.console import setup_verbose_handlers
setup_verbose_handlers()

state = {'i': None, 'prefix': config.root_dir, 'index': index}

for instruction, arg in plan:

log.debug(' %s(%r)' % (instruction, arg))

if state['i'] is not None and instruction in progress_cmds:
state['i'] += 1
getLogger('progress.update').info((arg, state['i']))
cmd = _commands.get(instruction)

if cmd is None:
raise InvalidInstruction(instruction)

cmd(state, arg)

if (state['i'] is not None and instruction in progress_cmds
and state['maxval'] == state['i']):
state['i'] = None
getLogger('progress.stop').info(None)

install.messages(state['prefix'])
12 changes: 6 additions & 6 deletions conda/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
from conda import config
from conda import install
from conda.api import get_index
from conda.plan import (RM_EXTRACTED, EXTRACT, UNLINK, LINK,
ensure_linked_actions, execute_actions)
from conda.instructions import RM_EXTRACTED, EXTRACT, UNLINK, LINK
from conda.plan import ensure_linked_actions, execute_actions
from conda.compat import iteritems


Expand Down Expand Up @@ -83,7 +83,7 @@ def untracked(prefix, exclude_self_build=False):
conda_files = conda_installed_files(prefix, exclude_self_build)
return {path for path in walk_prefix(prefix) - conda_files
if not (path.endswith('~') or
(sys.platform=='darwin' and path.endswith('.DS_Store')) or
(sys.platform == 'darwin' and path.endswith('.DS_Store')) or
(path.endswith('.pyc') and path[:-1] in conda_files))}


Expand Down Expand Up @@ -175,7 +175,7 @@ def clone_env(prefix1, prefix2, verbose=True, quiet=False):
s = data.decode('utf-8')
s = s.replace(prefix1, prefix2)
data = s.encode('utf-8')
except UnicodeDecodeError: # data is binary
except UnicodeDecodeError: # data is binary
pass

with open(dst, 'wb') as fo:
Expand Down Expand Up @@ -306,8 +306,8 @@ def make_icon_url(info):
if 'channel' in info and 'icon' in info:
base_url = dirname(info['channel'].rstrip('/'))
icon_fn = info['icon']
#icon_cache_path = join(config.pkgs_dir, 'cache', icon_fn)
#if isfile(icon_cache_path):
# icon_cache_path = join(config.pkgs_dir, 'cache', icon_fn)
# if isfile(icon_cache_path):
# return url_path(icon_cache_path)
return '%s/icons/%s' % (base_url, icon_fn)
return ''
Expand Down
Loading

0 comments on commit 75001d2

Please sign in to comment.