# Copyright (C) 2020 by the Georgia Tech Research Institute (GTRI)
# This software may be modified and distributed under the terms of
# the BSD 3-Clause license. See the LICENSE file for details.
defmodule Hex.Scanner do
require HTTPoison.Retry
@moduledoc """
Scanner scans for mix dependencies to run analysis on.
"""
def scan(mix?, _project_types) when mix? == false, do: {[], 0}
@doc """
scan: takes in a path to mix dependencies and returns the
dependencies mapped to their analysis and the number of dependencies.
"""
@spec scan(boolean(), %{node: []}) :: {[any], non_neg_integer}
def scan(_mix?, %{mix: [path_to_mix_exs | path_to_mix_lock]}) do
{:ok, {_mixfile, deps_count}} =
File.read!(path_to_mix_exs)
|> Hex.Mixfile.parse!()
{:ok, {lockfile, _count}} =
File.read!(path_to_mix_lock)
|> Hex.Lockfile.parse!()
# lib_map = Hex.Encoder.mixfile_map(mixfile)
lib_map = Hex.Encoder.lockfile_map(lockfile)
result_map =
Enum.map(lib_map, fn {key, _value} ->
query_hex(key)
end)
{result_map, deps_count}
end
defp query_hex(package) do
HTTPoison.start()
response =
HTTPoison.get!("https://hex.pm/api/packages/#{package}")
|> HTTPoison.Retry.autoretry(
max_attempts: 5,
wait: 15000,
include_404s: false,
retry_unknown_errors: false
)
case response.status_code do
200 ->
hex_package_links = Poison.decode!(response.body)["meta"]["links"]
# Hex.pm API doesn't handle case stuff for us.
hex_package_links =
for {k, v} <- hex_package_links, into: %{}, do: {String.downcase(k), v}
cond do
Map.has_key?(hex_package_links, "github") ->
{:ok, report} =
AnalyzerModule.analyze(hex_package_links["github"], "mix.scan", %{types: true})
report
Map.has_key?(hex_package_links, "bitbucket") ->
{:ok, report} =
AnalyzerModule.analyze(hex_package_links["bitbucket"], "mix.scan", %{types: true})
report
Map.has_key?(hex_package_links, "gitlab") ->
{:ok, report} =
AnalyzerModule.analyze(hex_package_links["gitlab"], "mix.scan", %{types: true})
report
true ->
{:ok, report} = AnalyzerModule.analyze(package, "mix.scan", %{types: true})
report
end
_ ->
{:ok, report} = AnalyzerModule.analyze(package, "mix.scan", %{types: true})
report
end
end
end