diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-25 03:20:08 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-25 03:33:09 +0900 |
| commit | c65cab710bb3d79db20862c9361d4dbbac8ac5d7 (patch) | |
| tree | b4d192237bbb8dbaa80166f1ffa24703e57243f4 /crates/shirabe | |
| parent | f73e9ab05f8d94937d2437919199d9d9681c8cde (diff) | |
| download | php-shirabe-c65cab710bb3d79db20862c9361d4dbbac8ac5d7.tar.gz php-shirabe-c65cab710bb3d79db20862c9361d4dbbac8ac5d7.tar.zst php-shirabe-c65cab710bb3d79db20862c9361d4dbbac8ac5d7.zip | |
feat(php-shim): model $_ENV/$_SERVER as OsString snapshots
Rework the environment shim around getenv/putenv on the real environment
and $_ENV/$_SERVER as startup snapshots, all over OsString. Migrate every
caller off the old server()/server_argv() helpers and force the snapshots
in main() before any putenv() runs. Document the porting rules in
docs/dev/env-vars-porting.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe')
| -rw-r--r-- | crates/shirabe/src/autoload/autoload_generator.rs | 7 | ||||
| -rw-r--r-- | crates/shirabe/src/command/init_command.rs | 52 | ||||
| -rw-r--r-- | crates/shirabe/src/console/application.rs | 28 | ||||
| -rw-r--r-- | crates/shirabe/src/main.rs | 7 | ||||
| -rw-r--r-- | crates/shirabe/src/util/platform.rs | 32 | ||||
| -rw-r--r-- | crates/shirabe/tests/command/init_command_test.rs | 14 | ||||
| -rw-r--r-- | crates/shirabe/tests/config_test.rs | 6 | ||||
| -rw-r--r-- | crates/shirabe/tests/util/ini_helper_test.rs | 10 |
8 files changed, 107 insertions, 49 deletions
diff --git a/crates/shirabe/src/autoload/autoload_generator.rs b/crates/shirabe/src/autoload/autoload_generator.rs index 7b02841..ded7cee 100644 --- a/crates/shirabe/src/autoload/autoload_generator.rs +++ b/crates/shirabe/src/autoload/autoload_generator.rs @@ -148,7 +148,12 @@ impl AutoloadGenerator { if self.run_scripts { // set COMPOSER_DEV_MODE in case not set yet so it is available in the dump-autoload event listeners - if shirabe_php_shim::server_get("COMPOSER_DEV_MODE").is_none() { + if shirabe_php_shim::PHP_SERVER + .lock() + .unwrap() + .get("COMPOSER_DEV_MODE") + .is_none() + { Platform::put_env( "COMPOSER_DEV_MODE", if self.dev_mode.unwrap_or(false) { diff --git a/crates/shirabe/src/command/init_command.rs b/crates/shirabe/src/command/init_command.rs index 9683b89..557ebca 100644 --- a/crates/shirabe/src/command/init_command.rs +++ b/crates/shirabe/src/command/init_command.rs @@ -10,11 +10,11 @@ use shirabe_external_packages::symfony::console::input::ArrayInput; use shirabe_external_packages::symfony::console::input::InputInterface; use shirabe_external_packages::symfony::console::output::OutputInterface; use shirabe_php_shim::{ - FILE_IGNORE_NEW_LINES, InvalidArgumentException, PHP_EOL, PhpMixed, array_filter, array_flip, - array_flip_strings, array_intersect_key, array_keys, array_map, basename, empty, explode, file, - file_exists, file_get_contents, file_put_contents, function_exists, get_current_user, implode, - is_dir, is_string, preg_quote, realpath, server_get, sprintf, str_replace, strpos, strtolower, - trim, ucwords, + FILE_IGNORE_NEW_LINES, InvalidArgumentException, PHP_EOL, PHP_SERVER, PhpMixed, array_filter, + array_flip, array_flip_strings, array_intersect_key, array_keys, array_map, basename, empty, + explode, file, file_exists, file_get_contents, file_put_contents, function_exists, + get_current_user, implode, is_dir, is_string, preg_quote, realpath, sprintf, str_replace, + strpos, strtolower, trim, ucwords, }; use shirabe_spdx_licenses::SpdxLicenses; use std::cell::RefCell; @@ -723,7 +723,11 @@ impl Command for InitCommand { .as_string() .map(|s| s.to_string()); if license.is_none() { - let default_license = server_get("COMPOSER_DEFAULT_LICENSE"); + let default_license = PHP_SERVER + .lock() + .unwrap() + .get("COMPOSER_DEFAULT_LICENSE") + .map(|value| value.to_string_lossy().into_owned()); if !empty( &default_license .clone() @@ -1163,7 +1167,21 @@ impl InitCommand { let name = self.sanitize_package_name_component(&name); let mut vendor = name.clone(); - let composer_default_vendor = server_get("COMPOSER_DEFAULT_VENDOR"); + let composer_default_vendor = PHP_SERVER + .lock() + .unwrap() + .get("COMPOSER_DEFAULT_VENDOR") + .map(|value| value.to_string_lossy().into_owned()); + let server_username = PHP_SERVER + .lock() + .unwrap() + .get("USERNAME") + .map(|value| value.to_string_lossy().into_owned()); + let server_user = PHP_SERVER + .lock() + .unwrap() + .get("USER") + .map(|value| value.to_string_lossy().into_owned()); if !empty( &composer_default_vendor .clone() @@ -1174,19 +1192,19 @@ impl InitCommand { } else if git.contains_key("github.user") { vendor = git.get("github.user").cloned().unwrap_or_default(); } else if !empty( - &server_get("USERNAME") + &server_username .clone() .map(PhpMixed::String) .unwrap_or(PhpMixed::Null), ) { - vendor = server_get("USERNAME").unwrap_or_default(); + vendor = server_username.unwrap_or_default(); } else if !empty( - &server_get("USER") + &server_user .clone() .map(PhpMixed::String) .unwrap_or(PhpMixed::Null), ) { - vendor = server_get("USER").unwrap_or_default(); + vendor = server_user.unwrap_or_default(); } else if !get_current_user().is_empty() { vendor = get_current_user(); } @@ -1200,7 +1218,11 @@ impl InitCommand { let git = self.get_git_config(); let mut author_name: Option<String> = None; - let composer_default_author = server_get("COMPOSER_DEFAULT_AUTHOR"); + let composer_default_author = PHP_SERVER + .lock() + .unwrap() + .get("COMPOSER_DEFAULT_AUTHOR") + .map(|value| value.to_string_lossy().into_owned()); if !empty( &composer_default_author .clone() @@ -1213,7 +1235,11 @@ impl InitCommand { } let mut author_email: Option<String> = None; - let composer_default_email = server_get("COMPOSER_DEFAULT_EMAIL"); + let composer_default_email = PHP_SERVER + .lock() + .unwrap() + .get("COMPOSER_DEFAULT_EMAIL") + .map(|value| value.to_string_lossy().into_owned()); if !empty( &composer_default_email .clone() diff --git a/crates/shirabe/src/console/application.rs b/crates/shirabe/src/console/application.rs index 251fc67..319e8dd 100644 --- a/crates/shirabe/src/console/application.rs +++ b/crates/shirabe/src/console/application.rs @@ -1402,7 +1402,10 @@ impl Application { input.borrow_mut().set_interactive(false); } - let mut shell_verbosity = shirabe_php_shim::getenv("SHELL_VERBOSITY").unwrap_or_default(); + let shell_verbosity = shirabe_php_shim::getenv("SHELL_VERBOSITY") + .unwrap_or_default() + .to_string_lossy() + .into_owned(); let shell_verbosity_int: i64 = shell_verbosity.parse().unwrap_or(0); let mut shell_verbosity: i64 = shell_verbosity_int; match shell_verbosity_int { @@ -1500,10 +1503,16 @@ impl Application { } if shirabe_php_shim::function_exists("putenv") { - shirabe_php_shim::putenv(&format!("SHELL_VERBOSITY={}", shell_verbosity)); + unsafe { shirabe_php_shim::putenv("SHELL_VERBOSITY", shell_verbosity.to_string()) }; } - shirabe_php_shim::env_set("SHELL_VERBOSITY", shell_verbosity.to_string()); - shirabe_php_shim::server_set("SHELL_VERBOSITY", shell_verbosity.to_string()); + shirabe_php_shim::PHP_ENV + .lock() + .unwrap() + .put("SHELL_VERBOSITY".into(), shell_verbosity.to_string().into()); + shirabe_php_shim::PHP_SERVER + .lock() + .unwrap() + .put("SHELL_VERBOSITY".into(), shell_verbosity.to_string().into()); let _ = &mut shell_verbosity; @@ -2285,7 +2294,12 @@ impl ApplicationHandle { { io.write_error(&format!( "<warning>Warning: This development build of Composer is over 60 days old. It is recommended to update it by running \"{} self-update\" to get the latest version.</warning>", - shirabe_php_shim::server_get("PHP_SELF").unwrap_or_default(), + shirabe_php_shim::PHP_SERVER + .lock() + .unwrap() + .get("PHP_SELF") + .unwrap_or_default() + .to_string_lossy(), )); } @@ -2598,8 +2612,8 @@ impl ApplicationHandle { let app = application.borrow(); (app.terminal.get_height(), app.terminal.get_width()) }; - shirabe_php_shim::putenv(&format!("LINES={}", height)); - shirabe_php_shim::putenv(&format!("COLUMNS={}", width)); + unsafe { shirabe_php_shim::putenv("LINES", height.to_string()) }; + unsafe { shirabe_php_shim::putenv("COLUMNS", width.to_string()) }; } let input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>> = match input { diff --git a/crates/shirabe/src/main.rs b/crates/shirabe/src/main.rs index 3e3623d..538d89d 100644 --- a/crates/shirabe/src/main.rs +++ b/crates/shirabe/src/main.rs @@ -1,8 +1,13 @@ //! ref: composer/bin/composer -use shirabe_php_shim::run_shutdown_functions; +use shirabe_php_shim::{PHP_ENV, PHP_SERVER, run_shutdown_functions}; fn main() { + // Take the $_ENV / $_SERVER snapshots before any putenv() mutates the real environment. + // See `docs/dev/env-vars-porting.md` for details. + std::sync::LazyLock::force(&PHP_ENV); + std::sync::LazyLock::force(&PHP_SERVER); + let result = shirabe::run(std::env::args().collect()); run_shutdown_functions(); let mut exit_code = match result { diff --git a/crates/shirabe/src/util/platform.rs b/crates/shirabe/src/util/platform.rs index 72fe5f9..889da6e 100644 --- a/crates/shirabe/src/util/platform.rs +++ b/crates/shirabe/src/util/platform.rs @@ -5,11 +5,11 @@ use std::sync::Mutex; use anyhow::Result; use shirabe_external_packages::composer::pcre::Preg; use shirabe_php_shim::{ - PhpMixed, PhpResource, RuntimeException, defined, env_contains_key, env_get, env_set, - env_unset, file_exists, file_get_contents, fstat, function_exists, getcwd, getenv, in_array, - ini_get, is_array, is_readable, mb_strlen, php_os_family, posix_geteuid, posix_getpwuid, - posix_getuid, posix_isatty, putenv, realpath, server_contains_key, server_get, server_set, - server_unset, stream_isatty, stripos, strlen, strtoupper, substr, usleep, + PHP_ENV, PHP_SERVER, PhpMixed, PhpResource, RuntimeException, defined, file_exists, + file_get_contents, fstat, function_exists, getcwd, getenv, in_array, ini_get, is_array, + is_readable, mb_strlen, php_os_family, posix_geteuid, posix_getpwuid, posix_getuid, + posix_isatty, putenv, putenv_clear, realpath, stream_isatty, stripos, strlen, strtoupper, + substr, usleep, }; use crate::util::ProcessExecutor; @@ -66,28 +66,28 @@ impl Platform { /// /// @return string|false pub fn get_env(name: &str) -> Option<String> { - if server_contains_key(name) { - return Some(server_get(name).unwrap_or_default()); + if let Some(value) = PHP_SERVER.lock().unwrap().get(name) { + return Some(value.to_string_lossy().into_owned()); } - if env_contains_key(name) { - return Some(env_get(name).unwrap_or_default()); + if let Some(value) = PHP_ENV.lock().unwrap().get(name) { + return Some(value.to_string_lossy().into_owned()); } - getenv(name) + getenv(name).map(|value| value.to_string_lossy().into_owned()) } /// putenv() equivalent but updates the runtime global variables too pub fn put_env(name: &str, value: &str) { - putenv(&format!("{}={}", name, value)); - server_set(name, value.to_string()); - env_set(name, value.to_string()); + unsafe { putenv(name, value) }; + PHP_SERVER.lock().unwrap().put(name.into(), value.into()); + PHP_ENV.lock().unwrap().put(name.into(), value.into()); } /// putenv('X') equivalent but updates the runtime global variables too pub fn clear_env(name: &str) { - putenv(name); - server_unset(name); - env_unset(name); + unsafe { putenv_clear(name) }; + PHP_SERVER.lock().unwrap().clear(name); + PHP_ENV.lock().unwrap().clear(name); } /// Parses tildes and environment variables in paths. diff --git a/crates/shirabe/tests/command/init_command_test.rs b/crates/shirabe/tests/command/init_command_test.rs index 1c2fca6..0c38bf4 100644 --- a/crates/shirabe/tests/command/init_command_test.rs +++ b/crates/shirabe/tests/command/init_command_test.rs @@ -4,12 +4,13 @@ use crate::test_case::{RunOptions, get_application_tester, init_temp_composer}; use serial_test::serial; use shirabe::command::init_command::InitCommand; use shirabe::json::JsonFile; -use shirabe_php_shim::{PhpMixed, server_set, server_unset}; +use shirabe_php_shim::{PHP_SERVER, PhpMixed}; use tempfile::TempDir; fn set_up() { - server_set("COMPOSER_DEFAULT_AUTHOR", "John Smith".to_string()); - server_set("COMPOSER_DEFAULT_EMAIL", "john@example.com".to_string()); + let mut server = PHP_SERVER.lock().unwrap(); + server.put("COMPOSER_DEFAULT_AUTHOR".into(), "John Smith".into()); + server.put("COMPOSER_DEFAULT_EMAIL".into(), "john@example.com".into()); } /// const DEFAULT_AUTHORS in PHP. @@ -497,12 +498,15 @@ fn test_run_guess_name_from_dir_sanitizes_dir() { std::fs::create_dir(dir_name).unwrap(); std::env::set_current_dir(dir_name).unwrap(); - server_set("COMPOSER_DEFAULT_VENDOR", ".vendorName".to_string()); + PHP_SERVER + .lock() + .unwrap() + .put("COMPOSER_DEFAULT_VENDOR".into(), ".vendorName".into()); let mut app_tester = get_application_tester(); let result = app_tester.run(non_interactive_input(vec![]), RunOptions::default()); - server_unset("COMPOSER_DEFAULT_VENDOR"); + PHP_SERVER.lock().unwrap().clear("COMPOSER_DEFAULT_VENDOR"); result.unwrap(); assert_eq!(0, app_tester.get_status_code()); diff --git a/crates/shirabe/tests/config_test.rs b/crates/shirabe/tests/config_test.rs index 9c2f80b..df29281 100644 --- a/crates/shirabe/tests/config_test.rs +++ b/crates/shirabe/tests/config_test.rs @@ -1,6 +1,7 @@ //! ref: composer/tests/Composer/Test/ConfigTest.php use indexmap::IndexMap; +use serial_test::serial; use shirabe::advisory::Auditor; use shirabe::config::Config; use shirabe::util::Platform; @@ -509,6 +510,7 @@ fn test_disable_tls_can_be_overridden() { } #[test] +#[serial] fn test_process_timeout() { Platform::put_env("COMPOSER_PROCESS_TIMEOUT", "0"); let config = Config::new(true, None); @@ -520,6 +522,7 @@ fn test_process_timeout() { #[ignore] #[test] +#[serial] fn test_htaccess_protect() { Platform::put_env("COMPOSER_HTACCESS_PROTECT", "0"); let config = Config::new(true, None); @@ -530,6 +533,7 @@ fn test_htaccess_protect() { } #[test] +#[serial] fn test_get_source_of_value() { Platform::clear_env("COMPOSER_PROCESS_TIMEOUT"); @@ -552,6 +556,7 @@ fn test_get_source_of_value() { } #[test] +#[serial] fn test_get_source_of_value_env_variables() { Platform::put_env("COMPOSER_HTACCESS_PROTECT", "0"); let mut config = Config::new(true, None); @@ -562,6 +567,7 @@ fn test_get_source_of_value_env_variables() { } #[test] +#[serial] fn test_audit() { let mut config = Config::new(true, None); let result = config.get("audit"); diff --git a/crates/shirabe/tests/util/ini_helper_test.rs b/crates/shirabe/tests/util/ini_helper_test.rs index f511d76..d1e2071 100644 --- a/crates/shirabe/tests/util/ini_helper_test.rs +++ b/crates/shirabe/tests/util/ini_helper_test.rs @@ -12,7 +12,8 @@ fn set_up() -> TearDown { // XdebugHandler is a unit struct with no name-registration API, so this // step is a no-op here. // Save current state - let env_original = getenv("COMPOSER_ORIGINAL_INIS"); + let env_original = + getenv("COMPOSER_ORIGINAL_INIS").map(|value| value.to_string_lossy().into_owned()); TearDown { env_original } } @@ -20,7 +21,7 @@ fn set_up() -> TearDown { fn tear_down(env_original: &Option<String>) { // Restore original state if let Some(env_original) = env_original { - putenv(&format!("COMPOSER_ORIGINAL_INIS={env_original}")); + unsafe { putenv("COMPOSER_ORIGINAL_INIS", env_original) }; } else { Platform::clear_env("COMPOSER_ORIGINAL_INIS"); } @@ -38,10 +39,7 @@ impl Drop for TearDown { } fn set_env(paths: &[&str]) { - putenv(&format!( - "COMPOSER_ORIGINAL_INIS={}", - paths.join(PATH_SEPARATOR) - )); + unsafe { putenv("COMPOSER_ORIGINAL_INIS", paths.join(PATH_SEPARATOR)) }; } #[test] |
