Skip to content

Commit 0b4052f

Browse files
committed
cli: Simplify conan argument passing
BREAKING CHANGE: This fundamentally changes how cloe-launch parses arguments. They now have the form: cloe-launch [OPTS] COMMAND [CMD_OPTS] CONANFILE [CONAN_INSTALL_ARGS] [-- ARGS] For commands such as `shell` and `exec` it's now necessary to use `--` to pass arguments to them. It is also no longer possible to provide options to the cloe-launch command after specifying the conanfile. These now go to conan.
1 parent ab0250e commit 0b4052f

31 files changed

+785
-783
lines changed

Makefile.package

+2-2
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ smoketest:
307307
@for conanfile in ${TEST_CONANFILES}; do \
308308
test -f "$${conanfile}" || continue; \
309309
printf "Running BATS tests with conanfile: $${conanfile}\n\n"; \
310-
SHELL=/bin/bash ${CLOE_LAUNCH} shell -P "$${conanfile}" -- -c "source ${PROJECT_ROOT}/tests/setup_testname.bash; bats tests"; \
310+
SHELL=/bin/bash ${CLOE_LAUNCH} shell "$${conanfile}" ${CONAN_OPTIONS} -- -c "source ${PROJECT_ROOT}/tests/setup_testname.bash; bats tests"; \
311311
done
312312

313313
.PHONY: smoketest-deps
@@ -316,7 +316,7 @@ smoketest-deps:
316316
@for conanfile in ${TEST_CONANFILES}; do \
317317
test -f "$${conanfile}" || continue; \
318318
echo "Building dependencies for conanfile: $${conanfile}"; \
319-
${CLOE_LAUNCH} prepare -P "$${conanfile}" || exit 1; \
319+
${CLOE_LAUNCH} prepare "$${conanfile}" ${CONAN_OPTIONS} || break; \
320320
done
321321

