Skip to content

Commit

Permalink
Improve biodynamo cli (#215)
Browse files Browse the repository at this point in the history
* Create build directory when using 'biodynamo new'

* Write output of build and run stage continously to stdout

* Add short 'bdm' command which is the same as 'biodynamo'
  • Loading branch information
LukasBreitwieser committed Oct 22, 2021
1 parent 18d45cd commit 2c1e9a9
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 123 deletions.
19 changes: 19 additions & 0 deletions cli/bdm.py
@@ -0,0 +1,19 @@
#!/usr/bin/env python3
# -----------------------------------------------------------------------------
#
# Copyright (C) 2021 CERN & Newcastle University for the benefit of the
# BioDynaMo collaboration. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
# See the LICENSE file distributed with this work for details.
# See the NOTICE file distributed with this work for additional information
# regarding copyright ownership.
#
# -----------------------------------------------------------------------------

from main import Main

if __name__ == "__main__":
Main()
80 changes: 2 additions & 78 deletions cli/biodynamo.py
Expand Up @@ -13,84 +13,8 @@
#
# -----------------------------------------------------------------------------

import argparse
import sys
from build_command import BuildCommand
from demo_command import DemoCommand
from new_command import NewCommand
from run_command import RunCommand
from bdm_version import Version
from main import Main

if __name__ == "__main__":
parser = argparse.ArgumentParser(
prog="biodynamo",
description="This is the BioDynaMo command line interface. It guides "
"you during the whole simulation workflow. From starting a new project,"
"to compiling and executing your simulation.",
epilog="",
)
Main()

sp = parser.add_subparsers(dest="cmd")
parser.add_argument("-v",
"--version",
action="store_true",
help="Display BioDynaMo version")
parser.add_argument("--shortversion",
action="store_true",
help="Display BioDynaMo short version")

build_sp = sp.add_parser("build", help="Builds the simulation binary")

clean_sp = sp.add_parser("clean", help="Removes all build files")

demo_sp = sp.add_parser("demo", help="Creates pre-built demos.")

new_sp = sp.add_parser(
"new",
help="Creates a new simulation project. Creates a template project, "
"renames it to the given simulation name, configures git.",
)
new_sp.add_argument("SIMULATION_NAME",
type=str,
help="simulation name help")
new_sp.add_argument("--github",
action="store_true",
help="Create a Github repository.")

run_sp = sp.add_parser("run", help="Executes the simulation")

args, unknown = parser.parse_known_args()

if args.cmd == "new":
if len(unknown) != 0:
new_sp.print_help()
sys.exit()
NewCommand(args.SIMULATION_NAME, args.github)
elif args.cmd == "build":
if len(unknown) != 0:
build_sp.print_help()
sys.exit()
BuildCommand()
elif args.cmd == "clean":
if len(unknown) != 0:
clean_sp.print_help()
sys.exit()
BuildCommand(clean=True, build=False)
elif args.cmd == "demo":
demo_name = None
destination = None
if len(unknown) >= 1:
demo_name = unknown[0]
if len(unknown) >= 2:
destination = unknown[1]
DemoCommand(demo_name, destination)
elif args.cmd == "run":
RunCommand(args=unknown)
elif args.version:
print(Version.string())
sys.exit()
elif args.shortversion:
print(Version.shortstring())
sys.exit()
else:
parser.print_help()
39 changes: 7 additions & 32 deletions cli/build_command.py
Expand Up @@ -16,60 +16,35 @@
import subprocess as sp
from pathlib import Path
from print_command import Print
from util import RunProcessAndWriteToStdOut


# The BioDynaMo CLI command to build a simulation binary.
def BuildCommand(clean=False, debug=False, build=True):
def BuildCommand(clean=False, build=True):
build_dir = "build"
debug_dir = "debug"

Print.new_step("Build")

if clean or debug:
if clean:
Print.new_step("Clean build directory")
sp.check_output(["rm", "-rf", build_dir])
sp.check_output(["mkdir", build_dir])
else:

elif build:
if not os.path.exists(build_dir):
sp.check_output(["mkdir", build_dir])

if debug:
if not os.path.exists(debug_dir):
sp.check_output(["mkdir", debug_dir])

with open(debug_dir + "/cmake_output.log", "w") as file:
try:
sp.check_call(["cmake", "-B./" + build_dir, "-H."],
stdout=file,
stderr=file)
except sp.CalledProcessError as err:
Print.error(
"Failed to run CMake. Generating debug/cmake_output.log..."
)
return

with open(debug_dir + "/make_output.log", "w") as file:
try:
sp.check_call(["make", "-C", build_dir],
stdout=file,
stderr=file)
except sp.CalledProcessError as err:
Print.error(
"Compilation failed. Generating debug/make_output.log...")
return

elif build:
# if CMakeCache.txt does not exist, run cmake
if not Path(build_dir + "/CMakeCache.txt").is_file():
try:
sp.check_output(["cmake", "-B./" + build_dir, "-H."])
RunProcessAndWriteToStdOut(["cmake", "-B./" + build_dir, "-H."])
except sp.CalledProcessError as err:
Print.error(
"Failed to run CMake. Check the debug output above.")
sys.exit(1)

try:
sp.check_output(["make", "-j4", "-C", build_dir])
RunProcessAndWriteToStdOut(["make", "-j4", "-C", build_dir])
except:
Print.error("Compilation failed. Check the debug output above.")
sys.exit(1)
97 changes: 97 additions & 0 deletions cli/main.py
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
# -----------------------------------------------------------------------------
#
# Copyright (C) 2021 CERN & Newcastle University for the benefit of the
# BioDynaMo collaboration. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
# See the LICENSE file distributed with this work for details.
# See the NOTICE file distributed with this work for additional information
# regarding copyright ownership.
#
# -----------------------------------------------------------------------------

import argparse
import sys
from build_command import BuildCommand
from demo_command import DemoCommand
from new_command import NewCommand
from run_command import RunCommand
from bdm_version import Version

def Main():
parser = argparse.ArgumentParser(
prog="biodynamo",
description="This is the BioDynaMo command line interface. It guides "
"you during the whole simulation workflow. From starting a new project,"
"to compiling and executing your simulation.",
epilog="",
)

sp = parser.add_subparsers(dest="cmd")
parser.add_argument("-v",
"--version",
action="store_true",
help="Display BioDynaMo version")
parser.add_argument("--shortversion",
action="store_true",
help="Display BioDynaMo short version")

build_sp = sp.add_parser("build", help="Builds the simulation binary")

clean_sp = sp.add_parser("clean", help="Removes all build files")

demo_sp = sp.add_parser("demo", help="Creates pre-built demos.")

new_sp = sp.add_parser(
"new",
help="Creates a new simulation project. Creates a template project, "
"renames it to the given simulation name, configures git.",
)
new_sp.add_argument("SIMULATION_NAME",
type=str,
help="simulation name help")
new_sp.add_argument("--github",
action="store_true",
help="Create a Github repository.")

run_sp = sp.add_parser("run", help="Executes the simulation")

args, unknown = parser.parse_known_args()

if args.cmd == "new":
if len(unknown) != 0:
new_sp.print_help()
sys.exit()
NewCommand(args.SIMULATION_NAME, args.github)
elif args.cmd == "build":
if len(unknown) != 0:
build_sp.print_help()
sys.exit()
BuildCommand()
elif args.cmd == "clean":
if len(unknown) != 0:
clean_sp.print_help()
sys.exit()
BuildCommand(clean=True, build=False)
elif args.cmd == "demo":
demo_name = None
destination = None
if len(unknown) >= 1:
demo_name = unknown[0]
if len(unknown) >= 2:
destination = unknown[1]
DemoCommand(demo_name, destination)
elif args.cmd == "run":
RunCommand(args=unknown)
elif args.version:
print(Version.string())
sys.exit()
elif args.shortversion:
print(Version.shortstring())
sys.exit()
else:
parser.print_help()

3 changes: 3 additions & 0 deletions cli/new_command.py
Expand Up @@ -102,6 +102,8 @@ def CustomizeFiles(sim_name):
Print.error("Error: File customizations failed")
CleanupOnError(sim_name)

def CreateBuildDir(build_dir):
sp.check_output(["mkdir", build_dir])

def NewCommand(sim_name, github):
if github:
Expand All @@ -114,6 +116,7 @@ def NewCommand(sim_name, github):
CopySupportFiles(sim_name)
CustomizeFiles(sim_name)
InitializeNewGitRepo(sim_name)
CreateBuildDir("{}/build".format(sim_name))
if github:
CreateNewGithubRepository(sim_name)

Expand Down
20 changes: 7 additions & 13 deletions cli/run_command.py
Expand Up @@ -17,33 +17,27 @@
from print_command import Print
from build_command import BuildCommand
from util import GetBinaryName
from util import RunProcessAndWriteToStdOut


## The BioDynaMo CLI command to run a simulation
##
## @param sim_name The simulation name
##
def RunCommand(args, debug=False):
def RunCommand(args):
sim_name = GetBinaryName()
args_str = " ".join(args)
cmd = "./build/" + sim_name
if platform.system() == "Darwin":
launcher = os.environ["BDMSYS"] + "/bin/launcher.sh"
else:
launcher = ""

try:
BuildCommand()
Print.new_step("Run " + sim_name + " " + args_str)
if debug:
sp.check_output(
[launcher + " " + cmd, "&>", "debug/runtime_output.log"])
if platform.system() == "Darwin":
launcher = os.environ["BDMSYS"] + "/bin/launcher.sh"
RunProcessAndWriteToStdOut([launcher, cmd, args_str])
else:
print(
sp.check_output([launcher + " " + cmd, args_str],
stderr=sp.STDOUT,
shell=True).decode("utf-8"))
Print.success("Finished successfully")
RunProcessAndWriteToStdOut([cmd, args_str])
Print.success("Finished successfully")
except sp.CalledProcessError as err:
print(err.output.decode("utf-8"))
Print.error("Error during execution of {0}".format(cmd))
14 changes: 14 additions & 0 deletions cli/util.py
Expand Up @@ -17,9 +17,23 @@
import re
import subprocess as sp
import sys
import select


def GetBinaryName():
with open("CMakeLists.txt") as f:
content = f.read()
return re.search("project\((.*)\)", content).group(1)

def RunProcessAndWriteToStdOut(cmd_args):
p = sp.Popen(cmd_args, stdout=sp.PIPE, stderr=sp.PIPE)

poll = select.poll()
poll.register(p.stdout)
poll.register(p.stderr)

while p.poll() is None:
rlist = poll.poll()
for fd, event in rlist:
sys.stdout.write(os.read(fd, 1024).decode('utf-8'))

7 changes: 7 additions & 0 deletions cmake/utils.cmake
Expand Up @@ -196,6 +196,13 @@ function(install_inside_build)
DEPENDS ${CMAKE_SOURCE_DIR}/cli/biodynamo.py
)
list(APPEND artifact_files_builddir ${CMAKE_INSTALL_BINDIR}/biodynamo)
# Copy bdm.py and make it executable.
add_custom_command(
OUTPUT ${CMAKE_INSTALL_BINDIR}/bdm
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/cli/bdm.py ${CMAKE_INSTALL_BINDIR}/bdm
DEPENDS ${CMAKE_SOURCE_DIR}/cli/bdm.py
)
list(APPEND artifact_files_builddir ${CMAKE_INSTALL_BINDIR}/bdm)

# Copy header files
add_copy_directory(copy_files_bdm
Expand Down

0 comments on commit 2c1e9a9

Please sign in to comment.