1#  -------------------------------------------------------------------
2#
3#  Copyright (c) 2014 Basho Technologies, Inc.
4#
5#  This file is provided to you under the Apache License,
6#  Version 2.0 (the "License"); you may not use this file
7#  except in compliance with the License.  You may obtain
8#  a copy of the License at
9#
10#    http://www.apache.org/licenses/LICENSE-2.0
11#
12#  Unless required by applicable law or agreed to in writing,
13#  software distributed under the License is distributed on an
14#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15#  KIND, either express or implied.  See the License for the
16#  specific language governing permissions and limitations
17#  under the License.
18#
19#  -------------------------------------------------------------------
20
21#  -------------------------------------------------------------------
22#  NOTE: This file is is from https://github.com/basho/tools.mk.
23#  It should not be edited in a project. It should simply be updated
24#  wholesale when a new version of tools.mk is released.
25#  -------------------------------------------------------------------
26
27REBAR ?= ./rebar
28REVISION ?= $(shell git rev-parse --short HEAD)
29PROJECT ?= $(shell basename `find src -name "*.app.src"` .app.src)
30
31.PHONY: compile-no-deps test docs xref dialyzer-run dialyzer-quick dialyzer \
32		cleanplt upload-docs
33
34compile-no-deps:
35	${REBAR} compile skip_deps=true
36
37test: compile
38	${REBAR} eunit skip_deps=true
39
40upload-docs: docs
41	@if [ -z "${BUCKET}" -o -z "${PROJECT}" -o -z "${REVISION}" ]; then \
42		echo "Set BUCKET, PROJECT, and REVISION env vars to upload docs"; \
43	        exit 1; fi
44	@cd doc; s3cmd put -P * "s3://${BUCKET}/${PROJECT}/${REVISION}/" > /dev/null
45	@echo "Docs built at: http://${BUCKET}.s3-website-us-east-1.amazonaws.com/${PROJECT}/${REVISION}"
46
47docs:
48	${REBAR} doc skip_deps=true
49
50xref: compile
51	${REBAR} xref skip_deps=true
52
53PLT ?= $(HOME)/.combo_dialyzer_plt
54LOCAL_PLT = .local_dialyzer_plt
55DIALYZER_FLAGS ?= -Wunmatched_returns
56
57${PLT}: compile
58	@if [ -f $(PLT) ]; then \
59		dialyzer --check_plt --plt $(PLT) --apps $(DIALYZER_APPS) && \
60		dialyzer --add_to_plt --plt $(PLT) --output_plt $(PLT) --apps $(DIALYZER_APPS) ; test $$? -ne 1; \
61	else \
62		dialyzer --build_plt --output_plt $(PLT) --apps $(DIALYZER_APPS); test $$? -ne 1; \
63	fi
64
65${LOCAL_PLT}: compile
66	@if [ -d deps ]; then \
67		if [ -f $(LOCAL_PLT) ]; then \
68			dialyzer --check_plt --plt $(LOCAL_PLT) deps/*/ebin  && \
69			dialyzer --add_to_plt --plt $(LOCAL_PLT) --output_plt $(LOCAL_PLT) deps/*/ebin ; test $$? -ne 1; \
70		else \
71			dialyzer --build_plt --output_plt $(LOCAL_PLT) deps/*/ebin ; test $$? -ne 1; \
72		fi \
73	fi
74
75dialyzer-run:
76	@echo "==> $(shell basename $(shell pwd)) (dialyzer)"
77# The bulk of the code below deals with the dialyzer.ignore-warnings file
78# which contains strings to ignore if output by dialyzer.
79# Typically the strings include line numbers. Using them exactly is hard
80# to maintain as the code changes. This approach instead ignores the line
81# numbers, but takes into account the number of times a string is listed
82# for a given file. So if one string is listed once, for example, and it
83# appears twice in the warnings, the user is alerted. It is possible but
84# unlikely that this approach could mask a warning if one ignored warning
85# is removed and two warnings of the same kind appear in the file, for
86# example. But it is a trade-off that seems worth it.
87# Details of the cryptic commands:
88#   - Remove line numbers from dialyzer.ignore-warnings
89#   - Pre-pend duplicate count to each warning with sort | uniq -c
90#   - Remove annoying white space around duplicate count
91#   - Save in dialyer.ignore-warnings.tmp
92#   - Do the same to dialyzer_warnings
93#   - Remove matches from dialyzer.ignore-warnings.tmp from output
94#   - Remove duplicate count
95#   - Escape regex special chars to use lines as regex patterns
96#   - Add pattern to match any line number (file.erl:\d+:)
97#   - Anchor to match the entire line (^entire line$)
98#   - Save in dialyzer_unhandled_warnings
99#   - Output matches for those patterns found in the original warnings
100	@if [ -f $(LOCAL_PLT) ]; then \
101		PLTS="$(PLT) $(LOCAL_PLT)"; \
102	else \
103		PLTS=$(PLT); \
104	fi; \
105	if [ -f dialyzer.ignore-warnings ]; then \
106		if [ $$(grep -cvE '[^[:space:]]' dialyzer.ignore-warnings) -ne 0 ]; then \
107			echo "ERROR: dialyzer.ignore-warnings contains a blank/empty line, this will match all messages!"; \
108			exit 1; \
109		fi; \
110		dialyzer $(DIALYZER_FLAGS) --plts $${PLTS} -c ebin > dialyzer_warnings ; \
111		cat dialyzer.ignore-warnings \
112		| sed -E 's/^([^:]+:)[^:]+:/\1/' \
113		| sort \
114		| uniq -c \
115		| sed -E '/.*\.erl: /!s/^[[:space:]]*[0-9]+[[:space:]]*//' \
116		> dialyzer.ignore-warnings.tmp ; \
117		egrep -v "^[[:space:]]*(done|Checking|Proceeding|Compiling)" dialyzer_warnings \
118		| sed -E 's/^([^:]+:)[^:]+:/\1/' \
119		| sort \
120		| uniq -c \
121		| sed -E '/.*\.erl: /!s/^[[:space:]]*[0-9]+[[:space:]]*//' \
122		| grep -F -f dialyzer.ignore-warnings.tmp -v \
123		| sed -E 's/^[[:space:]]*[0-9]+[[:space:]]*//' \
124		| sed -E 's/([]\^:+?|()*.$${}\[])/\\\1/g' \
125		| sed -E 's/(\\\.erl\\\:)/\1[[:digit:]]+:/g' \
126		| sed -E 's/^(.*)$$/^[[:space:]]*\1$$/g' \
127		> dialyzer_unhandled_warnings ; \
128		rm dialyzer.ignore-warnings.tmp; \
129		if [ $$(cat dialyzer_unhandled_warnings | wc -l) -gt 0 ]; then \
130		    egrep -f dialyzer_unhandled_warnings dialyzer_warnings ; \
131			found_warnings=1; \
132	    fi; \
133		[ "$$found_warnings" != 1 ] ; \
134	else \
135		dialyzer $(DIALYZER_FLAGS) --plts $${PLTS} -c ebin; \
136	fi
137
138dialyzer-quick: compile-no-deps dialyzer-run
139
140dialyzer: ${PLT} ${LOCAL_PLT} dialyzer-run
141
142cleanplt:
143	@echo
144	@echo "Are you sure?  It takes several minutes to re-build."
145	@echo Deleting $(PLT) and $(LOCAL_PLT) in 5 seconds.
146	@echo
147	sleep 5
148	rm $(PLT)
149	rm $(LOCAL_PLT)
150