#   Copyright (C) 2022, 2023, 2024  Kai Mertens <kmx@posteo.net>
#
#   This source describes Hardware of a Free Design for the Zerocat Chipflasher
#   Project and is licensed under the CERN-OHL-S v2.
#
#   You may redistribute and modify this source and make products using it under
#   the terms of the CERN-OHL-S v2 (https://ohwr.org/cern_ohl_s_v2.txt) or any
#   later version.
#
#   This source is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING
#   OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR
#   PURPOSE. Please see the CERN-OHL-S v2 for applicable conditions.
#
#   Source location:   git://zerocat.org/zerocat/projects/chipflasher.git
#
#   As per CERN-OHL-S v2 section 4, should You produce hardware based on this
#   source, You must where practicable maintain the Source Location visible on
#   the external case of the Chipflasher Device or other products you make using
#   this source.


#   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 "master")
#           (commit
#             "266a713ae3ac742258ff11b6edd966288177d9e9")
#           (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                            := vvvvv
TAB1                          := $(SPACE)$(SPACE)$(SPACE)$(SPACE)


# Root Paths
ROOT_HW                       := ../
ROOT_HW_GUIX                  := ../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))


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


# Files
GUIX_CHANNELS                 := $(ROOT_HW_GUIX)channels.scm
GUIX_MANIFEST                 := $(ROOT_HW_GUIX)manifest.scm


# 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)    "... end of target “$@”."\
	&& $(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\
	checkout\
	shell\
	environment\
	go\
	\
	clean-but-device-go\
	clean-go


# Targets
#   default target
default : help

#   display greeting
#     provided with usage 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 and help"\
	&& $(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)create profile generation, if not any"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "go"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)create environment on the fly and compile design files"\
	&& $(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_HW_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, 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, 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, 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-but-device-go"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)create environment on the fly and remove compiled design files, do not touch device folder"\
	&& $(ECHO) $(ECHO_FLAGS) ""\
	&& $(ECHO) $(ECHO_FLAGS) "clean-go"\
	&& $(ECHO) $(ECHO_FLAGS) "$(TAB1)create environment on the fly and remove compiled design files"\
	&& $(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."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_HW_GUIX) pull’ to create a guix profile."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_HW_GUIX) checkout’ to instantiate current profile generation."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_HW_GUIX) environment’ to instantiate current profile generation and create a pure shell environment."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_HW_GUIX) help’ to see more options."\
				; 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_HW_GUIX) shell’ to set up prerequisites."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘exit’ to restore initial environment."\
					&& $(ECHO) $(ECHO_FLAGS) "Run ‘make -C $(ROOT_HW_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) time-machine --channels=$<\
	&& $(DONE);
endif

##   checkout profile generation (on GNU Guix System)
ifneq ($(strip $(GUIX)),)
checkout : $(GUIX_CHANNELS)
	@$(HEADLINE)\
	&& $(GUIX) shell --profile=$$($(GUIX) time-machine --channels=$<)\
	&& $(DONE);
endif

##   set up pure environment, provide prerequisites in one go (on GNU Guix System)
ifneq ($(strip $(GUIX)),)
environment : $(GUIX_CHANNELS) $(GUIX_MANIFEST) hello
	@$(HEADLINE)\
	&& $(GUIX) time-machine --channels=$(GUIX_CHANNELS)\
		-- shell -q --pure --preserve=^LANG --rebuild-cache --manifest=$(GUIX_MANIFEST)\
	&& $(DONE);
endif

##   create guix environment on the fly, then compile design files
ifneq ($(strip $(GUIX)),)
go : $(GUIX_CHANNELS) $(GUIX_MANIFEST) hello
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS) "\
			make -C $(ROOT_HW) all\
		"\
	| $(GUIX) time-machine --channels=$<\
		-- shell -q --pure --preserve=^LANG --rebuild-cache --manifest=$(GUIX_MANIFEST)\
	&& $(DONE);
endif

##   create guix environment on the fly, then remove compiled design files, except device folder
ifneq ($(strip $(GUIX)),)
clean-but-device-go : $(GUIX_CHANNELS) $(GUIX_MANIFEST) hello
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS) "\
			make -C $(ROOT_HW) clean-but-device\
		"\
	| $(GUIX) time-machine --channels=$<\
		-- shell -q\
			--pure\
			--preserve=^LANG\
			--rebuild-cache\
			--manifest=$(GUIX_MANIFEST)\
	&& $(DONE);
endif

##   create guix environment on the fly, then remove compiled design files
ifneq ($(strip $(GUIX)),)
clean-go : $(GUIX_CHANNELS) $(GUIX_MANIFEST) hello
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS) "\
			make -C $(ROOT_HW) clean\
		"\
	| $(GUIX) time-machine --channels=$<\
		-- shell -q --pure --preserve=^LANG --rebuild-cache --manifest=$(GUIX_MANIFEST)\
	&& $(DONE);
endif


# 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_HW_GUIX) usage’ to get shell status."\
					&& "$${GUIX_ENVIRONMENT}/bin/guix"\
						shell -q\
							--pure\
							--preserve=^LANG\
							--rebuild-cache\
							--manifest=$<\
				; fi\
		; fi\
	&& $(DONE);
endif


#   end of conditional block
endif
