mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-10 18:34:18 +08:00
223 lines
13 KiB
Makefile
223 lines
13 KiB
Makefile
#
|
||
# Copyright (C) 2026
|
||
#
|
||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||
#
|
||
|
||
include $(TOPDIR)/rules.mk
|
||
|
||
PKG_NAME:=luci-theme-footstrap
|
||
# luci.mk keys the Build/Prepare hook name on LUCI_NAME, which defaults to the checkout's
|
||
# directory name — a differently-named checkout symlinked into the feed would silently skip
|
||
# the CSS build. Pin it.
|
||
LUCI_NAME:=luci-theme-footstrap
|
||
|
||
# Version is git-derived; never hardcode PKG_VERSION. CI injects FOOTSTRAP_VERSION from the
|
||
# tag (an SDK build has no .git, so it cannot derive one).
|
||
FOOTSTRAP_VERSION?=
|
||
ifneq ($(FOOTSTRAP_VERSION),)
|
||
PKG_VERSION:=$(FOOTSTRAP_VERSION)
|
||
PKG_RELEASE:=49
|
||
endif
|
||
|
||
LUCI_TITLE:=Footstrap Theme
|
||
# +luci-base is the WHOLE list, and keeping it that way is the constraint. Nothing this package ships
|
||
# fetches anything at run time, so there is no second name to justify — and the rule that got it here
|
||
# stands: the one convenience tool that ever wanted a dep was `curl`, which is NOT in OpenWrt's
|
||
# default set, on an 8 MB device, for one API call. Fall back to what the base image has
|
||
# (uclient-fetch, jsonfilter, sha256sum) or do without.
|
||
LUCI_DEPENDS:=+luci-base
|
||
LUCI_PKGARCH:=all
|
||
# Else luci.mk defaults these to LuCI's own, and the package claims MAINTAINER "OpenWrt LuCI
|
||
# community" / URL openwrt/luci.
|
||
LUCI_MAINTAINER:=Ivan Kvashonkin <vizzlef@gmail.com>
|
||
LUCI_URL:=https://github.com/VizzleTF/luci-theme-footstrap
|
||
|
||
# CSS: ship verbatim. luci.mk would run csstidy over it, which is old enough to mangle :has(),
|
||
# color-mix() and nested calc() and break the layout. build-css.sh minifies instead.
|
||
LUCI_MINIFY_CSS:=0
|
||
#
|
||
# JS: two minify paths, chosen by who is building.
|
||
#
|
||
# CI (the released packages) pre-minifies with terser BEFORE the SDK build — tools/minify-js.mjs
|
||
# mangles top-level identifiers too, which jsmin cannot: ~41 KB against jsmin's ~57 KB, −27% — and
|
||
# signals it with FOOTSTRAP_PREMIN=1.
|
||
# jsmin must then stay away from the already-minified output: terser legitimately emits
|
||
# `return/^v/.test(s)`, the exact one-character-lookback trap below, so LUCI_MINIFY_JS goes to 0.
|
||
#
|
||
# Everyone else (an SDK user, the buildbot — no node) builds the untouched source and keeps
|
||
# luci.mk's default jsmin: ~105 KB of this tree's JS is comments, and uhttpd serves /www with NO
|
||
# compression, so those are wire and flash bytes either way.
|
||
#
|
||
# The catch on the jsmin path, and why the gates exist: jsmin decides regex-or-division from a
|
||
# one-character lookback, and `n` (of `return`) and `>` (of `=>`) are not on its allow-list, so
|
||
# `return /re/` makes it eat the rest of the file AND EXIT 0 (openwrt/luci#8299). eslint's
|
||
# `wrap-regex` bans the shape in the source; tools/jsmin-verify.mjs proves jsmin's output is
|
||
# token-identical to it.
|
||
FOOTSTRAP_PREMIN?=
|
||
ifneq ($(FOOTSTRAP_PREMIN),)
|
||
LUCI_MINIFY_JS:=0
|
||
endif
|
||
|
||
# Apache-2.0, and not a free choice: styles/base began as a fork of luci-theme-bootstrap's
|
||
# cascade.css, the ucode templates derive from LuCI's own, and a few JS helpers are verbatim copies.
|
||
# The notices travel with it.
|
||
#
|
||
# No OFL-1.1: the theme ships no Font Software, so declaring it would be a false statement about the
|
||
# package's contents.
|
||
PKG_LICENSE:=Apache-2.0
|
||
PKG_LICENSE_FILES:=LICENSE
|
||
|
||
# /etc/config/footstrap is SHIPPED as an empty stub and WRITTEN AT RUNTIME: Appearance ->
|
||
# "Save as default" has rpcd uci-set the router-wide axes into that very file. Without this define
|
||
# the package manager owns it as an ordinary file and REPLACES it on upgrade, so the admin's saved
|
||
# defaults are wiped by the theme's own one-click Update, silently and reported as success.
|
||
# OpenWrt honours the define for BOTH formats (include/package-pack.mk), so one covers 24.10's opkg
|
||
# and 25.12's apk alike. Any future root/etc/config/* must be listed here too.
|
||
define Package/luci-theme-footstrap/conffiles
|
||
/etc/config/footstrap
|
||
endef
|
||
|
||
# reload, never restart: rpcd holds sessions in memory, so `restart` logs out every LuCI user,
|
||
# including the admin who just clicked Update. A session survives `reload` and dies across
|
||
# `restart` — verified on a live router.
|
||
#
|
||
# AND RELOAD RE-READS THE PLUGINS, not only /usr/share/rpcd/acl.d/*. That correction matters,
|
||
# because it is what makes the check below necessary rather than decorative. Measured on a
|
||
# SNAPSHOT stand, where the `luci` object comes from the ucode plugin
|
||
# /usr/share/rpcd/ucode/luci (24.10 and 25.12 use /usr/libexec/rpcd/luci):
|
||
#
|
||
# file removed + reload -> `ubus list` loses `luci` (and it does NOT come back on its own)
|
||
# file removed + restart -> still gone
|
||
# file restored + reload -> back
|
||
#
|
||
# So a reload that lands while another package is replacing that file leaves rpcd without the
|
||
# object, and every luci/getFeatures, luci/getTimezones and luci/getMountPoints call answers
|
||
# `-32000 Object not found` until something reloads it again — the page then renders with the
|
||
# system time blank and an RPCError box per call. Reported from the field on a SNAPSHOT router,
|
||
# cleared by a reboot; nine days of uptime before it, so it was an upgrade that did it.
|
||
#
|
||
# Hence: reload, then ASK whether the object is there, and reload once more if it is not. A second
|
||
# reload and not a restart, because the table above is the whole argument — reload already does
|
||
# everything restart would do to the plugin set, and restart adds only the logout. If the object is
|
||
# still missing after that, it is not this package's reload that removed it, and throwing every
|
||
# admin out of LuCI would not bring it back.
|
||
define Package/luci-theme-footstrap/postinst
|
||
#!/bin/sh
|
||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||
# uci-defaults registers the theme; refresh rpcd + drop caches so LuCI sees it without a
|
||
# reboot. Calling it ourselves is belt-and-braces: OpenWrt's default_postinst also runs
|
||
# (then deletes) every /etc/uci-defaults/* we ship, so it executes twice per install. It is
|
||
# idempotent: the second pass finds the theme already registered and changes nothing.
|
||
[ -f /etc/uci-defaults/30_luci-theme-footstrap ] && \
|
||
sh /etc/uci-defaults/30_luci-theme-footstrap >/dev/null 2>&1 || true
|
||
rm -f /tmp/luci-indexcache* /tmp/luci-modulecache/* >/dev/null 2>&1 || true
|
||
/etc/init.d/rpcd reload >/dev/null 2>&1 || true
|
||
# see the note above the define: a reload that raced another package's file replacement leaves
|
||
# rpcd without the `luci` object, and nothing brings it back on its own
|
||
ubus list 2>/dev/null | grep -qx luci || {
|
||
sleep 1
|
||
/etc/init.d/rpcd reload >/dev/null 2>&1 || true
|
||
}
|
||
}
|
||
exit 0
|
||
endef
|
||
|
||
define Package/luci-theme-footstrap/postrm
|
||
#!/bin/sh
|
||
# opkg runs the OLD package's postrm with arg "upgrade" during a version upgrade and "remove" on a
|
||
# real removal. On upgrade this script MUST change nothing: reverting mediaurlbase and wiping the
|
||
# theme registration here is what flipped every updating 24.10 user back to bootstrap. apk never
|
||
# runs this on upgrade (it uses the new package's pre/post-upgrade), so guarding on the arg is
|
||
# correct for both managers.
|
||
case "$$1" in *upgrade*) exit 0 ;; esac
|
||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||
uci -q delete luci.themes.Footstrap
|
||
# Don't leave the active theme pointing at the media dir we just removed: a theme needs its
|
||
# media dir AND its ucode template to render, so both are checked before handing the UI over.
|
||
case "$$(uci -q get luci.main.mediaurlbase)" in
|
||
/luci-static/footstrap*)
|
||
[ -d /www/luci-static/bootstrap ] && \
|
||
[ -f /usr/share/ucode/luci/template/themes/bootstrap/header.ut ] && \
|
||
uci set luci.main.mediaurlbase=/luci-static/bootstrap ;;
|
||
esac
|
||
uci commit luci
|
||
# The admin-uploaded login background (kept out of the package on purpose, so it survives an
|
||
# upgrade). A real removal is the one time it should go — this branch never runs on upgrade.
|
||
rm -rf /etc/footstrap >/dev/null 2>&1 || true
|
||
rm -f /tmp/luci-indexcache* /tmp/luci-modulecache/* >/dev/null 2>&1 || true
|
||
/etc/init.d/rpcd reload >/dev/null 2>&1 || true # see the postinst note: reload keeps sessions
|
||
}
|
||
endef
|
||
|
||
# Runs right after luci.mk copies luasrc/ucode/htdocs/root/src into PKG_BUILD_DIR, so it rewrites
|
||
# the build copy and never the source tree.
|
||
#
|
||
# 1. cascade.css is generated, not committed — and styles/ is not in luci.mk's copy list, so
|
||
# build-css.sh reads it from $(CURDIR) and writes into the build tree. cat and awk only, which
|
||
# is why it runs on an OpenWrt buildbot.
|
||
# 2. Stamp the git-derived version into fs-version.js. Unconditional: with PKG_VERSION empty it
|
||
# falls back to PKG_SRC_VERSION, which luci.mk always defines, so only an un-built source
|
||
# checkout keeps the literal '0.0.0-dev'.
|
||
#
|
||
# The catalogue is luci.mk's business and nothing here compiles it. `po/` is the directory
|
||
# LUCI_LANGUAGES globs, so luci.mk emits one `luci-i18n-footstrap-<lang>` package per language, the
|
||
# way it does for every luci-app — which is what a package in the luci tree has to look like, and
|
||
# what Weblate can see. It was `i18n/` while a fielded self-update script mis-picked a multi-asset
|
||
# release with `head -1` (issue #6); that script is retired and owfeed builds one theme artifact
|
||
# per format regardless.
|
||
define Build/Prepare/luci-theme-footstrap
|
||
# luci.mk's Build/Prepare copies only src/ luasrc/ htdocs/ root/ ucode/ into
|
||
# $(PKG_BUILD_DIR), and PKG_LICENSE_FILES resolves against THAT — so the Apache text has to
|
||
# be put there by hand or the declaration points at nothing.
|
||
$(CP) $(CURDIR)/LICENSE $(PKG_BUILD_DIR)/
|
||
$(SHELL) $(CURDIR)/build-css.sh $(PKG_BUILD_DIR)/htdocs/luci-static/footstrap/cascade.css
|
||
# The private `--fs-*` names are 16% of the sheet and mean nothing to a browser — the same trade
|
||
# terser makes for the JS. BEFORE strip-templates.sh on purpose: the reserved set is derived by
|
||
# reading the JS and the templates, so it must see them whole. Over-reserving costs bytes,
|
||
# under-reserving breaks the theme silently.
|
||
# The reserved set is read from $(CURDIR), the SOURCE, never from $(PKG_BUILD_DIR): in CI the
|
||
# build tree's JS has already been through terser, so its comments are gone and five names that
|
||
# are only MENTIONED in a comment stop being reserved. That made the shipped sheet depend on WHO
|
||
# built it — 10 reserved names via CI, 15 via a plain SDK build, same source. Reading the source
|
||
# over-reserves by ~1 KB and is the safe direction.
|
||
$(SHELL) $(CURDIR)/mangle-tokens.sh \
|
||
$(PKG_BUILD_DIR)/htdocs/luci-static/footstrap/cascade.css \
|
||
$(CURDIR)/htdocs/luci-static/resources $(CURDIR)/ucode
|
||
# Templates are mostly comments and shipped them all. jsmin/terser strip the JS, build-css.sh the
|
||
# CSS; the .ut files were simply never included in that trade. Only `{# … #}` goes — see the
|
||
# script for why the ucode-code `/* … */` deliberately stays. -22 KB of 60, git keeps every word,
|
||
# and dev-sync.sh does NOT run this: a router you are debugging on keeps its comments.
|
||
$(SHELL) $(CURDIR)/strip-templates.sh $(PKG_BUILD_DIR)/ucode
|
||
# The gate-only exports (`/* fs:probe */`). A handful of module-private functions are also
|
||
# listed in a module's baseclass so a gate in the source repository can call them — nothing on a
|
||
# router does. The functions stay; the export line goes, so the surface a package carries is the
|
||
# one the theme itself uses.
|
||
$(SHELL) $(CURDIR)/strip-probes.sh $(PKG_BUILD_DIR)/htdocs/luci-static/resources
|
||
# …and the same for the shell under root/ (71% and 95% comment lines). Whole-line `#` only.
|
||
$(SHELL) $(CURDIR)/strip-shell.sh $(PKG_BUILD_DIR)/root
|
||
# The two static assets luci.mk has no step for: the SVG favicon carries a 753-byte comment and
|
||
# the manifest its indentation, and both are fetched by every browser over a link uhttpd does
|
||
# not compress. awk only, so this runs on a buildbot with no node.
|
||
$(SHELL) $(CURDIR)/strip-assets.sh $(PKG_BUILD_DIR)/htdocs/luci-static/footstrap
|
||
$(SED) "s#const FS_VERSION *= *'[^']*'#const FS_VERSION = '$(if $(PKG_VERSION),$(PKG_VERSION),$(PKG_SRC_VERSION))'#" \
|
||
$(PKG_BUILD_DIR)/htdocs/luci-static/resources/fs-version.js
|
||
endef
|
||
|
||
# Absolute, not a relative path: CI rsyncs this package into package/, not into the feed.
|
||
include $(TOPDIR)/feeds/luci/luci.mk
|
||
|
||
# The line below is load-bearing and is NOT a signature — do not delete it as boilerplate.
|
||
#
|
||
# include/scan.mk builds the package list by GREPPING the Makefiles, not by parsing them:
|
||
# find -L package -name Makefile | xargs grep -aHE 'call (Build/DefaultTargets|BuildPackage|KernelPackage)'
|
||
# A Makefile that does not match is not in the list, so it is never dumped, no CONFIG_PACKAGE_*
|
||
# symbol is emitted for it, and `make package/<name>/compile` answers "No rule to make target" with
|
||
# no error naming the package anywhere in the build.
|
||
#
|
||
# This theme never calls BuildPackage itself; luci.mk does, at the include above, and the grep
|
||
# cannot see that. So the only thing that puts this package into the SDK's list is the literal text
|
||
# on the next line. tools/scan-marker.sh re-derives the grep from scan.mk and fails the build if it
|
||
# goes missing.
|
||
# call BuildPackage - OpenWrt buildroot signature
|