2017-03-28 16:41:41 +00:00
|
|
|
#
|
|
|
|
# \brief Common steps of creating an archive within the depot
|
|
|
|
# \author Norman Feske
|
|
|
|
# \date 2017-03-17
|
|
|
|
#
|
|
|
|
# Variables that must be defined when including this file:
|
|
|
|
#
|
|
|
|
# ARCHIVE - archive name, corresponds to recipe name
|
|
|
|
# RECIPE_DIR - location of the archive recipe within the source tree
|
|
|
|
# DEPOT_SUB_DIR - archive-type-dependent destination within the depot
|
|
|
|
# TAG_FILE - file within the archive used as tag for make dependencies
|
|
|
|
# UPDATE_VERSIONS - update recipe hash file if archive content changed
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
## Obtain information about the user-specified archive recipe
|
|
|
|
##
|
|
|
|
## Validate 'RECIPE_DIR', determine the version and content hash as given in
|
|
|
|
## the recipe, and define 'RECIPE_HASH_VALUE' and 'RECIPE_VERSION'. Rules using
|
|
|
|
## those definitions should depend on 'checked_recipe_hash_value_exists'.
|
|
|
|
##
|
|
|
|
|
|
|
|
checked_recipe_dir_specified:
|
|
|
|
ifeq ($(RECIPE_DIR),)
|
|
|
|
@$(ECHO) "Error: recipe for '$(TARGET)' is missing"; false
|
|
|
|
endif
|
|
|
|
|
|
|
|
$(TARGET): checked_recipe_dir_specified
|
|
|
|
|
|
|
|
checked_recipe_is_unique: checked_recipe_dir_specified
|
|
|
|
ifneq ($(RECIPE_DIR),$(firstword $(RECIPE_DIR)))
|
|
|
|
@echo "Error: recipe for '$(TARGET)' is ambiguous, candidates are:";\
|
|
|
|
for dir in $(RECIPE_DIR_CANDIDATES); do \
|
|
|
|
echo " $$dir"; done; \
|
|
|
|
false
|
|
|
|
RECIPE_DIR_CANDIDATES := $(subst %,&,$(RECIPE_DIR))
|
|
|
|
RECIPE_DIR :=
|
|
|
|
endif
|
|
|
|
|
|
|
|
$(TARGET): checked_recipe_is_unique
|
|
|
|
|
|
|
|
#
|
|
|
|
# Determine hash file of current archive version as defined by the recipe
|
|
|
|
#
|
|
|
|
|
|
|
|
ifneq ($(RECIPE_DIR),)
|
|
|
|
EXPECTED_RECIPE_HASH_FILE := $(RECIPE_DIR)/hash
|
|
|
|
RECIPE_HASH_FILE := $(wildcard $(EXPECTED_RECIPE_HASH_FILE))
|
|
|
|
endif
|
|
|
|
|
|
|
|
checked_recipe_hash_file_exists: checked_recipe_is_unique
|
|
|
|
ifeq ($(RECIPE_HASH_FILE),)
|
|
|
|
@$(ECHO) "Error: Recipe hash file is missing,\n" \
|
|
|
|
" expected at '$(EXPECTED_RECIPE_HASH_FILE)'"; false
|
|
|
|
endif
|
|
|
|
|
|
|
|
$(TARGET): checked_recipe_hash_file_exists
|
|
|
|
|
|
|
|
#
|
|
|
|
# Obtain hash value and version identifier from hash file. If no version
|
|
|
|
# identifier is present, the hash value is taken as version ('lastword' is
|
|
|
|
# the same as 'firstword'). This is the normal case for source archives.
|
|
|
|
#
|
|
|
|
|
|
|
|
ifneq ($(RECIPE_HASH_FILE),)
|
|
|
|
_RECIPE_HASH_FILE_CONTENT = $(call file_content,$(RECIPE_HASH_FILE))
|
|
|
|
RECIPE_HASH_VALUE = $(lastword $(_RECIPE_HASH_FILE_CONTENT))
|
|
|
|
RECIPE_VERSION = $(firstword $(_RECIPE_HASH_FILE_CONTENT))
|
|
|
|
endif
|
|
|
|
|
|
|
|
checked_recipe_hash_value_exists:
|
|
|
|
ifeq ($(RECIPE_HASH_VALUE),)
|
|
|
|
@$(ECHO) "Error: archive hash is undefined"; false
|
|
|
|
endif
|
|
|
|
|
|
|
|
#
|
|
|
|
# Remember content hash at invocation time, to detect a potential update caused
|
|
|
|
# by the 'UPDATE_VERSIONS' feature.
|
|
|
|
#
|
|
|
|
ORIG_RECIPE_HASH_VALUE := $(RECIPE_HASH_VALUE)
|
|
|
|
|
|
|
|
#
|
|
|
|
# Define name of temporary archive directory that we use until we know the
|
|
|
|
# archive hash.
|
|
|
|
#
|
|
|
|
|
2017-12-11 16:19:03 +00:00
|
|
|
DEPOT_ARCHIVE_DIR := $(DEPOT_SUB_DIR)/$(ARCHIVE)/incomplete
|
2017-03-28 16:41:41 +00:00
|
|
|
|
|
|
|
reset_stale_temporary_archive_dir:
|
|
|
|
ifneq ($(wildcard $(DEPOT_ARCHIVE_DIR)),)
|
|
|
|
$(VERBOSE)rm -rf $(DEPOT_ARCHIVE_DIR); mkdir -p $(DEPOT_ARCHIVE_DIR)
|
|
|
|
endif
|
|
|
|
|
|
|
|
$(DEPOT_ARCHIVE_DIR)/$(TAG_FILE): reset_stale_temporary_archive_dir
|
|
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
## Create archive
|
|
|
|
##
|
|
|
|
|
|
|
|
#
|
|
|
|
# Rename archive to the hashed name after successful completion
|
|
|
|
#
|
|
|
|
$(ARCHIVE): _rename_to_final_archive
|
|
|
|
|
|
|
|
#
|
|
|
|
# Rename archive name from the temporary name to the hashed name. However,
|
|
|
|
# if the hashed archive name already exists, keep the existing one and
|
|
|
|
# discard the just-built archive.
|
|
|
|
#
|
|
|
|
_rename_to_final_archive: _check_hash
|
2017-12-11 16:19:03 +00:00
|
|
|
$(VERBOSE)final_name=$(ARCHIVE)/$(RECIPE_VERSION); \
|
|
|
|
rm -rf $(DEPOT_SUB_DIR)/$$final_name; \
|
|
|
|
mv $(DEPOT_ARCHIVE_DIR) $(DEPOT_SUB_DIR)/$$final_name; \
|
|
|
|
hash=$$(< $(DEPOT_ARCHIVE_DIR).hash); hint=""; \
|
|
|
|
test $$hash = $(ORIG_RECIPE_HASH_VALUE) ||\
|
|
|
|
hint=" $(BRIGHT_COL)(new version)$(DEFAULT_COL)"; \
|
|
|
|
rm -f $(DEPOT_ARCHIVE_DIR).hash; \
|
|
|
|
$(ECHO) "$(DARK_COL)created$(DEFAULT_COL)" \
|
|
|
|
"$(USER)/$(notdir $(DEPOT_SUB_DIR))/$$final_name$$hint"; \
|
|
|
|
true;
|
2017-03-28 16:41:41 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# Generate suggested version name for 'HASH_OUT_OF_DATE_MESSAGE'
|
|
|
|
#
|
|
|
|
# We suggest to use the current date as version. If there is already a version
|
|
|
|
# with the current date, we add a single-letter suffix to distinguish the new
|
|
|
|
# version. If we run out of letters or if the old recipe's version cannot be
|
|
|
|
# compared with the current date, we suggest to append a '-x' to the old
|
|
|
|
# recipe's version. In the latter case (e.g., when using a versioning scheme
|
|
|
|
# not based on dates), the package creator may want to manually adjust the
|
|
|
|
# version identifier anyway.
|
|
|
|
#
|
|
|
|
suffix_from_list = $(subst $(EMPTY) $(EMPTY),,$(strip $1))
|
|
|
|
suffixed_version = $1$(if $(call suffix_from_list,$2),-$(call suffix_from_list,$2),)
|
|
|
|
|
|
|
|
_string_higher_than = $(filter-out $(firstword $(sort $1 $2)),$1)
|
|
|
|
_higher_string = $(if $(call _string_higher_than,$1,$2),$1,$2)
|
|
|
|
|
2018-08-22 09:32:34 +00:00
|
|
|
VERSION_CMD ?= $(strip $(shell date --iso-8601))
|
2017-03-28 16:41:41 +00:00
|
|
|
|
|
|
|
_version_higher_than_recipe = $(call _string_higher_than,\
|
|
|
|
$(call suffixed_version,$1,$2),$(RECIPE_VERSION))
|
|
|
|
|
|
|
|
_next_version = $(eval FOUND := $(if $(call _version_higher_than_recipe,$1,$2),\
|
|
|
|
$(call suffixed_version,$1,$2)))\
|
|
|
|
$(foreach C,a b c d e f g h i j k l m n o p q r s t u v w x y z,\
|
|
|
|
$(if $(FOUND),,\
|
|
|
|
$(if $(call _version_higher_than_recipe,$1,$2 $C),\
|
|
|
|
$(eval FOUND := $(call suffixed_version,$1,$2 $C)))))\
|
|
|
|
$(if $(FOUND),$(FOUND),$(addsuffix -x,$(RECIPE_VERSION)))
|
|
|
|
|
2018-08-22 09:32:34 +00:00
|
|
|
next_version = $(strip $(call _next_version,$(VERSION_CMD)))
|
2017-03-28 16:41:41 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# Message presented to the user whenever a recipe hash is out of date
|
|
|
|
#
|
|
|
|
define HASH_OUT_OF_DATE_MESSAGE
|
|
|
|
|
|
|
|
Error: $(RECIPE_HASH_FILE) is out of date.
|
|
|
|
|
|
|
|
This error indicates that the archived source code has changed, which should
|
|
|
|
be reflected by incrementing the archive version and updating the hash of
|
|
|
|
the recipe. You may update the recipe hash via the following command:
|
|
|
|
|
|
|
|
echo" "$(next_version)" $$hash "> $(RECIPE_HASH_FILE)
|
|
|
|
|
|
|
|
The above command takes the current date as version identifier. Should this
|
|
|
|
not be your intention, please adjust the hash file manually.
|
|
|
|
|
|
|
|
endef
|
|
|
|
|
|
|
|
|
|
|
|
ifeq ($(UPDATE_VERSIONS),)
|
|
|
|
HASH_MISMATCH_CMD = $(ECHO) "$(subst $(NEWLINE),\n,$(HASH_OUT_OF_DATE_MESSAGE))"; false
|
|
|
|
else
|
|
|
|
HASH_MISMATCH_CMD = echo "$(next_version) $$hash" > $(RECIPE_HASH_FILE);
|
|
|
|
endif
|
|
|
|
|
|
|
|
#
|
|
|
|
# Check the consistency between the hash of the archive recipe and the actual
|
|
|
|
# hash of the generated archive. If both hash values differ, we print the
|
|
|
|
# expected hash value and remove the archive. The user is expected to
|
|
|
|
# update the recipe hash before attempting the archive creation again.
|
|
|
|
#
|
|
|
|
_check_hash: $(DEPOT_ARCHIVE_DIR).hash checked_recipe_hash_value_exists
|
|
|
|
$(VERBOSE)hash=$$(< $(DEPOT_ARCHIVE_DIR).hash); \
|
|
|
|
test $$hash = $(RECIPE_HASH_VALUE) || ($(HASH_MISMATCH_CMD))
|
|
|
|
|
|
|
|
#
|
|
|
|
# Shell command used to calculate the hash of an archive
|
|
|
|
#
|
|
|
|
# The command is invoked from within the archive directory within the depot.
|
|
|
|
#
|
2019-02-22 11:21:29 +00:00
|
|
|
# The hash value depends on both the file names (the first 'find' command)
|
|
|
|
# found in the archive as well as the content of the files (the second 'find'
|
|
|
|
# command).
|
|
|
|
#
|
2017-03-28 16:41:41 +00:00
|
|
|
HASH_CMD := cd $(DEPOT_ARCHIVE_DIR); \
|
2019-02-22 11:21:29 +00:00
|
|
|
(find . -type f | sort; \
|
|
|
|
find . -type f | sort | xargs -d '\n' cat) \
|
|
|
|
| $(HASHSUM) | sed "s/ .*//"
|
2017-03-28 16:41:41 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# Generate the hash from the archive content
|
|
|
|
#
|
|
|
|
$(DEPOT_ARCHIVE_DIR).hash: $(DEPOT_ARCHIVE_DIR)/$(TAG_FILE)
|
|
|
|
$(VERBOSE)$(HASH_CMD) > $@
|
|
|
|
|
|
|
|
$(DEPOT_ARCHIVE_DIR):
|
|
|
|
$(VERBOSE)mkdir -p $@
|
|
|
|
|
|
|
|
$(DEPOT_ARCHIVE_DIR)/$(TAG_FILE): $(DEPOT_ARCHIVE_DIR)
|
|
|
|
|