Repository: ros-tooling/cross_compile

Issue:
cross compile script fails on OSX
## Description
I am trying to follow the tutorial and build the [demos](https://github.com/ros2/demos.git) for AARCH64 under OSX. The script unfortunately does not go through and fails with a stacktrace.

### Expected Behavior
Script exits correctly and `build_aarch64` is created.

### Actual Behavior
i am running `ros_cross_compile --arch aarch64 --os ubuntu --rosdistro foxy .`, where `.` is the current workspace.

```
INFO:Rosdep Gatherer:Running rosdep collector image on workspace .
Traceback (most recent call last):
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/docker/api/client.py", line 222, in _raise_for_status
    response.raise_for_status()
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/models.py", line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: http+docker://localunixsocket/v1.30/containers/create

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/karsten/.pyenv/versions/3.7.4/bin/ros_cross_compile", line 8, in <module>
    sys.exit(main())
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/ros_cross_compile/ros_cross_compile.py", line 172, in main
    cross_compile_pipeline(args)
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/ros_cross_compile/ros_cross_compile.py", line 163, in cross_compile_pipeline
    custom_data_dir=custom_data_dir)
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/ros_cross_compile/dependencies.py", line 84, in gather_rosdeps
    volumes=volumes,
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/ros_cross_compile/docker_client.py", line 128, in run_container
    network_mode='host',
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/docker/models/containers.py", line 719, in run
    detach=detach, **kwargs)
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/docker/models/containers.py", line 777, in create
    resp = self.client.api.create_container(**create_kwargs)
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/docker/api/container.py", line 450, in create_container
    return self.create_container_from_config(config, name)
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/docker/api/container.py", line 461, in create_container_from_config
    return self._result(res, True)
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/docker/api/client.py", line 228, in _result
    self._raise_for_status(response)
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/docker/api/client.py", line 224, in _raise_for_status
    raise create_api_error_from_http_exception(e)
  File "/Users/karsten/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages/docker/errors.py", line 31, in create_api_error_from_http_exception
    raise cls(e, response=response, explanation=explanation)
docker.errors.APIError: 400 Client Error: Bad Request ("create .: volume name is too short, names should be at least two alphanumeric characters")
```

## System (please complete the following information)
 - OSX
 - ROS 2 Distro: Foxy


Discussion:

Patch:
diff --git a/ros_cross_compile/ros_cross_compile.py b/ros_cross_compile/ros_cross_compile.py
index 38fb475..b37fd01 100644
--- a/ros_cross_compile/ros_cross_compile.py
+++ b/ros_cross_compile/ros_cross_compile.py
@@ -137,7 +137,12 @@ def cross_compile_pipeline(
 ):
     platform = Platform(args.arch, args.os, args.rosdistro, args.sysroot_base_image)
 
-    ros_workspace_dir = Path(args.ros_workspace)
+    ros_workspace_dir = Path(args.ros_workspace).resolve()
+    if not (ros_workspace_dir / 'src').is_dir():
+        raise ValueError(
+            'Specified workspace "{}" does not look like a colcon workspace '
+            '(there is no "src/" directory). Cannot continue'.format(ros_workspace_dir))
+
     skip_rosdep_keys = args.skip_rosdep_keys
     custom_data_dir = _path_if(args.custom_data_dir)
     custom_rosdep_script = _path_if(args.custom_rosdep_script)


Test patch:
diff --git a/test/test_entrypoint.py b/test/test_entrypoint.py
index 9058cb2..07dde78 100644
--- a/test/test_entrypoint.py
+++ b/test/test_entrypoint.py
@@ -12,6 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import contextlib
+import os
 from pathlib import Path
 from unittest.mock import Mock
 from unittest.mock import patch
@@ -26,12 +28,47 @@ from ros_cross_compile.ros_cross_compile import cross_compile_pipeline
 from ros_cross_compile.ros_cross_compile import parse_args
 
 
+@contextlib.contextmanager
+def chdir(dirname: str):
+    """Provide a "with" statement for changing the working directory."""
+    curdir = os.getcwd()
+    try:
+        os.chdir(dirname)
+        yield
+    finally:
+        os.chdir(curdir)
+
+
 def test_trivial_argparse():
     args = parse_args(['somepath', '-a', 'aarch64', '-o', 'ubuntu'])
     assert args
 
 
+def test_bad_workspace(tmpdir):
+    args = parse_args([str(tmpdir), '-a', 'aarch64', '-o', 'ubuntu', '-d', 'foxy'])
+    with pytest.raises(ValueError):
+        cross_compile_pipeline(args)
+
+
+def test_relative_workspace(tmpdir):
+    # Change directory to the tmp dir and invoke using '.' as the
+    # workspace to check if relative paths work
+    tmp = Path(str(tmpdir))
+    (tmp / 'src').mkdir()
+    relative_dir = '.'
+    args = parse_args([relative_dir, '-a', 'aarch64', '-o', 'ubuntu', '-d', 'foxy'])
+    with chdir(str(tmp)), patch(
+        'ros_cross_compile.ros_cross_compile.DockerClient', Mock()
+    ), patch(
+        'ros_cross_compile.ros_cross_compile.assert_install_rosdep_script_exists'
+    ):
+        # should not raise an exception
+        cross_compile_pipeline(args)
+
+
 def test_mocked_cc_pipeline(tmpdir):
+    tmp = Path(str(tmpdir))
+    (tmp / 'src').mkdir()
     args = parse_args([str(tmpdir), '-a', 'aarch64', '-o', 'ubuntu'])
     with patch(
         'ros_cross_compile.ros_cross_compile.DockerClient', Mock()