# Copyright 1999-2026 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

EAPI=8

inherit shell-completion systemd tmpfiles toolchain-funcs

# Upstream names every path, file and binary "ai-memory"; only the Portage
# package carries the -bin suffix.  MY_PN keeps the two apart so this ebuild
# stays a line-by-line mirror of dev-util/ai-memory.
MY_PN="${PN%-bin}"

DESCRIPTION="Local-first long-term memory MCP server for AI coding agents (upstream prebuilt)"
HOMEPAGE="https://github.com/akitaonrails/ai-memory"

# Upstream publishes one Linux asset per architecture at each tag, so both
# ~amd64 and ~arm64 are real builds rather than an untested keyword.  Neither
# tarball has a top-level directory -- they extract straight into ${WORKDIR}.
SRC_URI="
	amd64? (
		https://github.com/akitaonrails/ai-memory/releases/download/v${PV}/ai-memory-linux-x86_64.tar.gz
			-> ${P}-amd64.tar.gz
	)
	arm64? (
		https://github.com/akitaonrails/ai-memory/releases/download/v${PV}/ai-memory-linux-aarch64.tar.gz
			-> ${P}-arm64.tar.gz
	)
"
S="${WORKDIR}"

# License for the package itself
LICENSE="MIT"
# Every Rust crate dev-util/ai-memory compiles is linked into this binary, so
# the same license set applies to what is actually distributed here. Note the
# binary is NOT statically linked as a whole -- it needs libc, libm, libgcc_s
# and libz from the system (see RDEPEND); it is the crate graph that is
# internal to it.
LICENSE+="
	Apache-2.0 BSD CC0-1.0 CDLA-Permissive-2.0 ISC MIT MPL-2.0
	Unicode-3.0 ZLIB
"
SLOT="0"
KEYWORDS="-* ~amd64 ~arm64"

# The from-source ebuild has no USE flag for the LLM crate's local-embeddings
# feature and neither can this one: these ARE the release binaries that feature
# is default-on in, and a prebuilt exposes no build knobs at all.  It is
# pure-Rust CPU BERT inference -- no CUDA, ROCm, SYCL or Metal anywhere in the
# graph -- so nothing forces an accelerator dependency on anyone.
IUSE="+systemd"

# MIT grants redistribution of both source and binary form, so neither bindist
# nor mirror is warranted; only stripping is restricted, because upstream's
# release profile already stripped the binary and a prebuilt we cannot rebuild
# must not be rewritten by portage.
RESTRICT="strip"

QA_PREBUILT="usr/bin/ai-memory"

# Verified with `file`, `ldd` and `readelf` on the 2.1.0 x86_64 and aarch64
# assets: PIE ELF, dynamically linked, DT_NEEDED = libz.so.1, libgcc_s.so.1,
# libm.so.6, libc.so.6, and the highest versioned glibc symbol referenced is
# GLIBC_2.34.  libc and libm are implicit in every profile, so only zlib
# (libz, via virtual/zlib -- sys-libs/zlib is deprecated and zlib-ng[compat]
# provides the same libz.so.1) and gcc (libgcc_s) are named.  Note this is a glibc-linked binary and
# cannot work against musl; ::gentoo handles that class of package with a musl
# profile mask rather than an RDEPEND on sys-libs/glibc, which would be
# unsolvable on musl profiles.
#
# app-misc/ca-certificates because the binary is built with reqwest's
# `rustls-tls-native-roots`: it reads the PLATFORM trust store rather than a
# bundled webpki root set, so an empty store means every provider call fails
# with UnknownIssuer.
#
# The account is NOT created from upstream's sysusers.d drop-in (which this
# ebuild deliberately does not install); it comes from acct-user/ai-memory and
# acct-group/ai-memory, whose home is the /var/lib/ai-memory the unit declares
# as its StateDirectory.
#
# The block is weak and declared only here, following this overlay's own
# precedent in sys-apps/ai-jail-bin.  Both packages install /usr/bin/ai-memory,
# so they cannot coexist -- but nothing in the tree RDEPENDs on ai-memory, so
# portage can order the swap itself rather than stopping to make the user
# emerge -C by hand.  A strong "!!" buys nothing here and costs that.
# The acct-* pair is in DEPEND as well as RDEPEND, and that is load-bearing
# rather than belt-and-braces: src_install runs `fowners root:ai-memory` on
# /etc/ai-memory/env, and fowners is a chown against the BUILD host's account
# database, which only DEPEND guarantees is populated. With them in RDEPEND
# alone the install phase dies with "chown: invalid group: root:ai-memory" on
# any machine that does not already have the account. Same shape as
# net-misc/apt-cacher-ng and net-misc/asterisk in ::gentoo.
DEPEND="
	acct-group/ai-memory
	acct-user/ai-memory
"
RDEPEND="
	${DEPEND}
	!dev-util/ai-memory
	app-misc/ca-certificates
	sys-devel/gcc:*
	virtual/zlib
"

DOCS=( README.md docs/install.md )

