diff options
Diffstat (limited to 'crates/shirabe/src/command/require_command.rs')
| -rw-r--r-- | crates/shirabe/src/command/require_command.rs | 417 |
1 files changed, 225 insertions, 192 deletions
diff --git a/crates/shirabe/src/command/require_command.rs b/crates/shirabe/src/command/require_command.rs index a49428d..e5963e4 100644 --- a/crates/shirabe/src/command/require_command.rs +++ b/crates/shirabe/src/command/require_command.rs @@ -39,6 +39,7 @@ use crate::plugin::command_event::CommandEvent; use crate::plugin::plugin_events::PluginEvents; use crate::repository::composite_repository::CompositeRepository; use crate::repository::platform_repository::PlatformRepository; +use crate::repository::repository_interface::RepositoryInterface; use crate::repository::repository_set::RepositorySet; use crate::util::filesystem::Filesystem; use crate::util::package_sorter::PackageSorter; @@ -155,35 +156,28 @@ impl RequireCommand { input: &dyn InputInterface, output: &dyn OutputInterface, ) -> Result<i64> { - self.file = Factory::get_composer_file(); - let io = self.get_io(); + self.file = Factory::get_composer_file()?; if input.get_option("no-suggest").as_bool().unwrap_or(false) { - io.write_error3("<warning>You are using the deprecated option \"--no-suggest\". It has no effect and will break in Composer 3.</warning>", true, io_interface::NORMAL); + self.get_io().write_error3("<warning>You are using the deprecated option \"--no-suggest\". It has no effect and will break in Composer 3.</warning>", true, io_interface::NORMAL); } self.newly_created = !file_exists(&self.file); - if self.newly_created && file_put_contents(&self.file, b"{\n}\n").is_none() { - io.write_error3( - &format!("<error>{} could not be created.</error>", self.file), - true, - io_interface::NORMAL, - ); + let write_failed = self.newly_created && file_put_contents(&self.file, b"{\n}\n").is_none(); + if write_failed { + let msg = format!("<error>{} could not be created.</error>", self.file); + self.get_io().write_error3(&msg, true, io_interface::NORMAL); return Ok(1); } if !Filesystem::is_readable(&self.file) { - io.write_error3( - &format!("<error>{} is not readable.</error>", self.file), - true, - io_interface::NORMAL, - ); + let msg = format!("<error>{} is not readable.</error>", self.file); + self.get_io().write_error3(&msg, true, io_interface::NORMAL); return Ok(1); } - - if filesize(&self.file) == 0 { - file_put_contents(&self.file, "{\n}\n"); + if filesize(&self.file) == Some(0) { + file_put_contents(&self.file, b"{\n}\n"); } self.json = Some(JsonFile::new(self.file.clone(), None, None)?); @@ -200,9 +194,9 @@ impl RequireCommand { // to call self.get_io().write_error(...), self.revert_composer_file(), and handler.exit_with_last_signal() let signal_handler = SignalHandler::create( vec![ - SignalHandler::SIGINT, - SignalHandler::SIGTERM, - SignalHandler::SIGHUP, + SignalHandler::SIGINT.to_string(), + SignalHandler::SIGTERM.to_string(), + SignalHandler::SIGHUP.to_string(), ], Box::new(move |signal: String, handler: &SignalHandler| { // TODO(phase-b): self.get_io().write_error('Received '.$signal.', aborting', true, io_interface::DEBUG); @@ -224,17 +218,14 @@ impl RequireCommand { .ok() == Some(false) { - io.write_error3( - &format!("<error>{} is not writable.</error>", self.file), - true, - io_interface::NORMAL, - ); + let msg = format!("<error>{} is not writable.</error>", self.file); + self.get_io().write_error3(&msg, true, io_interface::NORMAL); return Ok(1); } if input.get_option("fixed").as_bool() == Some(true) { - let config = self.json.as_ref().unwrap().read()?; + let config = self.json.as_mut().unwrap().read()?; let package_type = if empty(&config.get("type").cloned().unwrap_or(PhpMixed::Null)) { "library".to_string() @@ -248,10 +239,10 @@ impl RequireCommand { /// @see https://github.com/composer/composer/pull/8313#issuecomment-532637955 if package_type != "project" && !input.get_option("dev").as_bool().unwrap_or(false) { - io.write_error3("<error>The \"--fixed\" option is only allowed for packages with a \"project\" type or for dev dependencies to prevent possible misuses.</error>", true, io_interface::NORMAL); + self.get_io().write_error3("<error>The \"--fixed\" option is only allowed for packages with a \"project\" type or for dev dependencies to prevent possible misuses.</error>", true, io_interface::NORMAL); if config.get("type").is_none() { - io.write_error3("<error>If your package is not a library, you can explicitly specify the \"type\" by using \"composer config type project\".</error>", true, io_interface::NORMAL); + self.get_io().write_error3("<error>If your package is not a library, you can explicitly specify the \"type\" by using \"composer config type project\".</error>", true, io_interface::NORMAL); } return Ok(1); @@ -262,13 +253,22 @@ impl RequireCommand { let repos = composer.get_repository_manager().get_repositories(); let platform_overrides = composer.get_config().borrow_mut().get("platform"); + let platform_overrides_map: IndexMap<String, PhpMixed> = platform_overrides + .as_array() + .map(|m| m.iter().map(|(k, v)| (k.clone(), (**v).clone())).collect()) + .unwrap_or_default(); // initialize self.repos as it is used by the PackageDiscoveryTrait - let platform_repo = PlatformRepository::new(vec![], platform_overrides); + let platform_repo = PlatformRepository::new(vec![], platform_overrides_map)?; let mut combined: Vec< Box<dyn crate::repository::repository_interface::RepositoryInterface>, - > = vec![Box::new(platform_repo.clone())]; - for repo in repos { - combined.push(repo); + > = vec![ + // TODO(phase-b): PlatformRepository should be shared via Rc; use placeholder until + // CompositeRepository accepts shared references + Box::new(todo!("share platform_repo with PlatformRepository") as PlatformRepository), + ]; + for _repo in repos { + // TODO(phase-b): repos are borrowed from RepositoryManager; need to take ownership + combined.push(todo!("take ownership of repo from RepositoryManager")); } *self.get_repos_mut() = Some(CompositeRepository::new(combined)); @@ -290,7 +290,7 @@ impl RequireCommand { .collect() }) .unwrap_or_default(), - &platform_repo, + Some(&platform_repo), &preferred_stability, // if there is no update, we need to use the best possible version constraint directly as we cannot rely on the solver to guess the best constraint input.get_option("no-update").as_bool().unwrap_or(false), @@ -320,7 +320,7 @@ impl RequireCommand { let mut requirements = self.format_requirements(requirements)?; if !input.get_option("dev").as_bool().unwrap_or(false) - && io.is_interactive() + && self.get_io().is_interactive() && !composer.is_global() { let mut dev_packages: Vec<Vec<String>> = vec![]; @@ -336,9 +336,14 @@ impl RequireCommand { continue; } - let pkg = PackageSorter::get_most_current_version( - self.get_repos().find_packages(name, None), - ); + // TODO(phase-b): find_packages returns Vec<Box<dyn BasePackage>> but + // get_most_current_version expects Vec<Box<dyn PackageInterface>>; needs trait + // upcasting once Rust supports it stably or an adapter. + let _ = self.get_repos().find_packages(name, None); + let pkg: Option<Box<dyn PackageInterface>> = + PackageSorter::get_most_current_version(todo!( + "convert Vec<Box<dyn BasePackage>> to Vec<Box<dyn PackageInterface>>" + )); // TODO(phase-b): instanceof CompletePackageInterface downcast let pkg_as_complete: Option<&dyn CompletePackageInterface> = None; if let Some(pkg_complete) = pkg_as_complete { @@ -368,26 +373,19 @@ impl RequireCommand { } else { "it is" }; - let pkg_dev_tags: Vec<String> = array_unique(&array_merge_recursive( - dev_packages - .iter() - .map(|v| { - PhpMixed::List( - v.iter() - .map(|s| Box::new(PhpMixed::String(s.clone()))) - .collect(), - ) - }) - .collect(), - )); - io.warning(format!( + // TODO(phase-b): PHP's array_merge_recursive + array_unique on a list of + // string lists; collapsed here to a flat unique Vec<String>. + let merged: Vec<String> = dev_packages.iter().flatten().cloned().collect(); + let pkg_dev_tags: Vec<String> = array_unique(&merged); + let warn_msg = format!( "The package{} you required {} recommended to be placed in require-dev (because {} tagged as \"{}\") but you did not use --dev.", plural, plural2, plural3, implode("\", \"", &pkg_dev_tags), - )); - if io.ask_confirmation( + ); + self.get_io().warning(&warn_msg, &[]); + if self.get_io().ask_confirmation( "<info>Do you want to re-run the command with --dev?</> [<comment>yes</>]? " .to_string(), true, @@ -423,10 +421,11 @@ impl RequireCommand { let version_parser = VersionParser::new(); for (package, constraint) in &requirements { if strtolower(package) == composer.get_package().get_name() { - io.write_error3(&sprintf( + let msg = sprintf( "<error>Root package '%s' cannot require itself in its composer.json</error>", &[PhpMixed::String(package.clone())], - ), true, io_interface::NORMAL); + ); + self.get_io().write_error3(&msg, true, io_interface::NORMAL); return Ok(1); } @@ -440,7 +439,7 @@ impl RequireCommand { self.get_inconsistent_require_keys(&requirements, require_key); if (inconsistent_require_keys.len() as i64) > 0 { for package in &inconsistent_require_keys { - io.warning(sprintf( + let warn_msg = sprintf( "%s is currently present in the %s key and you ran the command %s the --dev flag, which will move it to the %s key.", &[ PhpMixed::String(package.clone()), @@ -455,38 +454,35 @@ impl RequireCommand { ), PhpMixed::String(require_key.to_string()), ], - )); + ); + self.get_io().warning(&warn_msg, &[]); } - if io.is_interactive() { - if !io.ask_confirmation( - sprintf( - "<info>Do you want to move %s?</info> [<comment>no</comment>]? ", + if self.get_io().is_interactive() { + let q1 = sprintf( + "<info>Do you want to move %s?</info> [<comment>no</comment>]? ", + &[PhpMixed::String( + if (inconsistent_require_keys.len() as i64) > 1 { + "these requirements" + } else { + "this requirement" + } + .to_string(), + )], + ); + if !self.get_io().ask_confirmation(q1, false) { + let q2 = sprintf( + "<info>Do you want to re-run the command %s --dev?</info> [<comment>yes</comment>]? ", &[PhpMixed::String( - if (inconsistent_require_keys.len() as i64) > 1 { - "these requirements" + if input.get_option("dev").as_bool().unwrap_or(false) { + "without" } else { - "this requirement" + "with" } .to_string(), )], - ), - false, - ) { - if !io.ask_confirmation( - sprintf( - "<info>Do you want to re-run the command %s --dev?</info> [<comment>yes</comment>]? ", - &[PhpMixed::String( - if input.get_option("dev").as_bool().unwrap_or(false) { - "without" - } else { - "with" - } - .to_string(), - )], - ), - true, - ) { + ); + if !self.get_io().ask_confirmation(q2, true) { return Ok(0); } @@ -508,7 +504,7 @@ impl RequireCommand { self.first_require = self.newly_created; if !self.first_require { - let composer_definition = self.json.as_ref().unwrap().read()?; + let composer_definition = self.json.as_mut().unwrap().read()?; let require_count = composer_definition .get("require") .and_then(|v| v.as_array()) @@ -534,19 +530,17 @@ impl RequireCommand { ); } - io.write_error3( - &format!( - "<info>{} has been {}</info>", - self.file, - if self.newly_created { - "created" - } else { - "updated" - } - ), - true, - io_interface::NORMAL, + let updated_msg = format!( + "<info>{} has been {}</info>", + self.file, + if self.newly_created { + "created" + } else { + "updated" + } ); + self.get_io() + .write_error3(&updated_msg, true, io_interface::NORMAL); if input.get_option("no-update").as_bool().unwrap_or(false) { return Ok(0); @@ -555,8 +549,16 @@ impl RequireCommand { composer.get_plugin_manager().deactivate_installed_plugins(); // try/catch/finally - let do_update_result = - self.do_update(input, output, io, &requirements, require_key, remove_key); + // TODO(phase-b): do_update borrows io from self while also needing &mut self for state + // mutations; needs an Rc<dyn IOInterface> on self for clean sharing. + let do_update_result = self.do_update( + input, + output, + todo!("share io reference for do_update"), + &requirements, + require_key, + remove_key, + ); let dry_run = input.get_option("dry-run").as_bool().unwrap_or(false); let result = match do_update_result { @@ -596,7 +598,7 @@ impl RequireCommand { /// @param array<string, string> $newRequirements /// @return string[] fn get_inconsistent_require_keys( - &self, + &mut self, new_requirements: &IndexMap<String, String>, require_key: &str, ) -> Vec<String> { @@ -615,8 +617,8 @@ impl RequireCommand { } /// @return array<string, string> - fn get_packages_by_require_key(&self) -> IndexMap<String, String> { - let composer_definition = self.json.as_ref().unwrap().read().unwrap_or_default(); + fn get_packages_by_require_key(&mut self) -> IndexMap<String, String> { + let composer_definition = self.json.as_mut().unwrap().read().unwrap_or_default(); let mut require: IndexMap<String, PhpMixed> = IndexMap::new(); let mut require_dev: IndexMap<String, PhpMixed> = IndexMap::new(); @@ -682,14 +684,14 @@ impl RequireCommand { ) -> Result<i64> { // Update packages self.reset_composer()?; - let composer = self.require_composer(None, None)?; + let mut composer = self.require_composer(None, None)?; self.dependency_resolution_completed = false; - composer.get_event_dispatcher().add_listener( + // TODO(phase-b): add_listener expects a Callable enum; PHP closure should set + // self.dependency_resolution_completed = true when invoked. + composer.get_event_dispatcher().borrow_mut().add_listener( InstallerEvents::PRE_OPERATIONS_EXEC, - Box::new(move || { - // TODO(phase-b): self.dependency_resolution_completed = true; - }), + crate::event_dispatcher::event_dispatcher::Callable::Closure, 10000, ); @@ -699,7 +701,11 @@ impl RequireCommand { IndexMap::new(); links.insert("require".to_string(), root_package.get_requires()); links.insert("require-dev".to_string(), root_package.get_dev_requires()); - let loader = ArrayLoader::new(None, None, false); + let loader = ArrayLoader::new(None, false); + let requirements_mixed: IndexMap<String, PhpMixed> = requirements + .iter() + .map(|(k, v)| (k.clone(), PhpMixed::String(v.clone()))) + .collect(); let new_links = loader.parse_links( root_package.get_name(), root_package.get_pretty_version(), @@ -707,8 +713,8 @@ impl RequireCommand { .get(require_key) .map(|t| t.method) .unwrap_or_default(), - requirements, - ); + requirements_mixed, + )?; if let Some(section) = links.get_mut(require_key) { for (k, v) in new_links { section.insert(k, v); @@ -719,20 +725,20 @@ impl RequireCommand { section.shift_remove(package); } } - root_package.set_requires(links.get("require").cloned().unwrap_or_default()); - root_package.set_dev_requires(links.get("require-dev").cloned().unwrap_or_default()); - - // extract stability flags & references as they weren't present when loading the unmodified composer.json - let mut references = root_package.get_references(); - references = RootPackageLoader::extract_references(requirements, references); - root_package.set_references(references); - let mut stability_flags = root_package.get_stability_flags(); - stability_flags = RootPackageLoader::extract_stability_flags( + // TODO(phase-b): root_package mutation requires &mut RootPackageInterface but + // Composer::get_package() exposes only & dyn; needs accessor returning &mut for + // the dry-run case to update requires/dev-requires/stability flags/references. + let _ = &links; + let _ = root_package.get_references().clone(); + let _ = RootPackageLoader::extract_references( + requirements, + root_package.get_references().clone(), + ); + let _ = RootPackageLoader::extract_stability_flags( requirements, root_package.get_minimum_stability(), - stability_flags, + root_package.get_stability_flags().clone(), ); - root_package.set_stability_flags(stability_flags); // unset($stabilityFlags, $references); } @@ -828,16 +834,19 @@ impl RequireCommand { let command_event = CommandEvent::new(PluginEvents::COMMAND, "require", input, output); composer .get_event_dispatcher() + .borrow_mut() .dispatch(Some(command_event.get_name()), None); composer - .get_installation_manager() + .get_installation_manager_mut() .set_output_progress(!input.get_option("no-progress").as_bool().unwrap_or(false)); - let install = Installer::create(io, &composer); + // TODO(phase-b): Installer::create takes Box<dyn IOInterface> for ownership but io is a + // borrowed &dyn here; needs Rc<dyn IOInterface> for proper sharing. + let mut install = Installer::create(todo!("share io as Box<dyn IOInterface>"), &composer); let (prefer_source, prefer_dist) = - self.get_preferred_install_options(&*composer.get_config().borrow(), input)?; + self.get_preferred_install_options(&*composer.get_config().borrow(), input, false)?; install .set_dry_run(input.get_option("dry-run").as_bool().unwrap_or(false)) @@ -847,10 +856,10 @@ impl RequireCommand { .set_dev_mode(update_dev_mode) .set_optimize_autoloader(optimize) .set_class_map_authoritative(authoritative) - .set_apcu_autoloader(apcu, apcu_prefix.as_deref()) + .set_apcu_autoloader(apcu, apcu_prefix.clone()) .set_update(true) .set_install(!input.get_option("no-install").as_bool().unwrap_or(false)) - .set_update_allow_transitive_dependencies(update_allow_transitive_dependencies) + .set_update_allow_transitive_dependencies(update_allow_transitive_dependencies)? .set_platform_requirement_filter(BaseCommand::get_platform_requirement_filter( self, input, )?) @@ -912,22 +921,43 @@ impl RequireCommand { dry_run: bool, fixed: bool, ) -> Result<i64> { - let composer = self.require_composer(None, None)?; - let locker = composer.get_locker(); + let mut composer = self.require_composer(None, None)?; + let locker_is_locked = composer.get_locker_mut().is_locked(); let mut requirements: IndexMap<String, String> = IndexMap::new(); - let version_selector = VersionSelector::new(RepositorySet::new(None, None), None); - let repo = if locker.is_locked() { - composer.get_locker().get_locked_repository(Some(true))? + let mut version_selector = VersionSelector::new( + RepositorySet::new( + "stable", + IndexMap::new(), + vec![], + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + ), + None, + )?; + // TODO(phase-b): get_locked_repository returns LockArrayRepository (owned) and + // get_local_repository returns &dyn InstalledRepositoryInterface; need a common + // interface for find_package. + let locked_repo; + let repo: &dyn RepositoryInterface = if locker_is_locked { + locked_repo = composer.get_locker_mut().get_locked_repository(true)?; + &locked_repo } else { - composer.get_repository_manager().get_local_repository() + todo!("convert &dyn InstalledRepositoryInterface to &dyn RepositoryInterface") }; for package_name in requirements_to_update { - let mut package = repo.find_package(package_name, "*"); + let mut package = repo.find_package( + package_name, + crate::repository::repository_interface::FindPackageConstraint::String( + "*".to_string(), + ), + ); // TODO(phase-b): `$package instanceof AliasPackage` downcast - let mut package_as_alias: Option<&AliasPackage> = None; - while let Some(alias) = package_as_alias { - package = Some(Box::new(alias.get_alias_of().clone()) as Box<dyn PackageInterface>); - package_as_alias = None; + let package_as_alias: Option<&AliasPackage> = None; + while let Some(_alias) = package_as_alias { + // TODO(phase-b): get_alias_of returns &dyn BasePackage; clone is not available + // and BasePackage is not PackageInterface (the latter is a super-trait). + package = todo!("upcast alias.get_alias_of() to Box<dyn BasePackage>"); } let package = match package { @@ -941,9 +971,13 @@ impl RequireCommand { package.get_pretty_version().to_string(), ); } else { + // TODO(phase-b): trait upcast from &dyn BasePackage to &dyn PackageInterface + // is not yet stable in Rust; use explicit as_package_interface() when available. + let pkg_as_pi: &dyn PackageInterface = + todo!("upcast &dyn BasePackage to &dyn PackageInterface"); requirements.insert( package_name.clone(), - version_selector.find_recommended_require_version(&*package), + version_selector.find_recommended_require_version(pkg_as_pi)?, ); } self.get_io().write_error3( @@ -969,10 +1003,13 @@ impl RequireCommand { ) .unwrap_or(false) { - self.get_io().warning(format!( - "Version {} looks like it may be a feature branch which is unlikely to keep working in the long run and may be in an unstable state", - requirements.get(package_name).cloned().unwrap_or_default(), - )); + self.get_io().warning( + &format!( + "Version {} looks like it may be a feature branch which is unlikely to keep working in the long run and may be in an unstable state", + requirements.get(package_name).cloned().unwrap_or_default(), + ), + &[], + ); if self.get_io().is_interactive() && !self.get_io().ask_confirmation( "Are you sure you want to use this constraint (<comment>y</comment>) or would you rather abort (<comment>n</comment>) the whole operation [<comment>y,n</comment>]? " @@ -988,14 +1025,19 @@ impl RequireCommand { } if !dry_run { - self.update_file( - self.json.as_ref().unwrap(), + // TODO(phase-b): update_file takes &mut self while self.json is borrowed; needs + // refactor to pass the JsonFile owned/cloned or use interior mutability. + let json_path = self.json.as_ref().unwrap().get_path().to_string(); + let _ = ( + json_path, &requirements, require_key, remove_key, sort_packages, ); - if locker.is_locked() + todo!("call self.update_file without overlapping borrows of self.json"); + #[allow(unreachable_code)] + if locker_is_locked && composer .get_config() .borrow_mut() @@ -1009,21 +1051,9 @@ impl RequireCommand { IndexMap::new(), ); let stability_flags_clone = stability_flags.clone(); - locker.update_hash( - self.json.as_ref().unwrap(), - Box::new(move |mut lock_data: IndexMap<String, PhpMixed>| { - for (package_name, flag) in &stability_flags_clone { - let entry = lock_data - .entry("stability-flags".to_string()) - .or_insert_with(|| PhpMixed::Array(IndexMap::new())); - if let PhpMixed::Array(m) = entry { - m.insert(package_name.clone(), Box::new(PhpMixed::Int(*flag))); - } - } - - lock_data - }), - ); + // TODO(phase-b): get_locker_mut needs update_hash with stability flags rewriter. + let _ = &stability_flags_clone; + todo!("update locker hash with stability flags rewriter"); } } @@ -1032,7 +1062,7 @@ impl RequireCommand { /// @param array<string, string> $new fn update_file( - &self, + &mut self, json: &JsonFile, new: &IndexMap<String, String>, require_key: &str, @@ -1043,13 +1073,16 @@ impl RequireCommand { return; } - let mut composer_definition = self.json.as_ref().unwrap().read().unwrap_or_default(); + let composer_definition_mixed = self.json.as_mut().unwrap().read().unwrap_or_default(); + let mut composer_definition: IndexMap<String, Box<PhpMixed>> = composer_definition_mixed + .as_array() + .cloned() + .unwrap_or_default(); for (package, version) in new { - if let Some(section) = composer_definition + let section = composer_definition .entry(require_key.to_string()) - .or_insert_with(|| PhpMixed::Array(IndexMap::new())) - .as_array_mut() - { + .or_insert_with(|| Box::new(PhpMixed::Array(IndexMap::new()))); + if let Some(section) = section.as_array_mut() { section.insert(package.clone(), Box::new(PhpMixed::String(version.clone()))); } if let Some(section) = composer_definition @@ -1067,12 +1100,11 @@ impl RequireCommand { composer_definition.shift_remove(remove_key); } } - let _ = self.json.as_ref().unwrap().write(PhpMixed::Array( - composer_definition - .into_iter() - .map(|(k, v)| (k, Box::new(v))) - .collect(), - )); + let _ = self + .json + .as_ref() + .unwrap() + .write(PhpMixed::Array(composer_definition)); } /// @param array<string, string> $new @@ -1086,20 +1118,29 @@ impl RequireCommand { ) -> bool { let contents = file_get_contents(json.get_path()).unwrap_or_default(); - let manipulator = JsonManipulator::new(&contents); + let mut manipulator = match JsonManipulator::new(contents) { + Ok(m) => m, + Err(_) => return false, + }; for (package, constraint) in new { - if !manipulator.add_link(require_key, package, constraint, sort_packages) { + if !manipulator + .add_link(require_key, package, constraint, sort_packages) + .unwrap_or(false) + { return false; } - if !manipulator.remove_sub_node(remove_key, package) { + if !manipulator + .remove_sub_node(remove_key, package) + .unwrap_or(false) + { return false; } } - manipulator.remove_main_key_if_empty(remove_key); + let _ = manipulator.remove_main_key_if_empty(remove_key); - file_put_contents(json.get_path(), &manipulator.get_contents()); + file_put_contents(json.get_path(), manipulator.get_contents().as_bytes()); true } @@ -1107,41 +1148,33 @@ impl RequireCommand { pub(crate) fn interact(&self, _input: &dyn InputInterface, _output: &dyn OutputInterface) {} fn revert_composer_file(&mut self) { - let io = self.get_io(); - if self.newly_created { - io.write_error3( - &format!( - "\n<error>Installation failed, deleting {}.</error>", - self.file - ), - true, - io_interface::NORMAL, + let msg = format!( + "\n<error>Installation failed, deleting {}.</error>", + self.file ); + self.get_io().write_error3(&msg, true, io_interface::NORMAL); unlink(self.json.as_ref().unwrap().get_path()); if file_exists(&self.lock) { unlink(&self.lock); } } else { - let msg = if self.lock_backup.is_some() { + let extra = if self.lock_backup.is_some() { format!(" and {} to their ", self.lock) } else { " to its ".to_string() }; - io.write_error3( - &format!( - "\n<error>Installation failed, reverting {}{}original content.</error>", - self.file, msg - ), - true, - io_interface::NORMAL, + let msg = format!( + "\n<error>Installation failed, reverting {}{}original content.</error>", + self.file, extra ); + self.get_io().write_error3(&msg, true, io_interface::NORMAL); file_put_contents( self.json.as_ref().unwrap().get_path(), - &self.composer_backup, + self.composer_backup.as_bytes(), ); if let Some(ref lock_backup) = self.lock_backup { - file_put_contents(&self.lock, lock_backup); + file_put_contents(&self.lock, lock_backup.as_bytes()); } } } |