322322
# CONFIGURATION TARGETS -------------------------------------------------------

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,9 @@ used.
125125
Once the `cloe-launch` tool is available, you can do one of the following:
126126
127127
1. Launch a shell with the environment adjusted:
128+
<!-- TODO: Update this example!! -->
128129
```console
129-
$ cloe-launch -v shell -P tests/conanfile_default.py
130+
$ cloe-launch -v shell tests/conanfile_default.py
130131
Source profile: tests/conanfile_default.py
131132
Profile name: 7745ffb0e036192c8e29a8b8cc2b9571e7a72c8c
132133
Configuration:
@@ -141,8 +142,9 @@ Once the `cloe-launch` tool is available, you can do one of the following:
141142
...
142143
```
143144
2. Launch `cloe-engine` directly:
145+
<!-- TODO: Update this example!! -->
144146
```console
145-
$ cloe-launch -v exec -P conanfile.py -- usage
147+
$ cloe-launch -v exec conanfile.py -- usage
146148
Source profile: tests/conanfile_default.py
147149
Profile name: 7745ffb0e036192c8e29a8b8cc2b9571e7a72c8c
148150
Configuration:

cli/Makefile

+2-14
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,12 @@ help:
2626
.PHONY: install
2727
install: export
2828
command -v ${PIP} >/dev/null 2>&1
29-
# Work-around pip confused by pyproject.toml
30-
-mv pyproject.toml pyproject.toml.bak
31-
${PIP} install ${PIP_INSTALL_ARGS} . || ( \
32-
mv pyproject.toml.bak pyproject.toml; \
33-
exit 1; \
34-
)
35-
mv pyproject.toml.bak pyproject.toml
29+
${PIP} install ${PIP_INSTALL_ARGS}
3630

3731
.PHONY: editable
3832
editable: export
3933
command -v ${PIP} >/dev/null 2>&1
40-
# Work-around pip confused by pyproject.toml
41-
-mv pyproject.toml pyproject.toml.bak
42-
${PIP} install -e ${PIP_INSTALL_ARGS} . || ( \
43-
mv pyproject.toml.bak pyproject.toml; \
44-
exit 1; \
45-
)
46-
mv pyproject.toml.bak pyproject.toml
34+
${PIP} install -e ${PIP_INSTALL_ARGS}
4735

4836
.PHONY: export
4937
export:

cli/README.md

+19-9
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,33 @@ pip. The easiest way is to just use the `Makefile`:
1010
```
1111
make install
1212
```
13-
If you want to install in editable mode, you unfortunately need to disable
14-
use of PEP-517 temporarily, which you can do by renaming `pyproject.toml`:
15-
```
16-
mv pyproject.toml{,.bak} && pipx install -e . && mv pyproject.toml{.bak,}
17-
```
18-
This is easiest with the `Makefile`, which automates the whole process:
13+
14+
## Usage
15+
1916
```
20-
make editable
17+
cloe-launch [-v] clean CONANFILE
18+
19+
cloe-launch [-v] prepare CONANFILE [CONAN_INSTALL_ARGS]
20+
21+
cloe-launch [-v] activate [-c] CONANFILE [CONAN_INSTALL_ARGS]
22+
cloe-launch -v activate -c tests/conanfile.py -o cloe-engine:server=True
23+
24+
cloe-launch [-v] deploy [-c] [-f] [-r] [-D PATH] CONANFILE [CONAN_INSTALL_ARGS]
25+
26+
cloe-launch [-v] exec [-c] [-e VAR] [-E] [-d] CONANFILE [CONAN_INSTALL_ARGS] -- [ENGINE_ARGS]
27+
28+
cloe-launch exec tests/conanfile.py -o cloe-engine:server=False -- -l debug run
29+
30+
cloe-launch [-v] shell [-c] [-e VAR] [-E] CONANFILE [CONAN_INSTALL_ARGS] -- [SHELL_ARGS]
31+
2132
```
2233

2334
## Design Considerations
2435

2536
The CLI interface to `cloe-engine` should do as little as possible and as much
2637
as necessary. The order of operations should be clear.
2738

28-
1. Convert YAML to JSON
39+
1. Convert YAML to JSON (not implemented yet)
2940
2. Relay STDIN and anonymous files
3041
3. Generate runtime environment from profile
3142
4. Run cloe-engine
@@ -42,7 +53,6 @@ and refining the module.py plugin configuration method.
4253
This is what still needs to be done:
4354

4455
- [ ] Merge with Cloe CLI
45-
- [ ] Replace profile with more generic solution
4656
- [ ] Finalize module.py design
4757
- [ ] Allow combination of multiple sources
4858

cli/cloe_launch/__init__.py

+18-76
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
import shutil
88
import subprocess
99

10-
from typing import List
11-
from typing import Optional
10+
from typing import (
11+
List,
12+
Optional,
13+
)
1214

1315
import toml
1416

@@ -23,7 +25,6 @@ class Configuration:
2325
config_dir = os.path.expanduser("~/.config/cloe/launcher/")
2426

2527
config_file = os.path.expanduser("~/.config/cloe/launcher/conf.toml")
26-
profiles_dir = os.path.join(config_dir, "profiles")
2728
runtime_dir = os.path.expanduser("~/.cache/cloe/launcher")
2829

2930
conf_version = "1"
@@ -38,20 +39,13 @@ class Configuration:
3839
},
3940
}
4041

41-
all_profiles: List[str] = []
42-
default_profile: Optional[str] = None
43-
current_profile = None
44-
45-
def __init__(self, profile: str = None):
42+
def __init__(self):
4643
# Make configuration and runtime directories if needed:
4744
if not os.path.exists(self.config_dir):
48-
logging.info("Create configuration directory:", self.config_dir)
45+
logging.info("Create configuration directory: %s", self.config_dir)
4946
os.makedirs(self.config_dir)
50-
if not os.path.exists(self.profiles_dir):
51-
logging.info("Create profile directory:", self.profiles_dir)
52-
os.makedirs(self.profiles_dir)
5347
if not os.path.exists(self.runtime_dir):
54-
logging.info("Create runtime directory:", self.runtime_dir)
48+
logging.info("Create runtime directory: %s", self.runtime_dir)
5549
os.makedirs(self.runtime_dir)
5650

5751
# Load configuration file:
@@ -63,76 +57,24 @@ def __init__(self, profile: str = None):
6357
)
6458
for k in conf.keys():
6559
self._conf[k] = conf[k]
66-
self.default_profile = self._conf["default_profile"]
67-
68-
# Read all profile names from profile directory
69-
self.all_profiles = [
70-
f
71-
for f in os.listdir(self.profiles_dir)
72-
if os.path.isfile(self.profile_path(f))
73-
]
74-
75-
# Set current profile
76-
if profile is not None:
77-
self.set_current(profile)
78-
elif self.default_profile is not None:
79-
self.set_current(self.default_profile)
80-
81-
def profile_path(self, profile: str) -> str:
82-
"""Return the path to named profile."""
83-
return os.path.join(self.profiles_dir, profile)
8460

85-
def profile_runtime(self, profile: str) -> str:
61+
def profile_runtime(self, hash: str) -> str:
8662
"""Return the path to the runtime directory of the profile."""
87-
return os.path.join(self.runtime_dir, profile)
63+
return os.path.join(self.runtime_dir, hash)
8864

89-
def set_current(self, profile: str) -> None:
90-
"""Set the current profile and make sure it exists."""
91-
self.current_profile = profile
92-
93-
def set_default(self, profile: str) -> None:
94-
"""Set the default profile and write it to the configuration."""
95-
if profile is not None and profile not in self.all_profiles:
96-
raise ConfigurationError(f"profile {profile} does not exist")
97-
self.default_profile = profile
98-
self._conf["default_profile"] = profile
65+
def write(self) -> None:
66+
"""Write current configuration to the disk."""
9967
logging.info(f"Write configuration to {self.config_file}:\n {self._conf}")
100-
with open(self.config_file, "w") as file:
68+
with open(self.config_file, "w", encoding="utf-8") as file:
10169
toml.dump(self._conf, file)
10270

103-
def read(self, profile: str) -> str:
104-
"""Read the specified profile."""
105-
logging.info("Open:", self.profile_path(profile))
106-
with open(self.profile_path(profile)) as file:
107-
return file.read()
108-
109-
def edit(self, profile: str, create: bool = False) -> None:
110-
"""Open the specified profile in the user's editor."""
71+
def edit(self, create: bool = False) -> None:
72+
"""Open the configuration in the user's editor."""
11173
editor = os.getenv("EDITOR")
11274
if editor is None:
11375
raise ConfigurationError("environment variable EDITOR is unset")
114-
if not create and not os.path.exists(self.profile_path(profile)):
115-
raise ConfigurationError(f"profile {profile} does not exist")
116-
cmd = [editor, self.profile_path(profile)]
117-
logging.info("Exec:", " ".join(cmd))
76+
if not create and not os.path.exists(self.config_file):
77+
raise ConfigurationError(f"configuration {self.config_file} does not exist")
78+
cmd = [editor, self.config_file]
79+
logging.info("Exec: %s", " ".join(cmd))
11880
subprocess.call(cmd)
119-
120-
def add(self, profile: str, file: str, force: bool = False) -> None:
121-
"""Add the file as a profile."""
122-
if profile in self.all_profiles and not force:
123-
raise ConfigurationError(
124-
f"cannot overwrite profile {profile} unless forced"
125-
)
126-
logging.debug("Copy: {} -> {}".format(file, self.profile_path(profile)))
127-
shutil.copyfile(file, self.profile_path(profile))
128-
if profile not in self.all_profiles:
129-
self.all_profiles.append(profile)
130-
131-
def remove(self, profile: str) -> None:
132-
"""Remove the profile, if it exists."""
133-
file = os.path.join(self.profiles_dir, profile)
134-
if os.path.exists(file):
135-
logging.info("Remove:", file)
136-
os.remove(file)
137-
if self.default_profile == profile:
138-
self.set_default(None)

0 commit comments

Comments
 (0)