#   Zerocat Chipflasher --- Flash free firmware, kick the Management Engine.
#
#   Copyright (C) 2022, 2023  Kai Mertens <kmx@posteo.net>
#
#   This file is part of Zerocat Chipflasher.
#
#   Zerocat Chipflasher is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by the Free
#   Software Foundation, either version 3 of the License, or (at your option) any
#   later version.
#
#   Zerocat Chipflasher is distributed in the hope that it will be useful, but
#   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
#   FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
#   details.
#
#   You should have received a copy of the GNU General Public License
#   along with Zerocat Chipflasher.
#   If not, see <http://www.gnu.org/licenses/>.


#   Initial Guix Channel
#   ====================
#
#   This make file has been tested on GNU Guix System,
#   generated from channel guix ‘6992e66b21’:
#
#   guix describe -f channels
#   --------------------------------------------------------------------------
#   (list (channel
#           (name 'guix)
#           (url "https://git.savannah.gnu.org/git/guix.git")
#           (branch #f)
#           (commit
#             "6992e66b21a1bda67f4928729564efe25aa7337c")
#           (introduction
#             (make-channel-introduction
#               "9edb3f66fd807b096b48283debdcddccfea34bad"
#               (openpgp-fingerprint
#                 "BBB0 2DDF 2CEA F6A8 0D1D  E643 A2A0 6DF2 A33A 54FA")))))


#   Usage
#   =====
#
#   To get an overview of targets, type:
#
#           make -C ../guix help


#   Workaround for GNU Make < 4.3
#   =============================
#
#   Finalize commands within a $(shell) function with semicolon, e.g.:
#
#           $(shell echo;)


# Shell
SHELL                         := /bin/sh


# White Space
EMPTY                         :=
SPACE                         := $(EMPTY) $(EMPTY)
COMMA                         := ,
M5                            := xxxxx
TAB1                          := \r\t\t
TAB2                          := \r\t\t\t


# Suffixes
.SUFFIXES :


# Root Paths
ROOT                          := ../
ROOT_DOC                      := ../doc/
ROOT_GUIX                     := ../guix/
ROOT_FW1_GUIX                 := ../firmware1/guix/
ROOT_FW2_GUIX                 := ../firmware2/guix/


# Utilities
WHEREIS                       := $(shell command -v whereis;)
WHEREIS_FLAGS                 := -b
$(if $(strip $(WHEREIS)),,    $(error Cannot find whereis utility))

CD                            := $(shell command -v cd;)
CD_FLAGS                      :=
$(if $(strip $(CD)),,         $(error Cannot find cd utility))

LS                            := $(shell command -v ls;)
LS_FLAGS                      :=
$(if $(strip $(LS)),,         $(error Cannot find ls utility))

RM                            := $(shell command -v rm;)
RM_FLAGS                      := -f
$(if $(strip $(RM)),,         $(error Cannot find rm utility))

CUT                           := $(shell command -v cut;)
CUT_FLAGS                     := -d' '
$(if $(strip $(CUT)),,        $(error Cannot find cut utility))

GIT                           := $(shell command -v git;)
GIT_FLAGS                     :=
$(if $(strip $(GIT)),,        $(error Cannot find git utility))

ECHO                          := $(shell $(WHEREIS) $(WHEREIS_FLAGS) echo | $(CUT) $(CUT_FLAGS) -f2;)
ECHO_FLAGS                    := -e
$(if $(strip $(ECHO)),,       $(error Cannot find echo utility))

FALSE                         := $(shell command -v false;)
FALSE_FLAGS                   :=
$(if $(strip $(FALSE)),,      $(error Cannot find ‘false’ utility))

#    Do not err out, use warning instead.
GUIX                          := $(shell command -v guix;)
GUIX_FLAGS                    :=
$(if $(strip $(GUIX)),,       $(warning Cannot find guix utility))


# Files
GUIX_CHANNELS                 := $(ROOT_GUIX)channels.scm
GUIX_PROFILE                  := $(ROOT_GUIX)profile
GUIX_MANIFEST                 := $(ROOT_GUIX)manifest0.scm


# Settings
PROJECT_TITLE                 := Zerocat Chipflasher
PROJECT_BRIEF                 := Flash free firmware to BIOS chips, kick the Management Engine.
MAKEFILE_TITLE                := Environment Setup with Guix
ISENV                         = $(shell $(ECHO) $(ECHO_FLAGS) "$${GUIX_ENVIRONMENT}";)


