Skip to content

Commit cefea02

Browse files
committed
fix(importers[tmuxinator]): Map pre to on_project_start instead of before_script
before_script calls run_before_script() which uses shlex.split + Popen(shell=False) — it expects a file path. tmuxinator pre is a raw shell command (e.g., pre: "mysql.server start"). Imported configs with raw commands crashed with BeforeLoadScriptNotExists. on_project_start uses run_hook_commands(shell=True) which handles raw shell commands correctly, matching tmuxinator's template.erb behavior where pre is emitted as a raw shell line.
1 parent 4094acf commit cefea02

6 files changed

Lines changed: 24 additions & 46 deletions

File tree

docs/cli/import.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ $ tmuxp import tmuxinator /path/to/file.json
8484

8585
The tmuxinator importer now supports:
8686

87-
- **Hook mapping**`pre` maps to `before_script`, `pre_window` maps to `shell_command_before`
87+
- **Hook mapping**`pre` maps to `on_project_start`, `pre_window` maps to `shell_command_before`
8888
- **CLI args**`cli_args` values (`-f`, `-S`, `-L`) are parsed into tmuxp config equivalents
8989
- **Synchronize**`synchronize` window key is converted
9090
- **Startup focus**`startup_window` / `startup_pane` convert to `focus: true`

src/tmuxp/workspace/importers.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -153,21 +153,16 @@ def import_tmuxinator(workspace_dict: dict[str, t.Any]) -> dict[str, t.Any]:
153153
if "tabs" in workspace_dict:
154154
workspace_dict["windows"] = workspace_dict.pop("tabs")
155155

156-
# Handle pre → before_script (independent of pre_window chain)
156+
# Handle pre → on_project_start (independent of pre_window chain)
157+
# tmuxinator's pre is a raw shell command emitted as a line in a bash script.
158+
# on_project_start uses run_hook_commands(shell=True) which handles raw commands.
159+
# before_script requires a file path and would crash on raw commands.
157160
if "pre" in workspace_dict:
158161
pre_val = workspace_dict["pre"]
159162
if isinstance(pre_val, list):
160-
if (
161-
workspace_dict.get("pre_window") is None
162-
and workspace_dict.get("pre_tab") is None
163-
):
164-
logger.info(
165-
"multi-command pre list mapped to before_script; "
166-
"consider splitting into before_script and shell_command_before",
167-
)
168-
tmuxp_workspace["before_script"] = "; ".join(pre_val)
163+
tmuxp_workspace["on_project_start"] = "; ".join(pre_val)
169164
else:
170-
tmuxp_workspace["before_script"] = pre_val
165+
tmuxp_workspace["on_project_start"] = pre_val
171166

172167
# Resolve shell_command_before using tmuxinator's exclusive precedence:
173168
# rbenv > rvm > pre_tab > pre_window (only ONE is selected)

