11#!/usr/bin/env python
22
33
4- """Provide a command line tool for finding new container images and building them ."""
4+ """Provide a command line tool for building Singularity images from BioContainers ."""
55
66
77import argparse
1111from functools import partial
1212from html .parser import HTMLParser
1313from pathlib import Path
14+ from string import Template
1415from typing import List , Tuple , Dict , Optional , Iterable
1516
1617import aiometer
@@ -313,13 +314,13 @@ def parse_denylist(filename: Path) -> List[str]:
313314 return [entry for line in handle .readlines () if (entry := line .strip ())]
314315
315316
316- def generate_build_script (filename : Path , images : List [str ]) -> None :
317- """Generate a build script with one new image per line."""
318- with filename .open ("w" ) as handle :
317+ def generate_build_script (filename : Path , images : List [str ], template : Path ) -> None :
318+ """Generate a build script from provided templates."""
319+ with template .open () as handle :
320+ img_template = Template (handle .read ())
321+ with filename .open ("a" ) as handle :
319322 for idx , img in enumerate (images , start = 1 ):
320- handle .write (
321- f"sudo singularity build { img } docker://quay.io/biocontainers/{ img } > /dev/null 2>&1 && rsync -azq -e 'ssh -i ssh_key -o StrictHostKeyChecking=no' ./{ img } [email protected] :/srv/nginx/depot.galaxyproject.org/root/singularity/ && rm { img } && echo 'Container { img } built ({ idx } /{ len (images )} ).'\n " 322- )
323+ handle .write (img_template .substitute (img = img , idx = idx , total = len (images )))
323324
324325
325326def parse_args (argv : Optional [List [str ]] = None ) -> argparse .Namespace :
@@ -345,6 +346,15 @@ def parse_args(argv: Optional[List[str]] = None) -> argparse.Namespace:
345346 type = Path ,
346347 help = f"Output the Singularity build script (default '{ default_build_script } ')." ,
347348 )
349+ default_image_template = Path ("image_template.sh" )
350+ parser .add_argument (
351+ "--image-template" ,
352+ metavar = "PATH" ,
353+ default = default_image_template ,
354+ type = Path ,
355+ help = f"The template for building a single Singularity image (default "
356+ f"'{ default_image_template } '). Uses Python `string.Template` syntax." ,
357+ )
348358 default_quay_api = "https://quay.io/api/v1/"
349359 parser .add_argument (
350360 "--quay-api" ,
@@ -384,6 +394,8 @@ def main(argv: Optional[List[str]] = None) -> None:
384394 handlers = [RichHandler (markup = True , rich_tracebacks = True )],
385395 )
386396 assert args .denylist .is_file (), f"File not found '{ args .denylist } '."
397+ assert args .build_script .is_file (), f"File not found '{ args .build_script } '."
398+ assert args .image_template .is_file (), f"File not found '{ args .image_template } '."
387399 args .build_script .parent .mkdir (parents = True , exist_ok = True )
388400 logger .info ("Fetching quay.io BioContainers images." )
389401 quay_images = asyncio .run (QuayImageFetcher .fetch_all (api_url = args .quay_api ))
@@ -400,7 +412,7 @@ def main(argv: Optional[List[str]] = None) -> None:
400412 logger .warning ("No new images found." )
401413 return
402414 logger .info (f"{ len (images ):,} new images found. Generating build script." )
403- generate_build_script (args .build_script , images )
415+ generate_build_script (args .build_script , images , args . image_template )
404416
405417
406418if __name__ == "__main__" :
0 commit comments