bootstrap.mk 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. # Copyright (c) 2014, Loïc Hoguin <essen@ninenines.eu>
  2. # This file is part of erlang.mk and subject to the terms of the ISC License.
  3. .PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates
  4. # Core targets.
  5. help::
  6. @printf "%s\n" "" \
  7. "Bootstrap targets:" \
  8. " bootstrap Generate a skeleton of an OTP application" \
  9. " bootstrap-lib Generate a skeleton of an OTP library" \
  10. " bootstrap-rel Generate the files needed to build a release" \
  11. " new t=TPL n=NAME Generate a module NAME based on the template TPL" \
  12. " bootstrap-lib List available templates"
  13. # Bootstrap templates.
  14. bs_appsrc = "{application, $(PROJECT), [" \
  15. " {description, \"\"}," \
  16. " {vsn, \"0.1.0\"}," \
  17. " {modules, []}," \
  18. " {registered, []}," \
  19. " {applications, [" \
  20. " kernel," \
  21. " stdlib" \
  22. " ]}," \
  23. " {mod, {$(PROJECT)_app, []}}," \
  24. " {env, []}" \
  25. "]}."
  26. bs_appsrc_lib = "{application, $(PROJECT), [" \
  27. " {description, \"\"}," \
  28. " {vsn, \"0.1.0\"}," \
  29. " {modules, []}," \
  30. " {registered, []}," \
  31. " {applications, [" \
  32. " kernel," \
  33. " stdlib" \
  34. " ]}" \
  35. "]}."
  36. bs_Makefile = "PROJECT = $(PROJECT)" \
  37. "include erlang.mk"
  38. bs_app = "-module($(PROJECT)_app)." \
  39. "-behaviour(application)." \
  40. "" \
  41. "-export([start/2])." \
  42. "-export([stop/1])." \
  43. "" \
  44. "start(_Type, _Args) ->" \
  45. " $(PROJECT)_sup:start_link()." \
  46. "" \
  47. "stop(_State) ->" \
  48. " ok."
  49. bs_relx_config = "{release, {$(PROJECT)_release, \"1\"}, [$(PROJECT)]}." \
  50. "{extended_start_script, true}." \
  51. "{sys_config, \"rel/sys.config\"}." \
  52. "{vm_args, \"rel/vm.args\"}."
  53. bs_sys_config = "[" \
  54. "]."
  55. bs_vm_args = "-name $(PROJECT)@127.0.0.1" \
  56. "-setcookie $(PROJECT)" \
  57. "-heart"
  58. # Normal templates.
  59. tpl_supervisor = "-module($(n))." \
  60. "-behaviour(supervisor)." \
  61. "" \
  62. "-export([start_link/0])." \
  63. "-export([init/1])." \
  64. "" \
  65. "start_link() ->" \
  66. " supervisor:start_link({local, ?MODULE}, ?MODULE, [])." \
  67. "" \
  68. "init([]) ->" \
  69. " Procs = []," \
  70. " {ok, {{one_for_one, 1, 5}, Procs}}."
  71. tpl_gen_server = "-module($(n))." \
  72. "-behaviour(gen_server)." \
  73. "" \
  74. "%% API." \
  75. "-export([start_link/0])." \
  76. "" \
  77. "%% gen_server." \
  78. "-export([init/1])." \
  79. "-export([handle_call/3])." \
  80. "-export([handle_cast/2])." \
  81. "-export([handle_info/2])." \
  82. "-export([terminate/2])." \
  83. "-export([code_change/3])." \
  84. "" \
  85. "-record(state, {" \
  86. "})." \
  87. "" \
  88. "%% API." \
  89. "" \
  90. "-spec start_link() -> {ok, pid()}." \
  91. "start_link() ->" \
  92. " gen_server:start_link(?MODULE, [], [])." \
  93. "" \
  94. "%% gen_server." \
  95. "" \
  96. "init([]) ->" \
  97. " {ok, \#state{}}." \
  98. "" \
  99. "handle_call(_Request, _From, State) ->" \
  100. " {reply, ignored, State}." \
  101. "" \
  102. "handle_cast(_Msg, State) ->" \
  103. " {noreply, State}." \
  104. "" \
  105. "handle_info(_Info, State) ->" \
  106. " {noreply, State}." \
  107. "" \
  108. "terminate(_Reason, _State) ->" \
  109. " ok." \
  110. "" \
  111. "code_change(_OldVsn, State, _Extra) ->" \
  112. " {ok, State}."
  113. tpl_cowboy_http = "-module($(n))." \
  114. "-behaviour(cowboy_http_handler)." \
  115. "" \
  116. "-export([init/3])." \
  117. "-export([handle/2])." \
  118. "-export([terminate/3])." \
  119. "" \
  120. "-record(state, {" \
  121. "})." \
  122. "" \
  123. "init(_, Req, _Opts) ->" \
  124. " {ok, Req, \#state{}}." \
  125. "" \
  126. "handle(Req, State=\#state{}) ->" \
  127. " {ok, Req2} = cowboy_req:reply(200, Req)," \
  128. " {ok, Req2, State}." \
  129. "" \
  130. "terminate(_Reason, _Req, _State) ->" \
  131. " ok."
  132. tpl_cowboy_loop = "-module($(n))." \
  133. "-behaviour(cowboy_loop_handler)." \
  134. "" \
  135. "-export([init/3])." \
  136. "-export([info/3])." \
  137. "-export([terminate/3])." \
  138. "" \
  139. "-record(state, {" \
  140. "})." \
  141. "" \
  142. "init(_, Req, _Opts) ->" \
  143. " {loop, Req, \#state{}, 5000, hibernate}." \
  144. "" \
  145. "info(_Info, Req, State) ->" \
  146. " {loop, Req, State, hibernate}." \
  147. "" \
  148. "terminate(_Reason, _Req, _State) ->" \
  149. " ok."
  150. tpl_cowboy_rest = "-module($(n))." \
  151. "" \
  152. "-export([init/3])." \
  153. "-export([content_types_provided/2])." \
  154. "-export([get_html/2])." \
  155. "" \
  156. "init(_, _Req, _Opts) ->" \
  157. " {upgrade, protocol, cowboy_rest}." \
  158. "" \
  159. "content_types_provided(Req, State) ->" \
  160. " {[{{<<\"text\">>, <<\"html\">>, '_'}, get_html}], Req, State}." \
  161. "" \
  162. "get_html(Req, State) ->" \
  163. " {<<\"<html><body>This is REST!</body></html>\">>, Req, State}."
  164. tpl_cowboy_ws = "-module($(n))." \
  165. "-behaviour(cowboy_websocket_handler)." \
  166. "" \
  167. "-export([init/3])." \
  168. "-export([websocket_init/3])." \
  169. "-export([websocket_handle/3])." \
  170. "-export([websocket_info/3])." \
  171. "-export([websocket_terminate/3])." \
  172. "" \
  173. "-record(state, {" \
  174. "})." \
  175. "" \
  176. "init(_, _, _) ->" \
  177. " {upgrade, protocol, cowboy_websocket}." \
  178. "" \
  179. "websocket_init(_, Req, _Opts) ->" \
  180. " Req2 = cowboy_req:compact(Req)," \
  181. " {ok, Req2, \#state{}}." \
  182. "" \
  183. "websocket_handle({text, Data}, Req, State) ->" \
  184. " {reply, {text, Data}, Req, State};" \
  185. "websocket_handle({binary, Data}, Req, State) ->" \
  186. " {reply, {binary, Data}, Req, State};" \
  187. "websocket_handle(_Frame, Req, State) ->" \
  188. " {ok, Req, State}." \
  189. "" \
  190. "websocket_info(_Info, Req, State) ->" \
  191. " {ok, Req, State}." \
  192. "" \
  193. "websocket_terminate(_Reason, _Req, _State) ->" \
  194. " ok."
  195. tpl_ranch_protocol = "-module($(n))." \
  196. "-behaviour(ranch_protocol)." \
  197. "" \
  198. "-export([start_link/4])." \
  199. "-export([init/4])." \
  200. "" \
  201. "-type opts() :: []." \
  202. "-export_type([opts/0])." \
  203. "" \
  204. "-record(state, {" \
  205. " socket :: inet:socket()," \
  206. " transport :: module()" \
  207. "})." \
  208. "" \
  209. "start_link(Ref, Socket, Transport, Opts) ->" \
  210. " Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts])," \
  211. " {ok, Pid}." \
  212. "" \
  213. "-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok." \
  214. "init(Ref, Socket, Transport, _Opts) ->" \
  215. " ok = ranch:accept_ack(Ref)," \
  216. " loop(\#state{socket=Socket, transport=Transport})." \
  217. "" \
  218. "loop(State) ->" \
  219. " loop(State)."
  220. # Plugin-specific targets.
  221. bootstrap:
  222. ifneq ($(wildcard src/),)
  223. $(error Error: src/ directory already exists)
  224. endif
  225. @printf "%s\n" $(bs_Makefile) > Makefile
  226. @mkdir src/
  227. @printf "%s\n" $(bs_appsrc) > src/$(PROJECT).app.src
  228. @printf "%s\n" $(bs_app) > src/$(PROJECT)_app.erl
  229. $(eval n := $(PROJECT)_sup)
  230. @printf "%s\n" $(tpl_supervisor) > src/$(PROJECT)_sup.erl
  231. bootstrap-lib:
  232. ifneq ($(wildcard src/),)
  233. $(error Error: src/ directory already exists)
  234. endif
  235. @printf "%s\n" $(bs_Makefile) > Makefile
  236. @mkdir src/
  237. @printf "%s\n" $(bs_appsrc_lib) > src/$(PROJECT).app.src
  238. bootstrap-rel:
  239. ifneq ($(wildcard relx.config),)
  240. $(error Error: relx.config already exists)
  241. endif
  242. ifneq ($(wildcard rel/),)
  243. $(error Error: rel/ directory already exists)
  244. endif
  245. @printf "%s\n" $(bs_relx_config) > relx.config
  246. @mkdir rel/
  247. @printf "%s\n" $(bs_sys_config) > rel/sys.config
  248. @printf "%s\n" $(bs_vm_args) > rel/vm.args
  249. new:
  250. ifeq ($(wildcard src/),)
  251. $(error Error: src/ directory does not exist)
  252. endif
  253. ifndef t
  254. $(error Usage: make new t=TEMPLATE n=NAME)
  255. endif
  256. ifndef tpl_$(t)
  257. $(error Unknown template)
  258. endif
  259. ifndef n
  260. $(error Usage: make new t=TEMPLATE n=NAME)
  261. endif
  262. @printf "%s\n" $(tpl_$(t)) > src/$(n).erl
  263. list-templates:
  264. @echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES))))