You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 regels
4.5 KiB

10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
10 jaren geleden
  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. -module(rebar_prv_upgrade).
  4. -behaviour(provider).
  5. -export([init/1,
  6. do/1,
  7. format_error/1]).
  8. -include("rebar.hrl").
  9. -define(PROVIDER, upgrade).
  10. -define(DEPS, []).
  11. %% Also only upgrade top-level (0) deps. Transitive deps shouldn't be
  12. %% upgradable -- if the user wants this, they should declare it at the
  13. %% top level and then upgrade.
  14. %% ===================================================================
  15. %% Public API
  16. %% ===================================================================
  17. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
  18. init(State) ->
  19. State1 =
  20. rebar_state:add_provider(State,
  21. providers:create([{name, ?PROVIDER},
  22. {module, ?MODULE},
  23. {bare, false},
  24. {deps, ?DEPS},
  25. {example, "rebar upgrade cowboy[,ranch]"},
  26. {short_desc, "Upgrade dependency."},
  27. {desc, ""},
  28. {opts, [
  29. {package, undefined, undefined, string, "Packages to upgrade."}
  30. ]}])),
  31. {ok, State1}.
  32. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
  33. do(State) ->
  34. {Args, _} = rebar_state:command_parsed_args(State),
  35. Names = parse_names(ec_cnv:to_binary(proplists:get_value(package, Args))),
  36. %% TODO: support many names. Only a subtree can be updated per app
  37. %% mentioned. When no app is named, unlock *everything*
  38. Locks = rebar_state:get(State, {locks, default}, []),
  39. Deps = rebar_state:get(State, deps),
  40. case prepare_locks(Names, Deps, Locks, []) of
  41. {error, Reason} ->
  42. {error, Reason};
  43. {Locks0, Unlocks0} ->
  44. Deps0 = top_level_deps(Deps, Locks),
  45. State1 = rebar_state:set(State, {deps, default}, Deps0),
  46. State2 = rebar_state:set(State1, {locks, default}, Locks0),
  47. State3 = rebar_state:set(State2, upgrade, true),
  48. Res = rebar_prv_install_deps:do(State3),
  49. case Res of
  50. {ok, S} ->
  51. ct:pal("original locks ~p", [Locks]),
  52. ct:pal("new locks ~p", [Locks0]),
  53. ct:pal("old deps: ~p", [Deps]),
  54. ct:pal("new deps: ~p", [Deps0]),
  55. ct:pal("Unlocks: ~p", [Unlocks0]),
  56. %% TODO: replace new locks onto the old locks list
  57. rebar_prv_lock:do(S);
  58. _ -> Res
  59. end
  60. end.
  61. parse_names(Bin) ->
  62. lists:usort(re:split(Bin, <<" *, *">>, [trim])).
  63. prepare_locks([], _, Locks, Unlocks) ->
  64. {Locks, Unlocks};
  65. prepare_locks([Name|Names], Deps, Locks, Unlocks) ->
  66. case lists:keyfind(Name, 1, Locks) of
  67. {_, _, 0} = Lock ->
  68. AtomName = binary_to_atom(Name, utf8),
  69. case lists:keyfind(AtomName, 1, Deps) of
  70. false ->
  71. {error, {unknown_dependency, Name}};
  72. Dep ->
  73. Source = case Dep of
  74. {_, Src} -> Src;
  75. {_, _, Src} -> Src
  76. end,
  77. {NewLocks, NewUnlocks} = unlock_higher_than(0, Locks -- [Lock]),
  78. prepare_locks(Names,
  79. %deps_like_locks(Deps, [{Name,Source,0} | NewLocks]),
  80. Deps,
  81. NewLocks,
  82. [{Name, Source, 0} | NewUnlocks ++ Unlocks])
  83. end;
  84. {_, _, Level} when Level > 0 ->
  85. {error, {transitive_dependency,Name}};
  86. false ->
  87. {error, {unknown_dependency,Name}}
  88. end.
  89. top_level_deps(Deps, Locks) ->
  90. [Dep || Dep <- Deps, lists:keymember(0, 3, Locks)].
  91. unlock_higher_than(Level, Locks) -> unlock_higher_than(Level, Locks, [], []).
  92. unlock_higher_than(_, [], Locks, Unlocks) ->
  93. {Locks, Unlocks};
  94. unlock_higher_than(Level, [App = {_,_,AppLevel} | Apps], Locks, Unlocks) ->
  95. if AppLevel > Level -> unlock_higher_than(Level, Apps, Locks, [App | Unlocks]);
  96. AppLevel =< Level -> unlock_higher_than(Level, Apps, [App | Locks], Unlocks)
  97. end.
  98. -spec format_error(any()) -> iolist().
  99. format_error(Reason) ->
  100. io_lib:format("~p", [Reason]).