#   Zerocat Dev Kit --- Put the fun back into hardware development!
#
#   Copyright (C) 2022, 2023, 2024  Kai Mertens <kmx@posteo.net>
#
#   This file is part of Zerocat Dev Kit.
#
#   Zerocat Dev Kit 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 Dev Kit 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 Dev Kit.
#   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                          := $(SPACE)$(SPACE)$(SPACE)$(SPACE)


# Root Paths
ROOT                          := ../
ROOT_DOC                      := ../doc/
ROOT_GUIX                     := ../guix/
ROOT_HW_GUIX                  := ../hardware/guix/


# Utilities
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 command -v echo;)
ECHO_FLAGS                    :=
$(if $(strip $(ECHO)),,       $(error Cannot find echo utility))

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

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


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


# Settings
MAKEFILE_TITLE                := Environment Setup with GNU Guix
PROJECT_TITLE                 := Zerocat Dev Kit
PROJECT_BRIEF                 := Put the fun back into hardware development!
ISENV                         = $(shell $(ECHO) $(ECHO_FLAGS) "$${GUIX_ENVIRONMENT}";)


# Tinned Cans: HEADER
define HEADER                 =
$(strip\
	$(ECHO) $(ECHO_FLAGS)    ""\
	&& $(ECHO) $(ECHO_FLAGS) "$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)"\
	&& $(ECHO) $(ECHO_FLAGS) "$(M5) $(PROJECT_TITLE)"\
	&& $(ECHO) $(ECHO_FLAGS) "$(M5) – $(PROJECT_BRIEF)"\
	&& $(ECHO) $(ECHO_FLAGS) "$(M5) $(MAKEFILE_TITLE)"\
	&& $(ECHO) $(ECHO_FLAGS) "$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)"\
)
endef


# Tinned Cans: HEADLINE
define HEADLINE               =
$(strip\
	$(ECHO) $(ECHO_FLAGS) "$(M5) Process target “$(@)” $(M5)$(M5)"\
)
endef


# Tinned Cans: DONE
define DONE                   =
$(strip\
	$(ECHO) $(ECHO_FLAGS)    "... successfully processed: “$@”"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
)
endef


# Suffixes, to be checked for old fashioned suffix rules
.SUFFIXES :


# Intermediate Targets
#~ .INTERMEDIATE :


# Secondary Targets
#~ .SECONDARY :                  # Uncomment for debugging


# Phony Targets
.PHONY :\
	default\
	\
	hello\
	help\
	usage\
	\
	pull\
	list\
	clear\
	checkout\
	shell\
	environment\
	go\
	\
	clean-go\
	clean


# Targets
#   default goal
default : help

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

