#!/usr/bin/env bash
# $Id: fetch-kicad-demos 159 2026-10-06 13:31:25Z peter $
#
# fetch-kicad-demos --- fetch KiCad's own official demo/example
# package as an external, on-demand, wider test surface for this
# project, per Péter's own direct request (2026-08-18, recorded in
# FutureResearch.org) and his own direct choices, across two real
# sessions (2026-08-26: kept EXTERNAL, fetched on demand, not copied
# into TestSchemes/; 2026-08-27: kept in a real, PERSISTENT cache,
# not re-fetched every real invocation, not touched by this
# project's own clean mechanisms, updated or cleaned only by a real,
# specific, explicit invocation of this same script -- plus a real,
# second, alternate method using a locally installable kicad-demos
# system package).
#
# Copyright (C) 2026 Péter Felecan
# Assisted by Claude Sonnet 5.5 (Anthropic)
#
# This program 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.
#
# Real, confirmed findings that shape what this script does, not
# just what's convenient:
#
# 1. The official demos live at gitlab.com/kicad/code/kicad (the
#    demos/ subdirectory of the MAIN KiCad source repository, not a
#    separate "kicad-demos" repo) -- confirmed directly, not
#    assumed, after finding no separate repo of that name. GitLab
#    itself is unreachable from a real, restricted environment (this
#    project's own development sandbox among them); a real, actively
#    synced GitHub mirror, KiCad/kicad-source-mirror, carries the
#    SAME content and IS reachable -- this is the real "git" method,
#    below.
#
# 2. The mirror's own default branch tracks LIVE KiCad development,
#    not a stable release -- confirmed directly: fetching demos/ at
#    "master" produced schematic files in a real, NEWER file format
#    (dated 2026-06-29) than a real, currently-released KiCad 10.0.5
#    can read at all ("Failed to load schematic", kicad-cli exit
#    status 3). Fetching the SAME path at the git tag matching the
#    real, installed kicad-cli's own version resolves this
#    completely -- every one of the 33 real demo schematics tested
#    loaded successfully once pinned this way.
#
# 3. A real, second, alternate method exists: the "kicad-demos"
#    system package Péter's own direct note named. Confirmed
#    directly (not assumed) to be genuinely installable WITHOUT root
#    (apt-get download, then dpkg-deb -x to extract -- never
#    touching the system's own package database at all) -- this is
#    the real "apt" method, below. On THIS project's own real
#    development sandbox (Ubuntu 24.04 LTS, "noble," released April
#    2024), the available apt package is version 7.0.11 -- a real,
#    much older KiCad release than the installed 10.0.5 -- purely
#    because 24.04 is itself an older, now-frozen Ubuntu release
#    (Ubuntu's own LTS releases don't pull in new upstream package
#    versions after release), NOT because the apt method itself is
#    inherently version-mismatched. Péter's own direct correction,
#    2026-08-27: on a MORE RECENT real system, where apt's own
#    kicad/kicad-demos packages are themselves more current, both
#    would be version-matched with NO real discrepancy at all,
#    since a distribution packages them together from the same real
#    upstream release. Confirmed, this environment's own real
#    mismatch produces a genuinely DIFFERENT set of demos, not a
#    subset or superset of the git method's own: this sandbox's own
#    older apt package's demos/ includes several real, older
#    projects the current git-mirror set no longer carries at all
#    (flat_hierarchy, electric, custom_pads_test, test_xil_95108),
#    while lacking the git method's own newer, larger additions
#    (jetson-agx-thor-baseboard, vme-wren, and others) -- on a more
#    recent real system, this real difference in CONTENT may narrow
#    or disappear too, if apt's own current kicad-demos already
#    carries the same real, newer projects the git mirror does.
#    Confirmed, not assumed, that THIS sandbox's own older schematic
#    format (dated 2023-01-21) still loads correctly through this
#    project's own real tools regardless -- KiCad reads older real
#    formats forward without issue, only newer-than-installed
#    formats fail.
#
# 4. Licensing, confirmed directly from the git mirror's own real
#    LICENSE.README: "All the demo files provided in demos/*" are
#    CC-BY-SA-4.0 by default; a real, small number of newer, more
#    elaborate demos (jetson-agx-thor-baseboard, cm5_minima,
#    openair-max, tiny_tapeout, royalblue54L_feather, stickhub, as of
#    this writing) carry their OWN, separate license file instead.
#    The apt method's own package is Debian/Ubuntu-packaged
#    (universe component); its own real licensing terms are that
#    distribution's own concern, not re-derived here. Neither method
#    ever writes into this project's own distributed archive -- see
#    .tar-exclude.
#
# A real, sparse, shallow clone -- fetching demos/ alone, not the
# full KiCad C++ source tree (hundreds of megabytes) this
# subdirectory lives inside -- confirmed to work directly with git's
# own --filter=blob:none --sparse combination, for the git method.

set -euo pipefail

prog="fetch-kicad-demos"
default_cache_dir="${XDG_CACHE_HOME:-${HOME}/.cache}/packpay/kicad-demos"
default_repo="https://github.com/KiCad/kicad-source-mirror.git"
default_apt_package="kicad-demos"

usage() {
	cat <<EOF
Usage: ${prog} [--method {git|apt}] [--update] [--clean]
                     [--cache-dir DIR] [-o DIR]
                     [--tag TAG] [--kicad-cli CMD] [--repo URL]
                     [--apt-package NAME]
       ${prog} --help
       ${prog} --version

Fetch KiCad's own official demo/example schematics into a real,
PERSISTENT cache -- not re-fetched on every real invocation, not
touched by this project's own clean mechanisms (make clean and
friends never look inside the cache directory at all), updated or
removed only by a real, explicit, separate invocation of this same
script (--update / --clean, below).

  --method {git|apt}
                 which real, independent source to use (default:
                 git). Both provide a genuinely DIFFERENT real set
                 of demos, not the same content twice -- see this
                 script's own header comment for the full real
                 account, and consider fetching BOTH (one call per
                 real --method) rather than picking only one.
                   git: a sparse, shallow clone of a real, actively
                     synced GitHub mirror of KiCad's own official
                     source repository, at the git tag matching the
                     real, installed KiCad version (auto-detected;
                     see --tag). The larger, more modern real set.
                   apt: the real, Debian/Ubuntu "${default_apt_package}"
                     system package (see --apt-package), fetched
                     with 'apt-get download' and extracted directly
                     -- never installed system-wide, no root needed.
                     A genuinely DIFFERENT real set from the git
                     method's own -- content and vintage both
                     depend on how current YOUR OWN system's apt
                     packages are, not on this method itself; on
                     this project's own development sandbox (an
                     older, frozen Ubuntu LTS release), it happens
                     to be an older, smaller set than git's own.
  --update       force a real refresh of the cache for the selected
                 --method, even if it already has content (default:
                 skip fetching entirely, and just report what's
                 already cached -- no real network access at all in
                 that case)
  --clean        remove the cache for the selected --method (or
                 the WHOLE real cache directory, both methods, if
                 --method is not also given) and exit -- does not
                 fetch anything
  --cache-dir DIR
                 the real, persistent cache root (default:
                 ${default_cache_dir}, following the real, standard
                 XDG Base Directory convention)
  -o DIR         fetch directly into DIR instead of the real cache
                 -- bypasses the cache mechanism entirely, for a
                 real, explicit, one-off copy (this project's own
                 real .tar-exclude does not know about an arbitrary
                 DIR, so a location under the project root is not
                 recommended here)
  --tag TAG      (git method only) the real git tag to fetch demos/
                 at, matching a real, specific KiCad release --
                 confirmed necessary, not optional: the mirror's own
                 default branch tracks live development, and a
                 schematic format newer than the real, installed
                 kicad-cli can read will fail outright (default:
                 auto-detected from '--kicad-cli CMD --version')
  --kicad-cli CMD
                 the kicad-cli command to ask for its own version,
                 when --tag isn't given (default: \$KICAD_CLI if
                 set, else 'kicad-cli' on PATH)
  --repo URL     (git method only) the git URL to fetch from
                 (default: ${default_repo})
  --apt-package NAME
                 (apt method only) the real package name to fetch
                 (default: ${default_apt_package})
  --help         show this message and exit
  --version      show this project's own current version and exit

After fetching, every real demo's own root schematic can be loaded
the same way any other real .kicad_sch file is -- e.g., once fetched
with --method git (the default):
    ./pprender --kicad-cli "\$KICAD_CLI" \\
        "\$(${prog} --method git)/demos/ecc83/ecc83-pp_v2.kicad_sch"
This script's own real stdout is always exactly one line: the
resolved cache path used, so it composes directly into another real
command this way. Every other real message goes to stderr.

See ResearchJournal.org's own 2026-08-26 entry for the full, real
component/net/anchor count table across all 33 git-method demos this
project's own tools have already confirmed load and place correctly
(or, in a real few cases, don't -- exactly the wider test surface
this script exists to provide).
EOF
}

_version() {
	# Matches every other real script's own convention here --
	# see ppnetlist's own identical helper for the fuller
	# reasoning (this being a bash, not Python, script is the
	# only real difference).
	here="$(cd "$(dirname "$0")" && pwd)"
	if [[ -f "${here}/VERSION" ]]
	then
		sed -n '2p' "${here}/VERSION"
	else
		echo unknown
	fi
}

method="git"
method_explicit=0
do_update=0
do_clean=0
cache_dir="${default_cache_dir}"
explicit_output=""
tag=""
kicad_cli="${KICAD_CLI:-kicad-cli}"
repo="${default_repo}"
apt_package="${default_apt_package}"

while [[ $# -gt 0 ]]
do
	case "$1" in
	--method)
		method="$2"; method_explicit=1; shift 2 ;;
	--update)
		do_update=1; shift ;;
	--clean)
		do_clean=1; shift ;;
	--cache-dir)
		cache_dir="$2"; shift 2 ;;
	-o)
		explicit_output="$2"; shift 2 ;;
	--tag)
		tag="$2"; shift 2 ;;
	--kicad-cli)
		kicad_cli="$2"; shift 2 ;;
	--repo)
		repo="$2"; shift 2 ;;
	--apt-package)
		apt_package="$2"; shift 2 ;;
	--help)
		usage; exit 0 ;;
	--version)
		echo "${prog} $(_version)"; exit 0 ;;
	*)
		echo "${prog}: unrecognized argument: $1" >&2
		usage >&2
		exit 2 ;;
	esac
done

if [[ "${method}" != "git" && "${method}" != "apt" ]]
then
	echo "${prog}: --method must be 'git' or 'apt', not '${method}'" >&2
	exit 2
fi

# A real, per-method subdirectory of the cache -- git and apt provide
# genuinely DIFFERENT content (see this script's own header comment),
# so both can be cached side by side rather than one overwriting the
# other.
target="${explicit_output:-${cache_dir}/${method}}"

if [[ ${do_clean} -eq 1 ]]
then
	if [[ -n "${explicit_output}" ]]
	then
		echo "${prog}: --clean with an explicit -o DIR would remove a real, user-given path outright; not doing that -- remove it yourself if that's genuinely intended" >&2
		exit 2
	fi
	if [[ ${method_explicit} -eq 1 ]]
	then
		# --method was genuinely given alongside --clean: only
		# that one real method's own cache subdirectory is
		# removed, matching this script's own documented
		# behavior exactly, not silently wiping the other real
		# method's own, unrelated cache too.
		rm -rf "${cache_dir}/${method}"
		echo "${prog}: removed the real ${method} cache (${cache_dir}/${method})" >&2
	else
		# No --method given at all: a bare --clean reads as
		# "clean everything," not "clean whichever method
		# happens to be this script's own default" -- the
		# whole real cache directory (both methods) is removed.
		rm -rf "${cache_dir}"
		echo "${prog}: removed the whole real cache (${cache_dir})" >&2
	fi
	exit 0
