mirror of https://github.com/mamba-org/mamba.git
add update functionality, remove multiprocessing, fix sort order of install
This commit is contained in:
parent
c301773da5
commit
489e83c1d3
|
@ -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";
|
||||
|
|
|
@ -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
|
175
mamba/mamba.py
175
mamba/mamba.py
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue