Browse Source

Add "necessary evil" autopatch feature

The point of this feature is to fix common issues users
experience.

This feature, when used, attempts to fix projects that
are incompatible with erlang.mk. It currently is able
to build a new Makefile based on information it finds
in a rebar.config file (only deps for now) and also
to fix the .app.src file in various ways.
Loïc Hoguin 10 years ago
parent
commit
1729811327
3 changed files with 112 additions and 0 deletions
  1. 18 0
      README.md
  2. 47 0
      core/deps.mk
  3. 47 0
      erlang.mk

+ 18 - 0
README.md

@@ -138,6 +138,24 @@ dep_ct_helper = git https://github.com/extend/ct_helper.git master
 Please note that the test dependencies will only be compiled once
 Please note that the test dependencies will only be compiled once
 when they are fetched, unlike the normal dependencies.
 when they are fetched, unlike the normal dependencies.
 
 
+Autopatch
+---------
+
+The autopatch features allows you to automatically fix packages
+that are not compatible with erlang.mk. It can also be used to
+convert compatible packages to use erlang.mk itself for building
+when used as dependency.
+
+The patching occurs only once, immediately after the package has
+been fetched.
+
+erlang.mk defines a number of packages to be patched. You can add
+more packages to the list by appending the `AUTOPATCH` variable.
+
+``` Makefile
+AUTOPATCH += gproc
+```
+
 Releases
 Releases
 --------
 --------
 
 

+ 47 - 0
core/deps.mk

@@ -5,6 +5,9 @@
 
 
 # Configuration.
 # Configuration.
 
 
+AUTOPATCH ?= edown gen_leader gproc
+export AUTOPATCH
+
 DEPS_DIR ?= $(CURDIR)/deps
 DEPS_DIR ?= $(CURDIR)/deps
 export DEPS_DIR
 export DEPS_DIR
 
 
@@ -42,6 +45,41 @@ distclean:: distclean-deps distclean-pkg
 
 
 # Deps related targets.
 # Deps related targets.
 
 
+define dep_autopatch
+	$(ERL) -eval " \
+DepDir = \"$(DEPS_DIR)/$(1)/\", \
+fun() -> \
+	{ok, Conf} = file:consult(DepDir ++ \"rebar.config\"), \
+	File = case lists:keyfind(deps, 1, Conf) of false -> []; {_, Deps} -> \
+		[begin {Method, Repo, Commit} = case Repos of \
+			{git, R} -> {git, R, master}; \
+			{M, R, {branch, C}} -> {M, R, C}; \
+			{M, R, {tag, C}} -> {M, R, C}; \
+			{M, R, C} -> {M, R, C} \
+		end, \
+		io_lib:format(\"DEPS += ~s\ndep_~s = ~s ~s ~s~n\", [Name, Name, Method, Repo, Commit]) \
+		end || {Name, _, Repos} <- Deps] \
+	end, \
+	ok = file:write_file(\"$(DEPS_DIR)/$(1)/Makefile\", [\"ERLC_OPTS = +debug_info\n\n\", File, \"\ninclude erlang.mk\"]) \
+end(), \
+AppSrcOut = \"$(DEPS_DIR)/$(1)/src/$(1).app.src\", \
+AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> \"$(DEPS_DIR)/$(1)/ebin/$(1).app\"; true -> AppSrcOut end, \
+fun() -> \
+	{ok, [{application, $(1), L}]} = file:consult(AppSrcIn), \
+	L2 = case lists:keyfind(modules, 1, L) of {_, _} -> L; false -> [{modules, []}|L] end, \
+	L3 = case lists:keyfind(vsn, 1, L2) of {vsn, git} -> lists:keyreplace(vsn, 1, L2, {vsn, \"git\"}); _ -> L2 end, \
+	ok = file:write_file(AppSrcOut, io_lib:format(\"~p.~n\", [{application, $(1), L3}])) \
+end(), \
+case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end, \
+halt()."
+endef
+
+ifeq ($(V),0)
+define dep_autopatch_verbose
+	@echo " PATCH " $(1);
+endef
+endif
+
 define dep_fetch
 define dep_fetch
 	if [ "$$$$VS" = "git" ]; then \
 	if [ "$$$$VS" = "git" ]; then \
 		git clone -n -- $$$$REPO $(DEPS_DIR)/$(1); \
 		git clone -n -- $$$$REPO $(DEPS_DIR)/$(1); \
@@ -73,6 +111,15 @@ else
 	COMMIT=$(word 3,$(dep_$(1))); \
 	COMMIT=$(word 3,$(dep_$(1))); \
 	$(call dep_fetch,$(1))
 	$(call dep_fetch,$(1))
 endif
 endif
