zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

ecto.ex (4517B)


      1 defmodule Mix.Ecto do
      2   @moduledoc """
      3   Conveniences for writing Ecto related Mix tasks.
      4   """
      5 
      6   @doc """
      7   Parses the repository option from the given command line args list.
      8 
      9   If no repo option is given, it is retrieved from the application environment.
     10   """
     11   @spec parse_repo([term]) :: [Ecto.Repo.t]
     12   def parse_repo(args) do
     13     parse_repo(args, [])
     14   end
     15 
     16   defp parse_repo([key, value|t], acc) when key in ~w(--repo -r) do
     17     parse_repo t, [Module.concat([value])|acc]
     18   end
     19 
     20   defp parse_repo([_|t], acc) do
     21     parse_repo t, acc
     22   end
     23 
     24   defp parse_repo([], []) do
     25     apps =
     26       if apps_paths = Mix.Project.apps_paths() do
     27         # TODO: Use the proper ordering from Mix.Project.deps_apps
     28         # when we depend on Elixir v1.11+.
     29         apps_paths |> Map.keys() |> Enum.sort()
     30       else
     31         [Mix.Project.config()[:app]]
     32       end
     33 
     34     apps
     35     |> Enum.flat_map(fn app ->
     36       Application.load(app)
     37       Application.get_env(app, :ecto_repos, [])
     38     end)
     39     |> Enum.uniq()
     40     |> case do
     41       [] ->
     42         Mix.shell().error """
     43         warning: could not find Ecto repos in any of the apps: #{inspect apps}.
     44 
     45         You can avoid this warning by passing the -r flag or by setting the
     46         repositories managed by those applications in your config/config.exs:
     47 
     48             config #{inspect hd(apps)}, ecto_repos: [...]
     49         """
     50         []
     51       repos ->
     52         repos
     53     end
     54   end
     55 
     56   defp parse_repo([], acc) do
     57     Enum.reverse(acc)
     58   end
     59 
     60   @doc """
     61   Ensures the given module is an Ecto.Repo.
     62   """
     63   @spec ensure_repo(module, list) :: Ecto.Repo.t
     64   def ensure_repo(repo, args) do
     65     # Do not pass the --force switch used by some tasks downstream
     66     args = List.delete(args, "--force")
     67 
     68     # TODO: Use only app.config when we depend on Elixir v1.11+.
     69     if Code.ensure_loaded?(Mix.Tasks.App.Config) do
     70       Mix.Task.run("app.config", args)
     71     else
     72       Mix.Task.run("loadpaths", args)
     73       "--no-compile" not in args && Mix.Task.run("compile", args)
     74     end
     75 
     76     case Code.ensure_compiled(repo) do
     77       {:module, _} ->
     78         if function_exported?(repo, :__adapter__, 0) do
     79           repo
     80         else
     81           Mix.raise "Module #{inspect repo} is not an Ecto.Repo. " <>
     82                     "Please configure your app accordingly or pass a repo with the -r option."
     83         end
     84 
     85       {:error, error} ->
     86         Mix.raise "Could not load #{inspect repo}, error: #{inspect error}. " <>
     87                   "Please configure your app accordingly or pass a repo with the -r option."
     88     end
     89   end
     90 
     91   @doc """
     92   Asks if the user wants to open a file based on ECTO_EDITOR.
     93 
     94   By default, it attempts to open the file and line using the
     95   `file:line` notation. For example, if your editor is called
     96   `subl`, it will open the file as:
     97 
     98       subl path/to/file:line
     99 
    100   It is important that you choose an editor command that does
    101   not block nor that attempts to run an editor directly in the
    102   terminal. Command-line based editors likely need extra
    103   configuration so they open up the given file and line in a
    104   separate window.
    105 
    106   Custom editors are supported by using the `__FILE__` and
    107   `__LINE__` notations, for example:
    108 
    109       ECTO_EDITOR="my_editor +__LINE__ __FILE__"
    110 
    111   and Elixir will properly interpolate values.
    112 
    113   """
    114   @spec open?(binary, non_neg_integer) :: boolean
    115   def open?(file, line \\ 1) do
    116     editor = System.get_env("ECTO_EDITOR") || ""
    117 
    118     if editor != "" do
    119       command =
    120         if editor =~ "__FILE__" or editor =~ "__LINE__" do
    121           editor
    122           |> String.replace("__FILE__", inspect(file))
    123           |> String.replace("__LINE__", Integer.to_string(line))
    124         else
    125           "#{editor} #{inspect(file)}:#{line}"
    126         end
    127 
    128       Mix.shell().cmd(command)
    129       true
    130     else
    131       false
    132     end
    133   end
    134 
    135   @doc """
    136   Gets a path relative to the application path.
    137 
    138   Raises on umbrella application.
    139   """
    140   def no_umbrella!(task) do
    141     if Mix.Project.umbrella?() do
    142       Mix.raise "Cannot run task #{inspect task} from umbrella project root. " <>
    143                   "Change directory to one of the umbrella applications and try again"
    144     end
    145   end
    146 
    147   @doc """
    148   Returns `true` if module implements behaviour.
    149   """
    150   def ensure_implements(module, behaviour, message) do
    151     all = Keyword.take(module.__info__(:attributes), [:behaviour])
    152     unless [behaviour] in Keyword.values(all) do
    153       Mix.raise "Expected #{inspect module} to implement #{inspect behaviour} " <>
    154                 "in order to #{message}"
    155     end
    156   end
    157 end