diff --git a/src/history.rs b/src/history.rs index fc174555d097a24e8a1464b963fdcf8599988044..60b22332cdc8a048636b95e471233da6fd3b1d6a 100644 --- a/src/history.rs +++ b/src/history.rs @@ -6,7 +6,7 @@ use color_eyre::eyre::WrapErr; use color_eyre::Result; use time::OffsetDateTime; use time::macros::format_description; - +use crate::eyre::eyre; use crate::models::*; impl PackageManager { @@ -214,20 +214,29 @@ impl PackageManager { // Apply package changes directly to FHS directories at root level // First phase: Link all packages - for (pkgline, _) in &new_packages { + for (pkgkey, _) in &new_packages { + let pkgline = rollback_packages.get(pkgkey) + .ok_or_else(|| eyre!("Package not found: {}", pkgkey))? + .pkgline.clone(); let fs_dir = store_root.join(pkgline).join("fs"); self.link_package(&fs_dir, &env_root)?; } // Second phase: Expose packages and handle appbin flags - for (pkgline, appbin_flag) in &new_packages { + for (pkgkey, appbin_flag) in &new_packages { + let pkgline = rollback_packages.get(pkgkey) + .ok_or_else(|| eyre!("Package not found: {}", pkgkey))? + .pkgline.clone(); let fs_dir = store_root.join(pkgline).join("fs"); if *appbin_flag { self.expose_package(&fs_dir, &env_root)?; } } - for pkgline in &del_packages { + for pkgkey in &del_packages { + let pkgline = current_packages.get(pkgkey) + .ok_or_else(|| eyre!("Package not found: {}", pkgkey))? + .pkgline.clone(); let fs_dir = store_root.join(pkgline).join("fs"); self.unlink_package(&fs_dir, &env_root)?; } diff --git a/src/install.rs b/src/install.rs index 692e4b6442f061f6d2482357c8cb521653a096e4..83d687333b9b8d589c9a48a9a3f7f1e5261b09a4 100644 --- a/src/install.rs +++ b/src/install.rs @@ -318,6 +318,19 @@ fn find_link_interpreter(interpreter_in_env: &Path, interpreter_basename: &str) return Ok(()); } + // if the soft link is broken, delete it + if let Ok(metadata) = fs::symlink_metadata(interpreter_in_env) { + if metadata.file_type().is_symlink() { + if fs::read_link(interpreter_in_env).map(|t| !t.exists()).unwrap_or(false) { + fs::remove_file(interpreter_in_env)? + } else { + return Ok(()); + } + } else { + return Ok(()); + } + } + // Get the parent directory to search in let parent = interpreter_in_env.parent() .ok_or_else(|| eyre::eyre!("Failed to get parent directory of {}", interpreter_in_env.display()))?; @@ -366,7 +379,17 @@ fn create_interpreter_wrapper(env_root: &Path, interpreter_path: &str, interpret let interpreter_in_env = Path::new(&interpreter_in_env); // Find and link the interpreter if needed - find_link_interpreter(interpreter_in_env, interpreter_basename)?; + match find_link_interpreter(interpreter_in_env, interpreter_basename) { + Ok(()) => {}, + Err(e) => { + if interpreter_basename.ends_with("sh") { + println!("Shell interpreter {} is not found in environment. you can install it later.", interpreter_basename); + return Ok("".to_string()); + } else { + return Err(e); + } + } + } // Example: store_interpreter = "/home/wfg/.epkg/store/twktsyye3ksj068w2fx9pz5fefwy70mw__bash__5.2.15__9.oe2403/fs/usr/bin/bash" // Create the wrapper @@ -395,8 +418,17 @@ fn create_shebang_line(env_root: &Path, first_line: &str) -> Result { .ok_or_else(|| eyre::eyre!("Failed to get interpreter basename"))? .to_string_lossy(); - let env_interpreter_path = create_interpreter_wrapper(env_root, &interpreter_path, &interpreter_basename) - .with_context(|| format!("Failed to create interpreter wrapper for {} with basename {}", interpreter_path, interpreter_basename))?; + let env_interpreter_path = match create_interpreter_wrapper(env_root, &interpreter_path, &interpreter_basename) + .with_context(|| format!("Failed to create interpreter wrapper for {} with basename {}", interpreter_path, interpreter_basename)) + { + Ok(path) => { + if path == "" { + return Ok(first_line.to_string()); + } + path + }, + Err(e) => return Err(e), + }; // Example output: "#!/home/wfg/.epkg/envs/main/ebin/sh " Ok(format!("#!{} {}\n", env_interpreter_path, params)) @@ -444,6 +476,37 @@ impl PackageManager { self.load_installed_packages()?; let mut packages_to_install = self.resolve_package_info(package_specs.clone()); + let mut packages_to_install_clone = packages_to_install.clone(); + let mut depends_pkg : HashMap = HashMap::new(); + let channel_config = self.get_channel_config(config().common.env.clone())?; + let repo_format = channel_config.format; + for (pkgline, pkginfo) in packages_to_install_clone.drain() { + let mut tmp_pkg = HashMap::new(); + tmp_pkg.insert(pkgline, pkginfo); + let mut tmp_depends : HashMap = HashMap::new(); + self.collect_depends(&mut tmp_pkg, &mut tmp_depends, 1, repo_format)?; + depends_pkg.extend(tmp_depends); + } + + for pkg in depends_pkg.keys() { + if let Some(info) = packages_to_install.get_mut(pkg) { + info.depend_depth = 1; + } + } + + let current_installed: Vec = packages_to_install + .keys() + .filter(|name| self.installed_packages.contains_key(*name)) + .cloned() + .collect(); + if packages_to_install.len() == current_installed.len() && + packages_to_install.keys().all(|k| current_installed.contains(k)) { + return Err(eyre::eyre!("All packages input have already installed")); + } + if current_installed.len() > 0 { + println!("These packages have already been installed: {}", current_installed.join(",")); + } + self.record_appbin_source(&mut packages_to_install)?; self.collect_essential_packages(&mut packages_to_install)?; self.collect_recursive_depends(&mut packages_to_install)?; diff --git a/src/repo.rs b/src/repo.rs index ee3bb6bc163bc13f77978ca2e53e01f8f8f81bba..c04d6d9787be3a14cebdb59970c7ae5dc0f877b1 100644 --- a/src/repo.rs +++ b/src/repo.rs @@ -688,7 +688,8 @@ pub fn list_repos() -> Result<()> { for entry in fs::read_dir(&manager_channel_dir)? { let path = entry?.path(); - if !path.is_file() || path.extension().unwrap_or_default() != "yaml" { + if !path.is_file() || path.extension().unwrap_or_default() != "yaml" + || path.file_name().unwrap_or_default() == "mirrors.yaml" { continue; } @@ -714,7 +715,7 @@ pub fn list_repos() -> Result<()> { }; println!("{:<30} | {:<15} | {}", - channel_config.channel, + channel_config.distro, repo_name, repo_url ); diff --git a/src/utils.rs b/src/utils.rs index 35a3772109541c1f6956d64f0a0676ec2fe763fd..1a52a1ec1e355a28733c4bae020eecb6e2adc5fc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -94,11 +94,16 @@ pub fn get_file_type(file: &Path) -> Result<(FileType, String)> { file.seek(SeekFrom::Start(0))?; let mut reader = BufReader::new(file); let mut first_line = String::new(); - let bytes_read = reader.read_line(&mut first_line)?; - if bytes_read == 0 { + let _bytes_read = match reader.read_line(&mut first_line) { + Ok(n) => n, + Err(_e) => { + 0 + } + }; + if _bytes_read == 0 { return Ok((FileType::Others, String::new())); } - + // Check if file starts with shebang if first_line.starts_with("#!") { let script_line0 = first_line.trim_end().to_string();