22//! and compatible with the Elixir Version module, which is used by Hex
33//! internally as well as be the Elixir build tool Hex client.
44
5- use std:: {
6- borrow:: Borrow , cell:: RefCell , cmp:: Ordering , collections:: HashMap , convert:: TryFrom ,
7- error:: Error as StdError , fmt,
8- } ;
9-
10- use crate :: { Dependency , Package , Release } ;
5+ use std:: { cmp:: Ordering , convert:: TryFrom , fmt} ;
116
127use self :: parser:: Parser ;
13- use pubgrub:: {
14- error:: PubGrubError ,
15- solver:: { Dependencies , choose_package_with_fewest_versions} ,
16- type_aliases:: Map ,
17- } ;
188use serde:: {
199 Deserialize , Serialize ,
2010 de:: { self , Deserializer } ,
@@ -27,8 +17,6 @@ mod parser;
2717#[ cfg( test) ]
2818mod tests;
2919
30- type PubgrubRange = pubgrub:: range:: Range < Version > ;
31-
3220/// In a nutshell, a version is represented by three numbers:
3321///
3422/// MAJOR.MINOR.PATCH
@@ -408,220 +396,3 @@ impl std::cmp::Ord for PreOrder<'_> {
408396 }
409397 }
410398}
411-
412- pub type PackageVersions = HashMap < String , Version > ;
413-
414- pub type ResolutionError = PubGrubError < String , Version > ;
415-
416- pub fn resolve_versions < Requirements > (
417- remote : Box < dyn PackageFetcher > ,
418- root_name : PackageName ,
419- dependencies : Requirements ,
420- locked : & HashMap < String , Version > ,
421- ) -> Result < PackageVersions , ResolutionError >
422- where
423- Requirements : Iterator < Item = ( String , Range ) > ,
424- {
425- let root_version = Version :: new ( 0 , 0 , 0 ) ;
426- let root = Package {
427- name : root_name. clone ( ) ,
428- repository : "local" . to_string ( ) ,
429- releases : vec ! [ Release {
430- version: root_version. clone( ) ,
431- outer_checksum: vec![ ] ,
432- retirement_status: None ,
433- requirements: root_dependencies( dependencies, locked) ?,
434- meta: ( ) ,
435- } ] ,
436- } ;
437- let packages = pubgrub:: solver:: resolve (
438- & DependencyProvider :: new ( remote, root, locked) ,
439- root_name. clone ( ) ,
440- root_version,
441- ) ?
442- . into_iter ( )
443- . filter ( |( name, _) | name. as_str ( ) != root_name. as_str ( ) )
444- . collect ( ) ;
445-
446- Ok ( packages)
447- }
448-
449- fn root_dependencies < Requirements > (
450- base_requirements : Requirements ,
451- locked : & HashMap < String , Version > ,
452- ) -> Result < HashMap < String , Dependency > , ResolutionError >
453- where
454- Requirements : Iterator < Item = ( String , Range ) > ,
455- {
456- // Record all of the already locked versions as hard requirements
457- let mut requirements: HashMap < _ , _ > = locked
458- . iter ( )
459- . map ( |( name, version) | ( name. to_string ( ) , Dependency :: from_version ( version) ) )
460- . collect ( ) ;
461-
462- for ( name, range) in base_requirements {
463- match locked. get ( & name) {
464- // If the package was not already locked then we can use the
465- // specified version requirement without modification.
466- None => {
467- let _ = requirements. insert ( name, Dependency :: from_range ( range) ) ;
468- }
469-
470- // If the version was locked we verify that the requirement is
471- // compatible with the locked version.
472- Some ( locked_version) => {
473- let compatible = range
474- . to_pubgrub ( )
475- . map_err ( |e| ResolutionError :: Failure ( format ! ( "Failed to parse range {}" , e) ) ) ?
476- . contains ( locked_version) ;
477- if !compatible {
478- return Err ( ResolutionError :: Failure ( format ! (
479- "{package} is specified with the requirement `{requirement}`, \
480- but it is locked to {version}, which is incompatible.",
481- package = name,
482- requirement = range,
483- version = locked_version,
484- ) ) ) ;
485- }
486- }
487- } ;
488- }
489-
490- Ok ( requirements)
491- // let locked = locked
492- // .iter()
493- // .map(|(name, version)| (name.to_string(), Range::new(version.to_string())));
494- // // Add the locked versions as new requirements that override any existing
495- // // entry in the dependencies list. Collection into a HashMap is used for
496- // // de-duplication.
497- // let deps: HashMap<_, _> = dependencies.chain(locked).collect();
498- // deps.into_iter()
499- // .map(|(package, requirement)| {
500- // (
501- // package,
502- // Dependency {
503- // app: None,
504- // optional: false,
505- // repository: None,
506- // requirement,
507- // },
508- // )
509- // })
510- // .collect()
511- }
512-
513- pub trait PackageFetcher {
514- fn get_dependencies ( & self , package : & str ) -> Result < Package , Box < dyn StdError > > ;
515- }
516-
517- struct DependencyProvider < ' a > {
518- packages : RefCell < HashMap < String , Package > > ,
519- remote : Box < dyn PackageFetcher > ,
520- locked : & ' a HashMap < String , Version > ,
521- }
522-
523- impl < ' a > DependencyProvider < ' a > {
524- fn new (
525- remote : Box < dyn PackageFetcher > ,
526- root : Package ,
527- locked : & ' a HashMap < String , Version > ,
528- ) -> Self {
529- let mut packages = HashMap :: new ( ) ;
530- let _ = packages. insert ( root. name . clone ( ) , root) ;
531- Self {
532- packages : RefCell :: new ( packages) ,
533- locked,
534- remote,
535- }
536- }
537-
538- /// Download information about the package from the registry into the local
539- /// store. Does nothing if the packages are already known.
540- ///
541- /// Package versions are sorted from newest to oldest, with all pre-releases
542- /// at the end to ensure that a non-prerelease version will be picked first
543- /// if there is one.
544- //
545- fn ensure_package_fetched (
546- // We would like to use `&mut self` but the pubgrub library enforces
547- // `&self` with interop mutability.
548- & self ,
549- name : & str ,
550- ) -> Result < ( ) , Box < dyn StdError > > {
551- let mut packages = self . packages . borrow_mut ( ) ;
552- if packages. get ( name) . is_none ( ) {
553- let mut package = self . remote . get_dependencies ( name) ?;
554- // Sort the packages from newest to oldest, pres after all others
555- package. releases . sort_by ( |a, b| a. version . cmp ( & b. version ) ) ;
556- package. releases . reverse ( ) ;
557- let ( pre, mut norm) : ( _ , Vec < _ > ) =
558- package. releases . into_iter ( ) . partition ( Release :: is_pre) ;
559- norm. extend ( pre) ;
560- package. releases = norm;
561- packages. insert ( name. to_string ( ) , package) ;
562- }
563- Ok ( ( ) )
564- }
565- }
566-
567- type PackageName = String ;
568-
569- impl pubgrub:: solver:: DependencyProvider < PackageName , Version > for DependencyProvider < ' _ > {
570- fn choose_package_version <
571- Name : Borrow < PackageName > ,
572- Ver : Borrow < pubgrub:: range:: Range < Version > > ,
573- > (
574- & self ,
575- potential_packages : impl Iterator < Item = ( Name , Ver ) > ,
576- ) -> Result < ( Name , Option < Version > ) , Box < dyn StdError > > {
577- let potential_packages: Vec < _ > = potential_packages
578- . map :: < Result < _ , Box < dyn StdError > > , _ > ( |pair| {
579- self . ensure_package_fetched ( pair. 0 . borrow ( ) ) ?;
580- Ok ( pair)
581- } )
582- . collect :: < Result < _ , _ > > ( ) ?;
583- let list_available_versions = |name : & String | {
584- self . packages
585- . borrow ( )
586- . get ( name)
587- . cloned ( )
588- . into_iter ( )
589- . flat_map ( |p| p. releases . into_iter ( ) )
590- . map ( |p| p. version )
591- } ;
592- Ok ( choose_package_with_fewest_versions (
593- list_available_versions,
594- potential_packages. into_iter ( ) ,
595- ) )
596- }
597-
598- fn get_dependencies (
599- & self ,
600- name : & PackageName ,
601- version : & Version ,
602- ) -> Result < pubgrub:: solver:: Dependencies < PackageName , Version > , Box < dyn StdError > > {
603- self . ensure_package_fetched ( name) ?;
604- let packages = self . packages . borrow ( ) ;
605- let release = match packages
606- . get ( name)
607- . into_iter ( )
608- . flat_map ( |p| p. releases . iter ( ) )
609- . find ( |r| & r. version == version)
610- {
611- Some ( release) => release,
612- None => return Ok ( Dependencies :: Unknown ) ,
613- } ;
614-
615- // Only use retired versions if they have been locked
616- if release. is_retired ( ) && self . locked . get ( name) != Some ( version) {
617- return Ok ( Dependencies :: Unknown ) ;
618- }
619-
620- let mut deps: Map < String , PubgrubRange > = Default :: default ( ) ;
621- for ( name, d) in & release. requirements {
622- let range = d. requirement . to_pubgrub ( ) ?;
623- deps. insert ( name. clone ( ) , range) ;
624- }
625- Ok ( Dependencies :: Known ( deps) )
626- }
627- }
0 commit comments