# Canned Rules
define HEADER                 =
$(strip\
	$(ECHO) $(ECHO_FLAGS)\
		"\n$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)"\
		"\n$(M5) $(PROJECT_TITLE)"\
		"\n$(M5) – $(PROJECT_BRIEF)"\
		"\n$(M5) $(MAKEFILE_TITLE)"\
		"\n$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)"\
)
endef
define HEADLINE               =
$(strip\
	$(ECHO) $(ECHO_FLAGS)\
		"$(M5) Process target “$(@)” $(M5)$(M5)"\
)
endef
define DONE                   =
$(strip\
	$(ECHO) $(ECHO_FLAGS)\
		"... successfully processed: “$@”"\
		"\n"\
)
endef


# Built-in Special Targets
#~ .SECONDARY :                  # Uncomment for debugging
.PHONY :\
	default\
	\
	hello\
	help\
	usage\
	\
	pull\
	environment\
	checkout\
	shell\
	list\
	clear\
	\
	clean


# Targets
#   default target
default : help
	@$(HEADLINE)\
	&& $(DONE);

#   display greeting
#     provided with usage, clean and help
hello :
	@$(HEADER)\
	&& $(DONE);

#   display help information
help : hello
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS)\
		"\nList of Targets"\
		"\n==============="\
		"\n"\
		"\nDefault"\
		"\n-------"\
		"\n"\
		"\ndefault$(TAB2)same as help"\
		"\n"\
		"\nHelp"\
		"\n----"\
		"\n"\
		"\nhello$(TAB2)greeter, provided with targets pull, environment, usage, clean and help"\
		"\nhelp$(TAB2)list available targets"\
		"\nusage$(TAB2)get environment status and usage information"\
		"\n"\
		"\nActions"\
		"\n-------"\
		"\n"\
		"\nTo end up with a proper environment, run, in that order:"\
		"\n"\
		"\n  $$ make -C $(ROOT_GUIX) pull"\
		"\n  $$ make -C $(ROOT_GUIX) environment"\
		"\n"\
		"\nTo get help during the process, run ‘make -C $(ROOT_GUIX) usage’."\
		"\nTo leave the environment when you are done, type ‘exit’."\
		"\n"\
		"\npull$(TAB2)pull into local guix profile, create profile generation"\
		"\nenvironment$(TAB2)checkout current profile generation, instantiate channels, create a pure shell"\
		"\ncheckout$(TAB2)checkout current profile generation, instantiate channels"\
		"\nshell$(TAB2)create a pure shell with nothing but prerequisites set up"\
		"\nlist$(TAB2)list all profile generations"\
		"\nclear$(TAB2)delete unused profile generations"\
		"\n"\
		"\nClean"\
		"\n-----"\
		"\n"\
		"\nclean$(TAB2)remove local guix profile"\
		"\n"\
	&& $(DONE);

