Skip to content

Commit

Permalink
Merge pull request #146 from epics-containers/dev
Browse files Browse the repository at this point in the history
add dev namespace CLI commands
  • Loading branch information
gilesknap authored Nov 21, 2023
2 parents 85df497 + 100bf7d commit 3aafc4e
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 11 deletions.
6 changes: 6 additions & 0 deletions src/ibek/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from ruamel.yaml import YAML

from ibek._version import __version__
from ibek.dev_cmds.commands import dev_cli
from ibek.globals import NaturalOrderGroup
from ibek.ioc_cmds.commands import ioc_cli
from ibek.runtime_cmds.commands import runtime_cli
Expand All @@ -26,6 +27,11 @@
name="runtime",
help="Commands for building IOC instance startup files at container runtime",
)
cli.add_typer(
dev_cli,
name="dev",
help="Commands for working inside Generic IOC development containers",
)

yaml = YAML()

Expand Down
Empty file added src/ibek/dev_cmds/__init__.py
Empty file.
70 changes: 70 additions & 0 deletions src/ibek/dev_cmds/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import logging
import shutil
from pathlib import Path

import typer

from ibek.globals import CONFIG_DIR_NAME, IOC_DIR_NAME, IOC_FOLDER, NaturalOrderGroup
from ibek.ioc_cmds.assets import get_ioc_source

log = logging.getLogger(__name__)
dev_cli = typer.Typer(cls=NaturalOrderGroup)


@dev_cli.command()
def instance(
instance: Path = typer.Argument(
..., help="The filepath to the ioc instance entity file"
),
):
"""
Symlink an IOC instance config folder into /epics/ioc/config.
Used in the devcontainer to allow the IOC instance to be run using
/epics/ioc/starts.sh. Changes made to the config will be immediately
available and also under version control.
e.g. if instance is /repos/bl38p/iocs/bl38p-mo-panda-01 then we need:
- /epics/ioc -> /epics/ioc-pandablocks/ioc
- /epics/ioc/config -> /repos/bl38p/iocs/bl38p-mo-panda-01/config
"""
# validate the instance folder has a config folder

generic_root = get_ioc_source()
ioc_folder = generic_root / IOC_DIR_NAME
config_folder = ioc_folder / CONFIG_DIR_NAME
instance_config = instance / CONFIG_DIR_NAME

if not instance_config.exists():
log.error(f"Could not find config folder {instance_config}")
raise typer.Exit(1)

# First make sure there is an ioc folder in the generic IOC source root
# and that it is symlinked from /epics/ioc, remove any existing config.
if not ioc_folder.exists():
ioc_folder.mkdir()

# remove any existing config folder and ioc symlink from /epics/ioc
for folder in [config_folder, IOC_FOLDER]:
if folder.is_symlink():
folder.unlink()
if folder.exists():
shutil.rmtree(folder)

IOC_FOLDER.symlink_to(ioc_folder)

# Now symlink the instance config folder into the generic IOC source root
config_folder.symlink_to(instance_config)


@dev_cli.command()
def support(
module: Path = typer.Argument(
..., help="The filepath to the support module to work on"
),
):
"""
enable a support module for development.
"""

raise NotImplementedError
2 changes: 2 additions & 0 deletions src/ibek/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
EPICS_ROOT = Path(os.getenv("EPICS_ROOT", "/epics/"))
IOC_FOLDER = Path(os.getenv("IOC", "/epics/ioc"))
SUPPORT = Path(os.getenv("SUPPORT", "/epics/support"))
CONFIG_DIR_NAME = "config"
IOC_DIR_NAME = "ioc"

# the global RELEASE file which lists all support modules
RELEASE = SUPPORT / "configure/RELEASE"
Expand Down
26 changes: 17 additions & 9 deletions src/ibek/ioc_cmds/assets.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
import os
import shutil
import subprocess
Expand All @@ -8,6 +9,8 @@

from ibek.globals import EPICS_ROOT, IBEK_DEFS, IOC_FOLDER, PVI_DEFS

log = logging.getLogger(__name__)


def get_ioc_source() -> Path:
"""
Expand All @@ -19,17 +22,22 @@ def get_ioc_source() -> Path:
Functions that use this should provide an override variable that allows
the ibek caller to specify the location.
"""
try:
ibek_support = (
list(EPICS_ROOT.glob("*/ibek-support"))
or list(Path("..").glob("/**/ibek-support"))
)[0]
except IndexError:
raise RuntimeError(
"Could NOT find a suitable location for the IOC source folder. "
ibek_supports = list(EPICS_ROOT.glob("*/ibek-support"))

if len(ibek_supports) > 1:
log.error(
"Found more than one ibek-support folder. "
"ibek must be run in a container a single generic IOC source folder"
)
raise typer.Exit(1)
elif len(ibek_supports) == 0:
log.error(
"Could NOT find a generic IOC source folder containing ibek-support. "
"ibek must be run in a container with the generic IOC source folder"
)
return (ibek_support / "..").resolve()
raise typer.Exit(1)

return (ibek_supports[0] / "..").resolve()


def move_file(src: Path, dest: Path, binary: List[str]):
Expand Down
8 changes: 6 additions & 2 deletions src/ibek/ioc_cmds/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,14 @@ def make_source_template(
if destination is None:
destination = get_ioc_source() / "ioc"

if not destination.exists():
# use a known file to check if the destination is already an IOC
# because an empty folder can be created by 'ibek dev instance'
dest_release = destination / "configure" / "RELEASE"

if not dest_release.exists():
if destination.is_symlink():
destination.unlink()
shutil.copytree(TEMPLATES / "ioc", destination)
shutil.copytree(TEMPLATES / "ioc", destination, dirs_exist_ok=True)

# make a symlink to the ioc folder in the root of the epics folder
# this becomes the standard place for code to look for the IOC
Expand Down

0 comments on commit 3aafc4e

Please sign in to comment.