# Confluent Kafka Packaging
#
# The 'master' branch contains a script for packaging a plain archive file,
# including a more standardized (i.e. non-Java project) layout. Other branches,
# e.g. 'debian' build on this basic functionality. In order to support
# traditional installation, a normal 'install' target is provided, and the
# default 'archive' target just compresses the target prefix directory. Note
# that for safety and testing, the default PREFIX is specified relative to the
# working directory.
#
# In order to use any of the branches, including this one, you must merge it
# with the Kafka code. We use this model since it makes packaging some
# distributions, such as debian, much simpler since the normally use
# overlay-based packaging. You should start by generating a new branch for the
# type of package and Kafka version you're releasing:
#
#     git checkout -b archive-0.8.2
#
# and then merge in the upstream tree, presumably a tagged version:
#
#     git merge 0.8.2
#
# and finally create the package:
#
#     make archive
#
# which will generate kafka-0.8.2.tar.gz in this case. Note that the version
# used in these scripts is determined automatically by looking at tags, so it is
# not affected by the branch name 'archive-0.8.2'; that name is purely for you
# to keep track of release branches. Since the branch is a simple merge, it can
# be discarded after generating the release.
#
# In order to be able to apply patches cleanly and repeatably, this script *will
# use git-reset to clean out any changes that aren't already committed to the
# tree*. You need to make sure the changes you want applied are either:
# a) in the Kafka source tree, b) committed to the archive packaging branch, or
# c) in the form of a patch in patches/ and listed in patches/series.
#
# Dependencies you'll probably need to install to compile this: make, curl, git,
# zip, unzip, patch, java7-jdk | openjdk-7-jdk.

BASEDIR=$(dir $(realpath $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))))/..

# Release specifics. Note that some of these (VERSION, SCALA_VERSION, DESTDIR)
# are required and passed to create_archive.sh as environment variables. That
# script can also pick up some other settings (PREFIX, SYSCONFDIR) to customize
# layout of the installation.
# Source version *must* be extracted from the source code since we need it to
# use files that are generated.
SOURCE_VERSION=$(shell grep version= gradle.properties | awk -F= '{ print $$2 }')
# Version is our own packaged version number.
ifndef VERSION
ifeq ($(wildcard .git),.git)
tag=$(shell git describe --abbrev=0)
ver=$(shell echo $(tag) | sed -e 's/kafka-//' -e 's/-incubating-candidate-[0-9]//')
VERSION=$(ver)
else
VERSION=$(SOURCE_VERSION)
endif
endif

ifndef SCALA_VERSIONS
SCALA_VERSIONS=$(shell test -e $(BASEDIR)/debian/control && grep Package $(BASEDIR)/debian/control | awk -F- '{ print $$3 }')
endif

ifndef GRADLEW_INSTALL_ARGS
GRADLEW_INSTALL_ARGS="install"
endif

ifndef SECURITY_SUFFIX
SECURITY_SUFFIX=
endif

export PACKAGE_NAME=confluent-kafka-$(VERSION)$(SECURITY_SUFFIX)

GRADLEUSERHOME=/tmp/gradleuserhome
GRADLEPROJECTHOME=/tmp/confluent/gradleprojecthome_$(PACKAGE_NAME)
GRADLEARGS=--no-daemon --console=plain -g $(GRADLEUSERHOME) --project-cache-dir $(GRADLEPROJECTHOME)

# Install directories
ifeq ($(PACKAGE_TYPE),deb)
DESTDIR=$(CURDIR)/
else
DESTDIR=$(CURDIR)/BUILD/
endif

# For platform-specific packaging you'll want to override this to a normal
# PREFIX like /usr or /usr/local. Using the PACKAGE_NAME here makes the default
# zip/tgz files use a format like:
#   kafka-version-scalaversion/
#     bin/
#     etc/
#     share/kafka/
ifeq ($(PACKAGE_TYPE),archive)
	PREFIX=$(PACKAGE_NAME)
	SYSCONFDIR=$(PREFIX)/etc/kafka
else
	PREFIX=/usr
	SYSCONFDIR=/etc/kafka
endif

ifeq ($(PACKAGE_TYPE),archive)
	INCLUDE_WINDOWS_BIN=yes
else
	INCLUDE_WINDOWS_BIN=no
endif

# Log directories are created by packaging specific tools, such as debian .postinst,
# to ensure proper permissions.
ifeq ($(PACKAGE_TYPE),archive)
	CREATE_VAR_LOG_KAFKA=yes
else
	CREATE_VAR_LOG_KAFKA=no
endif

export SOURCE_VERSION
export VERSION
export PREFIX
export SYSCONFDIR
export INCLUDE_WINDOWS_BIN
export CREATE_VAR_LOG_KAFKA
export CONFLUENT_VERSION

all: install


archive: install
	rm -f $(CURDIR)/$(PACKAGE_NAME).tar.gz && cd $(DESTDIR) && tar -czf $(CURDIR)/$(PACKAGE_NAME).tar.gz $(PREFIX)
	rm -f $(CURDIR)/$(PACKAGE_NAME).zip && cd $(DESTDIR) && zip -r $(CURDIR)/$(PACKAGE_NAME).zip $(PREFIX)

remove_sh_from_bin_filenames:
	$(shell for file in bin/*.sh; do mv -f $$file "$${file%.sh}"; done)
	$(shell find bin/ -type f -exec sed -i -e 's/kafka-run-class.sh/kafka-run-class/g' {} \;)

rename_tmp_path:
ifneq ($(PACKAGE_TYPE),archive)
	$(shell sed -i -e 's/\/tmp\/kafka-logs/\/var\/lib\/kafka/' config/server.properties)
	$(shell sed -i -e 's/\/tmp\/zookeeper/\/var\/lib\/zookeeper/' config/zookeeper.properties)
	$(shell sed -i -e 's/$$base_dir\/logs/\/var\/log\/kafka/' bin/kafka-run-class)
	$(shell sed -i -e 's/\/tmp\/kafka-streams/\/var\/lib\/kafka-streams/' streams/src/main/java/org/apache/kafka/streams/StreamsConfig.java)
endif

kafka: remove_sh_from_bin_filenames rename_tmp_path $(foreach v,$(SCALA_VERSIONS),kafka-$(v))

# $* is SCALA_VERSION, $(subst .,_,$*) is SCALA_VERSION_UNDERSCORE
kafka-%:
	# Note that the clean task is not invoked before install, as it would remove artifacts based
	# on the previously-installed Scala version, given two or more defined by SCALA_VERSIONS.
	# Packaging subsequent projects relies on the presence of artifacts in the build directory.
	./gradlew $(GRADLEARGS) -PscalaVersion=$* $(GRADLEW_INSTALL_ARGS)
	./gradlew $(GRADLEARGS) -PscalaVersion=$* -PcommitId=$(KAFKA_COMMIT_ID) releaseTarGz

install: kafka $(foreach v,$(SCALA_VERSIONS),install-$(v))

# Because of the way debian packaging invokes this, it's a pain to override some
# variables safely. Instead, we pass the SCALA_VERSION and DESTDIR via command
# line arguments.
install-%:
ifeq ($(PACKAGE_TYPE),deb)
	$(BASEDIR)/debian/create_archive.sh $* $(BASEDIR)/debian/confluent-kafka
else
	$(BASEDIR)/debian/create_archive.sh $(SCALA_VERSION) $(DESTDIR)
endif

clean:
	rm -rf $(DESTDIR)$(PREFIX)
	rm -rf $(CURDIR)/$(PACKAGE_NAME)*
	rm -rf confluent-kafka-$(RPM_VERSION)*rpm
	rm -rf RPM_BUILDING

distclean: clean
	rm -rf $(GRADLEUSERHOME)
	rm -rf $(GRADLEPROJECTHOME)
	git reset --hard HEAD
	git status --ignored --porcelain | cut -d ' ' -f 2 | xargs rm -rf

test:

.PHONY: clean install debian-control


# This generates the debian control file. You should only be running this from
# the top-level directory using make -f debian/Makefile, never while in the
# debian/ directory.
debian-control:
	rm -rf $(BASEDIR)/debian/control
	cp $(BASEDIR)/debian/control.in $(BASEDIR)/debian/control
	for SVERSION in $(SCALA_VERSIONS); do \
		cat $(BASEDIR)/debian/control.binary.in | sed s@##SCALAVERSION##@$$SVERSION@g >> $(BASEDIR)/debian/control; \
	done
	git add $(BASEDIR)/debian/control
	git commit -m "Add control file."

export RPM_VERSION=$(shell echo $(VERSION) | sed -e 's/-alpha[0-9]*//' -e 's/-beta[0-9]*//' -e 's/-rc[0-9]*//' -e 's/-SNAPSHOT//' -e 's/-cp[0-9]*//' -e 's/-hotfix[0-9]*//' -e 's/-hf[0-9]*//' -e 's/-[0-9]*//')
# Get any -alpha, -beta, -rc piece that we need to put into the Release part of
# the version since RPM versions don't support non-numeric
# characters. Ultimately, for something like 0.8.2-beta, we want to end up with
# Version=0.8.2 Release=0.X.beta
# where X is the RPM release # of 0.8.2-beta (the prefix 0. forces this to be
# considered earlier than any 0.8.2 final releases since those will start with
# Version=0.8.2 Release=1)
export RPM_RELEASE_POSTFIX=$(subst -,,$(subst $(RPM_VERSION),,$(VERSION)))
ifneq ($(RPM_RELEASE_POSTFIX),)
	export RPM_RELEASE_POSTFIX_UNDERSCORE=_$(RPM_RELEASE_POSTFIX)
endif

rpm: RPM_BUILDING/SOURCES/confluent-kafka-$(RPM_VERSION).tar.gz
	echo "Building the rpm"
	rpmbuild --define="_topdir `pwd`/RPM_BUILDING" -tb $<
	find RPM_BUILDING/{,S}RPMS/ -type f | xargs -n1 -iXXX mv XXX .
	echo
	echo "================================================="
	echo "The rpms have been created and can be found here:"
	@ls -laF confluent-kafka*rpm
	echo "================================================="

# Unfortunately, because of version naming issues and the way rpmbuild expects
# the paths in the tar file to be named, we need to rearchive the package. So
# instead of depending on archive, this target just uses the unarchived,
# installed version to generate a new archive. Note that we always regenerate
# the symlink because the RPM_VERSION doesn't include all the version info -- it
# can leave of things like -beta, -rc1, etc.
RPM_BUILDING/SOURCES/confluent-kafka-$(RPM_VERSION).tar.gz: rpm-build-area install $(BASEDIR)/debian/confluent-kafka.spec.in RELEASE_$(RPM_VERSION)$(RPM_RELEASE_POSTFIX_UNDERSCORE)
	rm -rf confluent-kafka-$(RPM_VERSION)
	mkdir confluent-kafka-$(RPM_VERSION)
	cp -R $(CURDIR)/*/build/* confluent-kafka-$(RPM_VERSION)
	cp -R $(DESTDIR)/* confluent-kafka-$(RPM_VERSION)
	rm -rf confluent-kafka-$(RPM_VERSION)/libs
	rm -rf confluent-kafka-$(RPM_VERSION)/dependant-libs*
	rm -rf confluent-kafka-$(RPM_VERSION)/generated
	rm -rf confluent-kafka-$(RPM_VERSION)/kafka
	rm -rf confluent-kafka-$(RPM_VERSION)/extracted-include-protos
	rm -rf confluent-kafka-$(RPM_VERSION)/flatbuffers*
	rm -rf confluent-kafka-$(RPM_VERSION)/docs
	rm -rf confluent-kafka-$(RPM_VERSION)/classes
	rm -rf confluent-kafka-$(RPM_VERSION)/tmp
	rm -rf confluent-kafka-$(RPM_VERSION)/resources
	rm -rf confluent-kafka-$(RPM_VERSION)/distributions
	rm -rf confluent-kafka-$(RPM_VERSION)/poms
	$(BASEDIR)/debian/create_spec.sh $(BASEDIR)/debian/confluent-kafka.spec.in confluent-kafka-$(RPM_VERSION)/confluent-kafka.spec
	rm -f $@ && tar -czf $@ confluent-kafka-$(RPM_VERSION)
	# Cleanup temporary space used for generating source RPM tar.gz
	rm -rf confluent-kafka-$(RPM_VERSION)

rpm-build-area: RPM_BUILDING/BUILD RPM_BUILDING/RPMS RPM_BUILDING/SOURCES RPM_BUILDING/SPECS RPM_BUILDING/SRPMS

RPM_BUILDING/%:
	mkdir -p $@

confluent-kafka.spec:
	$(BASEDIR)/debian/create_spec.sh $(BASEDIR)/debian/confluent-kafka.spec.in confluent-kafka.spec

RELEASE_%:
	echo 0 > $@
