diff --git a/example_projects/project-upgrade/rproject.toml b/example_projects/project-upgrade/rproject.toml index a0d98fae..dc9bbede 100644 --- a/example_projects/project-upgrade/rproject.toml +++ b/example_projects/project-upgrade/rproject.toml @@ -4,7 +4,8 @@ name = "project-upgrade" r_version = "4.4" repositories = [ - {alias = "PPM", url = "https://packagemanager.posit.co/cran/2024-12-22"} + {alias = "PPM", url = "https://packagemanager.posit.co/cran/2025-04-12"}, + {alias = "PPM-old", url = "https://packagemanager.posit.co/cran/2025-04-01"} ] dependencies = [ diff --git a/example_projects/project-upgrade/rv.lock b/example_projects/project-upgrade/rv.lock index d0876ca5..46a845bb 100644 --- a/example_projects/project-upgrade/rv.lock +++ b/example_projects/project-upgrade/rv.lock @@ -3,70 +3,52 @@ version = 1 r_version = "4.4" -[[packages]] -name = "MASS" -version = "7.3-60.2" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } -path = "4.4.0/Recommended" -force_source = false -dependencies = [] - -[[packages]] -name = "Matrix" -version = "1.6-5" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } -path = "4.4.0/Recommended" -force_source = false -dependencies = [ - "lattice", -] - [[packages]] name = "R6" -version = "2.5.1" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "2.6.1" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "RColorBrewer" version = "1.1-3" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "cli" -version = "3.6.2" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "3.6.4" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "colorspace" -version = "2.1-0" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "2.1-1" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "fansi" version = "1.0.6" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "farver" -version = "2.1.1" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "2.1.2" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "ggplot2" -version = "3.4.4" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "3.5.1" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [ "cli", @@ -74,8 +56,6 @@ dependencies = [ "gtable", "isoband", "lifecycle", - "MASS", - "mgcv", "rlang", "scales", "tibble", @@ -85,15 +65,15 @@ dependencies = [ [[packages]] name = "glue" -version = "1.7.0" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "1.8.0" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "gtable" -version = "0.3.4" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "0.3.6" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [ "cli", @@ -105,29 +85,21 @@ dependencies = [ [[packages]] name = "isoband" version = "0.2.7" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "labeling" version = "0.4.3" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } -force_source = false -dependencies = [] - -[[packages]] -name = "lattice" -version = "0.22-5" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } -path = "4.4.0/Recommended" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "lifecycle" version = "1.0.4" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [ "cli", @@ -138,48 +110,26 @@ dependencies = [ [[packages]] name = "magrittr" version = "2.0.3" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] -[[packages]] -name = "mgcv" -version = "1.9-1" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } -path = "4.4.0/Recommended" -force_source = false -dependencies = [ - "nlme", - "Matrix", -] - [[packages]] name = "munsell" -version = "0.5.0" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "0.5.1" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [ "colorspace", ] -[[packages]] -name = "nlme" -version = "3.1-164" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } -path = "4.4.0/Recommended" -force_source = false -dependencies = [ - "lattice", -] - [[packages]] name = "pillar" -version = "1.9.0" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "1.10.1" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [ "cli", - "fansi", "glue", "lifecycle", "rlang", @@ -190,21 +140,21 @@ dependencies = [ [[packages]] name = "pkgconfig" version = "2.0.3" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "rlang" -version = "1.1.3" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "1.1.5" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "scales" version = "1.3.0" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [ "cli", @@ -222,7 +172,7 @@ dependencies = [ [[packages]] name = "tibble" version = "3.2.1" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [ "fansi", @@ -237,14 +187,14 @@ dependencies = [ [[packages]] name = "utf8" version = "1.2.4" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "vctrs" version = "0.6.5" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [ "cli", @@ -256,13 +206,13 @@ dependencies = [ [[packages]] name = "viridisLite" version = "0.4.2" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] [[packages]] name = "withr" -version = "3.0.0" -source = { repository = "https://packagemanager.posit.co/cran/2024-02-22" } +version = "3.0.2" +source = { repository = "https://packagemanager.posit.co/cran/2025-04-01" } force_source = false dependencies = [] diff --git a/src/activate.rs b/src/activate.rs index e0857c3d..3ae3ab30 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -97,8 +97,7 @@ fn scripts_as_paths(is_home: bool) -> (PathBuf, PathBuf) { fn write_activate_file(dir: impl AsRef, is_home: bool) -> Result<(), ActivateError> { let template = ACTIVATE_FILE_TEMPLATE.to_string(); - let global_wd_content = if is_home - { + let global_wd_content = if is_home { r#" owd <- getwd() setwd("~") diff --git a/src/lockfile.rs b/src/lockfile.rs index 7a61d4c0..0a20ec90 100644 --- a/src/lockfile.rs +++ b/src/lockfile.rs @@ -481,6 +481,16 @@ impl Lockfile { true } + pub fn contains_resolved_dep(&self, dep: &ResolvedDependency) -> bool { + self.packages + .iter() + .find(|lock_pkg| { + lock_pkg.name == dep.name.as_ref() + && lock_pkg.version == dep.version.as_ref().original + }) + .is_some() + } + /// Gets a set of all the package names listed in the lockfile pub fn package_names(&self) -> HashSet<&str> { let mut out = HashSet::new(); diff --git a/src/main.rs b/src/main.rs index c0a98e40..77122c05 100644 --- a/src/main.rs +++ b/src/main.rs @@ -123,8 +123,8 @@ pub enum MigrateSubcommand { }, } -#[derive(Debug, Clone)] -enum SyncMode { +#[derive(Debug, Clone, PartialEq)] +enum ResolveMode { Default, FullUpgrade, // TODO: PartialUpgrade -- allow user to specify packages to upgrade @@ -132,7 +132,15 @@ enum SyncMode { /// Resolve dependencies for the project. If there are any unmet dependencies, they will be printed /// to stderr and the cli will exit. -fn resolve_dependencies(context: &CliContext) -> Vec { +fn resolve_dependencies<'a>( + context: &'a CliContext, + resolve_mode: &ResolveMode, +) -> Vec> { + let lockfile = match resolve_mode { + ResolveMode::Default => &context.lockfile, + ResolveMode::FullUpgrade => &None, + }; + let mut resolver = Resolver::new( &context.project_dir, &context.databases, @@ -143,8 +151,9 @@ fn resolve_dependencies(context: &CliContext) -> Vec { .map(|x| x.url()) .collect(), &context.r_version, - context.lockfile.as_ref(), + lockfile.as_ref(), ); + if context.show_progress_bar { resolver.show_progress_bar(); } @@ -164,24 +173,46 @@ fn resolve_dependencies(context: &CliContext) -> Vec { ::std::process::exit(1) } - resolution.found + // If upgrade and there is a lockfile, we want to adjust the resolved dependencies s.t. if the resolved dep has the same + // name and version in the lockfile, we say that it was resolved from the lockfile + let resolved = if resolve_mode == &ResolveMode::FullUpgrade && context.lockfile.is_some() { + resolution + .found + .into_iter() + .map(|mut dep| { + dep.from_lockfile = context + .lockfile + .as_ref() + .unwrap() + .contains_resolved_dep(&dep); + dep + }) + .collect::>() + } else { + resolution.found + }; + + resolved } fn _sync( mut context: CliContext, dry_run: bool, has_logs_enabled: bool, - sync_mode: SyncMode, + resolve_mode: ResolveMode, ) -> Result<()> { if !has_logs_enabled { context.show_progress_bar(); } - context.load_databases_if_needed()?; - match sync_mode { - SyncMode::Default => (), - SyncMode::FullUpgrade => context.lockfile = None, + + // If the sync mode is an upgrade, we want to load the databases even if all packages are contained in the lockfile + // because we ignore the lockfile during initial resolution + match resolve_mode { + ResolveMode::Default => context.load_databases_if_needed()?, + ResolveMode::FullUpgrade => context.load_databases()?, } - let resolved = resolve_dependencies(&context); + + let resolved = resolve_dependencies(&context, &resolve_mode); match timeit!( if dry_run { @@ -312,16 +343,21 @@ fn try_main() -> Result<()> { } Command::Plan { upgrade } => { let upgrade = if upgrade { - SyncMode::FullUpgrade + ResolveMode::FullUpgrade } else { - SyncMode::Default + ResolveMode::Default }; let context = CliContext::new(&cli.config_file)?; _sync(context, true, cli.verbose.is_present(), upgrade)?; } Command::Sync => { let context = CliContext::new(&cli.config_file)?; - _sync(context, false, cli.verbose.is_present(), SyncMode::Default)?; + _sync( + context, + false, + cli.verbose.is_present(), + ResolveMode::Default, + )?; } Command::Add { packages, @@ -349,7 +385,7 @@ fn try_main() -> Result<()> { context, dry_run, cli.verbose.is_present(), - SyncMode::Default, + ResolveMode::Default, )?; } Command::Upgrade { dry_run } => { @@ -358,7 +394,7 @@ fn try_main() -> Result<()> { context, dry_run, cli.verbose.is_present(), - SyncMode::FullUpgrade, + ResolveMode::FullUpgrade, )?; } Command::Info { @@ -396,7 +432,7 @@ fn try_main() -> Result<()> { let info = CacheInfo::new( &context.config, &context.cache, - resolve_dependencies(&context), + resolve_dependencies(&context, &ResolveMode::Default), ); if json { println!( @@ -451,7 +487,7 @@ fn try_main() -> Result<()> { Command::Summary { json } => { let mut context = CliContext::new(&cli.config_file)?; context.load_databases()?; - let resolved = resolve_dependencies(&context); + let resolved = resolve_dependencies(&context, &ResolveMode::Default); let summary = ProjectSummary::new( &context.library, &resolved, diff --git a/src/resolver/dependency.rs b/src/resolver/dependency.rs index e7f19375..3ed86f41 100644 --- a/src/resolver/dependency.rs +++ b/src/resolver/dependency.rs @@ -27,7 +27,7 @@ pub struct ResolvedDependency<'d> { pub(crate) kind: PackageType, pub(crate) installation_status: InstallationStatus, pub(crate) path: Option>, - pub(crate) from_lockfile: bool, + pub from_lockfile: bool, pub(crate) from_remote: bool, // Remotes are only for local/git deps so the values will always be owned pub(crate) remotes: HashMap, PackageRemote)>,