add update functionality, remove multiprocessing, fix sort order of install

This commit is contained in:
Wolf Vollprecht 2019-03-29 14:06:18 +01:00
parent c301773da5
commit 489e83c1d3
3 changed files with 158 additions and 25 deletions

View File

@ -138,6 +138,7 @@ std::tuple<std::vector<std::tuple<std::string, std::string, std::string>>,
solve(std::vector<std::pair<std::string, std::string>> repos,
std::string installed,
std::vector<std::string> jobs,
bool update,
bool strict_priority)
{
Pool* pool = pool_create();
@ -201,11 +202,15 @@ solve(std::vector<std::pair<std::string, std::string>> repos,
Queue q;
queue_init(&q);
int update_or_install = SOLVER_INSTALL;
if (update) {
update_or_install = SOLVER_UPDATE;
}
for (const auto& job : jobs)
{
int rel = parse_to_relation(job, pool);
std::cout << "Job: " << pool_dep2str(pool, rel) << std::endl;;
queue_push2(&q, SOLVER_INSTALL | SOLVER_SOLVABLE_NAME, rel);
queue_push2(&q, update_or_install | SOLVER_SOLVABLE_NAME, rel);
}
std::cout << "\n";

View File

@ -9,6 +9,7 @@ std::tuple<std::vector<std::tuple<std::string, std::string, std::string>>,
solve(std::vector<std::pair<std::string, std::string>> repos,
std::string installed,
std::vector<std::string> jobs,
bool update,
bool strict_priority);
#endif

View File

@ -6,6 +6,8 @@ from __future__ import absolute_import, division, print_function, unicode_litera
import sys, os
from os.path import abspath, basename, exists, isdir, isfile, join
from conda.cli.main import generate_parser, init_loggers
from conda.base.context import context
from conda.core.index import calculate_channel_urls, check_whitelist #, get_index
@ -14,30 +16,42 @@ from conda.models.records import PackageRecord
from conda.models.match_spec import MatchSpec
from conda.cli.main_list import list_packages
from conda.core.prefix_data import PrefixData
from conda.misc import clone_env, explicit, touch_nonadmin
from conda.common.serialize import json_dump
from conda.cli.common import specs_from_args, specs_from_url, confirm_yn
from conda.cli.common import specs_from_args, specs_from_url, confirm_yn, check_non_admin, ensure_name_or_prefix
from conda.core.subdir_data import SubdirData
from conda.common.url import join_url
from conda.core.link import UnlinkLinkTransaction, PrefixSetup
from conda.cli.install import handle_txn
from conda.base.constants import ChannelPriority
from conda.cli.install import handle_txn, check_prefix, clone, print_activate
from conda.base.constants import ChannelPriority, ROOT_ENV_NAME, UpdateModifier
from conda.core.solve import diff_for_unlink_link_precs
# create support
from conda.common.path import paths_equal
from conda.exceptions import CondaValueError
from conda.gateways.disk.delete import rm_rf
from conda.exceptions import (CondaExitZero, CondaImportError, CondaOSError, CondaSystemExit,
CondaValueError, DirectoryNotACondaEnvironmentError,
DirectoryNotFoundError, DryRunExit, EnvironmentLocationNotFound,
NoBaseEnvironmentError, PackageNotInstalledError, PackagesNotFoundError,
TooManyArgumentsError, UnsatisfiableError)
from conda.gateways.disk.create import mkdir_p
from conda.gateways.disk.delete import rm_rf, delete_trash, path_is_clean
from conda.gateways.disk.test import is_conda_environment
from conda._vendor.boltons.setutils import IndexedSet
from conda.models.prefix_graph import PrefixGraph
from logging import getLogger
from os.path import isdir
import json
import tempfile
from multiprocessing.pool import Pool as MPool
from .FastSubdirData import FastSubdirData
import mamba.mamba_api as api
log = getLogger(__name__)
stderrlog = getLogger('mamba.stderr')
banner = """
__ __ __ __
/ \\ / \\ / \\ / \\
@ -62,18 +76,26 @@ banner = """
"""
import threading
def get_channel(x):
def get_channel(x, result_container):
print("Getting ", x)
return FastSubdirData(Channel(x)).load()
return result_container.append(FastSubdirData(Channel(x)).load())
def get_index(channel_urls=(), prepend=True, platform=None,
use_local=False, use_cache=False, unknown=None, prefix=None):
channel_urls = calculate_channel_urls(channel_urls, prepend, platform, use_local)
check_whitelist(channel_urls)
pl = MPool(8)
result = pl.map(get_channel, channel_urls)
threads = []
result = []
for url in channel_urls:
t = threading.Thread(target=get_channel, args=(url, result))
threads.append(t)
t.start()
for t in threads:
t.join()
return result
def to_package_record_from_subjson(subdir, pkg, jsn_string):
@ -103,8 +125,53 @@ def get_installed_packages(prefix, show_channel_urls=None):
return installed, result
def install(args, parser, function):
context.__init__(argparse_args=args)
def install(args, parser, command='install'):
"""
mamba install, mamba update, and mamba create
"""
context.validate_configuration()
check_non_admin()
newenv = bool(command == 'create')
isupdate = bool(command == 'update')
isinstall = bool(command == 'install')
if newenv:
ensure_name_or_prefix(args, command)
prefix = context.target_prefix
if newenv:
check_prefix(prefix, json=context.json)
if context.force_32bit and prefix == context.root_prefix:
raise CondaValueError("cannot use CONDA_FORCE_32BIT=1 in base env")
if isupdate and not (args.file or args.packages
or context.update_modifier == UpdateModifier.UPDATE_ALL):
raise CondaValueError("""no package names supplied
# If you want to update to a newer version of Anaconda, type:
#
# $ conda update --prefix %s anaconda
""" % prefix)
if not newenv:
if isdir(prefix):
delete_trash(prefix)
if not isfile(join(prefix, 'conda-meta', 'history')):
if paths_equal(prefix, context.conda_prefix):
raise NoBaseEnvironmentError()
else:
if not path_is_clean(prefix):
raise DirectoryNotACondaEnvironmentError(prefix)
else:
# fall-through expected under normal operation
pass
else:
if args.mkdir:
try:
mkdir_p(prefix)
except EnvironmentError as e:
raise CondaOSError("Could not create directory: %s" % prefix, caused_by=e)
else:
raise EnvironmentLocationNotFound(prefix)
# context.__init__(argparse_args=args)
prepend = not args.override_channels
prefix = context.target_prefix
@ -117,6 +184,25 @@ def install(args, parser, function):
'use_local': args.use_local
}
args_packages = [s.strip('"\'') for s in args.packages]
if newenv and not args.no_default_packages:
# Override defaults if they are specified at the command line
# TODO: rework in 4.4 branch using MatchSpec
args_packages_names = [pkg.replace(' ', '=').split('=', 1)[0] for pkg in args_packages]
for default_pkg in context.create_default_packages:
default_pkg_name = default_pkg.replace(' ', '=').split('=', 1)[0]
if default_pkg_name not in args_packages_names:
args_packages.append(default_pkg)
num_cp = sum(s.endswith('.tar.bz2') for s in args_packages)
if num_cp:
if num_cp == len(args_packages):
explicit(args_packages, prefix, verbose=not context.quiet)
return
else:
raise CondaValueError("cannot mix specifications with conda package"
" filenames")
index = get_index(channel_urls=index_args['channel_urls'],
prepend=index_args['prepend'], platform=None,
use_local=index_args['use_local'], use_cache=index_args['use_cache'],
@ -129,8 +215,6 @@ def install(args, parser, function):
installed_json_f.write(json_dump(output))
installed_json_f.flush()
args_packages = [s.strip('"\'') for s in args.packages]
specs = []
if args.file:
for fpath in args.file:
@ -145,14 +229,50 @@ def install(args, parser, function):
specs.extend(specs_from_args(args_packages, json=context.json))
specs = [MatchSpec(s).conda_build_form() for s in specs]
if isinstall and args.revision:
get_revision(args.revision, json=context.json)
elif isinstall and not (args.file or args_packages):
raise CondaValueError("too few arguments, "
"must supply command line package specs or --file")
# for 'conda update', make sure the requested specs actually exist in the prefix
# and that they are name-only specs
if isupdate and context.update_modifier == UpdateModifier.UPDATE_ALL:
print("Currently, mamba can only update explicit packages! (e.g. mamba update numpy python ...)")
exit()
if isupdate and context.update_modifier != UpdateModifier.UPDATE_ALL:
prefix_data = PrefixData(prefix)
for spec in specs:
spec = MatchSpec(spec)
if not spec.is_name_only_spec:
raise CondaError("Invalid spec for 'conda update': %s\n"
"Use 'conda install' instead." % spec)
if not prefix_data.get(spec.name, None):
raise PackageNotInstalledError(prefix, spec.name)
if newenv and args.clone:
if args.packages:
raise TooManyArgumentsError(0, len(args.packages), list(args.packages),
'did not expect any arguments for --clone')
clone(args.clone, prefix, json=context.json, quiet=context.quiet, index_args=index_args)
touch_nonadmin(prefix)
print_activate(args.name if args.name else prefix)
return
specs = [MatchSpec(s) for s in specs]
mamba_solve_specs = [s.conda_build_form() for s in specs]
print("\n\nLooking for: {}\n\n".format(specs))
strict_priority = (context.channel_priority == ChannelPriority.STRICT)
to_link, to_unlink = api.solve(channel_json, installed_json_f.name, specs, strict_priority)
to_link, to_unlink = api.solve(channel_json, installed_json_f.name, mamba_solve_specs, isupdate, strict_priority)
to_link_records, to_unlink_records = [], []
final_precs = IndexedSet(PrefixData(prefix).iter_records())
def get_channel(c):
for x in index:
if str(x.channel) == c:
@ -161,6 +281,7 @@ def install(args, parser, function):
for c, pkg in to_unlink:
for i_rec in installed_pkg_recs:
if i_rec.fn == pkg:
final_precs.remove(i_rec)
to_unlink_records.append(i_rec)
break
else:
@ -169,18 +290,24 @@ def install(args, parser, function):
for c, pkg, jsn_s in to_link:
sdir = get_channel(c)
rec = to_package_record_from_subjson(sdir, pkg, jsn_s)
final_precs.add(rec)
to_link_records.append(rec)
unlink_precs, link_precs = diff_for_unlink_link_precs(prefix,
final_precs=IndexedSet(PrefixGraph(final_precs).graph),
specs_to_add=specs,
force_reinstall=context.force_reinstall)
pref_setup = PrefixSetup(
target_prefix = prefix,
unlink_precs = to_unlink_records,
link_precs = to_link_records,
unlink_precs = unlink_precs,
link_precs = link_precs,
remove_specs = [],
update_specs = specs
)
conda_transaction = UnlinkLinkTransaction(pref_setup)
handle_txn(conda_transaction, prefix, args, True)
handle_txn(conda_transaction, prefix, args, newenv)
try:
installed_json_f.close()
@ -229,8 +356,8 @@ def do_call(args, parser):
exit_code = install(args, parser, 'install')
elif relative_mod == '.main_create':
exit_code = create(args, parser)
# elif relative_mod == '.main_update':
# exit_code = update(args, parser)
elif relative_mod == '.main_update':
exit_code = update(args, parser)
else:
print("Currently, only install, create, list, search, run, info and clean are supported through mamba.")
return 0
@ -269,4 +396,4 @@ def main(*args, **kwargs):
args = tuple(ensure_text_type(s) for s in args)
from conda.exceptions import conda_exception_handler
return conda_exception_handler(_wrapped_main, *args, **kwargs)
return _wrapped_main(*args, **kwargs)