@ -2,20 +2,19 @@
- export ( [ get / 2
, get_all_names / 1
, get_package_versions / 3
, get_package_deps / 3
, get_package_versions / 4
, get_package_deps / 4
, new_package_table / 0
, load_and_verify_version / 1
, registry_dir / 1
, package_dir / 1
, registry_checksum / 3
, find_highest_matching / 6
, find_highest_matching / 4
, find_highest_matching_ / 6
, registry_checksum / 4
, find_highest_matching / 5
, find_highest_matching_ / 5
, verify_table / 1
, format_error / 1
, update_package / 2
, resolve_version / 4 ] ) .
, update_package / 3
, resolve_version / 5 ] ) .
- ifdef ( TEST ) .
- export ( [ cmp_ / 4 , cmpl_ / 4 , valid_vsn / 1 ] ) .
@ -31,55 +30,93 @@
- type package ( ) : : pkg_name ( ) | { pkg_name ( ) , vsn ( ) } .
format_error ( { missing_package , Name , Vsn } ) - >
io_lib : format ( " Package not found in registry : ~ ts- ~ ts. " , [ rebar_utils : to_binary ( Name ) ,
io_lib : format ( " Package not found in any repo : ~ ts- ~ ts. " , [ rebar_utils : to_binary ( Name ) ,
rebar_utils : to_binary ( Vsn ) ] ) ;
format_error ( { missing_package , Pkg } ) - >
io_lib : format ( " Package not found in registry : ~p . " , [ Pkg ] ) .
io_lib : format ( " Package not found in any repo : ~p . " , [ Pkg ] ) .
- spec get ( hex_core : config ( ) , binary ( ) ) - > { ok , map ( ) } | { error , term ( ) } .
get ( Config , Name ) - >
case hex_api_package : get ( Config , Name ) of
try hex_api_package : get ( Config , Name ) of
{ ok , { 200 , _ Headers , PkgInfo } } - >
{ ok , PkgInfo } ;
_ - >
{ error , blewup }
{ ok , { 404 , _ , _ } } - >
{ error , not_found } ;
Error - >
? DEBUG ( " Hex api request failed: ~p " , [ Error ] ) ,
{ error , unknown }
catch
error : { badmatch , { error , { failed_connect , _ } } } - >
{ error , failed_to_connect } ;
_ : Exception - >
? DEBUG ( " hex_api_package:get failed: ~p " , [ Exception ] ) ,
{ error , unknown }
end .
- spec get_all_names ( rebar_state : t ( ) ) - > [ binary ( ) ] .
get_all_names ( State ) - >
verify_table ( State ) ,
lists : usort ( ets : select ( ? PACKAGE_TABLE , [ { #package { key = { '$1' , '_' } ,
lists : usort ( ets : select ( ? PACKAGE_TABLE , [ { #package { key = { '$1' , '_' , '_' },
_ = '_' } ,
[ ] , [ '$1' ] } ] ) ) .
- spec get_package_versions ( binary ( ) , ets : tid ( ) , rebar_state : t ( ) ) - > [ vsn ( ) ] .
get_package_versions ( Dep , Table , State ) - >
- spec get_package_versions ( unicode : unicode_binary ( ) , unicode : unicode_binary ( ) , ets : tid ( ) , rebar_state : t ( ) )
- > [ vsn ( ) ] .
get_package_versions ( Dep , Repo , Table , State ) - >
? MODULE : verify_table ( State ) ,
ets : select ( Table , [ { #package { key = { Dep , '$1' } ,
ets : select ( Table , [ { #package { key = { Dep , '$1' , Repo },
_ = '_' } ,
[ ] , [ '$1' ] } ] ) .
get_package ( Dep , Vsn , Hash , Repo , Table , State ) - >
get_package ( Dep , Vsn , Hash , false , [ Repo ] , Table , State ) .
- spec get_package ( unicode : unicode_binary ( ) , unicode : unicode_binary ( ) ,
binary ( ) | undefined | '_' , boolean ( ) | '_' ,
unicode : unicode_binary ( ) | '_' | list ( ) , ets : tab ( ) , rebar_state : t ( ) )
- > { ok , #package { } } | not_found .
get_package ( Dep , Vsn , undefined , Retired , Repo , Table , State ) - >
get_package ( Dep , Vsn , '_' , Retired , Repo , Table , State ) ;
get_package ( Dep , Vsn , Hash , Retired , Repos , Table , State ) when is_list ( Repos ) - >
? MODULE : verify_table ( State ) ,
case ets : select ( Table , [ { #package { key = { Dep , Vsn , Repo } ,
checksum = Hash ,
retired = Retired ,
_ = '_' } , [ ] , [ '$_' ] } | | Repo < - Repos ] ) of
% % have to allow multiple matches in the list for cases that Repo is ` _ `
[ Package | _ ] - >
{ ok , Package } ;
_ - >
not_found
end ;
get_package ( Dep , Vsn , Hash , Retired , Repo , Table , State ) - >
get_package ( Dep , Vsn , Hash , Retired , [ Repo ] , Table , State ) .
new_package_table ( ) - >
ets : new ( ? PACKAGE_TABLE , [ named_table , public , ordered_set , { keypos , 2 } ] ) ,
ets : insert ( package_index , { ? PACKAGE_INDEX_VERSION , package_index_version } ) .
? PACKAGE_TABLE = ets : new ( ? PACKAGE_TABLE , [ named_table , public , ordered_set , { keypos , 2 } ] ) ,
ets : insert ( ? PACKAGE_TABLE , { ? PACKAGE_INDEX_VERSION , package_index_version } ) .
- spec get_package_deps ( binary ( ) , vsn ( ) , rebar_state : t ( ) ) - > [ map ( ) ] .
get_package_deps ( Name , Vsn , State ) - >
try_lookup ( ? PACKAGE_TABLE , { Name , Vsn } , #package.dependencies , State ) .
- spec get_package_deps ( unicode : unicode_binary ( ) , unicode : unicode_binary ( ) , vsn ( ) , rebar_state : t ( ) )
- > [ map ( ) ] .
get_package_deps ( Name , Vsn , Repo , State ) - >
try_lookup ( ? PACKAGE_TABLE , { Name , Vsn , Repo } , #package.dependencies , State ) .
- spec registry_checksum ( binary ( ) , vsn ( ) , rebar_state : t ( ) ) - > binary ( ) .
registry_checksum ( Name , Vsn , State ) - >
try_lookup ( ? PACKAGE_TABLE , { Name , Vsn } , #package.checksum , State ) .
- spec registry_checksum ( unicode : unicode_binary ( ) , vsn ( ) , unicode : unicode_binary ( ) , rebar_state : t ( ) )
- > binary ( ) .
registry_checksum ( Name , Vsn , Repo , State ) - >
try_lookup ( ? PACKAGE_TABLE , { Name , Vsn , Repo } , #package.checksum , State ) .
try_lookup ( Table , Key , Element , State ) - >
try_lookup ( Table , Key = { _ , _ , Repo } , Element , State ) - >
? MODULE : verify_table ( State ) ,
try
ets : lookup_element ( Table , Key , Element )
catch
_ : _ - >
handle_missing_package ( Key , State , fun ( _ ) - >
ets : lookup_element ( Table , Key , Element )
end )
handle_missing_package ( Key , Repo , State, fun ( _ ) - >
ets : lookup_element ( Table , Key , Element )
end )
end .
load_and_verify_version ( State ) - >
@ -101,10 +138,10 @@ load_and_verify_version(State) ->
new_package_table ( )
end .
handle_missing_package ( PkgKey , State , Fun ) - >
handle_missing_package ( PkgKey , Repo , State, Fun ) - >
Name =
case PkgKey of
{ N , Vsn } - >
{ N , Vsn , _ Repo } - >
? DEBUG ( " Package ~ ts- ~ ts not found. Fetching registry updates for "
" package and trying again... " , [ N , Vsn ] ) ,
N ;
@ -114,7 +151,7 @@ handle_missing_package(PkgKey, State, Fun) ->
PkgKey
end ,
update_package ( Name , State ) ,
update_package ( Name , Repo , State) ,
try
Fun ( State )
catch
@ -174,30 +211,27 @@ package_dir(State) ->
% % ` ~ > 2 . 1 . 3 - dev ` | ` > = 2 . 1 . 3 - dev and < 2 . 2 . 0 `
% % ` ~ > 2 . 0 ` | ` > = 2 . 0 . 0 and < 3 . 0 . 0 `
% % ` ~ > 2 . 1 ` | ` > = 2 . 1 . 0 and < 3 . 0 . 0 `
find_highest_matching ( Dep , Constraint , Table , State ) - >
find_highest_matching ( undefined , undefined , Dep , Constraint , Table , State ) .
find_highest_matching ( Pkg , PkgVsn , Dep , Constraint , Table , State ) - >
try find_highest_matching_ ( Pkg , PkgVsn , Dep , Constraint , Table , State ) of
find_highest_matching ( Dep , Constraint , Repo , Table , State ) - >
try find_highest_matching_ ( Dep , Constraint , Repo , Table , State ) of
none - >
handle_missing_package ( Dep , State ,
handle_missing_package ( Dep , Repo , State ,
fun ( State1 ) - >
find_highest_matching_ ( Pkg , PkgVsn , Dep, Constraint , Table , State1 )
find_highest_matching_ ( Dep , Constraint , Repo , Table , State1 )
end ) ;
Result - >
Result
catch
_ : _ - >
handle_missing_package ( Dep , State ,
handle_missing_package ( Dep , Repo , State,
fun ( State1 ) - >
find_highest_matching_ ( Pkg , PkgVsn , Dep, Constraint , Table , State1 )
find_highest_matching_ ( Dep , Constraint , Repo , Table , State1 )
end )
end .
find_highest_matching_ ( Pkg , PkgVsn , Dep , Constraint , Table , State ) - >
try get_package_versions ( Dep , Table , State ) of
find_highest_matching_ ( Dep , Constraint , #{ name : = Repo } , Table , State ) - >
try get_package_versions ( Dep , Repo , Table, State ) of
[ Vsn ] - >
handle_single_vsn ( Pkg , PkgVsn , Dep , Vsn, Constraint ) ;
handle_single_vsn ( Vsn , Constraint ) ;
Vsns - >
case handle_vsns ( Constraint , Vsns ) of
none - >
@ -221,20 +255,12 @@ handle_vsns(Constraint, Vsns) ->
end
end , none , Vsns ) .
handle_single_vsn ( Pkg , PkgVsn , Dep , Vsn, Constraint ) - >
handle_single_vsn ( Vsn , Constraint ) - >
case ec_semver : pes ( Vsn , Constraint ) of
true - >
{ ok , Vsn } ;
false - >
case { Pkg , PkgVsn } of
{ undefined , undefined } - >
? DEBUG ( " Only existing version of ~ ts is ~ ts which does not match constraint ~~ > ~ ts. "
" Using anyway, but it is not guaranteed to work. " , [ Dep , Vsn , Constraint ] ) ;
_ - >
? DEBUG ( " [ ~ ts: ~ ts] Only existing version of ~ ts is ~ ts which does not match constraint ~~ > ~ ts. "
" Using anyway, but it is not guaranteed to work. " , [ Pkg , PkgVsn , Dep , Vsn , Constraint ] )
end ,
{ ok , Vsn }
none
end .
verify_table ( State ) - >
@ -252,47 +278,129 @@ parse_checksum(<>) ->
parse_checksum ( Checksum ) - >
Checksum .
update_package ( Name , State ) - >
Resources = rebar_state : resources ( State ) ,
#{ hex_config : = HexConfig } = rebar_resource : find_resource_state ( pkg , Resources ) ,
case hex_repo : get_package ( HexConfig , Name ) of
update_package ( Name , RepoConfig = #{ name : = Repo } , State ) - >
? MODULE : verify_table ( State ) ,
try hex_repo : get_package ( RepoConfig , Name ) of
{ ok , { 200 , _ Headers , #{ releases : = Releases } } } - >
_ = insert_releases ( Name , Releases , ? PACKAGE_TABLE ) ,
_ = insert_releases ( Name , Releases , Repo , ? PACKAGE_TABLE ) ,
{ ok , RegistryDir } = rebar_packages : registry_dir ( State ) ,
PackageIndex = filename : join ( RegistryDir , ? INDEX_FILE ) ,
ok = ets : tab2file ( ? PACKAGE_TABLE , PackageIndex ) ;
_ - >
Error - >
? DEBUG ( " Hex get_package request failed: ~p " , [ Error ] ) ,
% % TODO : add better log message . hex_core should export a format_error
? WARN ( " Failed to update package from repo ~ ts " , [ Repo ] ) ,
fail
catch
_ : Exception - >
? DEBUG ( " hex_repo:get_package failed for package ~p : ~p " , [ Name , Exception ] ) ,
fail
end .
insert_releases ( Name , Releases , Table ) - >
insert_releases ( Name , Releases , Repo , Table) - >
[ true = ets : insert ( Table ,
#package { key = { Name , Version } ,
#package { key = { Name , Version , Repo },
checksum = parse_checksum ( Checksum ) ,
retired = maps : get ( retired , Release , false ) ,
dependencies = parse_deps ( Dependencies ) } )
| | #{ checksum : = Checksum ,
version : = Version ,
dependencies : = Dependencies } < - Releases ] .
resolve_version ( Dep , undefined , HexRegistry , State ) - >
find_highest_matching ( Dep , " 0 " , HexRegistry , State ) ;
resolve_version ( Dep , DepVsn , HexRegistry , State ) - >
case { valid_vsn ( DepVsn ) , DepVsn } of
{ false , Vsn } - >
{ error , { invalid_vsn , Vsn } } ;
{ _ , < < " ~ > " , Vsn / binary > > } - >
highest_matching ( Dep , rm_ws ( Vsn ) , HexRegistry , State ) ;
{ _ , < < " >= " , Vsn / binary > > } - >
cmp ( Dep , rm_ws ( Vsn ) , HexRegistry , State , fun ec_semver : gte / 2 ) ;
{ _ , < < " > " , Vsn / binary > > } - >
cmp ( Dep , rm_ws ( Vsn ) , HexRegistry , State , fun ec_semver : gt / 2 ) ;
{ _ , < < " <= " , Vsn / binary > > } - >
cmpl ( Dep , rm_ws ( Vsn ) , HexRegistry , State , fun ec_semver : lte / 2 ) ;
{ _ , < < " < " , Vsn / binary > > } - >
cmpl ( Dep , rm_ws ( Vsn ) , HexRegistry , State , fun ec_semver : lt / 2 ) ;
{ _ , < < " == " , Vsn / binary > > } - >
| | Release = #{ checksum : = Checksum ,
version : = Version ,
dependencies : = Dependencies } < - Releases ] .
- spec resolve_version ( unicode : unicode_binary ( ) , unicode : unicode_binary ( ) | undefined ,
binary ( ) | undefined ,
ets : tab ( ) , rebar_state : t ( ) )
- > { error , { invalid_vsn , unicode : unicode_binary ( ) } } |
not_found |
{ ok , #package { } , map ( ) } .
% % if checksum is defined search for any matching repo matching pkg - vsn and checksum
resolve_version ( Dep , DepVsn , Hash , HexRegistry , State ) when is_binary ( Hash ) - >
Resources = rebar_state : resources ( State ) ,
#{ repos : = RepoConfigs } = rebar_resource : find_resource_state ( pkg , Resources ) ,
RepoNames = [ RepoName | | #{ name : = RepoName } < - RepoConfigs ] ,
% % allow retired packages when we have a checksum
case get_package ( Dep , DepVsn , Hash , '_' , RepoNames , HexRegistry , State ) of
{ ok , Package = #package { key = { _ , _ , RepoName } } } - >
{ ok , RepoConfig } = ec_lists : find ( fun ( #{ name : = N } ) when N =:= RepoName - >
true ;
( _ ) - >
false
end , RepoConfigs ) ,
{ ok , Package , RepoConfig } ;
_ - >
Fun = fun ( Repo ) - >
case resolve_version_ ( Dep , DepVsn , Repo , HexRegistry , State ) of
none - >
not_found ;
{ ok , Vsn } - >
get_package ( Dep , Vsn , Hash , Repo , HexRegistry , State )
end
end ,
handle_missing_no_exception ( Fun , Dep , State )
end ;
resolve_version ( Dep , undefined , Hash , HexRegistry , State ) - >
Fun = fun ( Repo ) - >
case highest_matching ( Dep , " 0 " , Repo , HexRegistry , State ) of
none - >
not_found ;
{ ok , Vsn } - >
get_package ( Dep , Vsn , Hash , Repo , HexRegistry , State )
end
end ,
handle_missing_no_exception ( Fun , Dep , State ) ;
resolve_version ( Dep , DepVsn , Hash , HexRegistry , State ) - >
case valid_vsn ( DepVsn ) of
false - >
{ error , { invalid_vsn , DepVsn } } ;
_ - >
Fun = fun ( Repo ) - >
case resolve_version_ ( Dep , DepVsn , Repo , HexRegistry , State ) of
none - >
not_found ;
{ ok , Vsn } - >
get_package ( Dep , Vsn , Hash , Repo , HexRegistry , State )
end
end ,
handle_missing_no_exception ( Fun , Dep , State )
end .
check_all_repos ( Fun , RepoConfigs ) - >
ec_lists : search ( fun ( #{ name : = R } ) - >
Fun ( R )
end , RepoConfigs ) .
handle_missing_no_exception ( Fun , Dep , State ) - >
Resources = rebar_state : resources ( State ) ,
#{ repos : = RepoConfigs } = rebar_resource : find_resource_state ( pkg , Resources ) ,
% % first check all repos in order for a local match
% % if none is found then we step through checking after updating the repo registry
case check_all_repos ( Fun , RepoConfigs ) of
not_found - >
ec_lists : search ( fun ( Config = #{ name : = R } ) - >
? MODULE : update_package ( Dep , Config , State ) ,
Fun ( R )
end , RepoConfigs ) ;
Result - >
Result
end .
resolve_version_ ( Dep , DepVsn , Repo , HexRegistry , State ) - >
case DepVsn of
< < " ~ > " , Vsn / binary > > - >
highest_matching ( Dep , rm_ws ( Vsn ) , Repo , HexRegistry , State ) ;
< < " >= " , Vsn / binary > > - >
cmp ( Dep , rm_ws ( Vsn ) , Repo , HexRegistry , State , fun ec_semver : gte / 2 ) ;
< < " > " , Vsn / binary > > - >
cmp ( Dep , rm_ws ( Vsn ) , Repo , HexRegistry , State , fun ec_semver : gt / 2 ) ;
< < " <= " , Vsn / binary > > - >
cmpl ( Dep , rm_ws ( Vsn ) , Repo , HexRegistry , State , fun ec_semver : lte / 2 ) ;
< < " < " , Vsn / binary > > - >
cmpl ( Dep , rm_ws ( Vsn ) , Repo , HexRegistry , State , fun ec_semver : lt / 2 ) ;
< < " == " , Vsn / binary > > - >
{ ok , Vsn } ;
{ _ , Vsn } - >
Vsn - >
{ ok , Vsn }
end .
@ -308,22 +416,21 @@ valid_vsn(Vsn) ->
SupportedVersions = " ^(>=?|<=?| ~ >|==)? \\ s* " ++ SemVerRegExp ++ " $ " ,
re : run ( Vsn , SupportedVersions , [ unicode ] ) =/= nomatch .
highest_matching ( Dep , Vsn , HexRegistry , State ) - >
case find_highest_matching_ ( undefined , undefined , Dep , Vsn , HexRegistry , State ) of
{ ok , HighestDepVsn } - >
{ ok , HighestDepVsn } ;
none - >
{ error , { invalid_vsn , Vsn } }
end .
highest_matching ( Dep , Vsn , Repo , HexRegistry , State ) - >
find_highest_matching_ ( Dep , Vsn , #{ name = > Repo } , HexRegistry , State ) .
cmp ( Dep , Vsn , HexRegistry , State , CmpFun ) - >
Vsns = get_package_versions ( Dep , HexRegistry , State ) ,
cmp_ ( undefined , Vsn , Vsns , CmpFun ) .
cmp ( Dep , Vsn , Repo , HexRegistry , State , CmpFun ) - >
case get_package_versions ( Dep , Repo , HexRegistry , State ) of
[ ] - >
none ;
Vsns - >
cmp_ ( undefined , Vsn , Vsns , CmpFun )
end .
cmp_ ( undefined , MinVsn , [ ] , _ CmpFun ) - >
MinVsn ;
{ ok , MinVsn } ;
cmp_ ( HighestDepVsn , _ MinVsn , [ ] , _ CmpFun ) - >
HighestDepVsn ;
{ ok , HighestDepVsn } ;
cmp_ ( BestMatch , MinVsn , [ Vsn | R ] , CmpFun ) - >
case CmpFun ( Vsn , MinVsn ) of
@ -335,14 +442,18 @@ cmp_(BestMatch, MinVsn, [Vsn | R], CmpFun) ->
% % We need to treat this differently since we want a version that is LOWER but
% % the higest possible one .
cmpl ( Dep , Vsn , HexRegistry , State , CmpFun ) - >
Vsns = get_package_versions ( Dep , HexRegistry , State ) ,
cmpl_ ( undefined , Vsn , Vsns , CmpFun ) .
cmpl ( Dep , Vsn , Repo , HexRegistry , State , CmpFun ) - >
case get_package_versions ( Dep , Repo , HexRegistry , State ) of
[ ] - >
none ;
Vsns - >
cmpl_ ( undefined , Vsn , Vsns , CmpFun )
end .
cmpl_ ( undefined , MaxVsn , [ ] , _ CmpFun ) - >
MaxVsn ;
{ ok , MaxVsn } ;
cmpl_ ( HighestDepVsn , _ MaxVsn , [ ] , _ CmpFun ) - >
HighestDepVsn ;
{ ok , HighestDepVsn } ;
cmpl_ ( undefined , MaxVsn , [ Vsn | R ] , CmpFun ) - >
case CmpFun ( Vsn , MaxVsn ) of