Skip to content

Instantly share code, notes, and snippets.

@jemc
Created March 9, 2015 06:04
Show Gist options
  • Save jemc/9051252895b140df2ed0 to your computer and use it in GitHub Desktop.
Save jemc/9051252895b140df2ed0 to your computer and use it in GitHub Desktop.
elixir mix hg deps
defmodule Mix.SCM.Mercurial do
@behaviour Mix.SCM
@moduledoc false
def fetchable? do
true
end
def format(opts) do
opts[:hg]
end
def format_lock(opts) do
case opts[:lock] do
{:hg, _, lock_rev, lock_opts} ->
lock = String.slice(lock_rev, 0, 7)
case Enum.find_value [:branch, :ref, :tag], &List.keyfind(lock_opts, &1, 0) do
{:ref, _} -> lock <> " (ref)"
{key, val} -> lock <> " (#{key}: #{val})"
nil -> lock
end
_ ->
nil
end
end
def accepts_options(_app, opts) do
cond do
gh = opts[:hghub] ->
opts |> Keyword.delete(:hghub) |> Keyword.put(:hg, "hg://hghub.com/#{gh}.hg")
opts[:hg] ->
opts
true ->
nil
end
end
def checked_out?(opts) do
# Are we inside a hg repository?
File.regular?(Path.join(opts[:dest], ".hg/requires"))
end
def lock_status(opts) do
assert_hg
case opts[:lock] do
{:hg, lock_repo, lock_rev, lock_opts} ->
File.cd!(opts[:dest], fn ->
rev_info = get_rev_info
cond do
lock_repo != opts[:hg] -> :outdated
lock_opts != get_lock_opts(opts) -> :outdated
lock_rev != rev_info[:rev] -> :mismatch
lock_repo != rev_info[:origin] -> :outdated
true -> :ok
end
end)
nil ->
:mismatch
_ ->
:outdated
end
end
def equal?(opts1, opts2) do
opts1[:hg] == opts2[:hg] &&
get_lock_opts(opts1) == get_lock_opts(opts2)
end
def checkout(opts) do
assert_hg
path = opts[:dest]
location = opts[:hg]
_ = File.rm_rf!(path)
hg!(["clone", location, path])
File.cd! path, fn -> do_checkout(opts) end
end
def update(opts) do
assert_hg
File.cd! opts[:dest], fn ->
# Ensures origin is set the lock repo
location = opts[:hg]
# update_origin(location)
args = []
if opts[:tag] do
args = ["--tags"|args]
end
hg!(["pull" , "-u"|args])
do_checkout(opts)
end
end
## Helpers
defp do_checkout(opts) do
ref = get_lock_rev(opts[:lock]) || get_opts_rev(opts)
hg!(["update", ref])
get_lock(opts)
end
defp get_lock(opts) do
rev_info = get_rev_info()
{:hg, opts[:hg], rev_info[:rev], get_lock_opts(opts)}
end
defp get_lock_rev({:hg, _repo, lock, _opts}) when is_binary(lock), do: lock
defp get_lock_rev(_), do: nil
defp get_lock_opts(opts) do
lock_opts = Enum.find_value [:branch, :ref, :tag], &List.keyfind(opts, &1, 0)
lock_opts = List.wrap(lock_opts)
if opts[:submodules] do
lock_opts ++ [submodules: true]
else
lock_opts
end
end
defp get_opts_rev(opts) do
if branch = opts[:branch] do
"origin/#{branch}"
else
opts[:ref] || opts[:tag] || "default"
end
end
defp get_rev_info do
destructure [origin, rev],
:os.cmd('hg --hg-dir=.hg config remote.origin.url && hg --hg-dir=.hg rev-parse --verify --quiet HEAD')
|> IO.iodata_to_binary
|> String.split("\n", trim: true)
[origin: origin, rev: rev]
end
# defp update_origin(location) do
# hg!(["--hg-dir=.hg", "config" , "remote.origin.url", location])
# :ok
# end
defp hg!(args) do
{output, status} = System.cmd("hg", args, stderr_to_stdout: true)
if status != 0 do
Mix.raise "Command `hg #{Enum.join(args, " ")}` failed. Output:\n#{output}"
end
true
end
defp assert_hg do
case Mix.State.fetch(:hg_available) do
{:ok, true} ->
:ok
:error ->
if System.find_executable("hg") do
Mix.State.put(:hg_available, true)
else
Mix.raise "Error fetching/updating Mercurial repository: the `hg` " <>
"executable is not available in your PATH. Please install " <>
"Mercurial on this machine or pass --no-deps-check if you want to " <>
"run a previously built application on a system without Mercurial."
end
end
end
defp to_integer(string) do
{int, _} = Integer.parse(string)
int
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment