def export(**kwargs): """Create a bundle of a given environment. the following command copies all binaries from an environement and their associated images into a tar ball file named after the environment. damona export test1 --exclude "bowtie*" This create a bundle named damona_test1.tar. You can then create a new environment starting from this bundle: damona env --create TEST1 --from-bundle damona_test1.tar """ logger.debug(kwargs) environment = kwargs['environment'] exclude = kwargs['exclude'] # TODO This should be based on the binaries of the environment, not the images # to do so, we'll need an installed.txt file from damona import Environment envname = kwargs['environment'] env = Environment(envname) env.create_bundle(exclude=exclude) logger.info(f"Saved environment into {environment}.tar") logger.info( f"Use this command to create a new environment: damona env --create test --from-bundle {environment}.tar" )
def info(**kwargs): """Print information about a given environement. The default environment is called 'base'. \b damona info base damona info test1 Images abd binaries available are shown """ logger.debug(kwargs) envname = kwargs['environment'] from damona.environ import Environ manager = Environ() x = [ee for ee in manager.environments if ee.name == envname] if len(x) == 0: logger.error( f"Environment '{envname}' does not exist. Use 'damona env' to get the list" ) sys.exit(1) else: environ = x[0] print(environ) print("Images:") for item in sorted(environ.get_images()): print(" - " + pathlib.Path(item).name) print("Binaries:") for item in sorted(environ.get_installed_binaries()): print(" - " + pathlib.Path(item).name)
def build(**kwargs): #pragma: no cover """Build a container from dockerhub, singularity file or damona recipes. Note that to use this command, you must have sudo permissions. If not, you will need to download existing images. See the "damona install command". You can build a singularity image from a local singularity file. Note that your Singulary recipes must follow the naming convention Singularity.NAME_x,y,z \b # a local recipes (recipes must have a version) damona build Singularity.salmon_1.3.0 You may build an image from a singularity recipes to be found in Damona itself. In such case, the name and version are enough. Siuch recipes can be listed using "damona list" damona build salmon:1.3.0 You may also build image from a docker image to be found on docker hub: \b damona build docker://biocontainers/bowtie2:v2.4.1_cv1 damona build docker://kapeel/hisat2 TO be implemented: from singularity hub or sylabs.io """ logger.debug(kwargs) filename = kwargs['filename'] force = kwargs['force'] destination = kwargs['destination'] if destination: if destination.endswith(".img") is False: logger.warning("You should end your image with the .img extension") if "_" not in destination: logger.warning("You should name your image as NAME_x.y.z") if os.path.exists(filename) and os.path.isdir(filename) is False: # TODO check that it starts with Singularity # local recipes ? from damona.builders import BuilderFromSingularityRecipe builder = BuilderFromSingularityRecipe() builder.build(filename, destination=destination, force=force) elif kwargs['filename'].startswith("docker://"): from damona.builders import BuilderFromDocker builder = BuilderFromDocker() filename = filename.replace("docker://", "") builder.build(filename, destination=destination, force=force) else: # could be a damona recipes logger.info("Not a docker URL, nor a local file.")
def deactivate(**kwargs): """Deactivate the current Damona environment. deactivate the current environement: damona deactivate """ logger.debug(kwargs) from damona import Environ env = Environ() env.deactivate(kwargs['name'])
def env(**kwargs): """Get information about Damona environments. Print the current environments and available environments: damona env Check the disk usage of each environments:: damona env --disk-usage You can also create an environment and install a saved on in it: \b damona export test1 damona env --create copy_test1 --from-bundle damona_test1.tar """ logger.debug(kwargs) from damona import Environ envs = Environ() if kwargs['disk_usage']: import math from damona import Environ envs = Environ() #base = envs.get_current_env() + "/images/*img" #env_size = sum(os.path.getsize(f) for f in glob.glob(base) if os.path.isfile(f)) N = len(envs.images) usage = envs.images.get_disk_usage() #env_size = math.ceil(env_size/1e6) print(f"Found {N} images: Images usage: {usage}.Mb") elif kwargs['create'] is None and kwargs['delete'] is None: print( f"There is currently one base (default) environment and {envs.N-1} user environments." ) if envs.N != 0: for this in envs.environments: name = this.name print(f"{name} - {this}") current_env = envs.get_current_env() logger.info("""Your current env is {}.""".format(current_env)) elif kwargs['create'] and kwargs['delete']: # mutually exclusive logger.error("you cannot use --delete and --create together") elif kwargs['delete']: envs.delete(kwargs['delete']) elif kwargs['create']: if kwargs['from_bundle']: envs.create_from_bundle(kwargs['create'], bundle=kwargs['from_bundle'], force=kwargs['force']) else: envs.create(kwargs["create"])
def clean(**kwargs): """Remove orphan images and binaries from all environments. This commnd finds images that have no more binary in any environment. This may happen with prior version of a given binary. Note that if you want to remove an environmnt, just delete it or use: conda env --delete NAME """ logger.debug(kwargs) from damona import Damona dmn = Damona() # First we deal with orphans from the binaries directories orphans = dmn.find_orphan_binaries() if len(orphans) == 0: logger.info("No orphans binary found") if kwargs['remove']: for x in orphans: os.remove(os.path.expanduser(x)) logger.info(f"Removed {x}") else: logger.warning( "Please use --remove to confirm that you want to remove the orphans" ) # Second, we find images that have no more binaries orphans = dmn.find_orphan_images() if len(orphans) == 0: logger.info("No orphan images found") else: logger.info(f"Found {len(orphans)} orphans.") if kwargs['remove']: for x in orphans: answer = input( f"You are going to delete this image: {x}. Are you sure ? (yes/no)" ) if answer == "yes": os.remove(os.path.expanduser(x)) logger.info(f"Removed {x}") else: logger.info(f"skipped deletion of {x}") else: logger.warning( "Please use --remove to confirm that you want to remove the orphans" )
def search(**kwargs): """Search for a container given a pattern in damona registry. By default searches for a software in Damona only: damona search fastqc IF you want to list all software and their versions, just type: damona search "*" One can also search in an online registry: damona search fastqc --url https://biomics.pasteur.fr/salsa/damona/registry.txt You may define aliases to URLs in your ~/.config/damona/damona.cfg file to make it easier: damona search fastqc --url damona """ logger.debug(kwargs) from damona.registry import Registry if kwargs['url']: url = kwargs['url'] elif kwargs['from_url']: url = kwargs['from_url'] else: url = None if kwargs['pattern'] == "*": pattern = None else: pattern = kwargs['pattern'] modules = Registry(from_url=url).get_list(pattern=pattern) for mod in modules: print(mod)
def install(**kwargs): """Download and install an image and its binaries. The main idea of Damona is to download and install images already built for you and to install binaries to be found inside the image. An image has a name and a version and can be installed as: damona install NAME:version If the version is omitted, the latest version is installed. Therefore, the following two commands are equivalent (as of march 2021): \b damona install fastqc damona install fastqc:0.11.9 You may also install a local image. In such case, you must name your image with a version (e.g. fastqc_0.11.9.img). We assume that name of the image is the binary name, however, binaries can be set manually: \b damona install fastqc_0.4.2.img damona install test_0.4.2.img --binary fastqc By convention, images must follow the pattern NAME_[v]x.y.z[_info].img where the [v] character is optional and the [_info] is an optional _ character followed by any text. Finally, the extension can be .img or .sif Images are installed in the ~/.config/damona/images directory. It is the DAMONA_PATH environment variable. Therefore, you can redefine this variable to install images elsewhere. Finally, you may have images online on a website. To install such images, use the --from-url/--url (sse developer guide for details). """ logger.debug(kwargs) # url if kwargs['url']: url = kwargs['url'] elif kwargs['from_url']: url = kwargs['from_url'] else: url = None image_path = pathlib.Path(kwargs['image']).absolute() force = kwargs['force'] force_image = kwargs['force_image'] force_binaries = kwargs['force_binaries'] if force: force_image, force_binaries = True, True if kwargs['binaries']: if "," in kwargs['binaries']: binaries = kwargs['binaries'].split(",") else: binaries = [kwargs['binaries']] else: binaries = None if os.path.exists(image_path) is False: if kwargs['from_url']: url = kwargs['from_url'] logger.info(f"Installing from online registry (url: {url})") else: logger.info("Installing from Damona registry") from damona.install import RemoteImageInstaller p = RemoteImageInstaller(kwargs['image'], from_url=kwargs['from_url'], cmd=sys.argv, binaries=binaries) if p.is_valid(): p.pull_image(force=force_image) p.install_binaries(force=force_binaries) else: logger.critical( "Something wrong with your image/binaries. See message above") else: # This install the image and associated binary/binaries from damona import environ env = environ.Environ() cenv = env.get_current_env() logger.info(f"Installing local container in {cenv}") from damona.install import LocalImageInstaller lii = LocalImageInstaller(image_path, cmd=sys.argv, binaries=binaries) if lii.is_valid(): lii.install_image(force=force_image) lii.install_binaries(force=force_binaries) else: logger.critical( "Something wrong with your image/binaries. See message above")