Packages
nerves
1.14.3
1.15.0
1.14.3
1.14.2
1.14.1
1.14.0
1.13.2
1.13.1
1.13.0
1.12.0
1.11.3
1.11.2
1.11.1
1.11.0
1.10.5
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.3
1.9.2
retired
1.9.1
1.9.0
1.8.0
1.7.17
1.7.16
1.7.15
1.7.14
retired
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
retired
1.7.1
retired
1.7.0
retired
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.1
1.1.0
1.0.1
1.0.0
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.11.0
0.10.1
0.10.0
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.3
0.8.2
0.8.1
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.4.0-rc.0
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
Craft and deploy bulletproof embedded software
Current section
Files
Jump to
Current section
Files
lib/nerves/artifact/resolvers/gitea_api.ex
# SPDX-FileCopyrightText: 2023 James Harton
# SPDX-FileCopyrightText: 2024 Frank Hunleth
#
# SPDX-License-Identifier: Apache-2.0
#
defmodule Nerves.Artifact.Resolvers.GiteaAPI do
@moduledoc false
@behaviour Nerves.Artifact.Resolver
alias Nerves.Utils.HTTPClient
alias Nerves.Utils.Shell
defstruct [:org_repo_url, :api_url, :auth_token, :artifact_filename, :tag, :method]
@impl Nerves.Artifact.Resolver
def plan({:gitea_releases, repo_uri}, version, artifact_filename) do
plan({:gitea_releases, repo_uri, []}, version, artifact_filename)
end
def plan({:gitea_api, org_repo, opts}, version, artifact_filename) do
base_url = Keyword.fetch!(opts, :base_url)
base_uri = base_url |> String.trim_trailing("/") |> uri_parse_with_default_scheme()
prepared = %__MODULE__{
org_repo_url: URI.append_path(base_uri, "/" <> org_repo),
api_url: URI.append_path(base_uri, "/api/v1/repos/" <> org_repo),
auth_token: get_auth_token(opts),
artifact_filename: artifact_filename,
tag: Keyword.get(opts, :tag, "v#{version}"),
method: :gitea_api
}
{__MODULE__, prepared}
end
def plan({:gitea_releases, repo_uri, opts}, version, artifact_filename) do
prepared = %__MODULE__{
org_repo_url: uri_parse_with_default_scheme(repo_uri),
auth_token: get_auth_token(opts),
artifact_filename: artifact_filename,
tag: Keyword.get(opts, :tag, "v#{version}"),
method: :gitea_release
}
{__MODULE__, prepared}
end
def plan(_site, _version, _artifact_filename), do: nil
defp uri_parse_with_default_scheme(s) do
with %URI{scheme: nil} <- URI.parse(s) do
URI.parse("https://" <> s)
end
end
@impl Nerves.Artifact.Resolver
def get(%__MODULE__{} = opts, dest_path) do
auth_headers =
if opts.auth_token,
do: [{"Authorization", "token " <> opts.auth_token}],
else: []
info =
if System.get_env("NERVES_DEBUG") == "1",
do: "#{URI.to_string(opts.org_repo_url)} #{opts.tag}/#{opts.artifact_filename}",
else: opts.artifact_filename
Shell.info([" [Gitea] ", info])
case download(opts.method, opts, dest_path, auth_headers) do
:ok ->
:ok
{:error, reason} ->
{:error,
"""
Download failed: #{reason}
If this is a private repository, please check that you have a Gitea auth token.
Nerves checks the `GITEA_TOKEN` environment variable.
Alternatively, you can set `token:` in your Nerves system's `artifact_sites` specification.
`:gitea_releases` can work for private repositories when an auth token is provided.
If direct authenticated release downloads do not work for your Gitea setup, try
using `:gitea_api` instead.
This failure was specifically for downloading #{opts.artifact_filename}. Other
files could have been tried.
Check the release page for available artifacts:
"#{URI.to_string(opts.org_repo_url)}/releases/tag/#{opts.tag}"
Download method: #{opts.method}
"""}
end
end
defp download(:gitea_release, opts, dest_path, auth_headers) do
download_url =
URI.append_path(
opts.org_repo_url,
"/releases/download/#{opts.tag}/#{opts.artifact_filename}"
)
HTTPClient.download(download_url, dest_path, headers: auth_headers)
end
defp download(:gitea_api, opts, dest_path, auth_headers) do
release_url = URI.append_path(opts.api_url, "/releases/tags/#{opts.tag}")
with {:ok, release} <- HTTPClient.get_json(release_url, headers: auth_headers),
{:ok, download_url} <- find_asset_url(release, opts.artifact_filename) do
HTTPClient.download(download_url, dest_path, headers: auth_headers)
end
end
defp find_asset_url(%{"assets" => assets}, filename) do
case Enum.find(assets, fn a -> a["name"] == filename end) do
%{"browser_download_url" => url} -> {:ok, url}
nil -> {:error, "Asset '#{filename}' not found in release"}
end
end
defp find_asset_url(release, filename) do
{:error,
"Unexpected Gitea release response while looking for asset '#{filename}': " <>
"missing \"assets\" list in #{inspect(release)}"}
end
defp get_auth_token(opts) do
env_token = System.get_env("GITEA_TOKEN")
opts_token = opts[:token]
cond do
env_token != nil -> env_token
opts_token != nil -> opts_token
true -> nil
end
end
end