fi

mkdir -p "$(dirname "${target}")"

already_cached() {
	[[ -d "$1/demos" ]] && [[ -n "$(find "$1/demos" -name '*.kicad_sch' -print -quit 2>/dev/null)" ]]
}

if already_cached "${target}" && [[ ${do_update} -eq 0 ]]
then
	echo "${prog}: using already-cached demos at ${target} (pass --update to refresh)" >&2
else
	case "${method}" in
	git)
		if [[ -z "${tag}" ]]
		then
			# Auto-detected, not hardcoded -- a real,
			# different installed KiCad version should fetch
			# demos at ITS OWN matching real tag, not
			# silently reuse whatever version this script
			# was last confirmed against.
			raw_version="$(${kicad_cli} --version 2>/dev/null | head -1)" || {
				echo "${prog}: could not run '${kicad_cli} --version' to auto-detect a real tag; pass --tag explicitly" >&2
				exit 1
			}
			tag="$(echo "${raw_version}" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
			if [[ -z "${tag}" ]]
			then
				echo "${prog}: could not parse a real version number out of '${raw_version}'; pass --tag explicitly" >&2
				exit 1
			fi
		fi
		echo "${prog}: fetching demos/ at tag ${tag} from ${repo}" >&2
		if [[ -d "${target}/.git" ]]
		then
			(
				cd "${target}"
				git fetch --depth 1 origin "refs/tags/${tag}:refs/tags/${tag}" 2>&1 | sed "s/^/${prog}: /" >&2
				git checkout "${tag}" -- demos
			)
		else
			rm -rf "${target}"
			git clone --depth 1 --branch "${tag}" --filter=blob:none --sparse "${repo}" "${target}" 2>&1 | sed "s/^/${prog}: /" >&2
			(cd "${target}" && git sparse-checkout set demos)
		fi
		;;
	apt)
		echo "${prog}: fetching ${apt_package} via apt-get download (no root, no system-wide install)" >&2
		work="$(mktemp -d)"
		trap 'rm -rf "${work}"' EXIT
		if ! (cd "${work}" && apt-get download "${apt_package}") 2>&1 | sed "s/^/${prog}: /" >&2
		then
			echo "${prog}: 'apt-get download ${apt_package}' failed -- if this is a real 'package not found' error, try 'sudo apt-get update' first to refresh the package lists, then re-run this script" >&2
			exit 1
		fi
		deb="$(find "${work}" -maxdepth 1 -name '*.deb' -print -quit)"
		if [[ -z "${deb}" ]]
		then
			echo "${prog}: apt-get download reported success but produced no real .deb file" >&2
			exit 1
		fi
		rm -rf "${target}"
		mkdir -p "${target}"
		dpkg-deb -x "${deb}" "${work}/extracted"
		# The real package installs under usr/share/kicad/demos;
		# re-rooted here so BOTH real methods share the exact
		# same "<target>/demos/..." shape.
		if [[ -d "${work}/extracted/usr/share/kicad/demos" ]]
		then
			mv "${work}/extracted/usr/share/kicad/demos" "${target}/demos"
		else
			echo "${prog}: ${apt_package} did not contain the expected usr/share/kicad/demos directory" >&2
			exit 1
		fi
		;;
	esac
fi

count="$(find "${target}/demos" -name '*.kicad_sch' | wc -l)"
echo "${prog}: ${count} real schematic files available under ${target}/demos" >&2
echo "${target}"

# Local Variables:
# mode: shell-script
# End:
