Packages
version_tasks
0.10.21
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.29
0.10.28
0.10.27
0.10.26
0.10.25
0.10.24
0.10.23
0.10.22
0.10.21
0.10.20
0.10.19
0.10.18
0.10.17
0.10.16
0.10.15
0.10.14
0.10.13
0.10.12
0.10.11
0.10.10
0.10.9
0.10.8
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
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.1
0.7.0
0.6.0
0.5.0
0.4.0
0.3.3
0.3.1
0.2.6
A suite of mix tasks for managing your libs version numbers with git and hex
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/bin/ff.ex
defmodule Mix.Tasks.Version.Bin.Ff do
use Mix.Task
@shortdoc "Add a FeatureFlags (FF) GenServer with release helper scripts to enable/disable them"
def run(_) do
[
"./rel/commands",
]
|> Enum.each(fn dirname ->
:ok = dirname |> Path.expand |> File.mkdir_p!
end)
appname = Mix.Project.config[:app]
module_name = appname |> Atom.to_string |> Macro.camelize
"""
defmodule #{module_name}.FeatureFlags do
use GenServer
alias GenServer, as: GS
alias #{module_name}.FeatureFlags, as: W
### Public API
def start_link(), do: {:ok, _pid} = GS.start_link(__MODULE__, [], name: __MODULE__)
def reset, do: GS.call(W, :reset)
def enable(flag), do: GS.call(W, {:enable, flag |> clean_flag})
def disable(flag), do: GS.call(W, {:disable, flag |> clean_flag})
def remove(flag), do: GS.call(W, {:remove, flag |> clean_flag})
def enabled?(flag, default_answer \\\\ false), do: GS.call(W, {:enabled?, flag |> clean_flag, default_answer})
def disabled?(flag, default_answer \\\\ true), do: GS.call(W, {:disabled?, flag |> clean_flag, default_answer})
def available?(flag), do: GS.call(W, {:available?, flag |> clean_flag})
### Server Callbacks
def init(_) do
{:ok, %{}}
end
def handle_call(:reset, _from, state) do
{:reply, state, %{}}
end
def handle_call({:enable, flag}, _from, state) do
{:reply, :ok, state |> Map.put(flag, true)}
end
def handle_call({:disable, flag}, _from, state) do
{:reply, :ok, state |> Map.put(flag, false)}
end
def handle_call({:remove, flag}, _from, state) do
state
|> Map.get(flag)
|> (&{:reply, &1, Map.delete(state, flag)}).()
end
def handle_call({:enabled?, flag, default_answer}, _from, state) do
check_flag(state, flag, true, default_answer)
end
def handle_call({:disabled?, flag, default_answer}, _from, state) do
check_flag(state, flag, false, default_answer)
end
def handle_call({:available?, flag}, _from, state) do
{:reply, Map.has_key?(state, flag), state}
end
def clean_flag(flag) when is_atom(flag), do: flag
def clean_flag(flag) when is_binary(flag), do: String.to_atom(flag)
def clean_flag(flag) when is_list(flag), do: flag |> to_string |> String.to_atom
def clean_flag(flag), do: flag
def check_flag(state, flag, compare_to, default_if_missing) do
state
|> Map.has_key?(flag)
|> (fn
true -> Map.get(state, flag) == compare_to
false -> default_if_missing
end).()
|> (&{:reply, &1, state}).()
end
end
"""
|> write!("./lib/#{appname}/feature_flags.ex")
"""
#!/bin/bash
bin/#{appname} rpc Elixir.#{module_name}.FeatureFlags enable "$1"
"""
|> write!("./rel/commands/enable")
"""
#!/bin/bash
bin/#{appname} rpc Elixir.#{module_name}.FeatureFlags disable "$1"
"""
|> write!("./rel/commands/disable")
[
"./rel/commands/enable",
"./rel/commands/disable",
]
|> Enum.each(fn filename ->
:ok = filename
|> Path.expand
|> File.chmod(0o755)
end)
IO.puts "Installed several release scripts into ./bin/run and ./bin/package"
IO.puts "To enable ./rel/commands/enable and ./rel/commands/disable to be"
IO.puts "part of the release, then ensure you update your ./rel/config.exs with:"
IO.puts ""
IO.puts ""
example = """
release :#{appname} do
...
set commands: [
"enable": "rel/commands/enable"
"disable": "rel/commands/disable"
]
end
"""
IO.puts example
IO.puts ""
IO.puts "To enable a feature flag 'brb' (for example) you would run the following:"
IO.puts " ./bin/#{appname} enable brb"
IO.puts ""
IO.puts "To later disable that flag you would run the following:"
IO.puts " ./bin/#{appname} disable brb"
IO.puts ""
end
defp write!(content, relative_name) do
File.write!(relative_name |> Path.expand, content)
end
end