Skip to content

Commit

Permalink
Dangling branch
Browse files Browse the repository at this point in the history
  • Loading branch information
agyoungs committed Nov 15, 2024
1 parent d28dcd1 commit ad530c2
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 60 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
# importlib-metadata dependency can be removed when RHEL8 and other 3.6 based systems are not in support cycles

install_requires = [
'ConfigArgParse',
'empy',
'importlib-metadata; python_version < "3.8"',
'pexpect',
'packaging',
'urllib3',
'pyyaml',
]

# docker API used to be in a package called `docker-py` before the 2.0 release
Expand Down
27 changes: 12 additions & 15 deletions src/rocker/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import configargparse
import os
import sys
import yaml

from .core import DockerImageGenerator
from .core import get_rocker_version
Expand All @@ -28,15 +27,17 @@

def main():

parser = argparse.ArgumentParser(
parser = configargparse.ArgumentParser(
description='A tool for running docker with extra options',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
formatter_class=configargparse.ArgumentDefaultsHelpFormatter,
ignore_unknown_config_file_keys=False)
parser.add_argument('image')
parser.add_argument('command', nargs='*', default='')
parser.add_argument('--config', help='''Optional yaml file to handle command line arguments
(except positional args) as a config file. This config will override any other command line
arguments of the same name as the yaml keys (e.g. "--user-override-name" would have the key
"user_override_name" in the config file)''')
parser.add_argument('-c', '--config', is_config_file=True,
help='''Optional congig file to handle command line arguments (except positional args)
as a config file. Any setting in the config file will be overriden by the
command line arguments of the same name (e.g. '--user-override-name' would
override the key 'user_override_name' in the config file)''')
parser.add_argument('--noexecute', action='store_true', help='Deprecated')
parser.add_argument('--nocache', action='store_true')
parser.add_argument('--nocleanup', action='store_true', help='do not remove the docker container when stopped')
Expand All @@ -54,12 +55,8 @@ def main():

args = parser.parse_args()
args_dict = vars(args)

# Load config file if provided
if args.config:
with open(args.config, 'r') as f:
config = yaml.safe_load(f)
args_dict.update(config)
print(args)
print(args_dict)

if args.noexecute:
from .core import OPERATIONS_DRY_RUN
Expand All @@ -86,7 +83,7 @@ def main():


def detect_image_os():
parser = argparse.ArgumentParser(description='Detect the os in an image')
parser = configargparse.ArgumentParser(description='Detect the os in an image')
parser.add_argument('image')
parser.add_argument('--verbose', action='store_true',
help='Display verbose output of the process')
Expand Down
99 changes: 56 additions & 43 deletions src/rocker/ros_ws.py
Original file line number Diff line number Diff line change
@@ -1,68 +1,81 @@
import em
"""Extension for handling ROS workspaces in Rocker containers."""

import copy
import pkgutil
import getpass
import os
import tempfile
import xml.etree.ElementTree as ET
import pkgutil

import em
from vcstools import VcsClient

from rocker.core import get_user_name
from rocker.extensions import RockerExtension
from rocker.volume_extension import Volume
import tempfile
from vcstools import VcsClient
import xml.etree.ElementTree as ET
import yaml


class RosWs(RockerExtension):
"""
Extension for handling ROS workspaces in Rocker containers.
This extension enables mounting and building ROS workspaces inside Docker
containers, with support for dependency management and workspace
configuration.
"""

name = "ros_ws"

@classmethod
def get_name(cls):
"""Return the extension's name."""
return cls.name

def __init__(self):
"""Initialize the extension."""
self._env_subs = None
self.name = RosWs.get_name()

@staticmethod
def is_workspace_volume(workspace):
"""Check if the workspace is a valid volume."""
if os.path.isdir(os.path.expanduser(workspace)):
return True
else:
return False

def get_docker_args(self, cli_args):
"""
@param cli_args: {'volume': [[%arg%]]}
- 'volume' is fixed.
- %arg% can be:
- %path_host%: a path on the host. Same path will be populated in
the container.
- %path_host%:%path_cont%
- %path_host%:%path_cont%:%option%
"""
workspace = cli_args[self.name]
def get_docker_args(self, cliargs):
"""Get Docker arguments for mounting the workspace volume."""
workspace = cliargs[self.name]
if RosWs.is_workspace_volume(workspace):
args = Volume.get_volume_args([[os.path.expanduser(workspace) + ":" + os.path.join(RosWs.get_home_dir(cli_args), self.name, 'src')]])
args = Volume.get_volume_args(
[[os.path.expanduser(workspace) + ":" +
os.path.join(RosWs.get_home_dir(cliargs),
self.name, 'src')]])
return ' '.join(args)
else:
return ''

def precondition_environment(self, cli_args):
def precondition_environment(self, cliargs):
"""Prepare the environment before running the container."""
pass

def validate_environment(self, cli_args):
def validate_environment(self, cliargs):
"""Validate the environment before running the container."""
pass

def get_preamble(self, cli_args):
def get_preamble(self, cliargs):
"""Return the preamble for the Dockerfile."""
return ""

def get_files(self, cli_args):
def get_files_from_path(path, only_ros_pacakges=False, is_ros_package=False):
def get_files(self, cliargs):
"""Get the files to be included in the Docker build context."""
def get_files_from_path(path,
only_ros_pacakges=False,
is_ros_package=False):
if os.path.isdir(path):
if (
not os.path.basename(path) == ".git"
): # ignoring the .git directory allows the docker build context to cache the build context if the directories haven't been modified
# ignoring the .git directory allows the docker build context
# to cache the build context if the directories weren't modified
if (not os.path.basename(path) == ".git"):
if not is_ros_package:
is_ros_package = os.path.exists(os.path.join(path, 'package.xml'))
for basename in os.listdir(path):
Expand All @@ -89,7 +102,7 @@ def generate_ws_files(dir, only_ros_pacakges=False):
ws_files[filepath.replace(os.path.expanduser(dir), "ros_ws_src" + os.path.sep)] = f.read()
return ws_files

workspace = cli_args[self.name]
workspace = cliargs[self.name]
if self.is_workspace_volume(workspace):
return generate_ws_files(workspace, only_ros_pacakges=True)
else:
Expand All @@ -100,7 +113,7 @@ def generate_ws_files(dir, only_ros_pacakges=False):
raise ValueError("Workspace file not currently supported")

with tempfile.TemporaryDirectory() as td:
workspace_file = cli_args[self.name]
workspace_file = cliargs[self.name]
with open(workspace_file, "r") as f:
repos = yaml.safe_load(f)
for repo in repos:
Expand Down Expand Up @@ -157,32 +170,32 @@ def get_rosdeps(workspace):
return sorted(deps - src_packages)

@staticmethod
def get_home_dir(cli_args):
if cli_args["user"]:
def get_home_dir(cliargs):
if cliargs["user"]:
return os.path.join(os.path.sep, "home", get_user_name())
else:
return os.path.join(os.path.sep, "root")

def get_snippet(self, cli_args):
def get_snippet(self, cliargs):
args = {}
args["home_dir"] = RosWs.get_home_dir(cli_args)
args["rosdeps"] = RosWs.get_rosdeps(cli_args[self.name])
args["install_deps"] = cli_args["ros_ws_install_deps"]
args["home_dir"] = RosWs.get_home_dir(cliargs)
args["rosdeps"] = RosWs.get_rosdeps(cliargs[self.name])
args["install_deps"] = cliargs["ros_ws_install_deps"]

snippet = pkgutil.get_data(
"rocker",
"templates/{}_snippet.Dockerfile.em".format(self.name),
).decode("utf-8")
return em.expand(snippet, args)

def get_user_snippet(self, cli_args):
def get_user_snippet(self, cliargs):
args = {}
args["home_dir"] = RosWs.get_home_dir(cli_args)
args["rosdeps"] = RosWs.get_rosdeps(cli_args[self.name])
args["build_source"] = cli_args["ros_ws_build_source"]
args["install_deps"] = cli_args["ros_ws_install_deps"]
args["ros_master_uri"] = cli_args["ros_ws_ros_master_uri"]
args["build_tool_args"] = cli_args["ros_ws_build_tool_args"]
args["home_dir"] = RosWs.get_home_dir(cliargs)
args["rosdeps"] = RosWs.get_rosdeps(cliargs[self.name])
args["build_source"] = cliargs["ros_ws_build_source"]
args["install_deps"] = cliargs["ros_ws_install_deps"]
args["ros_master_uri"] = cliargs["ros_ws_ros_master_uri"]
args["build_tool_args"] = cliargs["ros_ws_build_tool_args"]

snippet = pkgutil.get_data(
"rocker",
Expand Down
2 changes: 1 addition & 1 deletion src/rocker/volume_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def get_volume_args(cls, volume_args):

for volume in volumes:
elems = volume.split(':')
host_dir = os.path.abspath(elems[0])
host_dir = os.path.abspath(os.path.expanduser(elems[0]))
if len(elems) == 1:
args.append('{0} {1}:{1}'.format(cls.ARG_DOCKER_VOLUME, host_dir))
elif len(elems) == 2:
Expand Down

0 comments on commit ad530c2

Please sign in to comment.