src_install() {
	dobin ${MY_PN}
	einstalldocs

	# Agent hook scripts: shell plus one subdirectory per vendor
	# (claude-code, codex, cursor, ...). Copied with `cp -a` rather than
	# `doins -r` on purpose: the agents EXEC these files, and 80 of the 162
	# ship 0755 in the release tarball while doins forces 0644 on everything
	# it touches. A 0644 hook is a hook that silently never runs, and nothing
	# in the install would have looked wrong. Same call upstream's PKGBUILD
	# makes. Measured on the 2.1.0 x86_64 asset: 80 executable before, 0 after
	# a doins -r.
	dodir /usr/share/${MY_PN}
	cp -a hooks "${ED}"/usr/share/${MY_PN}/ || die

	# --- configuration -----------------------------------------------------
	insinto /etc/${MY_PN}
	newins crates/ai-memory-cli/templates/config.default.toml config.toml

	# The env file is meant to hold API keys (ANTHROPIC_API_KEY, ...), so it
	# is readable by the service account and by nobody else. 0640 root:ai-memory
	# matches what upstream ships (0640) while making the group the one that
	# actually needs to read it.
	newins packaging/env/${MY_PN}.env env
	fowners root:${MY_PN} /etc/${MY_PN}/env
	fperms 0640 /etc/${MY_PN}/env

	# --- state directory ---------------------------------------------------
	# StateDirectory=/StateDirectoryMode= only exist inside systemd. The
	# tmpfiles entry is what creates /var/lib/ai-memory 0750 ai-memory:ai-memory
	# on a non-systemd host too (opentmpfiles/systemd-tmpfiles both read it),
	# and the OpenRC service repeats it in start_pre so the daemon does not
	# depend on tmpfiles having run.
	newtmpfiles packaging/tmpfiles/${MY_PN}.conf ${MY_PN}.conf

	# --- service files -----------------------------------------------------
	# One service per scope, mirroring the two units upstream ships. The
	# OpenRC scripts are installed UNCONDITIONALLY: they cost a systemd user
	# nothing, and gating them would leave someone without systemd no way to
	# run the daemon at all. Only the units are behind USE=systemd.
	newinitd "${FILESDIR}"/${MY_PN}.initd ${MY_PN}
	newconfd "${FILESDIR}"/${MY_PN}.confd ${MY_PN}

	# User scope. newinitd has no user-scope variant, so the script goes in
	# as a plain executable, following sys-apps/xdg-desktop-portal and
	# sci-ml/lemonade-bin.
	exeinto /etc/user/init.d
	newexe "${FILESDIR}"/${MY_PN}-user.initd ${MY_PN}

	if use systemd; then
		systemd_dounit packaging/systemd/${MY_PN}.service
		# Upstream's file is ai-memory-user.service; the user manager looks
		# for ai-memory.service in the user directory, hence the rename.
		systemd_newuserunit packaging/systemd/${MY_PN}-user.service ${MY_PN}.service
	fi
	# packaging/sysusers/ai-memory.conf is deliberately NOT installed: the
	# account comes from acct-user/ai-memory + acct-group/ai-memory.

	# --- shell completions -------------------------------------------------
	# Generated from the binary that is about to be installed. `ai-memory
	# completions <shell>` renders the same derived clap Command the parser
	# uses, so the scripts cannot drift from the real CLI surface; a checked-in
	# script could. The subcommand takes no config and touches no data
	# directory, so it is safe to run here.
	#
	# SRC_URI fetches the asset matching the TARGET arch, so on a native build
	# the binary always runs. Only a cross (or otherwise emulated) build lands
	# an unrunnable binary here, which is the same condition the from-source
	# ebuild guards on -- hence the same guard, not a different one.
	if ! tc-is-cross-compiler; then
		local shell
		for shell in bash zsh fish; do
			./${MY_PN} completions ${shell} > "${T}"/${MY_PN}.${shell} \
				|| die "generating ${shell} completions failed"
		done
		newbashcomp "${T}"/${MY_PN}.bash ${MY_PN}
		newzshcomp "${T}"/${MY_PN}.zsh _${MY_PN}
		newfishcomp "${T}"/${MY_PN}.fish ${MY_PN}.fish
	else
		ewarn "Cross-compiling: shell completions were not generated."
	fi
}

pkg_postinst() {
	tmpfiles_process ${MY_PN}.conf

	elog "Start the system-wide server with one of:"
	elog "    rc-service ${MY_PN} start"
	elog "    systemctl enable --now ${MY_PN}.service"
	elog
	elog "Or run it in your own session (data under ~/.local/share/${MY_PN}):"
	elog "    rc-service --user ${MY_PN} start"
	elog "    systemctl --user enable --now ${MY_PN}.service"
	elog
	elog "API keys and other secrets belong in /etc/${MY_PN}/env (0640"
	elog "root:${MY_PN}) for the system service, or ~/.config/${MY_PN}/env for the"
	elog "user one. Server settings live in /etc/${MY_PN}/config.toml."
	elog
	elog "Agent hook scripts are installed under /usr/share/${MY_PN}/hooks."
}