#   usage: report environment status and usage information
usage : hello
	@$(HEADLINE)\
	&& if [ -z "$${GUIX_ENVIRONMENT}" ];\
		then\
			$(ECHO) $(ECHO_FLAGS)\
				"Initial Environment."\
			&& if [ -z "$(GUIX)" ];\
				then\
					$(ECHO) $(ECHO_FLAGS)\
						"Command ‘guix’ not available."\
						"\nInstall GNU Guix Package Manager, or run GNU Guix System.";\
				else\
					$(ECHO) $(ECHO_FLAGS)\
						"Command ‘guix’ available."\
					&& if [ -h $(GUIX_PROFILE) ];\
						then\
							$(ECHO) $(ECHO_FLAGS)\
								"Project’s guix profile available."\
								"\nRun ‘make -C $(ROOT_GUIX) pull’ to create an updated profile generation, if any."\
								"\nRun ‘make -C $(ROOT_GUIX) list’ to see all profile generations."\
								"\nRun ‘make -C $(ROOT_GUIX) environment’ to instantiate current profile generation and create a pure shell."\
								"\nRun ‘make -C $(ROOT_GUIX) checkout’ to instantiate current profile generation."\
								"\nRun ‘make -C $(ROOT_GUIX) clear’ to remove unused profile generations."\
								"\nRun ‘make -C $(ROOT_GUIX) clean’ to remove profile.";\
						else\
							$(ECHO) $(ECHO_FLAGS)\
								"Project’s guix profile not available."\
								"\nRun ‘make -C $(ROOT_GUIX) pull’ to create a guix profile.";\
						fi;\
				fi;\
		else\
			declare -a arr=($$($(LS) $(LS_FLAGS) "$${GUIX_ENVIRONMENT}/bin"))\
			&& if [ $${#arr[@]} -lt 3 ];\
				then\
					$(ECHO) $(ECHO_FLAGS)\
						"Checkout Environment, profile generation instantiated."\
						"\nRun ‘make -C $(ROOT_GUIX) shell’ to set up prerequisites."\
						"\nRun ‘exit’ to restore initial environment.";\
				else\
					$(ECHO) $(ECHO_FLAGS)\
						"Shell Environment, prerequisites set up."\
					&& if [ -z "$$LANG" ];\
						then\
							$(ECHO) $(ECHO_FLAGS)\
								"Run ‘export LANG=en_US.utf8’ to adjust terminal output,"\
								"\n  adapt language/country code to your needs.";\
						fi\
					&& $(ECHO) $(ECHO_FLAGS)\
						"Run ‘exit’ to leave environment.";\
				fi;\
		fi\
	&& $(DONE);

#   start of conditional block
ifeq ($(strip $(ISENV)),)

#   create profile and profile generation (on GNU Guix System)
ifneq ($(strip $(GUIX)),)
pull : $(GUIX_CHANNELS) hello
	@$(HEADLINE)\
	&& $(GUIX) $(GUIX_FLAGS)\
		pull\
			--channels=$<\
			--allow-downgrades\
			--profile=$(GUIX_PROFILE)\
	&& $(DONE);
endif

#   set up pure environment, provide prerequisites in one go (on GNU Guix System)
ifneq ($(strip $(GUIX)),)
environment : hello
	@$(HEADLINE)\
	&& if [ -h $(GUIX_PROFILE) ];\
		then\
			$(GUIX)\
				shell\
					--profile=$(GUIX_PROFILE)\
					-- $(MAKE) -C $(ROOT_GUIX) shell;\
		else\
			$(ECHO) $(ECHO_FLAGS)\
				"No local guix profile."\
			&& $(FALSE) $(FALSE_FLAGS);\
		fi\
	&& $(DONE);
endif

#   checkout profile generation (on GNU Guix System)
ifneq ($(strip $(GUIX)),)
checkout :
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS)\
		"Run ‘make -C $(ROOT_GUIX) usage’ to get shell status ..."\
	&& if [ -h $(GUIX_PROFILE) ];\
		then\
			$(GUIX)\
				shell\
					--profile=$(GUIX_PROFILE);\
		else\
			$(ECHO) $(ECHO_FLAGS)\
				"No local guix profile."\
			&& $(FALSE) $(FALSE_FLAGS);\
		fi\
	&& $(DONE);
endif

#   list profile generations (on GNU Guix System)
ifneq ($(strip $(GUIX)),)
list :
	@$(HEADLINE)\
	&& if [ -h $(GUIX_PROFILE) ];\
		then\
			$(GUIX) $(GUIX_FLAGS)\
				pull\
					--profile=$(GUIX_PROFILE)\
					--list-generations;\
		else\
			$(ECHO) $(ECHO_FLAGS)\
				"No local guix profile."\
			&& $(FALSE) $(FALSE_FLAGS);\
		fi\
	&& $(ECHO) $(ECHO_FLAGS)\
		"\nTo change the current profile generation, run:"\
		"\n"\
		"\n    guix pull --profile=$(GUIX_PROFILE) --switch-generation=PATTERN"\
		"\n"\
	&& $(DONE);
endif

#   clean profile generations (on GNU Guix System)
ifneq ($(strip $(GUIX)),)
clear :
	@$(HEADLINE)\
	&& if [ -h $(GUIX_PROFILE) ];\
		then\
			$(GUIX)\
				pull\
					--profile=$(GUIX_PROFILE)\
					--delete-generations;\
		else\
			$(ECHO) $(ECHO_FLAGS)\
				"No local guix profile."\
			&& $(FALSE) $(FALSE_FLAGS);\
		fi\
	&& $(DONE);
endif

#   remove profile (on GNU Guix System)
clean : hello
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS) -r\
		$(wildcard $(GUIX_PROFILE)*)\
	&& $(DONE);

else

#   set up shell within ‘checkout’ environment, thus using project’s profile generation
ifneq ($(strip $(GUIX)),)
shell : $(GUIX_MANIFEST)
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS)\
		"Run ‘make -C $(ROOT_GUIX) usage’ to get shell status ..."\
	&& if [ -n "$${GUIX_ENVIRONMENT}" ];\
		then\
			declare -a arr=($$($(LS) $(LS_FLAGS) "$${GUIX_ENVIRONMENT}/bin"))\
			&& if [ $${#arr[@]} -eq 2 ];\
				then\
					"$${GUIX_ENVIRONMENT}/bin/guix"\
						shell\
							--manifest=$<\
							--rebuild-cache\
							--pure\
							--preserve=^LANG;\
				fi;\
		else\
			$(ECHO) $(ECHO_FLAGS)\
				"No checkout environment."\
			&& $(FALSE) $(FALSE_FLAGS);\
		fi\
	&& $(DONE);
endif

#   end of conditional block
endif
