def fix_environment_deviations(self, prefix, spec, deviations=None, create=True): if deviations is None: deviations = self.find_environment_deviations(prefix, spec) if deviations.unfixable: raise CondaManagerError("Unable to update environment at %s" % prefix) if os.path.isdir(os.path.join(prefix, 'conda-meta')): to_update = list(set(deviations.missing_packages + deviations.wrong_version_packages)) if len(to_update) > 0: specs = spec.specs_for_conda_package_names(to_update) assert len(specs) == len(to_update) spec.apply_pins(prefix, specs) try: conda_api.install( prefix=prefix, pkgs=specs, channels=spec.channels, stdout_callback=self._on_stdout, stderr_callback=self._on_stderr) except conda_api.CondaError as e: raise CondaManagerError("Failed to install packages: {}: {}".format(", ".join(specs), str(e))) finally: spec.remove_pins(prefix) elif create: # Create environment from scratch command_line_packages = set(spec.conda_packages_for_create) # conda won't let us create a completely empty environment if len(command_line_packages) == 0: command_line_packages = set(['python']) try: conda_api.create( prefix=prefix, pkgs=list(command_line_packages), channels=spec.channels, stdout_callback=self._on_stdout, stderr_callback=self._on_stderr) except conda_api.CondaError as e: raise CondaManagerError("Failed to create environment at %s: %s" % (prefix, str(e))) else: raise CondaManagerError("Conda environment at %s does not exist" % (prefix)) # now add pip if needed missing = list(deviations.missing_pip_packages) if len(missing) > 0: specs = spec.specs_for_pip_package_names(missing) assert len(specs) == len(missing) try: pip_api.install(prefix=prefix, pkgs=specs) except pip_api.PipError as e: raise CondaManagerError("Failed to install missing pip packages: {}: {}".format( ", ".join(missing), str(e))) # write a file to tell us we can short-circuit next time self._write_timestamp_file(prefix, spec)
def resolve_dependencies(self, package_specs, channels, platforms): by_platform = {} current = conda_api.current_platform() resolve_for_platforms = list(platforms) # always resolve "current" first because it's confusing if # an error says resolution failed on another platform when # the real issue is that resolution will fail on all platforms. if current in resolve_for_platforms: resolve_for_platforms.remove(current) resolve_for_platforms = [current] + resolve_for_platforms for conda_platform in resolve_for_platforms: try: self._log_info("Resolving conda packages for %s" % conda_platform) deps = conda_api.resolve_dependencies(pkgs=package_specs, platform=conda_platform, channels=channels) except conda_api.CondaError as e: raise CondaManagerError("Error resolving for {}: {}".format( conda_platform, str(e))) locked_specs = ["%s=%s=%s" % dep for dep in deps] by_platform[conda_platform] = sorted(locked_specs) by_platform = _extract_common(by_platform) lock_set = CondaLockSet(package_specs_by_platform=by_platform, platforms=resolve_for_platforms) return lock_set
def _find_conda_deviations(self, prefix, env_spec): try: installed = conda_api.installed(prefix) except conda_api.CondaError as e: raise CondaManagerError("Conda failed while listing installed packages in %s: %s" % (prefix, str(e))) missing = set() wrong_version = set() for spec_string in env_spec.conda_packages_for_create: spec = conda_api.parse_spec(spec_string) name = spec.name if name not in installed: missing.add(name) else: def version_match(wanted, installed): if wanted == installed: return True else: return installed.startswith(wanted + ".") # The only constraint we are smart enough to understand is # the one we put in the lock file, which is plain =. # We can't do version comparisons, which is a bug. # We won't notice if non-= constraints are unmet. (_, installed_version, installed_build) = installed[name] if spec.exact_version is not None and not version_match(spec.exact_version, installed_version): wrong_version.add(name) elif spec.exact_build_string is not None and not version_match(spec.exact_build_string, installed_build): wrong_version.add(name) return (sorted(list(missing)), sorted(list(wrong_version)))
def remove_packages(self, prefix, packages): try: conda_api.remove(prefix, packages, stdout_callback=self._on_stdout, stderr_callback=self._on_stderr) except conda_api.CondaError as e: raise CondaManagerError("Failed to remove packages from %s: %s" % (prefix, str(e)))
def remove_packages(self, prefix, packages, pip=False): if pip: try: pip_api.remove(prefix, packages, stdout_callback=self._on_stdout, stderr_callback=self._on_stderr) except pip_api.PipError as e: raise CondaManagerError( 'Failed to remove pip packages from {}: {}'.format( prefix, str(e))) else: try: conda_api.remove(prefix, packages, stdout_callback=self._on_stdout, stderr_callback=self._on_stderr) except conda_api.CondaError as e: raise CondaManagerError( "Failed to remove packages from %s: %s" % (prefix, str(e)))
def _find_conda_missing(self, prefix, spec): try: installed = conda_api.installed(prefix) except conda_api.CondaError as e: raise CondaManagerError("Conda failed while listing installed packages in %s: %s" % (prefix, str(e))) # TODO: we don't verify that the environment contains the right versions # https://github.com/Anaconda-Server/anaconda-project/issues/77 missing = set() for name in spec.conda_package_names_set: if name not in installed: missing.add(name) return sorted(list(missing))
def _find_pip_missing(self, prefix, spec): # this is an important optimization to avoid a slow "pip # list" operation if the project has no pip packages if len(spec.pip_package_names_set) == 0: return [] try: installed = pip_api.installed(prefix) except pip_api.PipError as e: raise CondaManagerError("pip failed while listing installed packages in %s: %s" % (prefix, str(e))) # TODO: we don't verify that the environment contains the right versions # https://github.com/Anaconda-Server/anaconda-project/issues/77 missing = set() for name in spec.pip_package_names_set: if name not in installed: missing.add(name) return sorted(list(missing))
def fix_environment_deviations(self, prefix, spec, deviations=None, create=True): if deviations is None: deviations = self.find_environment_deviations(prefix, spec) if deviations.unfixable: raise CondaManagerError("Unable to update environment at %s" % prefix) conda_meta = os.path.join(prefix, 'conda-meta') packed = os.path.join(conda_meta, '.packed') install_pip = True if os.path.isdir(conda_meta) and os.path.exists(packed): with open(packed) as f: packed_arch = f.read().strip() matched = packed_arch == conda_api.current_platform() if matched: if 'win' in conda_api.current_platform(): unpack_script = [ 'python', os.path.join(prefix, 'Scripts', 'conda-unpack-script.py') ] else: unpack_script = os.path.join(prefix, 'bin', 'conda-unpack') try: subprocess.check_call(unpack_script) os.remove(packed) install_pip = False except (subprocess.CalledProcessError, OSError) as e: self._log_info( 'Warning: conda-unpack could not be run: \n{}\n' 'The environment will be recreated.'.format(str(e))) create = True shutil.rmtree(prefix) else: self._log_info( 'Warning: The unpacked env does not match the current architecture. ' 'It will be recreated.') create = True shutil.rmtree(prefix) if os.path.isdir(conda_meta): to_update = list( set(deviations.missing_packages + deviations.wrong_version_packages)) if len(to_update) > 0: specs = spec.specs_for_conda_package_names(to_update) assert len(specs) == len(to_update) spec.apply_pins(prefix, specs) try: conda_api.install(prefix=prefix, pkgs=specs, channels=spec.channels, stdout_callback=self._on_stdout, stderr_callback=self._on_stderr) except conda_api.CondaError as e: raise CondaManagerError( "Failed to install packages: {}: {}".format( ", ".join(specs), str(e))) finally: spec.remove_pins(prefix) elif create: # Create environment from scratch command_line_packages = set(spec.conda_packages_for_create) try: conda_api.create(prefix=prefix, pkgs=list(command_line_packages), channels=spec.channels, stdout_callback=self._on_stdout, stderr_callback=self._on_stderr) except conda_api.CondaError as e: raise CondaManagerError( "Failed to create environment at %s: %s" % (prefix, str(e))) else: raise CondaManagerError("Conda environment at %s does not exist" % (prefix)) # now add pip if needed missing = list(deviations.missing_pip_packages) if (len(missing) > 0) and install_pip: specs = spec.specs_for_pip_package_names(missing) assert len(specs) == len(missing) try: pip_api.install(prefix=prefix, pkgs=specs, stdout_callback=self._on_stdout, stderr_callback=self._on_stderr) except pip_api.PipError as e: raise CondaManagerError( "Failed to install missing pip packages: {}: {}".format( ", ".join(missing), str(e))) # write a file to tell us we can short-circuit next time self._write_timestamp_file(prefix, spec)
def remove_packages(self, prefix, packages): try: conda_api.remove(prefix, packages) except conda_api.CondaError as e: raise CondaManagerError("Failed to remove packages from %s: %s" % (prefix, str(e)))