diff --git a/lib/mix b/lib/mix new file mode 120000 index 0000000000..9b4e4f1db9 --- /dev/null +++ b/lib/mix @@ -0,0 +1 @@ +../extensions/bonfire/lib/mix \ No newline at end of file diff --git a/lib/mix/mess.exs b/lib/mix/mess.exs deleted file mode 100644 index 6dbfa7bba5..0000000000 --- a/lib/mix/mess.exs +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (c) 2020 James Laver, mess Contributors -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -if not Code.ensure_loaded?(Mess) do - defmodule Mess do - @sources [path: "deps.path", git: "deps.git", hex: "deps.hex"] - - @newline ~r/(?:\r\n|[\r\n])/ - @parser ~r/^(?\s*)((?[a-z_][a-z0-9_]+)\s*=\s*"(?[^"]+)")?(?.*)/ - @git_branch ~r/(?[^#]+)(#(?.+))?/ - - def umbrella_path(opts \\ []), - do: opts[:umbrella_path] || if(Mix.env() != :prod, do: "extensions/", else: nil) - - def deps(sources \\ @sources, extra_deps, opts \\ []), - do: Enum.flat_map(sources, fn {k, v} -> read(v, k) end) |> deps_packages(extra_deps, opts) - - defp deps_packages(packages, extra_deps, opts), - do: Enum.flat_map(packages, &dep_spec(&1, opts)) |> deps_uniq(extra_deps, opts) - - defp deps_uniq(packages, extra_deps, opts), - do: Enum.uniq_by(packages ++ extra_deps, &elem(&1, 0)) |> maybe_filter_umbrella(opts) - - defp maybe_filter_umbrella(deps, opts) do - if opts[:umbrella_root?] do - Enum.reject(deps, fn dep -> - dep_opts = elem(dep, 1) - is_list(dep_opts) and dep_opts[:from_umbrella] - end) - - # |> IO.inspect(label: "umbrella_root") - else - if umbrella_path(opts) do - umbrella_deps = read_umbrella("../../config/deps.path", opts) - - deps - |> Enum.map(fn dep -> - name = elem(dep, 0) - - case umbrella_deps[name] do - nil -> - dep - - dep_opts -> - if dep_opts[:from_umbrella] do - {name, in_umbrella: true, override: true} - else - {name, dep_opts |> Keyword.put(:path, "../../#{dep_opts[:path]}")} - end - end - end) - - # |> IO.inspect(label: "in_umbrella") - else - deps - end - end - end - - defp read_umbrella(path, opts) when is_binary(path) do - if File.exists?(path) do - read(path, :path) - |> Enum.flat_map(&dep_spec(&1, opts)) - else - [] - end - end - - defp read(path, kind) when is_binary(path), do: have_read(File.read(path), kind) - - defp have_read({:error, :enoent}, _kind), do: [] - - defp have_read({:ok, file}, kind), - do: Enum.map(String.split(file, @newline), &read_line(&1, kind)) - - defp read_line(line, kind), - do: Map.put(Regex.named_captures(@parser, line), :kind, kind) - - defp dep_spec(%{"package" => ""}, _opts), do: [] - - defp dep_spec(%{"package" => p, "value" => v, :kind => :hex}, _opts), - do: pkg(p, v, override: true) - - defp dep_spec(%{"package" => p, "value" => v, :kind => :path}, opts) do - umbrella_path = umbrella_path(opts) - - if umbrella_path && String.starts_with?(v, umbrella_path) do - pkg(p, from_umbrella: true, override: true, path: v) - else - pkg(p, path: v, override: true) - end - end - - defp dep_spec(%{"package" => p, "value" => v, :kind => :git}, _opts), do: git(v, p) - - defp git(line, p) when is_binary(line), - do: git(Regex.named_captures(@git_branch, line), p) - - defp git(%{"branch" => "", "repo" => r}, p), - do: pkg(p, git: r, override: true) - - defp git(%{"branch" => b, "repo" => r}, p), - do: pkg(p, git: r, branch: b, override: true) - - defp pkg(name, opts), do: [{String.to_atom(name), opts}] - defp pkg(name, version, opts), do: [{String.to_atom(name), version, opts}] - end -end diff --git a/lib/mix/mixer.ex b/lib/mix/mixer.ex deleted file mode 100644 index e66af7aaff..0000000000 --- a/lib/mix/mixer.ex +++ /dev/null @@ -1,299 +0,0 @@ -if not Code.ensure_loaded?(Bonfire.Mixer) do - defmodule Bonfire.Mixer do - def deps(config, deps_subtype) - - def deps(config, :bonfire) do - prefixes = multirepo_prefixes(config) - Enum.filter(config[:deps] || config, &in_multirepo?(&1, prefixes)) - end - - def deps(config, :update = deps_subtype) do - prefixes = multirepo_prefixes(config) - - Enum.filter( - config[:deps] || config, - &(include_dep?(deps_subtype, &1, config[:deps_prefixes][deps_subtype]) || - in_multirepo?(&1, prefixes)) - ) - - # |> IO.inspect(limit: :infinity) - end - - def deps(config, deps_subtype) when is_atom(deps_subtype), - do: - Enum.filter( - config[:deps] || config, - &include_dep?(deps_subtype, &1, config[:deps_prefixes][deps_subtype]) - ) - - def deps_for(type, deps \\ deps()) do - deps(deps, type) - |> Enum.map(&dep_name/1) - end - - def deps do - if function_exported?(Mix.Project, :config, 0), - do: Mix.Project.config()[:deps], - else: Bonfire.Application.deps() - end - - def mix_config do - if function_exported?(Mix.Project, :config, 0), - do: Mix.Project.config(), - else: Bonfire.Application.config() - end - - def multirepo_prefixes(config \\ mix_config()), - do: - List.wrap(config[:deps_prefixes] || mix_config()[:deps_prefixes]) - |> Enum.flat_map(fn {_, list} -> list || [] end) - |> Enum.uniq() - - def in_multirepo?(dep, deps_prefixes \\ multirepo_prefixes()), - do: include_dep?(:bonfire, dep, deps_prefixes) - - def deps_recompile(deps \\ deps_for(:bonfire)), - do: Mix.Task.run("bonfire.dep.compile", ["--force"] ++ List.wrap(deps)) - - # def flavour_path(path) when is_binary(path), do: path - def flavour_path(config), - do: System.get_env("FLAVOUR_PATH", "flavours/" <> flavour(config)) - - def flavour(config \\ mix_config()) - - def flavour(default_flavour) when is_binary(default_flavour), - do: System.get_env("FLAVOUR") || default_flavour - - def flavour(config), do: System.get_env("FLAVOUR") || config[:default_flavour] - - def config_path(config_or_flavour, filename), - do: Path.expand(Path.join([flavour_path(config_or_flavour), "config", filename])) - - def forks_path(), do: System.get_env("FORKS_PATH", "extensions/") - - def mess_sources(config_or_flavour) do - do_mess_sources(System.get_env("WITH_FORKS", "1")) - |> Enum.map(fn {k, v} -> {k, config_path(config_or_flavour, v)} end) - end - - defp do_mess_sources("0"), do: [git: "deps.git", hex: "deps.hex"] - - defp do_mess_sources(_), - do: [path: "deps.path", git: "deps.git", hex: "deps.hex"] - - def deps_to_clean(deps, type) do - deps(deps, type) - |> deps_names() - end - - def deps_to_update(config) do - deps(config, :update) - |> deps_names() - |> IO.inspect( - label: - "Running Bonfire #{version(config)} with configuration from #{flavour_path(config)} in #{Mix.env()} environment. You can run `just mix bonfire.deps.update` to update these extensions and dependencies" - ) - end - - # Specifies which paths to include in docs - - def beam_paths(deps, type \\ :all) do - build = Mix.Project.build_path() - - ([:bonfire] ++ deps(deps, type)) - |> Enum.map(&beam_path(&1, build)) - end - - defp beam_path(app, build), - do: Path.join([build, "lib", dep_name(app), "ebin"]) - - def readme_paths(config), - do: - List.wrap(config[:guides]) ++ - Enum.map(Path.wildcard("flavours/*/README.md"), &flavour_readme/1) ++ - Enum.map(Path.wildcard("docs/DEPENDENCIES/*.md"), &flavour_deps_doc/1) ++ - Enum.flat_map(deps(config, :docs), &readme_path/1) - - defp readme_path(dep) when not is_nil(dep), - do: dep_paths(dep, "README.md") |> List.first() |> readme_path(dep) - - defp readme_path(path, dep) when not is_nil(path), - do: [{path |> String.to_atom(), [filename: "extension-" <> dep_name(dep)]}] - - defp readme_path(_, _), do: [] - - def flavour_readme(path), - do: {path |> String.to_atom(), [filename: path |> String.split("/") |> Enum.at(1)]} - - def flavour_deps_doc(path), - do: - {path |> String.to_atom(), - [ - title: - path - |> String.split("/") - |> Enum.at(2) - |> String.slice(0..-4) - |> String.capitalize(), - filename: - path - |> String.split("/") - |> Enum.at(2) - |> String.slice(0..-4) - |> then(&"deps-#{&1}") - ]} - - # [plug: "https://myserver/plug/"] - def doc_deps(config), do: deps(config, :docs) |> Enum.map(&doc_dep/1) - defp doc_dep(dep), do: {elem(dep, 0), "./"} - - def source_url_pattern("deps/" <> _ = path, line), - do: bonfire_ext_pattern(path, line) - - def source_url_pattern("extensions/" <> _ = path, line), - do: bonfire_ext_pattern(path, line) - - def source_url_pattern("forks/" <> _ = path, line), - do: bonfire_ext_pattern(path, line) - - def source_url_pattern(path, line), do: bonfire_app_pattern(path, line) - - def bonfire_ext_pattern(path, line), - do: - bonfire_ext_pattern( - path |> String.split("/") |> Enum.at(1), - path |> String.split("/") |> Enum.slice(2..1000) |> Enum.join("/"), - line - ) - - def bonfire_ext_pattern(dep, path, line), - do: - bonfire_app_pattern( - "https://github.com/bonfire-networks/#{dep}/blob/main/%{path}#L%{line}", - path, - line - ) - - def bonfire_app_pattern(path, line), - do: - bonfire_app_pattern( - "https://github.com/bonfire-networks/bonfire-app/blob/main/%{path}#L%{line}", - path, - line - ) - - def bonfire_app_pattern(pattern, path, line), - do: - pattern - |> String.replace("%{path}", "#{path}") - |> String.replace("%{line}", "#{line}") - - # Specifies which paths to include when running tests - def test_paths(config), - do: ["test" | Enum.flat_map(deps(config, :test), &dep_paths(&1, "test"))] - - # Specifies which paths to compile per environment - def elixirc_paths(config, :test), - do: [ - "lib", - "test/support" - | Enum.flat_map(deps(config, :test), &dep_paths(&1, "test/support")) - ] - - def elixirc_paths(_, env), do: ["lib"] ++ catalogues(env) - - def include_dep?(type, dep, config_or_prefixes) - - def include_dep?(:update, dep, _config_or_prefixes) when is_tuple(dep), - do: unpinned_git_dep?(dep) - - # defp include_dep?(:docs = type, dep, deps_prefixes), do: String.starts_with?(dep_name(dep), deps_prefixes || @config[:deps_prefixes][type]) || git_dep?(dep) - def include_dep?(type, dep, config_or_prefixes) do - # IO.inspect(config_or_prefixes) - String.starts_with?( - dep_name(dep), - config_or_prefixes[:deps_prefixes][type] || config_or_prefixes[type] || config_or_prefixes - ) - end - - # defp git_dep?(dep) do - # spec = elem(dep, 1) - # is_list(spec) && spec[:git] - # end - - def unpinned_git_dep?(dep) do - spec = elem(dep, 1) - is_list(spec) && spec[:git] && !spec[:commit] - end - - def dep_name(dep) when is_tuple(dep), do: elem(dep, 0) |> dep_name() - def dep_name(dep) when is_atom(dep), do: Atom.to_string(dep) - def dep_name(dep) when is_binary(dep), do: dep - - def deps_names(deps) do - deps - |> Enum.map(&dep_name/1) - |> Enum.join(" ") - end - - def dep_path(dep) when is_binary(dep) do - path_if_exists(forks_path() <> dep) || - path_if_exists( - (Mix.Project.deps_path() <> "/" <> dep) - |> Path.expand(File.cwd!()) - ) || - "." - end - - def dep_path(dep) do - spec = elem(dep, 1) - - path = - if is_list(spec) && spec[:path], - do: spec[:path], - else: - (Mix.Project.deps_path() <> "/" <> dep_name(dep)) - |> Path.relative_to_cwd() - - path_if_exists(path) - end - - defp path_if_exists(path), do: if(File.exists?(path), do: path) - - def dep_paths(dep, extra) when is_list(extra), - do: Enum.flat_map(extra, &dep_paths(dep, &1)) - - def dep_paths(dep, extra) when is_binary(extra) do - dep_path = dep_path(dep) - - if dep_path do - path = Path.join(dep_path, extra) |> path_if_exists() - if path, do: [path], else: [] - else - [] - end - end - - def version(config) do - config[:version] - |> String.split("-", parts: 2) - |> List.insert_at(1, flavour(config)) - |> Enum.join("-") - end - - # def compilers(:dev) do - # [:unused] ++ compilers(nil) - # end - - def compilers(_) do - Mix.compilers() - end - - def catalogues(_env) do - [ - "deps/surface/priv/catalogue", - dep_path("bonfire_ui_social") <> "/priv/catalogue" - ] - end - end -end diff --git a/lib/mix/tasks/account/account.new.ex b/lib/mix/tasks/account/account.new.ex deleted file mode 100644 index 232754eda1..0000000000 --- a/lib/mix/tasks/account/account.new.ex +++ /dev/null @@ -1,103 +0,0 @@ -## About half of this code is taken from hex, therefore this whole -## file is considered under the same license terms as hex. -defmodule Mix.Tasks.Bonfire.Account.New do - use Mix.Task - - @shortdoc "Creates a new account in the database" - - @moduledoc """ - Creates an account in the database, automatically activated - - ## Usage - - ``` - mix bonfire.account.new [email@address] - ``` - - You will be prompted for a password and an email if it was not provided. - """ - - alias Bonfire.Me.Fake - - @spec run(OptionParser.argv()) :: :ok - def run(args) do - options = options(args, %{}) - Mix.Task.run("app.start") - email = get("Enter an email address: ", :email, options, true) - password = password("Enter a password:") - IO.inspect(password: password) - - Fake.fake_account!(%{ - credential: %{password: password}, - email: %{email_address: email} - }) - end - - defp options([], opts), do: opts - defp options([email], opts), do: Map.put(opts, :email, email) - - defp get(prompt, key, opts, must?) do - case opts[key] do - nil -> - case IO.gets(prompt) do - :eof -> - raise RuntimeError, message: "EOF" - - data when is_binary(data) -> - get(prompt, key, Map.put(opts, key, data), must?) - - data when is_list(data) -> - get(prompt, key, Map.put(opts, key, to_string(data)), must?) - end - - data -> - data = String.trim(data) - - if data == "" do - if must?, - do: get(prompt, key, Map.delete(opts, key), must?), - else: nil - else - data - end - end - end - - # Extracted from hex via https://dev.to/tizpuppi/password-input-in-elixir-31oo - defp password(prompt) do - pid = spawn_link(fn -> loop(prompt) end) - ref = make_ref() - password(prompt, pid, ref) - end - - defp password(prompt, pid, ref) do - value = String.trim(IO.gets(prompt)) - - if String.length(value) < 10 do - IO.puts( - :standard_error, - "Password too short, must be at least 10 characters long" - ) - - password(prompt, pid, ref) - else - send(pid, {:done, self(), ref}) - - receive do - {:done, ^pid, ^ref} -> value - end - end - end - - defp loop(prompt) do - receive do - {:done, parent, ref} -> - send(parent, {:done, self(), ref}) - IO.write(:standard_error, "\e[2K\r") - after - 1 -> - IO.write(:standard_error, "\e[2K\r#{prompt}") - loop(prompt) - end - end -end diff --git a/lib/mix/tasks/cleanup/import2alias.ex b/lib/mix/tasks/cleanup/import2alias.ex deleted file mode 100644 index a7049479f1..0000000000 --- a/lib/mix/tasks/cleanup/import2alias.ex +++ /dev/null @@ -1,35 +0,0 @@ -defmodule Mix.Tasks.Import2alias do - use Mix.Task - - @impl true - def run(args) do - unless Version.match?(System.version(), ">= 1.10.0-rc") do - Mix.raise("Elixir v1.10+ is required!") - end - - case args do - [module, alias] -> - run(Module.concat([module]), Module.concat([alias])) - - _ -> - Mix.raise("Usage: elixir -r lib_import2alias.ex -S mix import2alias MODULE ALIAS") - end - end - - defp run(module, alias) do - {:ok, _} = Import2Alias.Server.start_link(module) - - Code.compiler_options(parser_options: [columns: true]) - - args = ["--force", "--tracer", "Import2Alias.CallerTracer"] - - # Mix.Task.rerun("compile.elixir", args) - deps = Bonfire.Mixer.deps_for(:bonfire) - # |> IO.inspect() - - Mix.Tasks.Bonfire.Deps.Compile.try_compile(deps, args) - - entries = Import2Alias.Server.entries() - Import2Alias.import2alias(alias, entries) - end -end diff --git a/lib/mix/tasks/deps_compile.ex b/lib/mix/tasks/deps_compile.ex deleted file mode 100644 index 6c303f75a8..0000000000 --- a/lib/mix/tasks/deps_compile.ex +++ /dev/null @@ -1,279 +0,0 @@ -defmodule Mix.Tasks.Bonfire.Deps.Compile do - use Mix.Task - import Untangle - - @shortdoc "Compiles dependencies" - - @moduledoc """ - (re)compiles dependencies. - - This is a modified version of Elixir's `Mix.Tasks.Deps.Compile` which was needed to compile dependencies and extract localisable strings in `Mix.Tasks.Bonfire.Localise.Extract` - - By default, compile all dependencies. A list of dependencies - can be given compile multiple dependencies in order. - - This task attempts to detect if the project contains one of - the following files and act accordingly: - - * `mix.exs` - invokes `mix compile` - * otherwise skip - - If a list of dependencies is given, Mix will attempt to compile - them as is. For example, if project `a` depends on `b`, calling - `mix deps.compile a` will compile `a` even if `b` is out of - date. This is to allow parts of the dependency tree to be - recompiled without propagating those changes upstream. To ensure - `b` is included in the compilation step, pass `--include-children`. - """ - - import Mix.Dep, only: [available?: 1, mix?: 1] - - @switches [include_children: :boolean, force: :boolean] - - def force_compile(dep_or_deps, compile_args \\ []) do - # mark deps to be recompiled (run this task) - Mix.Tasks.Bonfire.Deps.Compile.run(["--force"] ++ List.wrap(dep_or_deps)) - - # If "compile" was never called, the reenabling is a no-op and - # "compile.elixir" is a no-op as well (because it wasn't re-enabled after - # running "compile"). If "compile" was already called, then running - # "compile" is a no-op and running "compile.elixir" will work because we - # manually re-enabled it. - Mix.Task.reenable("compile.elixir") - Mix.Task.run("compile", compile_args) - Mix.Task.run("compile.elixir", compile_args) - end - - def try_compile(dep_or_deps, compile_args \\ []) do - # mark deps to be recompiled (run this task) - Mix.Tasks.Bonfire.Deps.Compile.run(["--force"] ++ List.wrap(dep_or_deps)) - - Mix.Task.rerun("compile.elixir", compile_args) - end - - @spec run(OptionParser.argv()) :: :ok - def run(args) do - unless "--no-archives-check" in args do - Mix.Task.run("archive.check", args) - end - - Mix.Project.get!() - - case OptionParser.parse(args, switches: @switches) do - {opts, [], _} -> - # Because this command may be invoked explicitly with - # dep.compile, we simply try to compile any available - # dependency. - compile(Enum.filter(loaded_deps(), &available?/1), opts) - - {opts, tail, _} -> - compile(loaded_by_name(tail, [env: Mix.env()] ++ opts), opts) - end - end - - @doc false - def compile(deps, options \\ []) do - shell = Mix.shell() - config = Mix.Project.deps_config() - - Mix.Task.run("deps.precompile") - - compiled = - Enum.map(deps, fn %Mix.Dep{app: app, status: status, opts: opts, scm: scm} = dep -> - check_unavailable!(app, status) - - compiled? = - cond do - mix?(dep) -> - maybe_clean(dep, options) - do_mix(dep, config) - - true -> - shell.error( - "Could not compile #{inspect(app)}, no \"mix.exs\" found " <> - "(pass :compile as an option to customize compilation, set it to \"false\" to do nothing)" - ) - - false - end - - # We should touch fetchable dependencies even if they - # did not compile otherwise they will always be marked - # as stale, even when there is nothing to do. - fetchable? = touch_fetchable(scm, opts[:build]) - - compiled? and fetchable? - end) - - if true in compiled, do: Mix.Task.run("will_recompile"), else: :ok - end - - defp maybe_clean(dep, opts) do - # If a dependency was marked as fetched or with an out of date lock - # or missing the app file, we always compile it from scratch. - if Keyword.get(opts, :force, false) or Mix.Dep.compilable?(dep) do - File.rm_rf!(Path.join([Mix.Project.build_path(), "lib", Atom.to_string(dep.app)])) - end - end - - defp touch_fetchable(scm, path) do - if scm.fetchable? do - File.mkdir_p!(path) - File.touch!(Path.join(path, ".compile.fetch")) - true - else - false - end - end - - defp check_unavailable!(app, {:unavailable, _}) do - Mix.raise( - "Cannot compile dependency #{inspect(app)} because " <> - "it isn't available, run \"mix deps.get\" first" - ) - end - - defp check_unavailable!(_, _) do - :ok - end - - defp do_mix(dep, _config) do - Mix.Dep.in_dependency(dep, fn _ -> - if req = old_elixir_req(Mix.Project.config()) do - Mix.shell().error( - "warning: the dependency #{inspect(dep.app)} requires Elixir #{inspect(req)} " <> - "but you are running on v#{System.version()}" - ) - end - - Mix.shell().info("Recompiling extension #{inspect(dep.app)}") - - try do - # If "compile" was never called, the reenabling is a no-op and - # "compile.elixir" is a no-op as well (because it wasn't re-enabled after - # running "compile"). If "compile" was already called, then running - # "compile" is a no-op and running "compile.elixir" will work because we - # manually re-enabled it. - Mix.Task.reenable("compile.elixir") - Mix.Task.reenable("compile.leex") - Mix.Task.reenable("compile.all") - Mix.Task.reenable("compile") - - options = [ - # "--force", - "--no-deps-loading", - "--no-apps-loading", - "--no-archives-check", - "--no-elixir-version-check", - "--no-warnings-as-errors" - ] - - res = Mix.Task.run("compile", options) - - # Mix.shell.info(inspect res) - - match?({:ok, _}, res) - catch - kind, reason -> - app = dep.app - - Mix.shell().error( - "could not compile dependency #{inspect(app)}, \"mix compile\" failed. " <> - "You can recompile this dependency with \"mix deps.compile #{app}\", update it " <> - "with \"mix deps.update #{app}\" or clean it with \"mix deps.clean #{app}\"" - ) - - :erlang.raise(kind, reason, __STACKTRACE__) - end - end) - end - - defp old_elixir_req(config) do - req = config[:elixir] - - if req && not Version.match?(System.version(), req) do - req - end - end - - defp loaded_deps() do - if Keyword.has_key?(Mix.Dep.__info__(:functions), :cached) do - Mix.Dep.cached() - else - Mix.Dep.loaded() - end - end - - @doc """ - Receives a list of dependency names and returns loaded `Mix.Dep`s. - Logs a message if the dependency could not be found. - ## Exceptions - This function raises an exception if any of the dependencies - provided in the project are in the wrong format. - """ - def loaded_by_name(given, all_deps \\ nil, opts) do - all_deps = all_deps || loaded_deps() - # |> debug("all_deps") - - # Ensure all apps are atoms - apps = - to_app_names(given) - |> debug("deps to recompile") - - deps = - if opts[:include_children] do - get_deps_with_children(all_deps, apps) - else - get_deps(all_deps, apps) - end - - Enum.each(apps, fn app -> - unless Enum.any?(all_deps, &(&1.app == app)) do - warn("Unknown dependency #{app} for environment #{Mix.env()}") - end - end) - - deps - end - - defp to_app_names(given) do - Enum.map(given, fn app -> - if is_binary(app), do: String.to_atom(app), else: app - end) - end - - defp get_deps(all_deps, apps) do - Enum.filter(all_deps, &(&1.app in apps)) - end - - defp get_deps_with_children(all_deps, apps) do - deps = get_children(all_deps, apps) - apps = deps |> Enum.map(& &1.app) |> Enum.uniq() - get_deps(all_deps, apps) - end - - defp get_children(_all_deps, []), do: [] - - defp get_children(all_deps, apps) do - # Current deps - deps = get_deps(all_deps, apps) - - # Children apps - apps = - for %{deps: children} <- deps, - %{app: app} <- children, - do: app - - # Current deps + children deps - deps ++ get_children(all_deps, apps) - end - - def touch_manifests() do - # |> debug("manifests") - Enum.map(Mix.Tasks.Compile.Elixir.manifests(), &make_old_if_exists/1) - end - - defp make_old_if_exists(path) do - :file.change_time(path, {{2000, 1, 1}, {0, 0, 0}}) - end -end diff --git a/lib/mix/tasks/docs/docs_deps.ex b/lib/mix/tasks/docs/docs_deps.ex deleted file mode 100644 index 827c8c2bd1..0000000000 --- a/lib/mix/tasks/docs/docs_deps.ex +++ /dev/null @@ -1,109 +0,0 @@ -defmodule Mix.Tasks.Docs.Deps do - use Mix.Task - - @shortdoc "Generates docs for your app and its all deps" - @recursive true - @root Bonfire.Common.Config.get(:root_path) - - @moduledoc """ - `mix docs.deps` - - ## Command line options - * `--only` - the environment to include dependencies for - * `--target` - the target to include dependencies for - * `--exclude` - exclude dependencies which you do not want to see in docs. - * any arguments supported by `mix docs` will be passed along - """ - @switches [only: :string, target: :string, exclude: :keep] - - @impl true - def run(args) do - Mix.Project.get!() - {opts, args, _} = OptionParser.parse(args, switches: @switches) - - deps_opts = - for {switch, key} <- [only: :env, target: :target], - value = opts[switch], - do: {key, :"#{value}"} - - excluded = Keyword.get_values(opts, :exclude) - - deps = - Mix.Dep.load_on_environment(deps_opts) - |> prepare_list(opts) - |> List.flatten() - |> Enum.reject(&(Atom.to_string(dep_name(&1)) in excluded)) - |> Enum.uniq_by(&dep_name(&1)) - - config = Mix.Project.config() - build_path = Mix.Project.build_path() - - docs_config = Keyword.get(config, :docs, []) - - docs_config = - docs_config - |> Keyword.put(:deps, Enum.map(deps, &{dep_name(&1), "./"})) - |> Keyword.put( - :source_beam, - Enum.map( - deps, - &Path.join([build_path, "lib", Atom.to_string(dep_name(&1)), "ebin"]) - ) - ) - |> Keyword.put( - :extras, - Keyword.get(docs_config, :extras, []) ++ - Enum.flat_map(deps, &readme_path/1) - ) - - Mix.Tasks.Docs.run(args, Keyword.put(config, :docs, docs_config)) - end - - defp prepare_list(deps, opts) when is_list(deps) do - Enum.flat_map(deps, fn - %Mix.Dep{deps: nested_deps} = dep -> - [dep] ++ prepare_list(nested_deps, opts) - - dep -> - [dep] - end) - end - - defp readme_path(dep) when not is_nil(dep), - do: dep_paths(dep, "README.md") |> List.first() |> readme_path(dep) - - defp readme_path(path, dep) when not is_nil(path), - do: [{String.to_atom(path), [filename: "extension-#{dep_name(dep)}"]}] - - defp readme_path(_, _), do: [] - - defp dep_path(dep) do - path = - if is_list(dep) && dep[:path], - do: dep[:path], - else: (Mix.Project.deps_path() <> "/#{dep_name(dep)}") |> Path.expand(@root) - - path_if_exists(path) - end - - defp dep_paths(dep, extra) when is_list(extra), - do: Enum.flat_map(extra, &dep_paths(dep, &1)) - - defp dep_paths(dep, extra) when is_binary(extra) do - dep_path = dep_path(dep) - - if dep_path do - path = Path.join(dep_path, extra) |> path_if_exists() - if path, do: [path], else: [] - else - [] - end - end - - defp dep_name(%Mix.Dep{app: dep}) when is_atom(dep), do: dep - defp dep_name(dep) when is_tuple(dep), do: elem(dep, 0) |> dep_name() - defp dep_name(dep) when is_atom(dep), do: dep - defp dep_name(dep) when is_binary(dep), do: dep - - defp path_if_exists(path), do: if(File.exists?(path), do: path) -end diff --git a/lib/mix/tasks/localise/localise_extract.ex b/lib/mix/tasks/localise/localise_extract.ex deleted file mode 100644 index 06dfb9b0b5..0000000000 --- a/lib/mix/tasks/localise/localise_extract.ex +++ /dev/null @@ -1,99 +0,0 @@ -defmodule Mix.Tasks.Bonfire.Localise.Extract do - use Mix.Task - import Untangle - @recursive true - - @shortdoc "Extracts translations from source code" - - @moduledoc """ - Extracts translations by recompiling the Elixir source code. - - mix gettext.extract [OPTIONS] - - Translations are extracted into POT (Portable Object Template) files (with a - `.pot` extension). The location of these files is determined by the `:otp_app` - and `:priv` options given by Gettext modules when they call `use Gettext`. One - POT file is generated for each translation domain. - - It is possible to give the `--merge` option to perform merging - for every Gettext backend updated during merge: - - mix gettext.extract --merge - - All other options passed to `gettext.extract` are forwarded to the - `gettext.merge` task (`Mix.Tasks.Gettext.Merge`), which is called internally - by this task. For example: - - mix gettext.extract --merge --no-fuzzy - - """ - - @switches [merge: :boolean] - - def run(args) do - Application.ensure_all_started(:gettext) - _ = Mix.Project.get!() - mix_config = Mix.Project.config() - {opts, _} = OptionParser.parse!(args, switches: @switches) - - gettext_config = - (mix_config[:gettext] || []) - |> debug("gettext config") - - exts_to_localise = - Bonfire.Mixer.deps_for(:localise) - |> debug("bonfire extensions to localise") - - deps_to_localise = - Bonfire.Mixer.deps_for(:localise_self) - |> debug("other deps to localise") - - Mix.Tasks.Bonfire.Deps.Compile.touch_manifests() - - # first extract strings from all deps that use the Gettext module in bonfire_common - pot_files = extract(:bonfire_common, gettext_config, exts_to_localise) - - # then those that have their own Gettext - pot_files = - Enum.reduce(deps_to_localise, pot_files, fn dep, pot_files -> - pot_files ++ extract(String.to_atom(dep), gettext_config, dep) - end) - - # pot_files |> debug("extracted pot_files") - - for {path, contents} <- pot_files do - File.mkdir_p!(Path.dirname(path)) - File.write!(path, contents) - info("Extracted strings to #{Path.relative_to_cwd(path)}") - end - - if opts[:merge] do - run_merge(pot_files, args) - end - - :ok - end - - defp extract(app, gettext_config, deps_to_localise) do - Gettext.Extractor.enable() - - Mix.Tasks.Bonfire.Deps.Compile.force_compile(deps_to_localise) - - Gettext.Extractor.pot_files( - app, - gettext_config - ) - after - Gettext.Extractor.disable() - end - - defp run_merge(pot_files, argv) do - pot_files - |> Enum.map(fn {path, _} -> Path.dirname(path) end) - |> Enum.uniq() - |> Task.async_stream(&Mix.Tasks.Gettext.Merge.run([&1 | argv]), - ordered: false - ) - |> Stream.run() - end -end diff --git a/lib/mix/tasks/release/.gitignore b/lib/mix/tasks/release/.gitignore deleted file mode 100755 index 486faf9075..0000000000 --- a/lib/mix/tasks/release/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where third-party dependencies like ExDoc output generated docs. -/doc/ - -# Ignore .fetch files in case you like to edit your project deps locally. -/.fetch - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Ignore package tarball (built via "mix hex.build"). -release-*.tar - - -# Temporary files for e.g. tests -/tmp - -# The build -release \ No newline at end of file diff --git a/lib/mix/tasks/release/lib/release.ex b/lib/mix/tasks/release/lib/release.ex deleted file mode 100755 index 1cd8610da8..0000000000 --- a/lib/mix/tasks/release/lib/release.ex +++ /dev/null @@ -1,166 +0,0 @@ -defmodule Releaser.VersionUtils do - @doc """ - Some utilities to get and set version numbers in the `mix.exs` file - and to programmatically transform version numbers. - Maybe the `bump_*` functions should be in the standard library? - This script doesn't support pre-release versions or versions with build information. - """ - @version_line_regex ~r/(\n\s*version:\s+")([^\n]+)(")/ - - def bump_major(%Version{} = version) do - %{version | major: version.major + 1, minor: 0, patch: 0} - end - - def bump_minor(%Version{} = version) do - %{version | minor: version.minor + 1, patch: 0} - end - - def bump_patch(%Version{} = version) do - %{version | patch: version.patch + 1} - end - - def bump_pre(%Version{} = version, pre_label) do - IO.inspect(old_pre: version.pre) - - new_pre = - if is_list(version.pre) and List.first(version.pre) == pre_label do - [pre_label, List.last(version.pre) + 1] - else - [pre_label, 1] - end - - %{version | pre: new_pre} - end - - def version_to_string(%Version{ - major: major, - minor: minor, - patch: patch, - pre: pre - }) - when is_list(pre) and length(pre) > 0 do - "#{major}.#{minor}.#{patch}-" <> Enum.join(pre, ".") - end - - def version_to_string(%Version{major: major, minor: minor, patch: patch}) do - "#{major}.#{minor}.#{patch}" - end - - def get_version(mix_path \\ ".") do - version = - if Code.ensure_loaded?(Mix.Project) do - Mix.Project.config()[:version] - else - contents = File.read!(mix_path <> "/mix.exs") - Regex.run(@version_line_regex, contents) |> Enum.fetch!(2) - end - |> IO.inspect() - - Version.parse!(version) - end - - def set_version(version, mix_path \\ ".") do - contents = File.read!(mix_path <> "/mix.exs") - version_string = version_to_string(version) - - replaced = - Regex.replace(@version_line_regex, contents, fn _, pre, _version, post -> - "#{pre}#{version_string}#{post}" - end) - - File.write!(mix_path <> "/mix.exs", replaced) - end - - def update_version(%Version{} = version, "major"), do: bump_major(version) - def update_version(%Version{} = version, "minor"), do: bump_minor(version) - def update_version(%Version{} = version, "patch"), do: bump_patch(version) - - def update_version(%Version{} = version, "alpha" = pre_label), - do: bump_pre(version, pre_label) - - def update_version(%Version{} = version, "beta" = pre_label), - do: bump_pre(version, pre_label) - - def update_version(%Version{} = _version, type), - do: raise("Invalid version type: #{type}") -end - -defmodule Releaser.Git do - @doc """ - This module contains some git-specific functionality - """ - alias Releaser.VersionUtils - - def add_commit_and_tag(version) do - version_string = VersionUtils.version_to_string(version) - Mix.Shell.IO.cmd("git add .", []) - Mix.Shell.IO.cmd(~s'git commit -m "Bumped version number"') - - Mix.Shell.IO.cmd(~s'git tag -a v#{version_string} -m "Version #{version_string}"') - end -end - -defmodule Releaser.Tests do - def run_tests!() do - error_code = Mix.Shell.IO.cmd("mix test", []) - - if error_code != 0 do - raise "This version can't be released because tests are failing." - end - - :ok - end -end - -defmodule Releaser.Publish do - def publish!() do - error_code = Mix.Shell.IO.cmd("mix hex.publish", []) - - if error_code != 0 do - raise "Couldn't publish package on hex." - end - - :ok - end -end - -defmodule Mix.Tasks.Bonfire.Release do - alias Releaser.VersionUtils - - # for running as escript - def main(args) do - run(args) - end - - # when running as Mix task - def run(args) do - mix_path = if is_list(args) and length(args) > 0, do: List.first(args), else: "." - - # TODO make the default configurable - release_type = if is_list(args) and length(args) > 1, do: List.last(args), else: "alpha" - - IO.inspect(release_type: release_type) - - # Run the tests before generating the release. - # If any test fails, stop. - # Tests.run_tests!() - - # Get the current version from the mix.exs file. - old_version = VersionUtils.get_version(mix_path) - IO.inspect(old_version: old_version) - - new_version = VersionUtils.update_version(old_version, release_type) - IO.inspect(new_version: VersionUtils.version_to_string(new_version)) - - # Set a new version on the mix.exs file - VersionUtils.set_version(new_version, mix_path) - - # Commit the changes and ad a new 'v*.*.*' tag - # Git.add_commit_and_tag(new_version) - - # Try to publish the package on hex. - # If this fails, we don't want to run all the code above, - # so you should run `mix hex.publish" again manually to try to solve the problem - # Publish.publish!() - end -end diff --git a/lib/mix/tasks/release/mix.exs b/lib/mix/tasks/release/mix.exs deleted file mode 100755 index 67b1eacf8e..0000000000 --- a/lib/mix/tasks/release/mix.exs +++ /dev/null @@ -1,12 +0,0 @@ -defmodule Bonfire.Release do - use Mix.Project - - def project do - [ - app: :release, - version: "0.1.0-alpha.1", - elixir: "~> 1.11", - escript: [main_module: Mix.Tasks.Bonfire.Release] - ] - end -end diff --git a/lib/mix/tasks/secrets/.gitignore b/lib/mix/tasks/secrets/.gitignore deleted file mode 100755 index 3f8a8bb0cb..0000000000 --- a/lib/mix/tasks/secrets/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where third-party dependencies like ExDoc output generated docs. -/doc/ - -# Ignore .fetch files in case you like to edit your project deps locally. -/.fetch - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Ignore package tarball (built via "mix hex.build"). -release-*.tar - - -# Temporary files for e.g. tests -/tmp - -# The build -secrets \ No newline at end of file diff --git a/lib/mix/tasks/secrets/lib/secrets.ex b/lib/mix/tasks/secrets/lib/secrets.ex deleted file mode 100755 index c233d17257..0000000000 --- a/lib/mix/tasks/secrets/lib/secrets.ex +++ /dev/null @@ -1,45 +0,0 @@ -defmodule Mix.Tasks.Bonfire.Secrets do - @shortdoc "Generates some secrets" - - @moduledoc """ - Generates secrets and prints to the terminal. - mix secrets [length] - By default, it generates keys 64 characters long. - The minimum value for `length` is 32. - """ - use Mix.Task - - # for running as escript - def main(args) do - run(args) - end - - @doc false - def run([]), do: run(["64"]) - - def run([int]), - do: int |> parse!() |> random_string() |> Kernel.<>("\r\n") |> IO.puts() - - def run([int, iterate]), do: for(_ <- 1..parse!(iterate), do: run([int])) - def run(args), do: invalid_args!(args) - - defp parse!(int) do - case Integer.parse(int) do - {int, ""} -> int - _ -> invalid_args!(int) - end - end - - defp random_string(length) when length > 31 do - :crypto.strong_rand_bytes(length) - |> Base.encode64() - |> binary_part(0, length) - end - - defp random_string(_), - do: raise("Secrets should be at least 32 characters long") - - defp invalid_args!(args) do - raise "Expected a length as integer or no argument at all, got #{inspect(args)}" - end -end diff --git a/lib/mix/tasks/secrets/mix.exs b/lib/mix/tasks/secrets/mix.exs deleted file mode 100755 index 01b2e9c52f..0000000000 --- a/lib/mix/tasks/secrets/mix.exs +++ /dev/null @@ -1,12 +0,0 @@ -defmodule Bonfire.Secrets do - use Mix.Project - - def project do - [ - app: :secrets, - version: "0.1.0-alpha.1", - elixir: "~> 1.11", - escript: [main_module: Mix.Tasks.Bonfire.Secrets] - ] - end -end diff --git a/lib/mix/tasks/users/user.admin.promote.ex b/lib/mix/tasks/users/user.admin.promote.ex deleted file mode 100644 index 39a4a44c9a..0000000000 --- a/lib/mix/tasks/users/user.admin.promote.ex +++ /dev/null @@ -1,35 +0,0 @@ -## About half of this code is taken from hex, therefore this whole -## file is considered under the same license terms as hex. -defmodule Mix.Tasks.Bonfire.User.Admin.Promote do - use Mix.Task - - @shortdoc "Promotes a user to an administrator" - - @moduledoc """ - Creates an account in the database, automatically activated - - ## Usage - - ``` - mix bonfire.user.admin.promote username - ``` - """ - - alias Bonfire.Me.Users - - @spec run(OptionParser.argv()) :: :ok - def run(args) do - options = options(args, %{}) - Mix.Task.run("app.start") - - case Users.by_username!(options.username) do - nil -> - raise RuntimeError, message: "User not found" - - user -> - Users.make_admin(user) - end - end - - defp options([username], opts), do: Map.put(opts, :username, username) -end