Skip to content

Commit

Permalink
improvement: install from private hex repos with repo/package
Browse files Browse the repository at this point in the history
  • Loading branch information
zachallaun committed Nov 15, 2024
1 parent 6c974f4 commit 4bc9083
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 78 deletions.
147 changes: 72 additions & 75 deletions lib/igniter/project/deps.ex
Original file line number Diff line number Diff line change
Expand Up @@ -261,93 +261,90 @@ defmodule Igniter.Project.Deps do

@doc false
def determine_dep_type_and_version(requirement) do
case String.split(requirement, "@", trim: true, parts: 2) do
[package] ->
if Regex.match?(~r/^[a-z][a-z0-9_]*$/, package) do
:inets.start()
:ssl.start()
url = ~c"https://hex.pm/api/packages/#{package}"

case :httpc.request(:get, {url, [{~c"User-Agent", ~c"igniter-installer"}]}, [], []) do
{:ok, {{_version, _, _reason_phrase}, _headers, body}} ->
case Jason.decode(body) do
{:ok,
%{
"releases" => releases
} = body} ->
case first_non_rc_version_or_first_version(releases, body) do
%{"version" => version} ->
{String.to_atom(package),
Igniter.Util.Version.version_string_to_general_requirement!(version)}

_ ->
:error
end

_ ->
:error
end
[package | maybe_version] = String.split(requirement, "@", trim: true, parts: 2)

_ ->
:error
end
else
:error
end
{package, opts} =
case String.split(package, "/", parts: 2) do
[repo, package] ->
{package, repo: repo}

[package, version] ->
case version do
"git:" <> requirement ->
if String.contains?(requirement, "@") do
case String.split(requirement, ["@"], trim: true) do
[url, ref] ->
[git: url, ref: ref, override: true]
[package] ->
{package, []}
end

_ ->
:error
end
else
[git: requirement, override: true]
end
case maybe_version do
[] ->
with {:ok, version} <- fetch_latest_version(package) do
{version, []}
end

"github:" <> requirement ->
if String.contains?(requirement, "@") do
case String.split(requirement, ["/", "@"], trim: true) do
[org, project, ref] ->
[github: "#{org}/#{project}", ref: ref, override: true]
["git:" <> requirement] ->
{nil, git_dep_opts(requirement, :git)}

_ ->
:error
end
else
[github: requirement, override: true]
end
["github:" <> requirement] ->
{nil, git_dep_opts(requirement, :github)}

"path:" <> requirement ->
[path: requirement, override: true]
["path:" <> requirement] ->
{nil, path: requirement, override: true}

version ->
case Version.parse(version) do
{:ok, version} ->
"== #{version}"
[version] ->
case Version.parse(version) do
{:ok, version} ->
{"== #{version}", []}

_ ->
case Igniter.Util.Version.version_string_to_general_requirement(version) do
{:ok, requirement} ->
requirement
_ ->
case Igniter.Util.Version.version_string_to_general_requirement(version) do
{:ok, requirement} ->
{requirement, []}

_ ->
:error
end
_ ->
:error
end
end
|> case do
:error ->
:error

requirement ->
{String.to_atom(package), requirement}
end
_ ->
:error
end
|> case do
{version, additional_opts} ->
to_dependency_spec(package, version, additional_opts ++ opts)

:error ->
:error
end
end

defp to_dependency_spec(package, version, opts)
defp to_dependency_spec(package, version, []), do: {String.to_atom(package), version}
defp to_dependency_spec(package, nil, opts), do: {String.to_atom(package), opts}
defp to_dependency_spec(package, version, opts), do: {String.to_atom(package), version, opts}

defp git_dep_opts(string, kind) do
case String.split(string, "@", trim: true) do
[git_dep, ref] ->
[{kind, git_dep}, {:ref, ref}, {:override, true}]

[git_dep] ->
[{kind, git_dep}, {:override, true}]
end
end

defp fetch_latest_version(package) do
if Regex.match?(~r/^[a-z][a-z0-9_]*$/, package) do
:inets.start()
:ssl.start()
url = ~c"https://hex.pm/api/packages/#{package}"

with {:ok, {{_version, _, _reason_phrase}, _headers, body}} <-
:httpc.request(:get, {url, [{~c"User-Agent", ~c"igniter-installer"}]}, [], []),
{:ok, %{"releases" => releases} = body} <- Jason.decode(body),
%{"version" => version} <- first_non_rc_version_or_first_version(releases, body) do
{:ok, Igniter.Util.Version.version_string_to_general_requirement!(version)}
else
_ -> :error
end
else
:error
end
end

Expand Down
6 changes: 3 additions & 3 deletions lib/igniter/util/install.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ defmodule Igniter.Util.Install do
deps =
Enum.map(deps, fn dep ->
case Igniter.Project.Deps.determine_dep_type_and_version(dep) do
{install, requirement} ->
{install, requirement}

:error ->
raise "Could not determine source for requested package #{dep}"

dep_specification ->
dep_specification
end
end)

Expand Down
2 changes: 2 additions & 0 deletions lib/mix/tasks/igniter.install.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ defmodule Mix.Tasks.Igniter.Install do
* `package@git:git_url` - The package will be installed from the specified git url.
* `package@github:project/repo` - The package will be installed from the specified github repo.
* `package@path:path/to/dep` - The package will be installed from the specified path.
* `repo/package` - The package will be installed from a private Hex repo. This can be used
along with all the options above, e.g. `repo/package@version`.
## Switches
Expand Down
28 changes: 28 additions & 0 deletions test/igniter/project/deps_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,32 @@ defmodule Igniter.Project.DepsTest do
""")
end
end

describe "determine_dep_type_and_version/1" do
test "parses to a version" do
tests = [
"[email protected]": {:dep, "== 1.0.0"},
"[email protected]": {:dep, "~> 1.0"},
"dep@git:git_url": {:dep, git: "git_url", override: true},
"dep@git:git_url@ref": {:dep, git: "git_url", ref: "ref", override: true},
"dep@github:user/repo": {:dep, github: "user/repo", override: true},
"dep@github:user/repo@ref": {:dep, github: "user/repo", ref: "ref", override: true},
"dep@path:path/to/dep": {:dep, path: "path/to/dep", override: true},
"repo/[email protected]": {:dep, "== 1.0.0", repo: "repo"},
"repo/[email protected]": {:dep, "~> 1.0", repo: "repo"},
"repo/dep@git:git_url": {:dep, git: "git_url", override: true, repo: "repo"},
"repo/dep@git:git_url@ref":
{:dep, git: "git_url", ref: "ref", override: true, repo: "repo"},
"repo/dep@github:user/repo": {:dep, github: "user/repo", override: true, repo: "repo"},
"repo/dep@github:user/repo@ref":
{:dep, github: "user/repo", ref: "ref", override: true, repo: "repo"},
"repo/dep@path:path/to/dep": {:dep, path: "path/to/dep", override: true, repo: "repo"}
]

for {spec, expected} <- tests do
assert spec |> to_string() |> Igniter.Project.Deps.determine_dep_type_and_version() ==
expected
end
end
end
end

0 comments on commit 4bc9083

Please sign in to comment.