mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
fix(cli): only name an installer that is actually there
`update` hands off to install.sh (install.ps1 on Windows) and prints the command
to run. It built that command from cbm_detect_self_path - the BINARY's directory
- and treated "I resolved my own location" as "the installer is beside me".
Those are different questions. install.sh is placed beside the binary by
install.sh itself, but a binary that was moved, packaged by a distro, or built
from source has no installer next to it. We printed the path anyway:
bash "/home/<user>/.local/bin/install.sh"
/usr/bin/bash: /home/<user>/.local/bin/install.sh: No such file or directory
Reported on discussion #1560 (#1632) by a user who was already three releases
deep in install trouble and had just been told, by us, to run a file that does
not exist.
`update` exists to tell someone how to proceed. Ending the interaction on a
command that cannot run is the one outcome it must not produce - and the
fallback text was already there and already correct, naming install.sh as
shipping in the release archive without asserting a path.
The probe goes through cbm_path_info_utf8 so a non-ASCII install directory
resolves on Windows, and rejects a DIRECTORY of that name, because `bash <dir>`
is not a command either. A symlink still counts: it is reported rather than
followed, and the shell runs it perfectly well.
The Windows branch gets the same treatment; it had the identical assumption
about install.ps1.
Reproduce-first and revert-checked: with the probe forced to return true - the
old behaviour - the new test fails with "a directory with no installer must not
be named as one", and passes once it is restored. cli: 276 passed.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
1 parent
6ecbc5f046
commit
d58962c010
3 files changed
+90
No files matched your search
@@ -11972,6 +11972,36 @@ static bool check_already_latest(void) {
|
||||
|
||||
#endif /* CBM_CLI_ENABLE_TEST_API */
|
||||
|
||||
/* Is the installer script actually present beside the binary? (#1632)
|
||||
*
|
||||
* `update` hands off to install.sh / install.ps1 and prints the command to run.
|
||||
* It derived that path from the binary's own location, which is not the same
|
||||
* question: the installer is placed beside the binary by install.sh, but a
|
||||
* binary moved, packaged, or built from source has no installer next to it, and
|
||||
* we still printed the path. The user's session then ended on a command that
|
||||
* cannot run.
|
||||
*
|
||||
* Checked with cbm_path_info_utf8 so a non-ASCII install path resolves on
|
||||
* Windows. A symlink counts: it is reported rather than followed, and the shell
|
||||
* will run it perfectly well. */
|
||||
bool cbm_cli_installer_beside_binary(const char *dir) {
|
||||
if (!dir || !dir[0]) {
|
||||
return false;
|
||||
}
|
||||
char script[CLI_BUF_1K];
|
||||
#ifdef _WIN32
|
||||
const char *name = "install.ps1";
|
||||
#else
|
||||
const char *name = "install.sh";
|
||||
#endif
|
||||
int written = snprintf(script, sizeof(script), "%s/%s", dir, name);
|
||||
if (written <= 0 || (size_t)written >= sizeof(script)) {
|
||||
return false;
|
||||
}
|
||||
cbm_path_info_t info;
|
||||
return cbm_path_info_utf8(script, &info) == 0 && !info.is_directory;
|
||||
}
|
||||
|
||||
int cbm_cmd_update(int argc, char **argv) {
|
||||
parse_auto_answer(argc, argv);
|
||||
|
||||
|
||||
@@ -482,6 +482,12 @@ int cbm_cmd_uninstall(int argc, char **argv);
|
||||
|
||||
/* update: check latest release, prompt for index deletion, prompt for ui/standard,
|
||||
* download and replace binary. */
|
||||
/* True when the installer script (install.sh / install.ps1 on Windows) is
|
||||
* present beside the binary. `update` prints a command built from this;
|
||||
* naming a path that does not exist ends the interaction on a failing
|
||||
* command (#1632). Exposed for testing. */
|
||||
bool cbm_cli_installer_beside_binary(const char *dir);
|
||||
|
||||
int cbm_cmd_update(int argc, char **argv);
|
||||
|
||||
/* config: get/set/list/reset runtime config values. */
|
||||
|
||||
@@ -12636,7 +12636,61 @@ TEST(cli_windows_update_hands_off_to_install_script) {
|
||||
* Suite definition
|
||||
* ═══════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* #1632: `update` derives the installer command from the BINARY's directory,
|
||||
* which is not the same question as "is the installer there". A binary in
|
||||
* ~/.local/bin with no install.sh beside it still produced:
|
||||
*
|
||||
* bash "/home/<user>/.local/bin/install.sh"
|
||||
* /usr/bin/bash: .../install.sh: No such file or directory
|
||||
*
|
||||
* reported on discussion #1560 by a user already three releases deep in install
|
||||
* trouble. `update` exists to tell someone how to proceed; ending on a command
|
||||
* that cannot run is the one outcome it must not produce. */
|
||||
TEST(cli_update_only_names_an_installer_that_exists_issue1632) {
|
||||
char tmpdir[256];
|
||||
snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-installer-probe-XXXXXX");
|
||||
if (!cbm_mkdtemp(tmpdir)) {
|
||||
FAIL("cbm_mkdtemp failed");
|
||||
}
|
||||
#ifdef _WIN32
|
||||
const char *installer = "install.ps1";
|
||||
#else
|
||||
const char *installer = "install.sh";
|
||||
#endif
|
||||
|
||||
/* A directory holding the binary but no installer must not be advertised. */
|
||||
bool absent_is_refused = !cbm_cli_installer_beside_binary(tmpdir);
|
||||
|
||||
char script[512];
|
||||
snprintf(script, sizeof(script), "%s/%s", tmpdir, installer);
|
||||
write_test_file(script, "#!/bin/sh\nexit 0\n");
|
||||
bool present_is_accepted = cbm_cli_installer_beside_binary(tmpdir);
|
||||
|
||||
/* A directory of that name must not count: `bash <dir>` is not a command. */
|
||||
char decoy[512];
|
||||
snprintf(decoy, sizeof(decoy), "%s/decoy", tmpdir);
|
||||
test_mkdirp(decoy);
|
||||
char decoy_installer[640];
|
||||
snprintf(decoy_installer, sizeof(decoy_installer), "%s/%s", decoy, installer);
|
||||
test_mkdirp(decoy_installer);
|
||||
bool directory_is_refused = !cbm_cli_installer_beside_binary(decoy);
|
||||
|
||||
bool empty_is_refused = !cbm_cli_installer_beside_binary("");
|
||||
test_rmdir_r(tmpdir);
|
||||
|
||||
if (!absent_is_refused)
|
||||
FAIL("a directory with no installer must not be named as one");
|
||||
if (!present_is_accepted)
|
||||
FAIL("an installer that is present must be named");
|
||||
if (!directory_is_refused)
|
||||
FAIL("a DIRECTORY named install.sh is not a runnable installer");
|
||||
if (!empty_is_refused)
|
||||
FAIL("an empty directory string must be refused");
|
||||
PASS();
|
||||
}
|
||||
|
||||
SUITE(cli) {
|
||||
RUN_TEST(cli_update_only_names_an_installer_that_exists_issue1632);
|
||||
RUN_TEST(cli_progress_visibility_policy);
|
||||
RUN_TEST(cli_raw_mcp_result_preserves_tool_error_status);
|
||||
RUN_TEST(cli_maintenance_cancellation_forces_failure_status);
|
||||
|
||||
Reference in new issue
Block a user