def test_branch_recursive(self): """git with specified branch and recursive""" g = git() self.assertEqual(g.clone_step(repository='https://github.com/NVIDIA/hpc-container-maker.git', branch='master', recursive=True), 'mkdir -p /tmp && cd /tmp && git clone --depth=1 --branch master --recursive https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd -')
def test_branch_and_commit(self): """git with both specified branch and specified commit""" g = git() self.assertEqual(g.clone_step(repository='https://github.com/NVIDIA/hpc-container-maker.git', branch='master', commit='ac6ca95d0b20ed1efaffa6d58945a4dd2d80780c'), 'mkdir -p /tmp && cd /tmp && git clone https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd - && cd /tmp/hpc-container-maker && git checkout ac6ca95d0b20ed1efaffa6d58945a4dd2d80780c && cd -')
def test_verify(self): """git with verification enabled""" g = git() repository = 'https://github.com/NVIDIA/hpc-container-maker.git' valid_branch = 'master' invalid_branch = 'does_not_exist' valid_commit = '23996b03b3e72f77a41498e94d90de920935644a' invalid_commit = 'deadbeef' self.assertEqual(g.clone_step(repository=repository, branch=valid_branch, verify=True), 'mkdir -p /tmp && cd /tmp && git clone --depth=1 --branch master https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd -') self.assertEqual(g.clone_step(repository=repository, branch=invalid_branch, verify=True), 'mkdir -p /tmp && cd /tmp && git clone --depth=1 --branch does_not_exist https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd -') self.assertEqual(g.clone_step(repository=repository, commit=valid_commit, verify=True), 'mkdir -p /tmp && cd /tmp && git clone https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd - && cd /tmp/hpc-container-maker && git checkout 23996b03b3e72f77a41498e94d90de920935644a && cd -') self.assertEqual(g.clone_step(repository=repository, commit=invalid_commit, verify=True), 'mkdir -p /tmp && cd /tmp && git clone https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd - && cd /tmp/hpc-container-maker && git checkout deadbeef && cd -') with self.assertRaises(RuntimeError): g.clone_step(repository=repository, branch=invalid_branch, verify='fatal') with self.assertRaises(RuntimeError): g.clone_step(repository=repository, commit=invalid_commit, verify='fatal')
def test_lfs(self): """Basic git""" g = git() self.assertEqual( g.clone_step( repository='https://github.com/NVIDIA/hpc-container-maker.git', lfs=True), 'mkdir -p /tmp && cd /tmp && git lfs clone --depth=1 https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd -' )
def test_opts(self): """git with non-default command line options""" g = git(opts=['--single-branch']) self.assertEqual( g.clone_step( repository='https://github.com/NVIDIA/hpc-container-maker.git' ), 'mkdir -p /tmp && cd /tmp && git clone --single-branch https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd -' )
def test_path(self): """git with non-default base path""" g = git() self.assertEqual( g.clone_step( repository='https://github.com/NVIDIA/hpc-container-maker.git', path='/scratch'), 'mkdir -p /scratch && cd /scratch && git clone --depth=1 https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd -' )
def test_directory(self): """git with non-default directory to clone into""" g = git() self.assertEqual( g.clone_step( repository='https://github.com/NVIDIA/hpc-container-maker.git', directory='hpccm'), 'mkdir -p /tmp && cd /tmp && git clone --depth=1 https://github.com/NVIDIA/hpc-container-maker.git hpccm && cd -' )
def install_alpaka(stage: hpccm.Stage): """Install alpaka 0.4 to /usr/local/include :param stage: the hpccm stage :type stage: hpccm.Stage """ cm = [] git_conf = git() cm.append( git_conf.clone_step( repository= 'https://github.com/ComputationalRadiationPhysics/alpaka', branch='release-0.4.0', path='/opt')) cm.append('cp -r /opt/alpaka/include/alpaka /usr/include/') cm.append('rm -rf /opt/alpaka') stage += shell(commands=cm)
def test_tag(self): """git with specified tag""" g = git() valid_tag='v20.5.0' invalid_tag='v-1.-2.-3' self.assertEqual(g.clone_step(repository='https://github.com/NVIDIA/hpc-container-maker.git', branch=valid_tag), 'mkdir -p /tmp && cd /tmp && git clone --depth=1 --branch v20.5.0 https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd -') self.assertEqual(g.clone_step(repository='https://github.com/NVIDIA/hpc-container-maker.git', branch=invalid_tag), 'mkdir -p /tmp && cd /tmp && git clone --depth=1 --branch v-1.-2.-3 https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd -') self.assertEqual(g.clone_step(repository='https://github.com/NVIDIA/hpc-container-maker.git', branch=valid_tag, verify='fatal'), 'mkdir -p /tmp && cd /tmp && git clone --depth=1 --branch v20.5.0 https://github.com/NVIDIA/hpc-container-maker.git hpc-container-maker && cd -') with self.assertRaises(RuntimeError): g.clone_step(repository='https://github.com/NVIDIA/hpc-container-maker.git', branch=invalid_tag, verify='fatal')
Stage0 += baseimage(image='ubuntu:16.04') # Base dependencies Stage0 += python() Stage0 += gnu() # Additional dependencies ospackages = [ 'autoconf', 'build-essential', 'bzip2', 'ca-certificates', 'coreutils', 'curl', 'environment-modules', 'git', 'gzip', 'libssl-dev', 'make', 'openssh-client', 'patch', 'pkg-config', 'tcl', 'tar', 'unzip', 'zlib1g' ] Stage0 += apt_get(ospackages=ospackages) # Setup and install Spack Stage0 += shell(commands=[ git().clone_step(repository='https://github.com/spack/spack', branch=spack_branch, path='/opt'), '/opt/spack/bin/spack bootstrap', 'ln -s /opt/spack/share/spack/setup-env.sh /etc/profile.d/spack.sh', 'ln -s /opt/spack/share/spack/spack-completion.bash /etc/profile.d' ]) Stage0 += environment(variables={'PATH': '/opt/spack/bin:$PATH'}) spack_package = USERARG.get('package', None) if spack_package: Stage0 += shell(commands=[ 'spack install {}'.format(spack_package), 'spack clean --all' ])
# PMI2 Stage0 += slurm_pmi2() # OpenMPI Stage0 += openmpi( cuda=False, infiniband=True, pmi='/usr/local/slurm-pmi2', ucx=False, version=openmpi_version) # OpenFOAM Stage0 += shell(commands=[ 'mkdir -p /opt/OpenFOAM', 'cd /opt/OpenFOAM', git().clone_step(repository='https://github.com/OpenFOAM/OpenFOAM-8.git', branch='master', path='/opt/OpenFOAM'), git().clone_step(repository='https://github.com/OpenFOAM/ThirdParty-8.git', branch='master', path='/opt/OpenFOAM'), r"sed -i '45,46s/^/# /g' /opt/OpenFOAM/OpenFOAM-8/etc/bashrc", r"sed -i 's@^export FOAM_INST_DIR=$HOME/$WM_PROJECT@# export FOAM_INST_DIR=$HOME/$WM_PROJECT@' /opt/OpenFOAM/OpenFOAM-8/etc/bashrc", r"sed -i 's@^# export FOAM_INST_DIR=/opt/$WM_PROJECT@export FOAM_INST_DIR=/opt/$WM_PROJECT@' /opt/OpenFOAM/OpenFOAM-8/etc/bashrc", r"sed -i '229s/^/# /g' /opt/OpenFOAM/OpenFOAM-8/etc/bashrc", ]) Stage0 += shell(commands=[ 'alias wmRefresh="echo blah"', #https://github.com/willgpaik/openfoam5_aci/blob/master/Singularity.of5x, https://github.com/hpcng/singularity/issues/4445 '. /opt/OpenFOAM/OpenFOAM-8/etc/bashrc FOAMY_HEX_MESH=yes', 'cd $WM_PROJECT_DIR', 'export QT_SELECT=qt5', './Allwmake -j 6 2>&1 | tee log.make', './Allwmake -j 6 2>&1 | tee log.make'
Stage0 += packages(ospackages=['ca-certificates', 'cmake', 'git']) ofed = ofed() Stage0 += ofed ompi = openmpi(configure_opts=['--enable-mpi-cxx'], parallel=32, prefix="/opt/openmpi", version='3.0.0') Stage0 += ompi cm = CMakeBuild() build_cmds = [ git().clone_step(repository='https://github.com/gromacs/gromacs', branch='v' + gromacs_version, path='/gromacs', directory='src'), cm.configure_step(directory='/gromacs/src', build_directory='/gromacs/build', opts=[ '-DCMAKE_BUILD_TYPE=Release', '-DCMAKE_INSTALL_PREFIX=/gromacs/install', '-DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda', '-DGMX_BUILD_OWN_FFTW=ON', '-DGMX_GPU=ON', '-DGMX_MPI=OFF', '-DGMX_OPENMP=ON', '-DGMX_PREFER_STATIC_LIBS=ON', '-DMPIEXEC_PREFLAGS=--allow-run-as-root', '-DREGRESSIONTEST_DOWNLOAD=ON' ]), cm.build_step(), cm.build_step(target='install'),
Stage0 += shell(commands=[ 'curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.rpm.sh | bash' ]) else: Stage0 += packages(ospackages=['software-properties-common']) Stage0 += shell(commands=[ 'cd ~', 'add-apt-repository ppa:git-core/ppa', 'curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash' ]) Stage0 += packages(ospackages=['git', 'git-lfs']) Stage0 += shell(commands=['git lfs install']) Stage0 += shell(commands=[ git().clone_step(repository=repo, branch=branch, path='/scif/apps/ogs', directory='src', lfs=centos), 'cd /scif/apps/ogs/src && git fetch --tags', 'mkdir -p /scif/apps/ogs/build', 'cd /scif/apps/ogs/build', ('CONAN_SYSREQUIRES_SUDO=0 CC=mpicc CXX=mpic++ cmake /scif/apps/ogs/src ' + '-DCMAKE_BUILD_TYPE=Release ' + '-DCMAKE_INSTALL_PREFIX=/scif/apps/ogs ' + '-DOGS_USE_PETSC=ON ' + '-DOGS_USE_CONAN=ON ' + '-DOGS_CONAN_USE_SYSTEM_OPENMPI=ON ' + cmake_args), 'make -j', 'make install' ], _app='ogs', _appenv=True) Stage0 += runscript(commands=['/scif/apps/ogs/bin/ogs "$@"'], _app='ogs') Stage0 += label(metadata={ 'REPOSITORY': repo,
Stage0 += baseimage(image='nvidia/cuda:9.0-devel-ubuntu16.04', _as=Stage0.name) Stage0 += packages( ospackages=['autoconf', 'automake', 'ca-certificates', 'cmake', 'git']) ofed = ofed() Stage0 += ofed ompi = openmpi(configure_opts=['--enable-mpi-cxx'], prefix='/opt/openmpi', parallel=32, version='3.0.0') Stage0 += ompi # build QUDA g = git() cm = CMakeBuild() quda_cmds = [ g.clone_step(repository='https://github.com/lattice/quda', branch='v0.8.0', path='/quda', directory='src'), cm.configure_step( directory='/quda/src', build_directory='/quda/build', opts=[ '-DCMAKE_BUILD_TYPE=RELEASE', '-DQUDA_DIRAC_CLOVER=ON', '-DQUDA_DIRAC_DOMAIN_WALL=ON', '-DQUDA_DIRAC_STAGGERED=ON', '-DQUDA_DIRAC_TWISTED_CLOVER=ON', '-DQUDA_DIRAC_TWISTED_MASS=ON', '-DQUDA_DIRAC_WILSON=ON', '-DQUDA_FORCE_GAUGE=ON', '-DQUDA_FORCE_HISQ=ON', '-DQUDA_GPU_ARCH={}'.format(gpu_arch),
"rm -rf libmkl*", "unset GLOBIGNORE"]) Stage0 += raw(docker='SHELL ["/bin/sh", "-c"]') Stage0 += workdir(directory='/opt/bigdft/build') Stage0 += shell(commands=['chmod -R 777 /opt/bigdft/build']) Stage0 += shell(commands=['mkdir /docker', 'chmod -R 777 /docker']) Stage0 += raw(docker='USER lsim') Stage0 += environment(variables={"LD_LIBRARY_PATH": "/usr/local/lib:/usr/local/cuda/lib64:${LD_LIBRARY_PATH}"}) Stage0 += environment(variables={"LIBRARY_PATH": "/usr/local/cuda/lib64:${LIBRARY_PATH}"}) Stage0 += environment(variables={"PYTHON": "python"}) Stage0 += shell(commands=[git().clone_step(repository='https://github.com/BigDFT-group/ContainerXP.git', directory='/docker')]) Stage0 += copy(src="./rcfiles/container.rc", dest="/tmp/container.rc") mpi = USERARG.get('mpi', 'ompi') #due to a bug in mvapich <= 2.3.2, aligned_alloc causes segfaults. Default to posix_memalign #if mpi in ["mvapich2", "mvapich"]: # Stage0 += shell(commands=['sed -i "s/AC_CHECK_FUNCS(\[aligned_alloc\])//g" ../../futile/configure.ac']) #hardcoded compilation for all supported cuda architectures as of cuda 11, as JIT is not supported everywhere yet (windows wsl) cuda_version=USERARG.get('cuda', '10').split(".",1)[0] cuda_gencodes = """-arch=sm_50 -gencode=arch=compute_35,code=sm_35 -gencode=arch=compute_37,code=sm_37 -gencode=arch=compute_50,code=sm_50 -gencode=arch=compute_52,code=sm_52 -gencode=arch=compute_60,code=sm_60 -gencode=arch=compute_61,code=sm_61 -gencode=arch=compute_70,code=sm_70""" if cuda_version == "10": cuda_gencodes += """ -gencode=arch=compute_75,code=sm_75 -gencode=arch=compute_75,code=compute_75""" elif cuda_version == "11":
def main(): parser = argparse.ArgumentParser( description= 'Simple script for generating a singularity recipe for the GOL example.' ) parser.add_argument( '--build_prefix', type=str, default='/tmp/GOL_example', help= 'Define the path in which all projects will be built (default: /tmp/GOL_example).' ) parser.add_argument('-v ', '--version', action='store_true', help='print version of the container') args = parser.parse_args() if args.version: print(container_version) sys.exit(0) hpccm.config.set_container_format('singularity') hpccm.config.set_singularity_version('3.3') stage = hpccm.Stage() stage += label(metadata={'GOL_MAINTAINER': 'Simeon Ehrig'}) stage += label(metadata={'GOL_EMAIL': '*****@*****.**'}) stage += label(metadata={'GOL_Version': str(container_version)}) # copy example inside container stage += copy(src='notebook', dest='/') stage += copy(src='jupyter_notebook_config.py', dest='/') # copy and build the pnwriter library stage += packages(ospackages=['libpng-dev']) png = [] png_git = git() png.append( png_git.clone_step( repository='https://github.com/pngwriter/pngwriter.git', branch='dev', path='/opt/')) png_cmake = CMakeBuild(prefix='/notebook/pngwriter') png.append( png_cmake.configure_step(directory='/opt/pngwriter', opts=['-DBUILD_SHARED_LIBS=ON'])) png.append(png_cmake.build_step(target='install')) png.append('rm -rf /opt/pngwriter') stage += shell(commands=png) # Copy notebook examples and pngwriter lib to the host's /tmp file system to obtain a writable file system. stage += runscript(commands=[ 'if [ ! -d /tmp/GOL-xeus-cling-cuda ]; then \n' ' mkdir /tmp/GOL-xeus-cling-cuda &&' ' cp -r /notebook/ /tmp/GOL-xeus-cling-cuda &&' ' ln -s /tmp/GOL-xeus-cling-cuda/notebook/pngwriter' ' /tmp/GOL-xeus-cling-cuda/notebook/GTC_presentations/simulation/ \n fi', 'cd /tmp/GOL-xeus-cling-cuda/notebook', 'jupyter-notebook --config=/jupyter_notebook_config.py' ]) # Add the bootstrap manually because hpccm does not support .sregistry, recipe = stage.__str__() recipe = 'Bootstrap: library\nFrom: sehrig/default/xeus-cling-cuda:2.3\n\n' + recipe print(recipe)
def add_alpaka_dep_layer(stage: hpccm.Stage, ubuntu_version: str, cuda_support: bool, extra_compiler: List[str], alpaka=False) -> bool: """Add all dependencies to an hpccm stage that are necessary to build and run Alpaka. :param stage: At least a baseimage :type stage: hpccm.Stage :param ubuntu_version: Ubuntu version number: '16.04' or '18.04' :type ubuntu_version: str :param cuda_support: Set True, if the Stage supports CUDA :type cuda_support: bool :param extra_compiler: List of compilers, which are installed additional to the system compiler. Supported are: gcc:[5-9], clang:[5.0-7.0, 8-9] :type extra_compiler: str :param alpaka: install alpaka in /usr/local :type alpaka: bool :returns: Returns True if function was successful :rtype: bool """ if ubuntu_version != '16.04' and ubuntu_version != '18.04': print('not supported Ubuntu version: ' + ubuntu_version, file=sys.stderr) print('supported are: 16.04, 18.04', file=sys.stderr) return False apt_package_list = [ 'gcc', 'g++', 'make', 'software-properties-common', 'wget', 'libc6-dev', 'libomp-dev', 'unzip', 'git' ] if ubuntu_version == '16.04': apt_package_list.append('gnupg-agent') if ubuntu_version == '18.04': apt_package_list.append('gpg-agent') stage += packages(ospackages=apt_package_list) stage += cmake(eula=True, version='3.16.0') # install extra compiler if extra_compiler is not None: for com in extra_compiler: if com.startswith('gcc'): stage += gnu(extra_repository=True, version=com[len('gcc:'):]) if com.startswith('clang'): add_clang(stage, ubuntu_version, version=com[len('clang:'):]) #install boost stage += shell( commands=['add-apt-repository -y ppa:mhier/libboost-latest']) stage += packages(ospackages=['boost1.67']) if cuda_support: stage += environment( variables={ 'LD_LIBRARY_PATH': '$LD_LIBRARY_PATH:/usr/local/cuda/lib64' }) # alpaka use a function direct from the cuda driver library # in the container, the cuda libraries are not at the default path stage += environment( variables={ 'LIBRARY_PATH': '$LIBRARY_PATH:/usr/local/cuda/lib64/stubs' }) stage += environment( variables={'CMAKE_PREFIX_PATH': '/usr/local/cuda/lib64/stubs/'}) if alpaka: git_alpaka = git() cmake_alpaka = CMakeBuild() alpaka_commands = [] alpaka_commands.append( git_alpaka.clone_step( repository='https://github.com/alpaka-group/alpaka.git', path='/opt')) alpaka_commands.append( cmake_alpaka.configure_step( build_directory='build', directory='/opt/alpaka', opts=['-Dalpaka_BUILD_EXAMPLES=OFF', '-DBUILD_TESTING=OFF'])) alpaka_commands.append(cmake_alpaka.build_step(target='install')) alpaka_commands.append('rm -rf /opt/alpaka') stage += shell(commands=alpaka_commands) return True
def test_missing_repo(self): """Missing repository option""" g = git() self.assertEqual(g.clone_step(), '')
'PYTHONPATH': '$PYTHONPATH:/usr/lib/python{}/site-packages:/usr/local/lib/python{}/dist-packages:/builds/gmxapi/build:/builds/sample_restraint/build/src/pythonmodule' .format(python_version, python_version), 'PATH': '$PATH:/usr/local/gromacs/bin' }) ################################################ # GROMACS ################################################ Stage0 += comment("GROMACS 2019") cm = CMakeBuild() build_cmds = [ git().clone_step(repository='https://github.com/gromacs/gromacs', branch='release-2019', path='/builds/gromacs', directory='src'), cm.configure_step(directory='/builds/gromacs/src', build_directory='/builds/gromacs/build', opts=[ '-DCMAKE_BUILD_TYPE=Release', '-DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda', '-DGMX_BUILD_OWN_FFTW=ON', '-DGMX_GPU={}'.format(gpu), '-DGMX_MPI=OFF', '-DGMX_OPENMP=ON', '-DGMXAPI=ON', '-DMPIEXEC_PREFLAGS=--allow-run-as-root' ]), cm.build_step(), cm.build_step(target='install'), cm.build_step(target='check') ]
'sed -i \'s|"FCFLAGS=-O2 -fPIC -fopenmp"| "FCFLAGS=-march=skylake-avx512 -O2 -fPIC -fopenmp"|g\' ./buildrc ', 'sed -i "s/CFLAGS=-fPIC -O2 -fopenmp/CFLAGS=-march=skylake-avx512 -fPIC -O2 -fopenmp/g" ./buildrc', 'sed -i "s|PYTHON=/usr/bin/python|PYTHON=python|g" ./buildrc', 'sed -i \'s/conditions.add\("python"\)//g\' ./buildrc' ]) Stage0 += shell(commands=[ '../Installer.py build -y -v', 'ls install/bin/bigdft', 'cp -r install/lib /usr/local/bigdft/lib/haswell/avx512_1' ]) Stage0 += workdir(directory='/home/lsim') Stage0 += shell(commands=[ git().clone_step( repository='https://github.com/BigDFT-group/ContainerXP.git', directory='/docker') ]) ####### ## Runtime image ####### cuda_version = USERARG.get('cuda', '10.0') if cuda_version == "8.0": ubuntu_version = "16.04" else: ubuntu_version = USERARG.get('ubuntu', '16.04') image = 'nvidia/cuda:{}-runtime-ubuntu{}'.format(cuda_version, ubuntu_version) Stage1.name = 'runtime' Stage1.baseimage(image)
def main(): parser = argparse.ArgumentParser( description= 'Simple script for generating a singularity recipe for the GOL exercise.' ) parser.add_argument( '--build_prefix', type=str, default='/tmp/GOL_example', help= 'Define the path in which all projects will be built (default: /tmp/GOL_example).' ) parser.add_argument('-j', type=str, help='number of build threads for make (default: -j)') parser.add_argument( '-l', type=str, help='number of linker threads for the cling build (default: -j)') parser.add_argument('-v ', '--version', action='store_true', help='print version of the container') args = parser.parse_args() if args.version: print(container_version) sys.exit(0) if args.j: threads = int(args.j) if threads < 1: raise ValueError('-j have to be greater than 0') else: threads = None if args.l: linker_threads = int(args.l) if linker_threads < 1: raise ValueError('-l have to be greater than 0') else: linker_threads = None xcc_gen = gn.XCC_gen(build_prefix=args.build_prefix, threads=threads, linker_threads=linker_threads) stage = xcc_gen.gen_release_single_stage() stage += label(metadata={'EXAMPLE_CONTAINER_MAINTAINER': 'Simeon Ehrig'}) stage += label(metadata={'EXAMPLE_CONTAINER_EMAIL': '*****@*****.**'}) stage += label( metadata={'EXAMPLE_CONTAINER_Version': str(container_version)}) # disable the xsrf check, which avoid some problems in Firefox stage += copy(src='jupyter_notebook_config.py', dest='/') # copy and build the pnwriter library stage += packages(ospackages=['libpng-dev']) png_git = git() stage += png_git.clone_step( repository='https://github.com/pngwriter/pngwriter.git', branch='dev', path='/opt/') png_cmake = CMakeBuild() stage += shell(commands=[ png_cmake.configure_step(directory='/opt/pngwriter', opts=['-DBUILD_SHARED_LIBS=ON']), png_cmake.build_step(target='install') ]) # copy and install jitify jitify_git = git() stage += jitify_git.clone_step( repository='https://github.com/NVIDIA/jitify.git', path='/opt/') png_cmake = CMakeBuild() stage += shell(commands=['cp /opt/jitify/jitify.hpp /usr/local/include']) stage += shell(commands=['rm -rf /opt/pngwriter', 'rm -rf /opt/jitify']) # check if the path to the notebook is specified, otherwise use the current directory stage += runscript(commands=[ 'if [ $# -gt 0 ]', 'then', 'cd $1', 'fi', 'jupyter-notebook --config=/jupyter_notebook_config.py' ]) print(stage.__str__())