MAKEFLAGS += --warn-undefined-variables
SHELL := bash
.SHELLFLAGS := -eu -o pipefail -c
.DEFAULT_GOAL := help
.DELETE_ON_ERROR:
.SUFFIXES:
.SECONDARY:

RUN = uv run
# get values from about.yaml file
SCHEMA_NAME = linkml_model
SOURCE_SCHEMA_PATH = $(shell bash ./utils/get-value.sh source_schema_path)
SRC = .
DEST = staging
PYMODEL = linkml_model
DOCDIR = docs/source

$(PYMODEL):
	mkdir -p $@

$(DEST):
	mkdir -p $@

# basename of a YAML file in model/
.PHONY: all clean

help: status
	@echo ""
	@echo "make all -- makes site locally"
	@echo "make install -- install dependencies"
	@echo "make setup -- initial setup"
	@echo "make test -- runs tests"
	@echo "make testdoc -- builds docs and runs local test server"
	@echo "make deploy -- deploys site"
	@echo "make update -- updates linkml version"
	@echo "make help -- show this help"
	@echo ""

status: check-config
	@echo "Project: $(SCHEMA_NAME)"
	@echo "Source: $(SOURCE_SCHEMA_PATH)"

setup: install gen-project gen-doc git-init-add

install:
	uv sync
.PHONY: install

all: gen-project gen-doc precommit
%.yaml: gen-project
deploy: gen-doc mkd-gh-deploy