tests/fixtures/import_tmuxinator/test2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"socket_name": "foo",
5050
"config": "~/.tmux.mac.conf",
5151
"start_directory": "~/test",
52-
"before_script": "sudo /etc/rc.d/mysqld start",
52+
"on_project_start": "sudo /etc/rc.d/mysqld start",
5353
"shell_command_before": ["rbenv shell 2.0.0-p247"],
5454
"windows": [
5555
{

tests/fixtures/import_tmuxinator/test3.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"socket_name": "foo",
5151
"start_directory": "~/test",
5252
"config": "~/.tmux.mac.conf",
53-
"before_script": "sudo /etc/rc.d/mysqld start",
53+
"on_project_start": "sudo /etc/rc.d/mysqld start",
5454
"shell_command_before": ["rbenv shell 2.0.0-p247"],
5555
"windows": [
5656
{

tests/fixtures/import_tmuxinator/test5.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
expected = {
2424
"session_name": "ruby-app",
2525
"start_directory": "~/projects/ruby-app",
26-
"before_script": "./scripts/bootstrap.sh",
26+
"on_project_start": "./scripts/bootstrap.sh",
2727
"shell_command_before": ["rvm use 2.1.1"],
2828
"windows": [
2929
{"window_name": "editor", "panes": ["vim"]},

tests/workspace/test_import_tmuxinator.py

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -96,23 +96,6 @@ def test_import_tmuxinator_logs_debug(
9696
assert getattr(records[0], "tmux_session", None) == "test"
9797

9898

99-
def test_logs_info_on_multi_command_pre_list(
100-
caplog: pytest.LogCaptureFixture,
101-
) -> None:
102-
"""Test that multi-command pre list logs info about before_script mapping."""
103-
workspace = {
104-
"name": "multi-pre",
105-
"root": "~/test",
106-
"pre": ["cmd1", "cmd2"],
107-
"windows": [{"editor": "vim"}],
108-
}
109-
with caplog.at_level(logging.INFO, logger="tmuxp.workspace.importers"):
110-
importers.import_tmuxinator(workspace)
111-
112-
pre_records = [r for r in caplog.records if "multi-command pre list" in r.message]
113-
assert len(pre_records) == 1
114-
115-
11699
def test_startup_window_sets_focus_by_name() -> None:
117100
"""Startup_window sets focus on the matching window by name."""
118101
workspace = {
@@ -473,15 +456,15 @@ def test_import_tmuxinator_socket_name_same_no_warning(
473456
assert len(warning_records) == 0
474457

475458

476-
def test_import_tmuxinator_pre_list_joined_for_before_script() -> None:
477-
"""List pre values are joined with '; ' so expand() doesn't crash."""
459+
def test_import_tmuxinator_pre_list_joined_for_on_project_start() -> None:
460+
"""List pre values are joined with '; ' for on_project_start."""
478461
workspace = {
479462
"name": "pre-list",
480463
"windows": [{"editor": "vim"}],
481464
"pre": ["echo one", "echo two"],
482465
}
483466
result = importers.import_tmuxinator(workspace)
484-
assert result["before_script"] == "echo one; echo two"
467+
assert result["on_project_start"] == "echo one; echo two"
485468

486469
# Verify it survives expand() without TypeError
487470
from tmuxp.workspace import loader
@@ -587,45 +570,45 @@ class PreWindowStandaloneFixture(t.NamedTuple):
587570
test_id: str
588571
config_extra: dict[str, t.Any]
589572
expect_shell_command_before: list[str] | None
590-
expect_before_script: str | None
573+
expect_on_project_start: str | None
591574

592575

593576
PRE_WINDOW_STANDALONE_FIXTURES: list[PreWindowStandaloneFixture] = [
594577
PreWindowStandaloneFixture(
595578
test_id="pre_window-only",
596579
config_extra={"pre_window": "echo PRE"},
597580
expect_shell_command_before=["echo PRE"],
598-
expect_before_script=None,
581+
expect_on_project_start=None,
599582
),
600583
PreWindowStandaloneFixture(
601584
test_id="pre_tab-only",
602585
config_extra={"pre_tab": "rbenv shell 3.0"},
603586
expect_shell_command_before=["rbenv shell 3.0"],
604-
expect_before_script=None,
587+
expect_on_project_start=None,
605588
),
606589
PreWindowStandaloneFixture(
607590
test_id="pre_window-list",
608591
config_extra={"pre_window": ["echo a", "echo b"]},
609592
expect_shell_command_before=["echo a; echo b"],
610-
expect_before_script=None,
593+
expect_on_project_start=None,
611594
),
612595
PreWindowStandaloneFixture(
613596
test_id="pre-and-pre_window",
614597
config_extra={"pre": "sudo start", "pre_window": "echo PRE"},
615598
expect_shell_command_before=["echo PRE"],
616-
expect_before_script="sudo start",
599+
expect_on_project_start="sudo start",
617600
),
618601
PreWindowStandaloneFixture(
619602
test_id="pre-and-pre_window-list",
620603
config_extra={"pre": "sudo start", "pre_window": ["cd /app", "nvm use 18"]},
621604
expect_shell_command_before=["cd /app; nvm use 18"],
622-
expect_before_script="sudo start",
605+
expect_on_project_start="sudo start",
623606
),
624607
PreWindowStandaloneFixture(
625608
test_id="pre-only",
626609
config_extra={"pre": "sudo start"},
627610
expect_shell_command_before=None,
628-
expect_before_script="sudo start",
611+
expect_on_project_start="sudo start",
629612
),
630613
]
631614

@@ -639,7 +622,7 @@ def test_import_tmuxinator_pre_window_standalone(
639622
test_id: str,
640623
config_extra: dict[str, t.Any],
641624
expect_shell_command_before: list[str] | None,
642-
expect_before_script: str | None,
625+
expect_on_project_start: str | None,
643626
) -> None:
644627
"""pre_window/pre_tab map to shell_command_before independently of pre."""
645628
workspace: dict[str, t.Any] = {
@@ -654,10 +637,10 @@ def test_import_tmuxinator_pre_window_standalone(
654637
else:
655638
assert "shell_command_before" not in result
656639

657-
if expect_before_script is not None:
658-
assert result.get("before_script") == expect_before_script
640+
if expect_on_project_start is not None:
641+
assert result.get("on_project_start") == expect_on_project_start
659642
else:
660-
assert "before_script" not in result
643+
assert "on_project_start" not in result
661644

662645

663646
class PreWindowPrecedenceFixture(t.NamedTuple):

0 commit comments

Comments
 (0)