Skip to content

Commit f90e598

Browse files
authored
refactor: improve candidate selection logic and streamline version handling (#853)
1 parent a811c2d commit f90e598

File tree

6 files changed

+90
-26
lines changed

6 files changed

+90
-26
lines changed

core/src/ten_manager/src/cmd/cmd_install.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ use ten_rust::pkg_info::{
3535

3636
use crate::{
3737
config::{is_verbose, metadata::TmanMetadata, TmanConfig},
38-
constants::{APP_DIR_IN_DOT_TEN_DIR, DOT_TEN_DIR},
38+
constants::{
39+
APP_DIR_IN_DOT_TEN_DIR, DEFAULT_MAX_LATEST_VERSIONS_WHEN_INSTALL,
40+
DOT_TEN_DIR,
41+
},
3942
dep_and_candidate::get_all_candidates_from_deps,
4043
fs::{check_is_addon_folder, find_nearest_app_dir},
4144
install::{
@@ -87,6 +90,7 @@ pub struct InstallCommand {
8790
pub local_install_mode: LocalInstallMode,
8891
pub standalone: bool,
8992
pub cwd: String,
93+
pub max_latest_versions: i32,
9094

9195
/// When the user only inputs a single path parameter, if a `manifest.json`
9296
/// exists under that path, it indicates installation from a local path.
@@ -146,6 +150,15 @@ pub fn create_sub_cmd(args_cfg: &crate::cmd_line::ArgsCfg) -> Command {
146150
.value_name("DIR")
147151
.required(false),
148152
)
153+
.arg(
154+
Arg::new("MAX_LATEST_VERSIONS")
155+
.long("max-latest-versions")
156+
.help("Maximum number of latest versions to consider")
157+
.value_name("NUMBER")
158+
.value_parser(clap::value_parser!(i32))
159+
.default_value(crate::constants::DEFAULT_MAX_LATEST_VERSIONS_WHEN_INSTALL_STR)
160+
.required(false),
161+
)
149162
}
150163

151164
pub fn parse_sub_cmd(sub_cmd_args: &ArgMatches) -> Result<InstallCommand> {
@@ -163,6 +176,7 @@ pub fn parse_sub_cmd(sub_cmd_args: &ArgMatches) -> Result<InstallCommand> {
163176
local_install_mode: LocalInstallMode::Invalid,
164177
standalone: false,
165178
cwd: String::new(),
179+
max_latest_versions: DEFAULT_MAX_LATEST_VERSIONS_WHEN_INSTALL,
166180
local_path: None,
167181
};
168182

@@ -175,6 +189,13 @@ pub fn parse_sub_cmd(sub_cmd_args: &ArgMatches) -> Result<InstallCommand> {
175189
cmd.cwd = crate::fs::get_cwd()?.to_string_lossy().to_string();
176190
}
177191

192+
// Set max_latest_versions if provided.
193+
if let Some(max_versions) =
194+
sub_cmd_args.get_one::<i32>("MAX_LATEST_VERSIONS")
195+
{
196+
cmd.max_latest_versions = *max_versions;
197+
}
198+
178199
// Retrieve the first positional parameter (in the `PACKAGE_TYPE`
179200
// parameter).
180201
if let Some(first_arg) = sub_cmd_args.get_one::<String>("PACKAGE_TYPE") {
@@ -472,9 +493,7 @@ pub async fn execute_cmd(
472493
let local_path_str = command_data.local_path.clone().unwrap();
473494
let local_path = Path::new(&local_path_str);
474495
let local_path = local_path.canonicalize().with_context(|| {
475-
format!(
476-
"Failed to find the specified local path {local_path_str}"
477-
)
496+
format!("Failed to find the specified local path {local_path_str}")
478497
})?;
479498

480499
let local_manifest_dir = if local_path.is_dir() {
@@ -632,6 +651,7 @@ pub async fn execute_cmd(
632651
&all_candidates,
633652
locked_pkgs.as_ref(),
634653
out.clone(),
654+
command_data.max_latest_versions,
635655
)
636656
.await?;
637657

core/src/ten_manager/src/constants/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,6 @@ pub const CONFIG_JSON: &str = "config.json";
6868
pub const METADATA_FILE: &str = "metadata.json";
6969

7070
pub const BUF_WRITER_BUF_SIZE: usize = 1024 * 1024;
71+
72+
pub const DEFAULT_MAX_LATEST_VERSIONS_WHEN_INSTALL: i32 = 3;
73+
pub const DEFAULT_MAX_LATEST_VERSIONS_WHEN_INSTALL_STR: &str = "3";

core/src/ten_manager/src/designer/builtin_function/install.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ impl WsBuiltinFunction {
3535
standalone: false,
3636
local_path: None,
3737
cwd: base_dir.clone(),
38+
max_latest_versions:
39+
crate::constants::DEFAULT_MAX_LATEST_VERSIONS_WHEN_INSTALL,
3840
};
3941

4042
run_installation(

core/src/ten_manager/src/designer/builtin_function/install_all.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ impl WsBuiltinFunction {
2626
standalone: false,
2727
local_path: None,
2828
cwd: base_dir.clone(),
29+
max_latest_versions:
30+
crate::constants::DEFAULT_MAX_LATEST_VERSIONS_WHEN_INSTALL,
2931
};
3032

3133
run_installation(

core/src/ten_manager/src/solver/solve.rs

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ fn create_input_str_for_pkg_info_dependencies(
433433
pkg_info: &PkgInfo,
434434
dumped_pkgs_info: &mut HashSet<PkgBasicInfo>,
435435
all_candidates: &HashMap<PkgTypeAndName, HashMap<PkgBasicInfo, PkgInfo>>,
436+
max_latest_versions: i32,
436437
) -> Result<()> {
437438
// If this package has already been dumped, skip it.
438439
if dumped_pkgs_info.contains(&pkg_info.into()) {
@@ -470,13 +471,33 @@ fn create_input_str_for_pkg_info_dependencies(
470471
if let Some(candidates) = candidates {
471472
let mut found_matched = false;
472473

473-
for candidate in candidates {
474+
let mut candidates_vec: Vec<&PkgInfo> =
475+
candidates.values().collect();
476+
477+
// The sorting below places the larger versions at the front,
478+
// thus having smaller indexes. This is correct because, in the
479+
// Clingo solver, our optimization strategy is to minimize the
480+
// overall weight, and we prefer larger version numbers.
481+
// Therefore, larger version numbers have smaller weights, and
482+
// the index here is equivalent to the concept of weight in the
483+
// Clingo solver.
484+
candidates_vec.sort_by(|a, b| {
485+
b.manifest.version.cmp(&a.manifest.version)
486+
});
487+
488+
for (idx, candidate) in candidates_vec.into_iter().enumerate() {
489+
if max_latest_versions >= 0
490+
&& idx >= max_latest_versions as usize
491+
{
492+
break;
493+
}
494+
474495
// Get version requirement from dependency.
475496
let version_matches = match dependency {
476497
ManifestDependency::RegistryDependency {
477498
version_req,
478499
..
479-
} => version_req.matches(&candidate.1.manifest.version),
500+
} => version_req.matches(&candidate.manifest.version),
480501
ManifestDependency::LocalDependency { .. } => {
481502
// For local dependencies, just return true to
482503
// match all versions.
@@ -491,31 +512,35 @@ fn create_input_str_for_pkg_info_dependencies(
491512
pkg_info.manifest.type_and_name.pkg_type,
492513
pkg_info.manifest.type_and_name.name,
493514
pkg_info.manifest.version,
494-
candidate.1.manifest.type_and_name.pkg_type,
495-
candidate.1.manifest.type_and_name.name,
496-
candidate.1.manifest.version,
515+
candidate.manifest.type_and_name.pkg_type,
516+
candidate.manifest.type_and_name.name,
517+
candidate.manifest.version,
497518
));
498519

499520
create_input_str_for_pkg_info_dependencies(
500521
input_str,
501-
candidate.1,
522+
candidate,
502523
dumped_pkgs_info,
503524
all_candidates,
525+
max_latest_versions,
504526
)?;
505527

506528
found_matched = true;
507529
}
508530
}
509531

510-
if !found_matched {
532+
if max_latest_versions < 0 && !found_matched {
511533
return Err(anyhow!(
512534
"Failed to find candidates for {}",
513535
match dependency {
514536
ManifestDependency::RegistryDependency {
515537
pkg_type,
516538
name,
517539
version_req,
518-
} => format!("[{pkg_type}]{name} ({version_req})"),
540+
} => format!(
541+
"[{pkg_type}]{name}
542+
({version_req})"
543+
),
519544
ManifestDependency::LocalDependency {
520545
path,
521546
..
@@ -546,14 +571,14 @@ fn create_input_str_for_pkg_info_dependencies(
546571

547572
fn create_input_str_for_pkg_info_without_dependencies(
548573
input_str: &mut String,
549-
pkg_info: &PkgBasicInfo,
574+
pkg_info: &PkgInfo,
550575
weight: &usize,
551576
) -> Result<()> {
552577
input_str.push_str(&format!(
553578
"version_declared(\"{}\", \"{}\", \"{}\", {}).\n",
554-
pkg_info.type_and_name.pkg_type,
555-
pkg_info.type_and_name.name,
556-
pkg_info.version,
579+
pkg_info.manifest.type_and_name.pkg_type,
580+
pkg_info.manifest.type_and_name.name,
581+
pkg_info.manifest.version,
557582
weight
558583
));
559584

@@ -564,18 +589,19 @@ fn create_input_str_for_all_possible_pkgs_info(
564589
input_str: &mut String,
565590
all_candidates: &HashMap<PkgTypeAndName, HashMap<PkgBasicInfo, PkgInfo>>,
566591
locked_pkgs: Option<&HashMap<PkgTypeAndName, PkgInfo>>,
592+
max_latest_versions: i32,
567593
) -> Result<()> {
568594
for candidates in all_candidates {
569-
let mut candidates_vec: Vec<PkgBasicInfo> =
570-
candidates.1.values().map(|pkg_info| pkg_info.into()).collect();
595+
let mut candidates_vec: Vec<&PkgInfo> = candidates.1.values().collect();
571596

572597
// The sorting below places the larger versions at the front, thus
573598
// having smaller indexes. This is correct because, in the Clingo
574599
// solver, our optimization strategy is to minimize the overall weight,
575600
// and we prefer larger version numbers. Therefore, larger version
576601
// numbers have smaller weights, and the index here is equivalent to the
577602
// concept of weight in the Clingo solver.
578-
candidates_vec.sort_by(|a, b| b.cmp(a));
603+
candidates_vec
604+
.sort_by(|a, b| b.manifest.version.cmp(&a.manifest.version));
579605

580606
// Check if the locked package exists in the candidates. If it does,
581607
// move it to the front of the candidates_vec so that it has a smaller
@@ -588,26 +614,31 @@ fn create_input_str_for_all_possible_pkgs_info(
588614
// dependency, do not prioritize any candidate packages.
589615
if !locked_pkg.is_local_dependency {
590616
let idx = candidates_vec.iter().position(|pkg_info| {
591-
locked_pkg.manifest.version == pkg_info.version
617+
locked_pkg.manifest.version == pkg_info.manifest.version
592618
});
593619

594620
if let Some(idx) = idx {
595621
candidates_vec.remove(idx);
596-
candidates_vec.insert(0, locked_pkg.into());
622+
candidates_vec.insert(0, locked_pkg);
597623
}
598624
}
599625
}
600626

601627
for (idx, candidate) in candidates_vec.into_iter().enumerate() {
628+
if max_latest_versions >= 0 && idx >= max_latest_versions as usize {
629+
break;
630+
}
631+
602632
create_input_str_for_pkg_info_without_dependencies(
603-
input_str, &candidate, &idx,
633+
input_str, candidate, &idx,
604634
)?;
605635
}
606636
}
607637

608638
Ok(())
609639
}
610640

641+
#[allow(clippy::too_many_arguments)]
611642
async fn create_input_str(
612643
tman_config: Arc<tokio::sync::RwLock<TmanConfig>>,
613644
pkg_type: &PkgType,
@@ -616,6 +647,7 @@ async fn create_input_str(
616647
all_candidates: &HashMap<PkgTypeAndName, HashMap<PkgBasicInfo, PkgInfo>>,
617648
locked_pkgs: Option<&HashMap<PkgTypeAndName, PkgInfo>>,
618649
out: Arc<Box<dyn TmanOutput>>,
650+
max_latest_versions: i32,
619651
) -> Result<String> {
620652
let mut input_str = String::new();
621653

@@ -627,6 +659,7 @@ async fn create_input_str(
627659
&mut input_str,
628660
all_candidates,
629661
locked_pkgs,
662+
max_latest_versions,
630663
)?;
631664

632665
create_input_str_for_dependency_relationship(
@@ -644,6 +677,7 @@ async fn create_input_str(
644677
candidate.1,
645678
&mut dumped_pkgs_info,
646679
all_candidates,
680+
max_latest_versions,
647681
)?;
648682
}
649683
}
@@ -655,6 +689,7 @@ async fn create_input_str(
655689
Ok(input_str)
656690
}
657691

692+
#[allow(clippy::too_many_arguments)]
658693
pub async fn solve_all(
659694
tman_config: Arc<tokio::sync::RwLock<TmanConfig>>,
660695
pkg_type: &PkgType,
@@ -663,6 +698,7 @@ pub async fn solve_all(
663698
all_candidates: &HashMap<PkgTypeAndName, HashMap<PkgBasicInfo, PkgInfo>>,
664699
locked_pkgs: Option<&HashMap<PkgTypeAndName, PkgInfo>>,
665700
out: Arc<Box<dyn TmanOutput>>,
701+
max_latest_versions: i32,
666702
) -> SolveResult {
667703
let input_str = create_input_str(
668704
tman_config.clone(),
@@ -672,6 +708,7 @@ pub async fn solve_all(
672708
all_candidates,
673709
locked_pkgs,
674710
out.clone(),
711+
max_latest_versions,
675712
)
676713
.await?;
677714
solve(tman_config, &input_str, out).await

tools/rust/cargo_clippy.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#!/bin/bash
22

33
cd core/src/ten_rust || exit 1
4-
cargo clippy --all-features --tests -- -D warnings -W clippy::all
5-
cargo clippy --release --all-features --tests -- -D warnings -W clippy::all
4+
cargo clippy --tests -- -D warnings -W clippy::all
5+
cargo clippy --release --tests -- -D warnings -W clippy::all
66

77
cd ../../..
88

99
cd core/src/ten_manager || exit 1
10-
cargo clippy --all-features --tests -- -D warnings -W clippy::all
11-
cargo clippy --release --all-features --tests -- -D warnings -W clippy::all
10+
cargo clippy --tests -- -D warnings -W clippy::all
11+
cargo clippy --release --tests -- -D warnings -W clippy::all

0 commit comments

Comments
 (0)