+ifneq ($(filter $(1),$(AUTOPATCH)),)
+	$(call dep_autopatch_verbose,$(1)) if [ -f $(DEPS_DIR)/$(1)/rebar.config ]; then \
+		$(call dep_autopatch,$(1)); \
+		cd $(DEPS_DIR)/$(1)/ && ln -s ../../erlang.mk; \
+	elif [ ! -f $(DEPS_DIR)/$(1)/Makefile ]; then \
+		echo "ERLC_OPTS = +debug_info\ninclude erlang.mk" > $(DEPS_DIR)/$(1)/Makefile; \
+		cd $(DEPS_DIR)/$(1)/ && ln -s ../../erlang.mk; \
+	fi
+endif
 endef
 endef
 
 
 $(foreach dep,$(DEPS),$(eval $(call dep_target,$(dep))))
 $(foreach dep,$(DEPS),$(eval $(call dep_target,$(dep))))

+ 47 - 0
erlang.mk

@@ -110,6 +110,9 @@ erlang-mk:
 
 
 # Configuration.
 # Configuration.
 
 
+AUTOPATCH ?= edown gen_leader gproc
+export AUTOPATCH
+
 DEPS_DIR ?= $(CURDIR)/deps
 DEPS_DIR ?= $(CURDIR)/deps
 export DEPS_DIR
 export DEPS_DIR
 
 
@@ -147,6 +150,41 @@ distclean:: distclean-deps distclean-pkg
 
 
 # Deps related targets.
 # Deps related targets.
 
 
+define dep_autopatch
+	$(ERL) -eval " \
+DepDir = \"$(DEPS_DIR)/$(1)/\", \
+fun() -> \
+	{ok, Conf} = file:consult(DepDir ++ \"rebar.config\"), \
+	File = case lists:keyfind(deps, 1, Conf) of false -> []; {_, Deps} -> \
+		[begin {Method, Repo, Commit} = case Repos of \
+			{git, R} -> {git, R, master}; \
+			{M, R, {branch, C}} -> {M, R, C}; \
+			{M, R, {tag, C}} -> {M, R, C}; \
+			{M, R, C} -> {M, R, C} \
+		end, \
+		io_lib:format(\"DEPS += ~s\ndep_~s = ~s ~s ~s~n\", [Name, Name, Method, Repo, Commit]) \
+		end || {Name, _, Repos} <- Deps] \
+	end, \
+	ok = file:write_file(\"$(DEPS_DIR)/$(1)/Makefile\", [\"ERLC_OPTS = +debug_info\n\n\", File, \"\ninclude erlang.mk\"]) \
+end(), \
+AppSrcOut = \"$(DEPS_DIR)/$(1)/src/$(1).app.src\", \
+AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> \"$(DEPS_DIR)/$(1)/ebin/$(1).app\"; true -> AppSrcOut end, \
+fun() -> \
+	{ok, [{application, $(1), L}]} = file:consult(AppSrcIn), \
+	L2 = case lists:keyfind(modules, 1, L) of {_, _} -> L; false -> [{modules, []}|L] end, \
+	L3 = case lists:keyfind(vsn, 1, L2) of {vsn, git} -> lists:keyreplace(vsn, 1, L2, {vsn, \"git\"}); _ -> L2 end, \
+	ok = file:write_file(AppSrcOut, io_lib:format(\"~p.~n\", [{application, $(1), L3}])) \
+end(), \
+case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end, \
+halt()."
+endef
+
+ifeq ($(V),0)
+define dep_autopatch_verbose
+	@echo " PATCH " $(1);
+endef
+endif
+
 define dep_fetch
 define dep_fetch
 	if [ "$$$$VS" = "git" ]; then \
 	if [ "$$$$VS" = "git" ]; then \
 		git clone -n -- $$$$REPO $(DEPS_DIR)/$(1); \
 		git clone -n -- $$$$REPO $(DEPS_DIR)/$(1); \
@@ -178,6 +216,15 @@ else
 	COMMIT=$(word 3,$(dep_$(1))); \
 	COMMIT=$(word 3,$(dep_$(1))); \
 	$(call dep_fetch,$(1))
 	$(call dep_fetch,$(1))
 endif
 endif
+ifneq ($(filter $(1),$(AUTOPATCH)),)
+	$(call dep_autopatch_verbose,$(1)) if [ -f $(DEPS_DIR)/$(1)/rebar.config ]; then \
+		$(call dep_autopatch,$(1)); \
+		cd $(DEPS_DIR)/$(1)/ && ln -s ../../erlang.mk; \
+	elif [ ! -f $(DEPS_DIR)/$(1)/Makefile ]; then \
+		echo "ERLC_OPTS = +debug_info\ninclude erlang.mk" > $(DEPS_DIR)/$(1)/Makefile; \
+		cd $(DEPS_DIR)/$(1)/ && ln -s ../../erlang.mk; \
+	fi
+endif
 endef
 endef
 
 
 $(foreach dep,$(DEPS),$(eval $(call dep_target,$(dep))))
 $(foreach dep,$(DEPS),$(eval $(call dep_target,$(dep))))