# generates all project files
# and updates the artifacts in linkml-model
gen-project: $(PYMODEL) gen-py gen-rdf gen-sqlddl
	$(RUN) gen-project -d $(DEST) --config-file gen_project_config.yaml $(SOURCE_SCHEMA_PATH)
	cp -r $(DEST)/* $(PYMODEL)

gen-py: $(DEST)
	# for all the files in the schema folder, run the gen-python command and output the result to the top
	# level of the project.  In other repos, we'd include mergeimports=True, but we don't do that with
	# linkml-model.
	# extended_types.yaml is excluded because gen-python produces an empty file for it;
	# the schema is not ready for Python code generation yet.
	@for file in $(wildcard $(PYMODEL)/model/schema/*.yaml); do \
		base=$$(basename $$file); \
		if [ "$$base" = "extended_types.yaml" ]; then continue; fi; \
		filename_without_suffix=$${base%.*}; \
		$(RUN) gen-python --genmeta $$file > $(DEST)/$$filename_without_suffix.py; \
	done
	cp $(DEST)/*.py $(PYMODEL)

# gen-rdf and gen-sqlddl are run separately because they are no longer part of
# the default gen-project GEN_MAP (which only emits sqlschema/, owl/, shacl/, etc.).
# We keep generating rdf/ and sqlddl/ outputs to preserve the public API surface
# in linkml_files.py (Format.RDF, Format.NATIVE_RDF, Format.SQLDDL) and to stay
# in step with the artifacts shipped by linkml-runtime.
# array.yaml and extended_types.yaml are excluded to match the schema scope of
# jsonld/, jsonschema/, and shex/.
gen-rdf: $(DEST)
	mkdir -p $(DEST)/rdf
	@for file in $(wildcard $(PYMODEL)/model/schema/*.yaml); do \
		base=$$(basename $$file); \
		if [ "$$base" = "extended_types.yaml" ] || [ "$$base" = "array.yaml" ]; then continue; fi; \
		stem=$${base%.*}; \
		$(RUN) gen-rdf $$file > $(DEST)/rdf/$$stem.ttl; \
		$(RUN) gen-rdf --metauris $$file > $(DEST)/rdf/$$stem.model.ttl; \
	done

# sqlddl is an alias for the SQL-DDL output (gen-sqlddl shares its implementation
# with gen-sqltables, which feeds sqlschema/). The two directories therefore hold
# the same content; sqlddl/ is preserved purely for backwards compatibility.
gen-sqlddl: $(DEST)
	mkdir -p $(DEST)/sqlddl
	$(RUN) gen-sqlddl $(SOURCE_SCHEMA_PATH) > $(DEST)/sqlddl/meta.sql

gen-doc:
	$(RUN) gen-doc --genmeta --sort-by rank -d $(DOCDIR)/docs $(SOURCE_SCHEMA_PATH)
	cp -r linkml_model/model/docs/* $(DOCDIR)/docs
	# the destination must be removed first, otherwise a re-run copies the
	# source *into* the existing directory, yielding a nested $(PYMODEL)/$(PYMODEL)
	rm -rf $(DOCDIR)/$(PYMODEL)
	cp -r $(PYMODEL) $(DOCDIR)/$(PYMODEL)
	rm -rf $(DOCDIR)/$(PYMODEL)/model/docs
	cp README.md $(DOCDIR)
	mkdir -p $(DOCDIR)/javascripts
	cp $(SRC)/utils/scripts/*.js $(DOCDIR)/javascripts/

test: test-schema test-python test-validate-schema test-examples
test-schema:
	$(RUN) gen-project -d tmp --config-file gen_project_config.yaml $(SOURCE_SCHEMA_PATH)

test-python:
	$(RUN) pytest

# TODO: switch to linkml-run-examples when normalize is implemented
test-examples: $(SOURCE_SCHEMA_PATH)
	$(RUN) linkml-validate -s $(SOURCE_SCHEMA_PATH) tests/input/examples/schema_definition-*.yaml
#	$(RUN) linkml-run-examples -s $(SOURCE_SCHEMA_PATH) -e tests/input/examples -d /tmp/
#	find tests/input/examples | ./utils/run-examples.pl

test-validate-schema:
	$(RUN) linkml-normalize -s $(SOURCE_SCHEMA_PATH) $(SOURCE_SCHEMA_PATH) -o /tmp/schema

check-config:
	@(grep my-datamodel about.yaml > /dev/null && printf "\n**Project not configured**:\n\n  - Remember to edit 'about.yaml'\n\n" || exit 0)

convert-examples-to-%:
	$(patsubst %, $(RUN) linkml-convert  % -s $(SOURCE_SCHEMA_PATH) -C Person, $(shell find src/data/examples -name "*.yaml"))

examples/%.yaml: src/data/examples/%.yaml
	$(RUN) linkml-convert -s $(SOURCE_SCHEMA_PATH) -C Person $< -o $@
examples/%.json: src/data/examples/%.yaml
	$(RUN) linkml-convert -s $(SOURCE_SCHEMA_PATH) -C Person $< -o $@
examples/%.ttl: src/data/examples/%.yaml
	$(RUN) linkml-convert -P EXAMPLE=http://example.org/ -s $(SOURCE_SCHEMA_PATH) -C Person $< -o $@

upgrade:
	uv add --group dev linkml

precommit:
	$(RUN) pre-commit run --all-files

# Test documentation locally
serve: mkd-serve

testdoc: gen-doc serve

# --strict promotes mkdocs warnings (e.g., broken internal links) to errors,
# so CI fails on them.
builddoc:
	$(RUN) mkdocs build --strict

MKDOCS = $(RUN) mkdocs
mkd-%:
	$(MKDOCS) $*

PROJECT_FOLDERS = sqlschema shex shacl protobuf prefixmap owl jsonschema jsonld graphql excel
git-init-add: git-init git-add git-commit git-status
git-init:
	git init
git-add:
	git add .gitignore .github Makefile LICENSE *.md examples utils about.yaml mkdocs.yml uv.lock project.Makefile pyproject.toml src/linkml/*yaml src/*/datamodel/*py src/data
	git add $(patsubst %, project/%, $(PROJECT_FOLDERS))
git-commit:
	git commit -m 'Initial commit' -a
git-status:
	git status

clean:
	rm -rf $(DEST)
	rm -rf docs
	rm -rf tmp

spell:
	$(RUN) codespell

lint:
	$(RUN) yamllint -c .yamllint-config linkml_model/model/schema/*.yaml

include project.Makefile