#   display help information
help : hello
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "List of Targets"\
	&& $(ECHO) $(ECHO_FLAGS) "==============="\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "Default"\
	&& $(ECHO) $(ECHO_FLAGS) "-------"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "default"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)same as help"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "Help"\
	&& $(ECHO) $(ECHO_FLAGS) "----"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "hello"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)greeter, provided with targets pull, environment, usage, clean and help"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)greeter, provided with targets go, clean-go"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "help"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)list available targets"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "usage"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)get environment status and usage information"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "Actions"\
	&& $(ECHO) $(ECHO_FLAGS) "-------"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "pull"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)pull into local guix profile, create profile generation"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "list"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)list all profile generations"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "clear"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)delete unused profile generations"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "go"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)create environment on the fly and compile documentation"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "Environments"\
	&& $(ECHO) $(ECHO_FLAGS) "------------"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "To get help, run ‘make -C $(ROOT_GUIX) usage’."\
	&& $(ECHO) $(ECHO_FLAGS) "To leave an environment when you are done, type ‘exit’."\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "checkout"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)checkout current profile generation, instantiate channels"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)The “checkout” environment can be used to run project’s guix command,"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)e.g. to search for packages of project’s channels."\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)Goals pull, list, clear, clean, environment, go, go-clean are disabled."\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "shell"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)create a pure shell environment with nothing but prerequisites set up"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)This goal is available on “checkout” environment."\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)Goals pull, list, clear, clean, environment, go, go-clean are disabled."\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "environment"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)checkout current profile generation, instantiate channels, create a pure shell environment"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)Goals pull, list, clear, clean, environment, go, go-clean are disabled."\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "Clean"\
	&& $(ECHO) $(ECHO_FLAGS) "-----"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "clean-go"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)create environment on the fly and remove compiled documentation"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "clean"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)remove local guix profile"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(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’ is not available."\
					&& $(ECHO) $(ECHO_FLAGS) "Install GNU Guix Package Manager, or run GNU Guix System."\
				; else\
					$(ECHO) $(ECHO_FLAGS) "Command ‘guix’ is available."\
					&& if [ -h $(GUIX_PROFILE) ]\
						; then\
							$(ECHO) $(ECHO_FLAGS)    "Project’s guix profile is available."\
							&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_GUIX) pull’ to create an updated profile generation, if any."\
							&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_GUIX) list’ to see all profile generations."\
							&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_GUIX) clear’ to remove unused profile generations."\
							&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_GUIX) clean’ to remove profile."\
							&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_GUIX) checkout’ to instantiate current profile generation."\
							&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_GUIX) environment’ to instantiate current profile generation and create a pure shell environment."\
							&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_GUIX) help’ to see more options."\
						; else\
							$(ECHO) $(ECHO_FLAGS)    "Project’s guix profile not available."\
							&& $(ECHO) $(ECHO_FLAGS) "Run ‘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."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘guix search PATTERN’ to search for packages."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_GUIX) shell’ to set up prerequisites."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘exit’ to restore initial environment."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_GUIX) help’ to see more options."\
				; 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,"\
							&& $(ECHO) $(ECHO_FLAGS) "  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

##   list profile generations (on GNU Guix System)
ifneq ($(strip $(GUIX)),)
list :
	@$(HEADLINE)\
	&& if [ -h $(GUIX_PROFILE) ]\
		; then\
			LANG=en_US.utf8\
			&& $(GUIX) $(GUIX_FLAGS)\
				pull\
					--profile=$(GUIX_PROFILE)\
					--list-generations\
			&& $(ECHO) $(ECHO_FLAGS) ""\
			&& $(ECHO) $(ECHO_FLAGS) "To change the current profile generation, run:"\
			&& $(ECHO) $(ECHO_FLAGS) ""\
			&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)guix pull --profile=$(GUIX_PROFILE) --switch-generation=PATTERN"\
			&& $(ECHO) $(ECHO_FLAGS) ""\
		; else\
			$(ECHO) $(ECHO_FLAGS) "No local guix profile."\
		; fi\
	&& $(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."\
		; fi\
	&& $(DONE);
endif

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

##   create guix environment on the fly, then compile all files
ifneq ($(strip $(GUIX)),)
go : hello
	@$(HEADLINE)\
	&& $(MAKE) -C $(ROOT_HW_GUIX) go\
	&& $(ECHO) $(ECHO_FLAGS) "echo make -C $(ROOT_DOC) all | make -C $(ROOT_GUIX) shell"\
	| $(MAKE) -C $(ROOT_GUIX) checkout\
	&& $(DONE);
endif

##   create guix environment on the fly, then remove all compiled files
ifneq ($(strip $(GUIX)),)
clean-go : hello
	@$(HEADLINE)\
	&& $(MAKE) -C $(ROOT_HW_GUIX) clean-go\
	&& $(ECHO) $(ECHO_FLAGS) "echo make -C $(ROOT_DOC) clean | make -C $(ROOT_GUIX) shell"\
	| $(MAKE) -C $(ROOT_GUIX) checkout\
	&& $(DONE);
endif

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


# start of alternative block
else


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


#   end of conditional block
endif
