commit 55cccc49b46fdae17ffb4d6d35b6662a1547e112 Spenser Truex <truex@equwal.com> 2026-09-20 21:58:47 -0700 packaging: Homebrew, Gentoo, Arch, Debian, Chocolatey, Scoop, Nix, RPM, Alpine, Void, FreeBSD, MacPorts, Guix Templates. SBM_LICENSE_TBD and the SBM_*_TBD checksums wait for a LICENSE and a v0.3 tag; packaging/README.md lists every line.
packaging/README.md | 244 +++++++++++++++++++++ packaging/alpine/APKBUILD | 55 +++++ packaging/arch/sbm-git/PKGBUILD | 67 ++++++ packaging/arch/sbm/PKGBUILD | 59 +++++ packaging/chocolatey/sbm.nuspec | 76 +++++++ packaging/chocolatey/tools/chocolateyInstall.ps1 | 166 ++++++++++++++ packaging/chocolatey/tools/chocolateyUninstall.ps1 | 22 ++ packaging/debian/apt/README.md | 129 +++++++++++ packaging/debian/debian/changelog | 8 + packaging/debian/debian/control | 45 ++++ packaging/debian/debian/copyright | 23 ++ packaging/debian/debian/docs | 2 + packaging/debian/debian/examples | 2 + packaging/debian/debian/rules | 19 ++ packaging/debian/debian/source/format | 1 + packaging/debian/debian/tests/control | 9 + packaging/debian/debian/tests/smoke | 28 +++ packaging/debian/debian/tests/upstream-suite | 8 + packaging/debian/debian/upstream/metadata | 5 + packaging/debian/debian/watch | 4 + packaging/freebsd/deskutils/sbm/Makefile | 65 ++++++ packaging/freebsd/deskutils/sbm/distinfo | 3 + packaging/freebsd/deskutils/sbm/pkg-descr | 15 ++ packaging/freebsd/deskutils/sbm/pkg-plist | 11 + packaging/gentoo/app-misc/sbm/metadata.xml | 39 ++++ packaging/gentoo/app-misc/sbm/sbm-0.3.ebuild | 72 ++++++ packaging/gentoo/app-misc/sbm/sbm-9999.ebuild | 56 +++++ packaging/guix/sbm.scm | 133 +++++++++++ packaging/homebrew/sbm.rb | 76 +++++++ packaging/macports/Portfile | 85 +++++++ packaging/nix/default.nix | 106 +++++++++ packaging/nix/flake.nix | 34 +++ packaging/rpm/sbm.spec | 87 ++++++++ packaging/scoop/sbm.json | 68 ++++++ packaging/void/srcpkgs/sbm/template | 44 ++++ 35 files changed, 1866 insertions(+)
diff --git a/packaging/README.md b/packaging/README.md new file mode 100644 index 0000000..9ea3518 --- /dev/null +++ b/packaging/README.md @@ -0,0 +1,244 @@ +# Packaging sbm + +Package definitions for sbm 0.3, one directory per format. Nothing here is +submitted anywhere yet, and nothing here changes the rest of the repository. + +Two facts shape every file below. + +1. **There is no licence.** The repository has no `LICENSE` file and no + licence has been chosen. Every format needs a licence field, so every + licence field holds the token `SBM_LICENSE_TBD`. It is not a guess and it + is not a default. Every occurrence is listed under + [Placeholders](#placeholders). +2. **There is no release tag and no tarball.** The source URL pattern is + `https://github.com/equwal/sbm/archive/refs/tags/v0.3.tar.gz`, which + returns 404 today. Checksums hold placeholder tokens. Where a format has a + live or VCS variant, it is provided as well, because those work now: + `arch/sbm-git`, `gentoo/.../sbm-9999.ebuild`, and `head` in the Homebrew + formula. + +This is the edition without cloud sync. Nothing here packages, requires or +mentions a sync client. + +## What gets installed + +`make install` copies the programs in `TOOLS` to `${DESTDIR}${PREFIX}/bin`: + + bm bm-migrate bm-import bm-check bm-html bm-title bm-commit + +Nothing is compiled. There are no man pages. Every package calls +`make DESTDIR=... PREFIX=... install` rather than copying the scripts itself, +except the Windows packages, which unpack the release archive and generate +`.cmd` shims instead. + +`README` is installed as documentation. `usertags` and `engines` are +examples, not configuration: they go to the examples directory of whatever +format is in use, and the user copies them to `~/.local/share/sbm/`. + +## Dependencies, as the packages express them + +| | Programs | Why | +|---|---|---| +| Required | POSIX sh, awk | everything | +| Required | dmenu **or** fzf | the menu | +| Required | xclip **or** xsel **or** wl-clipboard | `bm --copy` | +| Recommended | xdg-utils | opening URLs (`xdg-open`) | +| Optional | curl | `bm-title`, `bm-check` | +| Optional | jq | `bm-import` of Chromium JSON files | +| Optional | git | `bm-commit` | + +Only Debian, Gentoo and RPM can say "a or b". The others pick one program as +the hard dependency and name the alternatives in the optional list, with a +comment saying so: + +* **Arch, FreeBSD, Gentoo, Debian, RPM**: dmenu is the first choice, because + `bm` prefers it whenever there is a display. +* **Alpine, Void, Homebrew, MacPorts, Chocolatey, Scoop, Nix**: fzf, because + it needs no display, and on macOS and Windows dmenu is not an option at + all. + +`bm` picks dmenu when `$DISPLAY` or `$WAYLAND_DISPLAY` is set and fzf +otherwise, so installing both is fine and needs no configuration. + +## The formats + +| Format | Path | Build and test locally | Where it goes | Status | +|---|---|---|---|---| +| Homebrew | `homebrew/sbm.rb` | `brew install --build-from-source ./sbm.rb`, `brew test sbm`, `brew audit --strict --new sbm` | Your own tap (`brew tap equwal/sbm`) first. homebrew-core has a notability bar: roughly 30 forks, 30 watchers, 75 stars, and a maintained, versioned release. sbm meets none of it today. | Written, not built. `license` and `sha256` are placeholders, so `brew audit` fails until they are real. `head` works now. | +| Gentoo | `gentoo/app-misc/sbm/` | Put it in a local overlay, then `ebuild sbm-0.3.ebuild manifest`, `emerge -av app-misc/sbm`, `FEATURES=test emerge app-misc/sbm`, `pkgcheck scan` | GURU (the user overlay) first: it takes anyone. `::gentoo` needs a developer or the proxy-maintainers project; `metadata.xml` already names proxy-maint. | Written, not built. `pkgcheck` will flag `SBM_LICENSE_TBD` as a nonexistent licence. `sbm-9999.ebuild` works now. | +| Arch | `arch/sbm/PKGBUILD`, `arch/sbm-git/PKGBUILD` | `makepkg -si`, `makepkg --printsrcinfo > .SRCINFO`, `namcap PKGBUILD` and `namcap *.pkg.tar.zst` | AUR: `git clone ssh://aur@aur.archlinux.org/sbm.git`, commit `PKGBUILD` and `.SRCINFO`, push. No review queue. `[extra]` needs a Trusted User. | Written, not built. `sbm-git` works now; `sbm` needs the tag. `.SRCINFO` is not committed here: it is generated, and it would go stale. | +| Debian | `debian/debian/`, notes in `debian/apt/README.md` | `dpkg-buildpackage -us -uc -b`, `lintian -i -I --pedantic`, `autopkgtest`. See `debian/apt/README.md`. | Debian proper needs an ITP bug and a sponsor through mentors.debian.net, which takes weeks. Your own signed apt repository (reprepro or aptly) works the same day; `debian/apt/README.md` covers both. | Written, not built. `debian/rules` and `debian/tests/*` need the execute bit set after copying. | +| Chocolatey | `chocolatey/sbm.nuspec`, `chocolatey/tools/` | `choco pack` (done, see below), then `choco install sbm -s .` on a throwaway machine | community.chocolatey.org, with automated checks plus human moderation. Moderators dislike embedded binaries and like package scripts that download from the official source, which is what this does. | `choco pack` succeeds. Not installed or pushed from here. | +| Scoop | `scoop/sbm.json` | `scoop install .\sbm.json`, `scoop checkver sbm <bucket>`, `scoop bucket add` your own bucket | Your own bucket repository. `ScoopInstaller/Extras` takes pull requests; `Main` is for widely used, well known programs. | Written, not installed. JSON parses and the shim generator was run for real. | +| Nix | `nix/default.nix`, `nix/flake.nix` | `nix build -f default.nix`, or `nix build .#sbm` in this directory, then `nixpkgs-review` | A pull request against NixOS/nixpkgs, package file under `pkgs/by-name/sb/sbm/package.nix`. | Written, not evaluated. `meta.license` must become `lib.licenses.<id>`, an attribute and not a string, before nixpkgs will take it. | +| RPM | `rpm/sbm.spec` | `rpmbuild -ba sbm.spec`, `mock -r fedora-rawhide-x86_64 --rebuild *.src.rpm`, `rpmlint sbm.spec` | Fedora: a package review bug in Bugzilla and a sponsor for the first package. openSUSE: a submit request to Factory through the Open Build Service, which is faster. | Written, not built. Rich dependencies `(dmenu or fzf)` need rpm 4.13 or newer: Fedora, and openSUSE Leap 15 and later. | +| Alpine | `alpine/APKBUILD` | `abuild -r`, `abuild checksum`, `apkbuild-lint APKBUILD` | A merge request against `alpinelinux/aports`, in `community/`. | Written, not built. Alpine hashes with sha512, so the token there is `SBM_SHA512_TBD`. | +| Void | `void/srcpkgs/sbm/template` | Inside a void-packages checkout: `./xbps-src pkg sbm`, `xlint srcpkgs/sbm/template` | A pull request against `void-linux/void-packages`. | Written, not built. | +| FreeBSD | `freebsd/deskutils/sbm/` | In a ports tree: `make makesum`, `make stage`, `make check-plist`, `make test`, `portlint -A` | A `ports` bug in Bugzilla with the shar or a patch, or a pull request against `freebsd/freebsd-ports`. | Written, not built. `USES=gmake` is needed; see [Upstream notes](#upstream-notes). | +| MacPorts | `macports/Portfile` | `port lint --nitpick`, `sudo port -v install` from a local ports tree | A pull request against `macports/macports-ports`. | Written, not built. `checksums` needs three tokens replaced, not one. | +| Guix | `guix/sbm.scm` | `guix build -L packaging/guix sbm`, `guix shell -L packaging/guix sbm -- bm --list`, `guix lint -L packaging/guix sbm` | A patch to `guix-patches@gnu.org`, or a channel of your own, which works immediately. | Written, not evaluated. The `#:use-module` lines are a best guess at where each program lives in `gnu/packages/`; `guix build` will say if one is wrong. | + +## Placeholders + +One search and replace per token finishes each job. Nothing else in these +files is a placeholder. + +### `SBM_LICENSE_TBD` — 31 lines in 16 files + +Replace with the licence, in whatever spelling the format wants: an SPDX +identifier for most, a name from `licenses/` for Gentoo, an abbreviation from +`Mk/bsd.licenses.db.mk` for FreeBSD, a `(guix licenses)` variable for Guix, a +`lib.licenses` attribute for Nix, and the full text plus a short name for +Debian. + +| File | Lines | +|---|---| +| `alpine/APKBUILD` | 10 (comment), 13 | +| `arch/sbm/PKGBUILD` | 10 (comment), 14 | +| `arch/sbm-git/PKGBUILD` | 14 | +| `chocolatey/sbm.nuspec` | 16 (comment), 19 | +| `debian/apt/README.md` | 13 (prose) | +| `debian/debian/copyright` | 8, 12, 14, 18 (prose) | +| `freebsd/deskutils/sbm/Makefile` | 11 (comment), 14 | +| `gentoo/app-misc/sbm/sbm-0.3.ebuild` | 14 (comment), 16 | +| `gentoo/app-misc/sbm/sbm-9999.ebuild` | 14 (comment), 15 | +| `guix/sbm.scm` | 128 (comment), 131 | +| `homebrew/sbm.rb` | 7 (comment), 9 | +| `macports/Portfile` | 26 (comment), 29 | +| `nix/default.nix` | 101 | +| `rpm/sbm.spec` | 7 (comment), 10 | +| `scoop/sbm.json` | 10 (comment), 17 | +| `void/srcpkgs/sbm/template` | 15 (comment), 17 | + +One of these is not a bare token. `choco pack` refuses a `licenseUrl` that +does not parse as a URL (error CHCU0001), so +`chocolatey/sbm.nuspec` line 19 carries the token inside a URL path: +`https://github.com/equwal/sbm/blob/master/SBM_LICENSE_TBD`. That URL does +not resolve. The same search and replace still finds it. + +### Checksum placeholders + +No tag means no tarball means no checksum. Four tokens, because the formats +do not agree on a hash. + +`SBM_SHA256_TBD` — 15 lines in 9 files: + +| File | Lines | Replace by running | +|---|---|---| +| `arch/sbm/PKGBUILD` | 32 (comment), 33 | `makepkg -g` | +| `chocolatey/tools/chocolateyInstall.ps1` | 24 (comment), 26 | `Get-FileHash .\v0.3.tar.gz -Algorithm SHA256` | +| `freebsd/deskutils/sbm/distinfo` | 2 | `make makesum` | +| `guix/sbm.scm` | 40 (comment), 42 | `guix download <url>` (base32, not hex) | +| `homebrew/sbm.rb` | 5 | `brew fetch --build-from-source sbm` | +| `macports/Portfile` | 34 | `port -v checksum sbm` | +| `nix/default.nix` | 34 (comment), 36 | `nix-prefetch-url --unpack <url>` (SRI, not hex) | +| `scoop/sbm.json` | 11 (comment), 26 | `scoop checkver sbm <bucket> -u` | +| `void/srcpkgs/sbm/template` | 21 (comment), 22 | `xgensum -i srcpkgs/sbm/template` | + +`SBM_SHA512_TBD` — `alpine/APKBUILD` lines 53 (comment) and 55. Alpine hashes +with sha512. Replace by running `abuild checksum`. + +`SBM_RMD160_TBD` and `SBM_SIZE_TBD` — `macports/Portfile` lines 33 and 35. +MacPorts wants rmd160, sha256 and the byte size. `port -v checksum sbm` +prints all three. + +`freebsd/deskutils/sbm/distinfo` also has `TIMESTAMP = 0` and `SIZE ... = 0`. +`make makesum` rewrites the whole file, so those need no hand editing. + +### Native "skip" values, used on purpose + +`arch/sbm-git/PKGBUILD` line 29 uses `sha256sums=('SKIP')`. That is correct, +not a placeholder: a git source has no fixed archive to hash. + +## Upstream notes + +Things a reviewer will raise, none of which are fixed in this directory, +because nothing outside `packaging/` was touched. + +* **No `LICENSE` file, no licence chosen.** Every repository above will + refuse the package, and an unlicensed work is not distributable at all. + This is the one blocker. +* **No tags.** Nine of the twelve formats need a versioned archive. + `debian/watch`, `checkver` and `autoupdate` all look for `v*` tags and find + nothing. +* **No man pages.** `TODO` lists them as unfinished. Debian, Fedora and + FreeBSD all expect a man page for a program in `bin`, and lintian will say + so. `config.mk` defines `MANPREFIX` and the `Makefile` never uses it. +* **`Makefile` needs GNU make, not POSIX make.** The first line is + `include config.mk`. BSD make wants `.include "config.mk"` and cannot parse + the file at all. That is why the FreeBSD port sets `USES=gmake`, which is + an odd thing to need in a project whose README says it keeps to POSIX. POSIX + make only gained `include` in the 2024 edition. Changing the line to + `.include` would break GNU make instead; supporting both means a small + shim, or moving the variables into the `Makefile`. +* **`install` and `uninstall` disagree.** `install` copies `${TOOLS}`; + `uninstall` removes `${SCRIPTS}`, the full list. Harmless for packages, + which never call `uninstall`, but surprising. +* **`.gitignore` contains `bm`.** The main program is already tracked, so it + is unaffected today, but deleting and re-adding `bm` would silently fail. + `bmks` and `tags.*` in the same file are fine. +* **`bm` has no `--version`.** Several ecosystems' smoke tests reach for it + first. The test blocks here use `bm --list` and `bm --merge` instead, which + are the two actions that never open a menu. +* **`make check` is not hermetic.** It runs shellcheck only when shellcheck + happens to be installed, so the same command lints or does not lint + depending on the machine. The Gentoo, Nix, Guix and MacPorts definitions + call `sh test/run.sh` directly for that reason, and declare shellcheck as a + build-time dependency where the format has one. +* **The test suite is not declared anywhere.** It uses `jq`, `git`, `node` + and `make` when they are present and skips those groups otherwise, so it + passes either way, but a build that has none of them tests less than a + build that has all of them. +* `DESTDIR` itself is well behaved: `make install DESTDIR=... PREFIX=...` + creates the directory and copies the scripts with mode 755, and the test + suite has its own check that `TOOLS` is honoured. + +## Release checklist + +1. **Choose a licence.** Add `LICENSE` at the top of the repository and a + line in `README`. Nothing else on this list matters until this is done. +2. Replace `SBM_LICENSE_TBD` everywhere listed above. Then add the licence + file to the packages that install one: + * Arch: `install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"` + * Alpine: `install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE` + * Void: `vlicense LICENSE` + * RPM: `%license LICENSE` in `%files` + * FreeBSD: `LICENSE_FILE=${WRKSRC}/LICENSE` + * Debian: the full text goes into `debian/copyright` +3. Tag the release: `git tag -a v0.3 -m 'sbm 0.3' && git push --tags`, and + check that + `https://github.com/equwal/sbm/archive/refs/tags/v0.3.tar.gz` downloads + and unpacks to `sbm-0.3/`. +4. Compute the checksums and replace the four checksum tokens, using the + commands in the table above. +5. Optional, and worth doing first: write the man pages that `TODO` asks for, + and decide what to do about `include config.mk` versus BSD make. +6. Submit, easiest first: + * **AUR** (`sbm`, `sbm-git`): push. No review. + * **Your own apt repository**: `debian/apt/README.md`. + * **Your own Homebrew tap and Scoop bucket**: push. + * **A Guix channel**: push. + * **GURU** (Gentoo user overlay): pull request. + * **Void, Alpine, nixpkgs, macports-ports, freebsd-ports**: pull request + or bug, reviewed but not sponsored. + * **Chocolatey community**: push, then wait for moderation. + * **Fedora, openSUSE Factory**: review bug or submit request. + * **Debian proper**: ITP bug, then a sponsor. Slowest. + * **homebrew-core**: only once the project clears the notability bar. + +## What was checked on this machine, and what was not + +Checked: `bash -n` on both PKGBUILDs, the APKBUILD, the Void template and +both ebuilds; `sh -n` on the autopkgtest scripts; Python XML parsing of +`metadata.xml` and `sbm.nuspec`; Python JSON parsing of `sbm.json`; the +PowerShell language parser on both `.ps1` files; `choco pack`, which built a +`.nupkg` that was then deleted; bracket balance and field syntax for the Nix, +Guix, Tcl, Ruby and Debian files; and the generated Windows `.cmd` shim, run +for real against the `bm` and `bm-html` in this repository. + +Not checked: nothing was installed or built as a package, because that needs +each distribution. There is no Ruby here, so the formula was not run through +`ruby -c`. There is no `make` and no shellcheck here, and `test/run.sh` does +not run under Git Bash: `mkdir -m 700` inside the Windows temporary directory +fails with "cannot change permissions". That is an MSYS and Windows problem, +not a fault in the suite. diff --git a/packaging/alpine/APKBUILD b/packaging/alpine/APKBUILD new file mode 100644 index 0000000..86b0e42 --- /dev/null +++ b/packaging/alpine/APKBUILD @@ -0,0 +1,55 @@ +# Contributor: Spenser Truex <truex@equwal.com> +# Maintainer: Spenser Truex <truex@equwal.com> +pkgname=sbm +pkgver=0.3 +pkgrel=0 +pkgdesc="Bookmark manager made of POSIX sh scripts, driven by fzf" +url="https://github.com/equwal/sbm" +arch="noarch" +# Upstream has not chosen a licence yet and ships no LICENSE file. Replace +# SBM_LICENSE_TBD with the SPDX identifier, and add +# install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE +# to package(). abuild's licence check rejects the token, which is intended. +license="SBM_LICENSE_TBD" +# abuild has no "a or b" operator. A menu is required; fzf is in community and +# works without a display, so it is the hard dependency. dmenu is in the +# aports tree too: install it instead if you run X11. +# sh and awk come from busybox, which is always installed. +depends="fzf" +makedepends="make" +checkdepends="shellcheck" +subpackages="$pkgname-doc" +source="$pkgname-$pkgver.tar.gz::https://github.com/equwal/sbm/archive/refs/tags/v$pkgver.tar.gz" + +build() { + # Nothing is compiled; the package is a set of sh scripts. + : +} + +check() { + # make check runs shellcheck -s sh over every script, then the test + # suite. The suite scripts the menu, the clipboard and curl: no display, + # no network. + make check +} + +package() { + make DESTDIR="$pkgdir" PREFIX=/usr install + + install -Dm644 README -t "$pkgdir"/usr/share/doc/$pkgname/ + install -Dm644 TODO -t "$pkgdir"/usr/share/doc/$pkgname/ + install -Dm644 usertags engines \ + -t "$pkgdir"/usr/share/doc/$pkgname/examples/ +} + +# Optional at runtime, none of them pulled in: +# curl bm-title, bm-check +# jq bm-import of Chromium JSON bookmark files +# git bm-commit +# xclip clipboard under X11 (or xsel, or wl-clipboard under Wayland) +# xdg-utils opening URLs with xdg-open + +# Alpine hashes sources with sha512, not sha256. No release tag exists yet, +# so there is nothing to hash: replace SBM_SHA512_TBD by running +# abuild checksum +sha512sums="SBM_SHA512_TBD sbm-0.3.tar.gz" diff --git a/packaging/arch/sbm-git/PKGBUILD b/packaging/arch/sbm-git/PKGBUILD new file mode 100644 index 0000000..85a40e6 --- /dev/null +++ b/packaging/arch/sbm-git/PKGBUILD @@ -0,0 +1,67 @@ +# Maintainer: Spenser Truex <truex@equwal.com> + +# This is the package that works today: upstream has no release tag yet, so +# sbm (the versioned package) has nothing to download. + +pkgname=sbm-git +_pkgname=sbm +pkgver=0.3.r0.gUNKNOWN +pkgrel=1 +pkgdesc='Bookmark manager made of POSIX sh scripts, driven by dmenu or fzf (git)' +arch=('any') +url='https://github.com/equwal/sbm' +# See the comment in ../sbm/PKGBUILD: no licence has been chosen upstream yet. +license=('SBM_LICENSE_TBD') +# makepkg has no "a or b" operator; see ../sbm/PKGBUILD. +depends=('dmenu' 'xclip') +makedepends=('git' 'make') +checkdepends=('shellcheck') +optdepends=('fzf: menu on a bare terminal, and an alternative to dmenu' + 'xsel: clipboard, instead of xclip' + 'wl-clipboard: clipboard under Wayland, instead of xclip' + 'curl: page titles for bm --add (bm-title) and dead-link checks (bm-check)' + 'jq: importing Chromium bookmark files with bm-import' + 'git: bookmark file history with bm-commit' + 'xdg-utils: opening URLs with xdg-open') +provides=("$_pkgname=$pkgver") +conflicts=("$_pkgname") +source=("$_pkgname::git+$url.git") +sha256sums=('SKIP') + +pkgver() { + cd "$_pkgname" + # There are no tags yet, so git describe has nothing to work from. Fall + # back to the version in config.mk plus the commit count. Once v0.3 is + # tagged the first branch takes over on its own. + # The exit status of a pipeline is sed's, which always succeeds: ask git + # first, and only then format. + if git describe --long --tags >/dev/null 2>&1; then + git describe --long --tags | sed 's/^v//; s/\([^-]*-g\)/r/; s/-/./g' + else + printf '%s.r%s.g%s' "$(sed -n 's/^VERSION=//p' config.mk)" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" + fi +} + +build() { + # Nothing is compiled; the package is a set of sh scripts. + : +} + +check() { + cd "$_pkgname" + make check +} + +package() { + cd "$_pkgname" + make DESTDIR="$pkgdir" PREFIX=/usr install + + install -Dm644 README -t "$pkgdir/usr/share/doc/$_pkgname" + install -Dm644 TODO -t "$pkgdir/usr/share/doc/$_pkgname" + install -Dm644 usertags engines -t "$pkgdir/usr/share/doc/$_pkgname/examples" +} + +# Before uploading to the AUR: +# makepkg --printsrcinfo > .SRCINFO +# A -git package's .SRCINFO records the pkgver produced by the last local +# build, so regenerate it after building. diff --git a/packaging/arch/sbm/PKGBUILD b/packaging/arch/sbm/PKGBUILD new file mode 100644 index 0000000..3622290 --- /dev/null +++ b/packaging/arch/sbm/PKGBUILD @@ -0,0 +1,59 @@ +# Maintainer: Spenser Truex <truex@equwal.com> + +pkgname=sbm +pkgver=0.3 +pkgrel=1 +pkgdesc='Bookmark manager made of POSIX sh scripts, driven by dmenu or fzf' +arch=('any') +url='https://github.com/equwal/sbm' +# Upstream has not chosen a licence yet and ships no LICENSE file. Replace +# SBM_LICENSE_TBD with the SPDX identifier, and add the usual +# install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE" +# to package() if the licence is not one of /usr/share/licenses/common. +# namcap reports the token as an unknown licence, which is intended. +license=('SBM_LICENSE_TBD') +# makepkg has no "a or b" operator, so the hard dependencies below name the +# usual choice and the alternatives are listed in optdepends: +# menu dmenu or fzf +# clipboard xclip or xsel or wl-clipboard +# sh (bash) and awk (gawk) are members of the base group and are not listed. +depends=('dmenu' 'xclip') +makedepends=('make') +checkdepends=('shellcheck') +optdepends=('fzf: menu on a bare terminal, and an alternative to dmenu' + 'xsel: clipboard, instead of xclip' + 'wl-clipboard: clipboard under Wayland, instead of xclip' + 'curl: page titles for bm --add (bm-title) and dead-link checks (bm-check)' + 'jq: importing Chromium bookmark files with bm-import' + 'git: bookmark file history with bm-commit' + 'xdg-utils: opening URLs with xdg-open') +source=("$pkgname-$pkgver.tar.gz::$url/archive/refs/tags/v$pkgver.tar.gz") +# No release tag exists yet, so there is nothing to hash. Replace +# SBM_SHA256_TBD with the output of: makepkg -g +sha256sums=('SBM_SHA256_TBD') + +build() { + # Nothing is compiled; the package is a set of sh scripts. + : +} + +check() { + cd "$pkgname-$pkgver" + # make check runs shellcheck -s sh over every script, then the test suite. + # The suite scripts the menu, the clipboard and curl: no display, no network. + make check +} + +package() { + cd "$pkgname-$pkgver" + make DESTDIR="$pkgdir" PREFIX=/usr install + + install -Dm644 README -t "$pkgdir/usr/share/doc/$pkgname" + install -Dm644 TODO -t "$pkgdir/usr/share/doc/$pkgname" + install -Dm644 usertags engines -t "$pkgdir/usr/share/doc/$pkgname/examples" +} + +# Before uploading to the AUR, regenerate the metadata: +# makepkg --printsrcinfo > .SRCINFO +# and commit PKGBUILD and .SRCINFO together. Check the result with +# namcap PKGBUILD && namcap sbm-0.3-1-any.pkg.tar.zst diff --git a/packaging/chocolatey/sbm.nuspec b/packaging/chocolatey/sbm.nuspec new file mode 100644 index 0000000..ca7d237 --- /dev/null +++ b/packaging/chocolatey/sbm.nuspec @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8"?> +<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> + <metadata> + <id>sbm</id> + <version>0.3</version> + <packageSourceUrl>https://github.com/equwal/sbm/tree/master/packaging/chocolatey</packageSourceUrl> + <owners>equwal</owners> + <title>sbm (bookmark manager)</title> + <authors>Spenser Truex</authors> + <projectUrl>https://github.com/equwal/sbm</projectUrl> + <!-- + Upstream has not chosen a licence yet and the repository has no LICENSE + file. licenseUrl must parse as a URL or "choco pack" refuses the + package outright (CHCU0001), so the placeholder token is carried in the + path instead of standing alone. The URL below does not resolve. + Replace SBM_LICENSE_TBD with the real file name, for example + https://github.com/equwal/sbm/blob/master/LICENSE + --> + <licenseUrl>https://github.com/equwal/sbm/blob/master/SBM_LICENSE_TBD</licenseUrl> + <requireLicenseAcceptance>false</requireLicenseAcceptance> + <projectSourceUrl>https://github.com/equwal/sbm</projectSourceUrl> + <docsUrl>https://github.com/equwal/sbm/blob/master/README</docsUrl> + <bugTrackerUrl>https://github.com/equwal/sbm/issues</bugTrackerUrl> + <tags>sbm bookmarks bookmark-manager fzf posix shell cli suckless</tags> + <summary>Bookmark manager made of POSIX sh scripts, driven by fzf</summary> + <description><![CDATA[ +sbm keeps bookmarks in one tab separated file: URL, description, tags. +`bm` picks one from a menu and opens it, copies it, edits it or deletes it. +Text that is no bookmark is opened as an address or searched for on the web. + +The other programs are small filters over bookmark lines: `bm-import`, +`bm-check`, `bm-html`, `bm-migrate`, `bm-title` and `bm-commit`. + +### What this package does + +sbm is POSIX shell. This package does not port it to PowerShell. It installs +the scripts and generates `.cmd` shims that run them through the `sh.exe` that +comes with Git for Windows, which is why `git` is a dependency. + +### What works on Windows + +* The menu is **fzf**. `bm` picks fzf when there is no X11 or Wayland + display, which is always the case here. +* Clipboard: the shims default `SBM_COPY` to `clip` and `SBM_PASTE` to + `powershell -NoProfile -Command Get-Clipboard` when you have not set them. +* Opening URLs: set `SBM_OPEN` yourself, for example + + setx SBM_OPEN "powershell -NoProfile -Command Start-Process" + +* `bm-title`, `bm-check`: need `curl`, which ships with Windows 10 1803 and + later, and with Git for Windows. +* `bm-import` of a Chromium JSON bookmark file needs `jq` + (`choco install jq`). +* `bm-commit` needs `git`, which is already a dependency. + +### What does not work on Windows + +* **dmenu.** It is an X11 program. There is no dmenu here and none is + installed. Everything menu driven goes through fzf. +* `xclip`, `xsel`, `wl-clipboard`, `xdg-open`: X11 and Wayland programs, + replaced by the `SBM_COPY`, `SBM_PASTE` and `SBM_OPEN` settings above. + +Bookmarks live in `%LOCALAPPDATA%` terms under the Git Bash HOME: +`~/.local/share/sbm/bookmarks`. Set `BOOKMARKS` to move it. +]]></description> + <releaseNotes>https://github.com/equwal/sbm/commits/master</releaseNotes> + <dependencies> + <!-- git supplies sh.exe; fzf is the menu. --> + <dependency id="git" version="2.30.0" /> + <dependency id="fzf" version="0.30.0" /> + </dependencies> + </metadata> + <files> + <file src="tools\**" target="tools" /> + </files> +</package> diff --git a/packaging/chocolatey/tools/chocolateyInstall.ps1 b/packaging/chocolatey/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000..26d3b08 --- /dev/null +++ b/packaging/chocolatey/tools/chocolateyInstall.ps1 @@ -0,0 +1,166 @@ +$ErrorActionPreference = 'Stop' + +$packageName = 'sbm' +$version = '0.3' +$toolsDir = Split-Path -Parent $MyInvocation.MyCommand.Definition +$stage = Join-Path $toolsDir 'staging' + +# What Makefile's TOOLS installs. +$scripts = @('bm', 'bm-migrate', 'bm-import', 'bm-check', 'bm-html', 'bm-title', 'bm-commit') + +# --------------------------------------------------------------------------- +# Fetch and unpack. +# +# GitHub serves a tag as .tar.gz. 7zip needs two passes for that: .tar.gz to +# .tar, then .tar to the tree. Nothing is embedded in this package, because no +# licence has been chosen upstream yet. +# --------------------------------------------------------------------------- + +$packageArgs = @{ + packageName = $packageName + unzipLocation = $stage + url = "https://github.com/equwal/sbm/archive/refs/tags/v$version.tar.gz" + # No release tag exists yet, so there is nothing to hash. Replace + # SBM_SHA256_TBD with the sha256 of the tarball once v0.3 is tagged: + # Get-FileHash .\v0.3.tar.gz -Algorithm SHA256 + checksum = 'SBM_SHA256_TBD' + checksumType = 'sha256' +} + +Install-ChocolateyZipPackage @packageArgs + +$tar = Get-ChildItem -Path $stage -Filter '*.tar' -File | Select-Object -First 1 +if (-not $tar) { + throw "sbm: no .tar found in $stage after unpacking the release archive." +} +Get-ChocolateyUnzip -FileFullPath $tar.FullName -Destination $stage -PackageName $packageName +Remove-Item -LiteralPath $tar.FullName -Force + +$src = Join-Path $stage "$packageName-$version" +if (-not (Test-Path -LiteralPath $src)) { + # A -git style archive, or a renamed top directory: take the only one there. + $only = Get-ChildItem -Path $stage -Directory | Select-Object -First 1 + if (-not $only) { throw "sbm: the release archive did not unpack into a directory." } + $src = $only.FullName +} + +foreach ($s in $scripts) { + $from = Join-Path $src $s + if (-not (Test-Path -LiteralPath $from)) { throw "sbm: $s is missing from the release archive." } + Copy-Item -LiteralPath $from -Destination (Join-Path $toolsDir $s) -Force +} +foreach ($extra in @('README', 'usertags', 'engines')) { + $from = Join-Path $src $extra + if (Test-Path -LiteralPath $from) { + Copy-Item -LiteralPath $from -Destination (Join-Path $toolsDir $extra) -Force + } +} +Remove-Item -LiteralPath $stage -Recurse -Force -ErrorAction SilentlyContinue + +# --------------------------------------------------------------------------- +# Find a POSIX sh. Git for Windows ships one; the package depends on git for +# exactly that reason. Look in several places rather than one hardcoded path, +# because Git installs per machine, per user, 32 bit, and through Chocolatey. +# --------------------------------------------------------------------------- + +function Get-PosixSh { + $candidates = New-Object 'System.Collections.Generic.List[string]' + + $gitCmd = Get-Command 'git.exe' -ErrorAction SilentlyContinue + if ($gitCmd) { + # ...\Git\cmd\git.exe and ...\Git\bin\git.exe both give ...\Git here. + $gitRoot = Split-Path -Parent (Split-Path -Parent $gitCmd.Source) + $candidates.Add((Join-Path $gitRoot 'bin\sh.exe')) + $candidates.Add((Join-Path $gitRoot 'usr\bin\sh.exe')) + } + + $keys = @( + 'HKLM:\SOFTWARE\GitForWindows', + 'HKLM:\SOFTWARE\WOW6432Node\GitForWindows', + 'HKCU:\SOFTWARE\GitForWindows' + ) + foreach ($key in $keys) { + try { + $installPath = (Get-ItemProperty -Path $key -Name 'InstallPath' -ErrorAction Stop).InstallPath + if ($installPath) { + $candidates.Add((Join-Path $installPath 'bin\sh.exe')) + $candidates.Add((Join-Path $installPath 'usr\bin\sh.exe')) + } + } catch { + # No such key on this machine. + } + } + + $roots = @( + $env:ProgramFiles, + ${env:ProgramFiles(x86)}, + $env:ProgramW6432, + $(if ($env:LOCALAPPDATA) { Join-Path $env:LOCALAPPDATA 'Programs' }), + $(if ($env:ChocolateyInstall) { Join-Path $env:ChocolateyInstall 'lib\git.install\tools' }) + ) + foreach ($root in $roots) { + if ($root) { + $candidates.Add((Join-Path $root 'Git\bin\sh.exe')) + $candidates.Add((Join-Path $root 'Git\usr\bin\sh.exe')) + } + } + + $shCmd = Get-Command 'sh.exe' -ErrorAction SilentlyContinue + if ($shCmd) { $candidates.Add($shCmd.Source) } + + foreach ($candidate in $candidates) { + if ($candidate -and (Test-Path -LiteralPath $candidate -PathType Leaf)) { return $candidate } + } + return $null +} + +$sh = Get-PosixSh +if (-not $sh) { + throw @' +sbm: no POSIX sh found. + +sbm is POSIX shell and needs one to run. Git for Windows ships sh.exe and is +a dependency of this package: + + choco install git + +If Git is installed somewhere unusual, sbm still works: put that sh.exe on +PATH and reinstall this package. +'@ +} +Write-Host "sbm: using $sh" + +# --------------------------------------------------------------------------- +# Generate a .cmd per script and register it on PATH. +# +# The sh path found above is baked in, with a fall back to whatever sh.exe is +# on PATH, so moving or upgrading Git does not break the shims outright. +# --------------------------------------------------------------------------- + +foreach ($s in $scripts) { + $cmdPath = Join-Path $toolsDir "$s.cmd" + $body = @" +@echo off +rem Generated by the sbm Chocolatey package. Do not edit: reinstalling +rem the package rewrites this file. +setlocal +if not defined SBM_COPY set "SBM_COPY=clip" +if not defined SBM_PASTE set "SBM_PASTE=powershell -NoProfile -Command Get-Clipboard" +set "SBM_SH=$sh" +if not exist "%SBM_SH%" set "SBM_SH=sh.exe" +"%SBM_SH%" "%~dp0$s" %* +"@ + Set-Content -LiteralPath $cmdPath -Value $body -Encoding ASCII + Install-BinFile -Name $s -Path $cmdPath +} + +Write-Host @' +sbm is installed. On Windows: + + * The menu is fzf. dmenu is an X11 program and is not available here. + * SBM_COPY and SBM_PASTE default to clip and Get-Clipboard. + * Set an opener yourself, for example: + setx SBM_OPEN "powershell -NoProfile -Command Start-Process" + * Example tag and engine files are in this package's tools directory. + Copy them to ~/.local/share/sbm/ (the HOME that Git Bash uses). +'@ diff --git a/packaging/chocolatey/tools/chocolateyUninstall.ps1 b/packaging/chocolatey/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000..2f40f0c --- /dev/null +++ b/packaging/chocolatey/tools/chocolateyUninstall.ps1 @@ -0,0 +1,22 @@ +$ErrorActionPreference = 'Stop' + +$toolsDir = Split-Path -Parent $MyInvocation.MyCommand.Definition + +$scripts = @('bm', 'bm-migrate', 'bm-import', 'bm-check', 'bm-html', 'bm-title', 'bm-commit') + +foreach ($s in $scripts) { + $cmdPath = Join-Path $toolsDir "$s.cmd" + Uninstall-BinFile -Name $s -Path $cmdPath + Remove-Item -LiteralPath $cmdPath -Force -ErrorAction SilentlyContinue + Remove-Item -LiteralPath (Join-Path $toolsDir $s) -Force -ErrorAction SilentlyContinue +} + +foreach ($extra in @('README', 'usertags', 'engines')) { + Remove-Item -LiteralPath (Join-Path $toolsDir $extra) -Force -ErrorAction SilentlyContinue +} + +Remove-Item -LiteralPath (Join-Path $toolsDir 'staging') -Recurse -Force -ErrorAction SilentlyContinue + +# The bookmark file is the user's data and is left alone. It is under +# ~/.local/share/sbm/ unless BOOKMARKS says otherwise. +Write-Host 'sbm: your bookmark file was not touched.' diff --git a/packaging/debian/apt/README.md b/packaging/debian/apt/README.md new file mode 100644 index 0000000..1b95c47 --- /dev/null +++ b/packaging/debian/apt/README.md @@ -0,0 +1,129 @@ +# Building the .deb, and serving it from your own apt repository + +`../debian/` is a complete `debian/` directory. It is kept one level down so +that `packaging/debian/` can hold this note beside it. To use it, copy it to +the top of a source tree: + + cp -r packaging/debian/debian /path/to/sbm-0.3/debian + +## Before the first build + +Two things in `debian/` are placeholders. + +* `debian/copyright` says `SBM_LICENSE_TBD`. Nothing can be uploaded + anywhere until a real licence is chosen: an unlicensed work is not + distributable. +* `debian/changelog` says `UNRELEASED` and has no `Closes:` line, because no + ITP bug has been filed. + +Git does not carry the execute bit through every path this directory may +travel, so check it: + + chmod 755 debian/rules debian/tests/smoke debian/tests/upstream-suite + +## Building + +`3.0 (quilt)` needs an orig tarball beside the source directory: + + sbm-0.3.orig.tar.gz + sbm-0.3/debian/... + +Once v0.3 is tagged, the tarball is the release archive renamed: + + wget -O sbm-0.3.orig.tar.gz \ + https://github.com/equwal/sbm/archive/refs/tags/v0.3.tar.gz + +Until then, `make dist` in the source tree produces `sbm-0.3.tar.gz` with the +same top level directory name, which works for local builds. + +Build a binary package: + + cd sbm-0.3 + dpkg-buildpackage -us -uc -b + +Build source and binary, in a clean chroot, which is what an upload needs: + + sbuild -d unstable + # or + pbuilder build ../sbm_0.3-1.dsc + +Check it: + + lintian -i -I --pedantic ../sbm_0.3-1_all.deb ../sbm_0.3-1.dsc + autopkgtest ../sbm_0.3-1_all.deb -- null + +Install it locally: + + sudo apt install ./sbm_0.3-1_all.deb + +## Getting into Debian proper + +Debian needs a Debian Developer to sponsor the first upload. + +1. Choose a licence and add a `LICENSE` file upstream. +2. Tag `v0.3` upstream so `debian/watch` has something to find. +3. File an ITP bug: `reportbug wnpp`, type `ITP`. Put the bug number in + `debian/changelog` as `Closes: #NNNNNN`. +4. Build in a clean chroot and get `lintian --pedantic` quiet. +5. Upload the source package to <https://mentors.debian.net/>. +6. Ask for a sponsor on debian-mentors@lists.debian.org, or in the RFS bug. + +This takes weeks to months. The apt repository below works the same day. + +## Your own signed apt repository + +Both tools below produce a repository that `apt` trusts once the user adds +your key. Pick one. + +### reprepro + +`conf/distributions`: + + Origin: equwal.com + Label: sbm + Codename: stable + Architectures: amd64 arm64 source + Components: main + Description: sbm packages + SignWith: YOURKEYID + +Then: + + mkdir -p ~/apt/conf # put the file above in there + cd ~/apt + reprepro includedeb stable /path/to/sbm_0.3-1_all.deb + reprepro include stable /path/to/sbm_0.3-1_amd64.changes # source too + +`reprepro` signs `Release` with the key named in `SignWith`. Copy `~/apt` +to any static web server; nothing server side is needed. + +### aptly + + aptly repo create -distribution=stable -component=main sbm + aptly repo add sbm /path/to/sbm_0.3-1_all.deb + aptly publish repo -gpg-key=YOURKEYID sbm + # publishes under ~/.aptly/public; copy that to the web server + +`aptly` can also mirror and snapshot, which matters once there is more than +one package. + +### The key + +Export the public half in binary form, which is what modern apt wants: + + gpg --export YOURKEYID > equwal-archive-keyring.gpg + +Serve it next to the repository. Users then write +`/etc/apt/sources.list.d/sbm.sources`: + + Types: deb + URIs: https://example.com/apt + Suites: stable + Components: main + Signed-By: /usr/share/keyrings/equwal-archive-keyring.gpg + +and put the exported key at that path. Do not tell users to pipe a key into +`apt-key`: it has been removed. + +`Architectures: amd64 arm64` is only about the index. The package itself is +`Architecture: all`, so one build serves every architecture. diff --git a/packaging/debian/debian/changelog b/packaging/debian/debian/changelog new file mode 100644 index 0000000..aa656a4 --- /dev/null +++ b/packaging/debian/debian/changelog @@ -0,0 +1,8 @@ +sbm (0.3-1) UNRELEASED; urgency=medium + + * Initial packaging. + * No ITP bug has been filed yet, so there is no Closes entry. File one + against wnpp and add "Closes: #NNNNNN" here before uploading, and change + UNRELEASED to unstable. + + -- Spenser Truex <truex@equwal.com> Sun, 20 Sep 2026 21:36:41 -0700 diff --git a/packaging/debian/debian/control b/packaging/debian/debian/control new file mode 100644 index 0000000..e1d4892 --- /dev/null +++ b/packaging/debian/debian/control @@ -0,0 +1,45 @@ +Source: sbm +Section: web +Priority: optional +Maintainer: Spenser Truex <truex@equwal.com> +Build-Depends: + debhelper-compat (= 13), + shellcheck <!nocheck>, +Standards-Version: 4.7.0 +Rules-Requires-Root: no +Homepage: https://github.com/equwal/sbm +Vcs-Browser: https://github.com/equwal/sbm +Vcs-Git: https://github.com/equwal/sbm.git + +Package: sbm +Architecture: all +# Depends can say "a or b", so the menu and the clipboard are honest here. +# sh and awk are not listed: dash and mawk are Priority: required. +Depends: + ${misc:Depends}, + dmenu | fzf, +Recommends: + xclip | xsel | wl-clipboard, + xdg-utils, +Suggests: + curl, + jq, + git, +Description: bookmark manager made of POSIX sh scripts + sbm keeps bookmarks in one tab separated file: URL, description, tags. + Lines starting with # are ignored, so cut, grep, awk and an editor work on + it as well as the tools do. + . + bm picks a bookmark with dmenu, or with fzf on a bare terminal, and then + opens it, copies it, edits it or deletes it. Text that is no bookmark is + opened as an address or searched for on the web. + . + The rest are small filters that read and write bookmark lines: + * bm-import turns a browser's bookmarks into bookmark lines; + * bm-check reports dead and permanently moved links; + * bm-html writes the bookmarks as one self-contained web page; + * bm-migrate converts a file from the old sbm format; + * bm-title prints a page's title, which bm --add offers as a description; + * bm-commit keeps the bookmark file's history in git. + . + Everything is POSIX sh and POSIX utilities. Nothing is compiled. diff --git a/packaging/debian/debian/copyright b/packaging/debian/debian/copyright new file mode 100644 index 0000000..b46fdec --- /dev/null +++ b/packaging/debian/debian/copyright @@ -0,0 +1,23 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: sbm +Upstream-Contact: Spenser Truex <truex@equwal.com> +Source: https://github.com/equwal/sbm + +Files: * +Copyright: 2024-2026 Spenser Truex <truex@equwal.com> +License: SBM_LICENSE_TBD + +Files: debian/* +Copyright: 2026 Spenser Truex <truex@equwal.com> +License: SBM_LICENSE_TBD + +License: SBM_LICENSE_TBD + The sbm repository carries no LICENSE file and upstream has not chosen a + licence yet. This paragraph is a placeholder, not a licence. + . + Replace every SBM_LICENSE_TBD in this file with the licence's short name, + and replace this text with the licence's full text, or with a pointer into + /usr/share/common-licenses when the licence is one of the common ones. + . + The package cannot be uploaded to Debian until that is done: an + unlicensed work is not distributable. diff --git a/packaging/debian/debian/docs b/packaging/debian/debian/docs new file mode 100644 index 0000000..724e084 --- /dev/null +++ b/packaging/debian/debian/docs @@ -0,0 +1,2 @@ +README +TODO diff --git a/packaging/debian/debian/examples b/packaging/debian/debian/examples new file mode 100644 index 0000000..456f1c1 --- /dev/null +++ b/packaging/debian/debian/examples @@ -0,0 +1,2 @@ +usertags +engines diff --git a/packaging/debian/debian/rules b/packaging/debian/debian/rules new file mode 100755 index 0000000..8243436 --- /dev/null +++ b/packaging/debian/debian/rules @@ -0,0 +1,19 @@ +#!/usr/bin/make -f +# Nothing here is compiled, so there is no build step and no hardening to do. + +%: + dh $@ + +override_dh_auto_build: + # The upstream "all" target only prints a reminder; there is nothing + # to build. + +# dh_auto_test finds the "check" target on its own, since there is no +# "test" target. It runs shellcheck -s sh over every script and then the +# test suite, which scripts the menu, the clipboard and curl: no display, +# no network. The override is here only to carry this comment. +override_dh_auto_test: + dh_auto_test + +override_dh_auto_install: + dh_auto_install -- PREFIX=/usr diff --git a/packaging/debian/debian/source/format b/packaging/debian/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/packaging/debian/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/packaging/debian/debian/tests/control b/packaging/debian/debian/tests/control new file mode 100644 index 0000000..a1919c4 --- /dev/null +++ b/packaging/debian/debian/tests/control @@ -0,0 +1,9 @@ +# smoke uses the installed programs; upstream-suite runs the source tree's +# own tests, which exercise the same scripts before they are installed. +Tests: smoke +Depends: @ +Restrictions: allow-stderr + +Tests: upstream-suite +Depends: @, make +Restrictions: allow-stderr diff --git a/packaging/debian/debian/tests/smoke b/packaging/debian/debian/tests/smoke new file mode 100755 index 0000000..5f43d15 --- /dev/null +++ b/packaging/debian/debian/tests/smoke @@ -0,0 +1,28 @@ +#!/bin/sh +# Exercise the installed programs. --list and --merge are the two actions +# that never open a menu, so this needs no display and no menu program. +set -e + +work=${AUTOPKGTEST_TMP:?AUTOPKGTEST_TMP is not set} + +BOOKMARKS="$work/bookmarks" +USERTAGS="$work/usertags" +export BOOKMARKS USERTAGS +SBM_GIT=0 +SBM_FETCH=0 +export SBM_GIT SBM_FETCH + +printf '%s\t%s\t%s\n' 'https://equwal.com' "Spenser Truex's website" 'users' \ + | bm --merge + +bm --list | grep -q 'https://equwal.com' + +# The same URL again, with a trailing slash, must be refused as a duplicate. +printf '%s\t%s\t%s\n' 'https://equwal.com/' 'duplicate' 'users' \ + | bm --merge | grep -q 'skipped 1' + +test "$(bm --list | wc -l)" = 1 + +bm-html | grep -q '<li>' + +echo 'smoke: ok' diff --git a/packaging/debian/debian/tests/upstream-suite b/packaging/debian/debian/tests/upstream-suite new file mode 100755 index 0000000..1b2c7dc --- /dev/null +++ b/packaging/debian/debian/tests/upstream-suite @@ -0,0 +1,8 @@ +#!/bin/sh +# Run upstream's own test suite against the source tree autopkgtest copied +# into the testbed. It scripts the menu, the clipboard and curl, so it needs +# no display and no network. +set -e + +cd "$(dirname "$0")/../.." +sh test/run.sh diff --git a/packaging/debian/debian/upstream/metadata b/packaging/debian/debian/upstream/metadata new file mode 100644 index 0000000..2f6b143 --- /dev/null +++ b/packaging/debian/debian/upstream/metadata @@ -0,0 +1,5 @@ +--- +Bug-Database: https://github.com/equwal/sbm/issues +Bug-Submit: https://github.com/equwal/sbm/issues/new +Repository: https://github.com/equwal/sbm.git +Repository-Browse: https://github.com/equwal/sbm diff --git a/packaging/debian/debian/watch b/packaging/debian/debian/watch new file mode 100644 index 0000000..50d18fe --- /dev/null +++ b/packaging/debian/debian/watch @@ -0,0 +1,4 @@ +version=4 +opts=filenamemangle=s%(?:.*?)?v?@ANY_VERSION@@ARCHIVE_EXT@%@PACKAGE@-$1.tar.gz% \ + https://github.com/equwal/sbm/tags \ + (?:.*?/)?v?@ANY_VERSION@@ARCHIVE_EXT@ debian uupdate diff --git a/packaging/freebsd/deskutils/sbm/Makefile b/packaging/freebsd/deskutils/sbm/Makefile new file mode 100644 index 0000000..d91d7fa --- /dev/null +++ b/packaging/freebsd/deskutils/sbm/Makefile @@ -0,0 +1,65 @@ +PORTNAME= sbm +DISTVERSIONPREFIX= v +DISTVERSION= 0.3 +CATEGORIES= deskutils + +MAINTAINER= truex@equwal.com +COMMENT= Bookmark manager made of POSIX sh scripts, driven by dmenu or fzf +WWW= https://github.com/equwal/sbm + +# Upstream has not chosen a licence yet and ships no LICENSE file. Replace +# SBM_LICENSE_TBD with an abbreviation from Mk/bsd.licenses.db.mk and add +# LICENSE_FILE= ${WRKSRC}/LICENSE +# The ports framework refuses an unknown licence, which is intended. +LICENSE= SBM_LICENSE_TBD + +# The ports framework has no "a or b" operator. A menu is required; fzf needs +# no display, so it is the hard dependency. Install x11/dmenu as well if you +# run X11: bm prefers it whenever $DISPLAY is set. +RUN_DEPENDS= fzf:textproc/fzf + +# FreeBSD's /bin/sh is POSIX and runs everything here as is. gmake is not +# about building, since nothing is compiled: upstream's Makefile starts with +# include config.mk +# which is GNU make syntax. bmake wants ".include" and cannot parse the file. +USES= gmake +USE_GITHUB= yes +GH_ACCOUNT= equwal + +NO_ARCH= yes +NO_BUILD= yes + +OPTIONS_DEFINE= DOCS EXAMPLES + +TEST_DEPENDS= shellcheck:devel/hs-ShellCheck + +# PREFIX is /usr/local here, not /usr, and the upstream config.mk already +# defaults to /usr/local. It is passed on the command line anyway, because a +# plain assignment in config.mk wins over the environment under GNU make. +do-install: + @${MKDIR} ${STAGEDIR}${PREFIX}/bin + cd ${WRKSRC} && ${SETENV} ${MAKE_ENV} ${MAKE_CMD} install \ + DESTDIR=${STAGEDIR} PREFIX=${PREFIX} + +post-install-DOCS-on: + @${MKDIR} ${STAGEDIR}${DOCSDIR} + ${INSTALL_DATA} ${WRKSRC}/README ${WRKSRC}/TODO ${STAGEDIR}${DOCSDIR} + +post-install-EXAMPLES-on: + @${MKDIR} ${STAGEDIR}${EXAMPLESDIR} + ${INSTALL_DATA} ${WRKSRC}/usertags ${WRKSRC}/engines \ + ${STAGEDIR}${EXAMPLESDIR} + +# make check runs shellcheck -s sh over every script, then the test suite. +# The suite scripts the menu, the clipboard and curl: no display, no network. +do-test: + cd ${WRKSRC} && ${SETENV} ${MAKE_ENV} ${MAKE_CMD} check + +# Optional at runtime, none of them pulled in: +# ftp/curl bm-title, bm-check +# textproc/jq bm-import of Chromium JSON bookmark files +# devel/git bm-commit +# x11/xclip clipboard under X11 (or x11/xsel, or x11/wl-clipboard) +# devel/xdg-utils opening URLs with xdg-open + +.include <bsd.port.mk> diff --git a/packaging/freebsd/deskutils/sbm/distinfo b/packaging/freebsd/deskutils/sbm/distinfo new file mode 100644 index 0000000..d5db7b4 --- /dev/null +++ b/packaging/freebsd/deskutils/sbm/distinfo @@ -0,0 +1,3 @@ +TIMESTAMP = 0 +SHA256 (equwal-sbm-v0.3_GH0.tar.gz) = SBM_SHA256_TBD +SIZE (equwal-sbm-v0.3_GH0.tar.gz) = 0 diff --git a/packaging/freebsd/deskutils/sbm/pkg-descr b/packaging/freebsd/deskutils/sbm/pkg-descr new file mode 100644 index 0000000..a39d5c2 --- /dev/null +++ b/packaging/freebsd/deskutils/sbm/pkg-descr @@ -0,0 +1,15 @@ +sbm keeps bookmarks in one tab separated file: URL, description, tags. Lines +starting with # are ignored, so cut, grep, awk and an editor work on it as +well as the tools do. + +bm picks a bookmark with dmenu, or with fzf on a bare terminal, and then +opens it, copies it, edits it or deletes it. Text that is no bookmark is +opened as an address or searched for on the web. + +The rest are small filters that read and write bookmark lines: bm-import +turns a browser's bookmarks into bookmark lines, bm-check reports dead links, +bm-html writes a searchable web page, bm-migrate converts the old file +format, bm-title prints a page's title and bm-commit keeps the bookmark +file's history in git. + +Everything is POSIX sh and POSIX utilities. Nothing is compiled. diff --git a/packaging/freebsd/deskutils/sbm/pkg-plist b/packaging/freebsd/deskutils/sbm/pkg-plist new file mode 100644 index 0000000..6edba24 --- /dev/null +++ b/packaging/freebsd/deskutils/sbm/pkg-plist @@ -0,0 +1,11 @@ +bin/bm +bin/bm-check +bin/bm-commit +bin/bm-html +bin/bm-import +bin/bm-migrate +bin/bm-title +%%PORTDOCS%%%%DOCSDIR%%/README +%%PORTDOCS%%%%DOCSDIR%%/TODO +%%PORTEXAMPLES%%%%EXAMPLESDIR%%/engines +%%PORTEXAMPLES%%%%EXAMPLESDIR%%/usertags diff --git a/packaging/gentoo/app-misc/sbm/metadata.xml b/packaging/gentoo/app-misc/sbm/metadata.xml new file mode 100644 index 0000000..b348689 --- /dev/null +++ b/packaging/gentoo/app-misc/sbm/metadata.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE pkgmetadata SYSTEM "https://www.gentoo.org/dtd/metadata.dtd"> +<pkgmetadata> + <maintainer type="person" proxied="yes"> + <email>truex@equwal.com</email> + <name>Spenser Truex</name> + </maintainer> + <maintainer type="project" proxied="proxy"> + <email>proxy-maint@gentoo.org</email> + <name>Proxy Maintainers</name> + </maintainer> + <longdescription lang="en"> + sbm keeps bookmarks in one tab separated file: URL, description, + tags. bm picks a bookmark with dmenu, or with fzf on a bare + terminal, and opens it, copies it, edits it or deletes it. Text + that is no bookmark is opened as an address or searched for on + the web. + + The rest are small filters that read and write bookmark lines: + bm-import reads a browser's bookmarks, bm-check reports dead + links, bm-html writes a searchable web page, bm-migrate converts + the old file format, bm-title fetches a page title and bm-commit + keeps the file's history in git. + + Everything is POSIX sh and POSIX utilities. Nothing is compiled. + </longdescription> + <!-- + No <use> block: X and wayland are global USE flags, and pkgcheck + reports a local description that duplicates a global one. + --> + <upstream> + <maintainer status="active"> + <email>truex@equwal.com</email> + <name>Spenser Truex</name> + </maintainer> + <bugs-to>https://github.com/equwal/sbm/issues</bugs-to> + <remote-id type="github">equwal/sbm</remote-id> + </upstream> +</pkgmetadata> diff --git a/packaging/gentoo/app-misc/sbm/sbm-0.3.ebuild b/packaging/gentoo/app-misc/sbm/sbm-0.3.ebuild new file mode 100644 index 0000000..7ae3492 --- /dev/null +++ b/packaging/gentoo/app-misc/sbm/sbm-0.3.ebuild @@ -0,0 +1,72 @@ +# Copyright 1999-2026 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit optfeature + +DESCRIPTION="Bookmark manager made of POSIX sh scripts, driven by dmenu or fzf" +HOMEPAGE="https://github.com/equwal/sbm" +SRC_URI="https://github.com/equwal/sbm/archive/refs/tags/v${PV}.tar.gz + -> ${P}.tar.gz" + +# Upstream has not chosen a licence yet and ships no LICENSE file. +# Replace SBM_LICENSE_TBD with a name from licenses/ in the tree. +# pkgcheck reports this token as a nonexistent licence, which is intended. +LICENSE="SBM_LICENSE_TBD" +SLOT="0" +KEYWORDS="~amd64 ~arm64 ~x86" +IUSE="+X wayland" + +# A menu is required and either program will do; || () says exactly that. +# The clipboard programs are per-display-server, so they hang off USE. +# Without X and without wayland nothing is pulled in and you set $SBM_COPY +# and $SBM_PASTE yourself. +RDEPEND=" + || ( + x11-misc/dmenu + app-shells/fzf + ) + X? ( + || ( + x11-misc/xclip + x11-misc/xsel + ) + ) + wayland? ( gui-apps/wl-clipboard ) +" + +src_compile() { + # Nothing is compiled; the package is a set of sh scripts. + : +} + +src_test() { + # "make check" also runs shellcheck when it happens to be installed, + # which would make the result depend on the build host. The suite itself + # is deterministic: it scripts the menu, the clipboard and curl, so it + # needs no display and no network. + sh test/run.sh || die "test suite failed" +} + +src_install() { + emake DESTDIR="${D}" PREFIX="${EPREFIX}/usr" install + + dodoc README TODO + docinto examples + dodoc usertags engines + + # Once upstream adds a LICENSE file, nothing extra is needed here: + # dodoc handles it through the LICENSE variable above. +} + +pkg_postinst() { + optfeature "page titles for 'bm --add' and dead-link checks" net-misc/curl + optfeature "importing Chromium bookmark files" app-misc/jq + optfeature "keeping the bookmark file's history in git" dev-vcs/git + optfeature "opening URLs with the desktop's handler" x11-misc/xdg-utils + + elog "Example tag and search-engine files are in" + elog " /usr/share/doc/${PF}/examples" + elog "Copy them to ~/.local/share/sbm/ if you want them." +} diff --git a/packaging/gentoo/app-misc/sbm/sbm-9999.ebuild b/packaging/gentoo/app-misc/sbm/sbm-9999.ebuild new file mode 100644 index 0000000..f96f947 --- /dev/null +++ b/packaging/gentoo/app-misc/sbm/sbm-9999.ebuild @@ -0,0 +1,56 @@ +# Copyright 1999-2026 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit git-r3 optfeature + +DESCRIPTION="Bookmark manager made of POSIX sh scripts, driven by dmenu or fzf" +HOMEPAGE="https://github.com/equwal/sbm" +EGIT_REPO_URI="https://github.com/equwal/sbm.git" +EGIT_BRANCH="master" + +# Upstream has not chosen a licence yet and ships no LICENSE file. +# Replace SBM_LICENSE_TBD with a name from licenses/ in the tree. +LICENSE="SBM_LICENSE_TBD" +SLOT="0" +# A live ebuild carries no KEYWORDS on purpose. +IUSE="+X wayland" + +RDEPEND=" + || ( + x11-misc/dmenu + app-shells/fzf + ) + X? ( + || ( + x11-misc/xclip + x11-misc/xsel + ) + ) + wayland? ( gui-apps/wl-clipboard ) +" + +src_compile() { + # Nothing is compiled; the package is a set of sh scripts. + : +} + +src_test() { + sh test/run.sh || die "test suite failed" +} + +src_install() { + emake DESTDIR="${D}" PREFIX="${EPREFIX}/usr" install + + dodoc README TODO + docinto examples + dodoc usertags engines +} + +pkg_postinst() { + optfeature "page titles for 'bm --add' and dead-link checks" net-misc/curl + optfeature "importing Chromium bookmark files" app-misc/jq + optfeature "keeping the bookmark file's history in git" dev-vcs/git + optfeature "opening URLs with the desktop's handler" x11-misc/xdg-utils +} diff --git a/packaging/guix/sbm.scm b/packaging/guix/sbm.scm new file mode 100644 index 0000000..c7a7053 --- /dev/null +++ b/packaging/guix/sbm.scm @@ -0,0 +1,133 @@ +;;; sbm: bookmarks in a plain file, picked with dmenu or fzf. +;;; +;;; Build it out of this file: +;;; +;;; guix build -L packaging/guix sbm +;;; guix shell -L packaging/guix sbm -- bm --list +;;; +;;; To send it upstream, move the package form into gnu/packages/, most +;;; likely web.scm or suckless.scm, and drop the define-module header. + +(define-module (sbm) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix gexp) + #:use-module (guix utils) + #:use-module (guix build-system gnu) + #:use-module ((guix licenses) #:prefix license:) + #:use-module (gnu packages base) + #:use-module (gnu packages curl) + #:use-module (gnu packages freedesktop) + #:use-module (gnu packages gawk) + #:use-module (gnu packages haskell-apps) + #:use-module (gnu packages suckless) + #:use-module (gnu packages terminals) + #:use-module (gnu packages version-control) + #:use-module (gnu packages web) + #:use-module (gnu packages xdisorg)) + +(define-public sbm + (package + (name "sbm") + (version "0.3") + (source + (origin + (method url-fetch) + (uri (string-append "https://github.com/equwal/sbm" + "/archive/refs/tags/v" version ".tar.gz")) + (file-name (string-append name "-" version ".tar.gz")) + ;; No release tag exists yet, so there is nothing to hash. Replace + ;; SBM_SHA256_TBD with the base32 hash that this prints: + ;; guix download <the URL above> + (sha256 (base32 "SBM_SHA256_TBD")))) + (build-system gnu-build-system) + (arguments + (list + #:make-flags + #~(list (string-append "PREFIX=" #$output)) + #:phases + #~(modify-phases %standard-phases + ;; There is no configure script, and nothing is compiled: the + ;; upstream "all" target only prints a reminder. + (delete 'configure) + (delete 'build) + (replace 'check + (lambda* (#:key tests? #:allow-other-keys) + (when tests? + ;; "make check" also runs shellcheck when it is installed, + ;; which would make the result depend on the build + ;; environment. The suite scripts the menu, the clipboard + ;; and curl: no display, no network. + (invoke "sh" "test/run.sh")))) + (add-after 'install 'install-doc + (lambda _ + (let* ((doc (string-append #$output "/share/doc/" #$name "-" + #$version)) + (examples (string-append doc "/examples"))) + (install-file "README" doc) + (install-file "TODO" doc) + (install-file "usertags" examples) + (install-file "engines" examples)))) + (add-after 'install-doc 'wrap-programs + (lambda* (#:key inputs #:allow-other-keys) + ;; bm calls bm-title and bm-commit by name, so $output/bin + ;; goes on the PATH as well as the runtime programs. + (let ((path + (cons (string-append #$output "/bin") + (map (lambda (file) + (dirname (search-input-file inputs file))) + '("bin/awk" + "bin/fzf" + "bin/dmenu" + "bin/xclip" + "bin/wl-copy" + "bin/xdg-open" + "bin/curl" + "bin/jq" + "bin/git"))))) + (for-each (lambda (program) + (wrap-program program + `("PATH" ":" prefix ,path))) + (find-files (string-append #$output "/bin"))))))))) + (inputs + (list coreutils + gawk + ;; A menu is required and either will do; both are wrapped in, so + ;; bm picks dmenu when there is a display and fzf otherwise. + dmenu + fzf + ;; Clipboard. + xclip + wl-clipboard + ;; Optional, but cheap and wrapped in so the tools just work: + ;; curl (bm-title, bm-check), jq (bm-import of Chromium JSON + ;; files), git (bm-commit), xdg-utils (opening URLs). + curl + jq + git + xdg-utils)) + (native-inputs + (list shellcheck)) + (home-page "https://github.com/equwal/sbm") + (synopsis "Bookmark manager made of POSIX sh scripts, driven by dmenu or fzf") + (description + "sbm keeps bookmarks in one tab separated file: URL, description, tags. +@command{bm} picks one with dmenu, or with fzf on a bare terminal, and then +opens it, copies it, edits it or deletes it. Text that is no bookmark is +opened as an address or searched for on the web. + +The rest are small filters that read and write bookmark lines: +@command{bm-import} turns a browser's bookmarks into bookmark lines, +@command{bm-check} reports dead links, @command{bm-html} writes a searchable +web page, @command{bm-migrate} converts the old file format, +@command{bm-title} prints a page's title and @command{bm-commit} keeps the +bookmark file's history in git. + +Everything is POSIX sh and POSIX utilities. Nothing is compiled.") + ;; Upstream has not chosen a licence yet and ships no LICENSE file. + ;; Replace SBM_LICENSE_TBD with a variable from (guix licenses), for + ;; example license:gpl3+. As written this is an unbound variable and + ;; evaluation fails, which is what a placeholder should do. + (license license:SBM_LICENSE_TBD))) + +sbm diff --git a/packaging/homebrew/sbm.rb b/packaging/homebrew/sbm.rb new file mode 100644 index 0000000..f413c95 --- /dev/null +++ b/packaging/homebrew/sbm.rb @@ -0,0 +1,76 @@ +class Sbm < Formula + desc "Bookmark manager made of POSIX sh scripts, driven by dmenu or fzf" + homepage "https://github.com/equwal/sbm" + url "https://github.com/equwal/sbm/archive/refs/tags/v0.3.tar.gz" + sha256 "SBM_SHA256_TBD" + # No licence has been chosen upstream yet and the repository carries no + # LICENSE file. Replace SBM_LICENSE_TBD with the SPDX identifier. + # `brew audit --strict` rejects this token, which is intended. + license "SBM_LICENSE_TBD" + head "https://github.com/equwal/sbm.git", branch: "master" + + # A menu is required: dmenu or fzf. Homebrew has no dmenu formula, and dmenu + # needs X11 on macOS, so fzf is the only practical menu here and is a hard + # dependency. See caveats. + depends_on "fzf" + + # Optional runtime helpers are deliberately not dependencies: + # curl ships with macOS (bm-title, bm-check) + # git ships with the CLT (bm-commit) + # jq only for Chromium JSON bookmark files (bm-import) + # Homebrew dropped :optional and :recommended, so these are named in caveats. + + def install + system "make", "install", "PREFIX=#{prefix}" + doc.install "README", "TODO" + (pkgshare/"examples").install "usertags", "engines" + end + + def caveats + <<~EOS + sbm expects a menu, a clipboard command and an opener. On macOS: + + * The menu is fzf. dmenu is an X11 program; if you run XQuartz and + build dmenu yourself, set SBM_MENU=dmenu. + * bm does not auto-detect pbcopy/pbpaste/open, so set these yourself: + + export SBM_COPY=pbcopy + export SBM_PASTE=pbpaste + export SBM_OPEN=open + + Example tag and search-engine files are installed in + + #{pkgshare}/examples + + Copy them if you want them: + + mkdir -p ~/.local/share/sbm + cp #{pkgshare}/examples/usertags #{pkgshare}/examples/engines ~/.local/share/sbm/ + + Optional programs: jq (bm-import of Chromium bookmark files). + curl and git come with macOS and the Command Line Tools. + EOS + end + + test do + ENV["BOOKMARKS"] = testpath/"bookmarks" + ENV["USERTAGS"] = testpath/"usertags" + ENV["SBM_GIT"] = "0" + ENV["SBM_FETCH"] = "0" + + # --list and --merge are the two actions that never open a menu. + merged = pipe_output("#{bin}/bm --merge", + "https://equwal.com\tSpenser Truex's website\tusers\n") + assert_match "added 1", merged + + # Merging the same URL again must be a no-op. + again = pipe_output("#{bin}/bm --merge", + "https://equwal.com/\tsame bookmark, trailing slash\tusers\n") + assert_match "skipped 1", again + + assert_equal "https://equwal.com\tSpenser Truex's website\tusers", + shell_output("#{bin}/bm --list").strip + + assert_match "<li>", shell_output("#{bin}/bm-html") + end +end diff --git a/packaging/macports/Portfile b/packaging/macports/Portfile new file mode 100644 index 0000000..d8cc83e --- /dev/null +++ b/packaging/macports/Portfile @@ -0,0 +1,85 @@ +# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:et:sw=4:ts=4:sts=4 + +PortSystem 1.0 +PortGroup github 1.0 + +github.setup equwal sbm 0.3 v +categories www +platforms any +supported_archs noarch +maintainers {equwal.com:truex @equwal} + +description Bookmark manager made of POSIX sh scripts, driven by fzf + +long_description sbm keeps bookmarks in one tab separated file: URL, \ + description, tags. bm picks one with fzf and opens it, \ + copies it, edits it or deletes it. Text that is no \ + bookmark is opened as an address or searched for on the \ + web. The rest are small filters over bookmark lines: \ + bm-import, bm-check, bm-html, bm-migrate, bm-title and \ + bm-commit. Everything is POSIX sh and POSIX utilities; \ + nothing is compiled. + +homepage https://github.com/equwal/sbm + +# Upstream has not chosen a licence yet and ships no LICENSE file. Replace +# SBM_LICENSE_TBD with a name from +# https://trac.macports.org/wiki/PortfileRecipes#license +# "port lint" rejects the token, which is intended. +license SBM_LICENSE_TBD + +# No release tag exists yet, so there is nothing to hash. Replace all three +# tokens at once by running: port -v checksum sbm +checksums rmd160 SBM_RMD160_TBD \ + sha256 SBM_SHA256_TBD \ + size SBM_SIZE_TBD + +# dmenu is an X11 program; on macOS fzf is the practical menu, so it is the +# only hard runtime dependency. bm picks fzf on its own when there is no +# display. +depends_run port:fzf + +use_configure no + +# Nothing is compiled; the upstream "all" target only prints a reminder. +build {} + +# destroot.destdir already carries DESTDIR=${destroot}. PREFIX has to be on +# the command line: config.mk assigns it plainly, and a plain assignment in a +# makefile wins over the environment. +destroot.args PREFIX=${prefix} + +post-destroot { + xinstall -d ${destroot}${prefix}/share/doc/${name} + xinstall -m 0644 -W ${worksrcpath} README TODO \ + ${destroot}${prefix}/share/doc/${name} + + xinstall -d ${destroot}${prefix}/share/examples/${name} + xinstall -m 0644 -W ${worksrcpath} usertags engines \ + ${destroot}${prefix}/share/examples/${name} +} + +# The suite scripts the menu, the clipboard and curl, so it needs no display +# and no network. "make check" is not used: it also runs shellcheck when one +# happens to be installed, which would make the result depend on the host. +test.run yes +test.cmd /bin/sh +test.target +test.args test/run.sh + +notes " +bm does not auto-detect the macOS clipboard or opener. Set them yourself: + + export SBM_COPY=pbcopy + export SBM_PASTE=pbpaste + export SBM_OPEN=open + +The menu is fzf. dmenu needs X11 and is not installed by this port. + +Example tag and search-engine files are in +${prefix}/share/examples/${name}; copy them to ~/.local/share/sbm/ if you +want them. + +Optional: jq, for importing Chromium JSON bookmark files with bm-import. +curl and git come with macOS and the Command Line Tools. +" diff --git a/packaging/nix/default.nix b/packaging/nix/default.nix new file mode 100644 index 0000000..026da55 --- /dev/null +++ b/packaging/nix/default.nix @@ -0,0 +1,106 @@ +{ lib +, stdenvNoCC +, fetchFromGitHub +, makeWrapper +, gawk +, coreutils +, fzf +, dmenu +, xclip +, wl-clipboard +, xdg-utils +, curl +, jq +, git + # dmenu is X11 only, so it is off on Darwin and fzf carries the menu there. +, withDmenu ? stdenvNoCC.hostPlatform.isLinux +, withWaylandClipboard ? stdenvNoCC.hostPlatform.isLinux + # Optional at runtime: bm-title and bm-check (curl), bm-import of Chromium + # JSON files (jq), bm-commit (git). Cheap enough to keep on by default. +, withCurl ? true +, withJq ? true +, withGit ? true +}: + +stdenvNoCC.mkDerivation (finalAttrs: { + pname = "sbm"; + version = "0.3"; + + src = fetchFromGitHub { + owner = "equwal"; + repo = "sbm"; + rev = "v${finalAttrs.version}"; + # No release tag exists yet, so there is nothing to hash. Replace + # SBM_SHA256_TBD with the SRI hash; lib.fakeHash makes the build print + # the real one. The token is left here so it shows up in a grep. + hash = "SBM_SHA256_TBD"; + }; + + nativeBuildInputs = [ makeWrapper ]; + + # Nothing is compiled. The upstream "all" target only prints a reminder. + dontBuild = true; + + doCheck = true; + + checkPhase = '' + runHook preCheck + # "make check" also runs shellcheck when it is installed, which would + # make the result depend on what is in the build environment. The suite + # itself scripts the menu, the clipboard and curl: no display, no network. + sh test/run.sh + runHook postCheck + ''; + + installPhase = '' + runHook preInstall + make install PREFIX="$out" + install -Dm444 README -t "$out/share/doc/sbm" + install -Dm444 TODO -t "$out/share/doc/sbm" + install -Dm444 usertags engines -t "$out/share/doc/sbm/examples" + runHook postInstall + ''; + + postFixup = + let + runtimeDeps = + # fzf is always there: it is the menu that needs no display. + # xclip, wl-clipboard, dmenu and xdg-utils are X11 or Wayland + # programs and do not evaluate on Darwin. + [ gawk coreutils fzf ] + ++ lib.optionals stdenvNoCC.hostPlatform.isLinux [ xclip xdg-utils ] + ++ lib.optional withDmenu dmenu + ++ lib.optional withWaylandClipboard wl-clipboard + ++ lib.optional withCurl curl + ++ lib.optional withJq jq + ++ lib.optional withGit git; + in + '' + # bm calls bm-title and bm-commit by name, so $out/bin goes on the + # PATH as well as the runtime programs. + for f in "$out"/bin/*; do + wrapProgram "$f" \ + --prefix PATH : "$out/bin:${lib.makeBinPath runtimeDeps}" + done + ''; + + meta = { + description = "Bookmark manager made of POSIX sh scripts, driven by dmenu or fzf"; + longDescription = '' + sbm keeps bookmarks in one tab separated file: URL, description, tags. + bm picks one from dmenu, or from fzf on a bare terminal, and opens it, + copies it, edits it or deletes it. Text that is no bookmark is opened as + an address or searched for on the web. The other programs are small + filters over bookmark lines: bm-import, bm-check, bm-html, bm-migrate, + bm-title and bm-commit. + ''; + homepage = "https://github.com/equwal/sbm"; + # Upstream has not chosen a licence yet and ships no LICENSE file. + # This must become lib.licenses.<id> (an attribute, not a string) before + # the package can go into nixpkgs; a string fails the meta check. + license = "SBM_LICENSE_TBD"; + mainProgram = "bm"; + maintainers = [ ]; + platforms = lib.platforms.unix; + }; +}) diff --git a/packaging/nix/flake.nix b/packaging/nix/flake.nix new file mode 100644 index 0000000..a883747 --- /dev/null +++ b/packaging/nix/flake.nix @@ -0,0 +1,34 @@ +{ + description = "sbm: bookmarks in a plain file, picked with dmenu or fzf"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = { self, nixpkgs }: + let + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + forAllSystems = f: + nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system}); + in + { + packages = forAllSystems (pkgs: rec { + sbm = pkgs.callPackage ./default.nix { }; + default = sbm; + }); + + # Build the working tree instead of the tagged release: + # nix build .#sbm --override-input nixpkgs ... + # or edit src in default.nix to fetchGit ../.. + # What "make check" wants, plus the runtime programs. dmenu is left out + # on purpose: it is X11 only and does not evaluate on Darwin. + devShells = forAllSystems (pkgs: { + default = pkgs.mkShellNoCC { + packages = with pkgs; [ shellcheck fzf curl jq git ]; + }; + }); + }; +} diff --git a/packaging/rpm/sbm.spec b/packaging/rpm/sbm.spec new file mode 100644 index 0000000..773b68c --- /dev/null +++ b/packaging/rpm/sbm.spec @@ -0,0 +1,87 @@ +Name: sbm +Version: 0.3 +Release: 1%{?dist} +Summary: Bookmark manager made of POSIX sh scripts, driven by dmenu or fzf + +# Upstream has not chosen a licence yet and ships no LICENSE file. Replace +# SBM_LICENSE_TBD with the SPDX identifier, and add the LICENSE file to the +# %%files section with %%license once upstream ships one. rpmlint reports +# the token as an invalid licence, which is intended. +License: SBM_LICENSE_TBD +URL: https://github.com/equwal/sbm +# No release tag exists yet. Once v0.3 is tagged, fetch with: +# spectool -g sbm.spec +Source0: %{url}/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz + +BuildArch: noarch + +BuildRequires: make +# make check runs shellcheck -s sh over every script before the test suite. +# Both Fedora and openSUSE call the package ShellCheck. +BuildRequires: ShellCheck + +# Rich dependencies need rpm >= 4.13: Fedora, and openSUSE Leap 15 and later. +# They are the only honest way to say "dmenu or fzf". +Requires: (dmenu or fzf) +Requires: /bin/sh +Requires: awk + +Recommends: (xclip or xsel or wl-clipboard) +Recommends: xdg-utils + +# bm-title and bm-check +Suggests: curl +# bm-import, for Chromium JSON bookmark files only +Suggests: jq +# bm-commit +Suggests: git-core + +%description +sbm keeps bookmarks in one tab separated file: URL, description, tags. Lines +starting with # are ignored, so cut, grep, awk and an editor work on it as +well as the tools do. + +bm picks a bookmark with dmenu, or with fzf on a bare terminal, and then +opens it, copies it, edits it or deletes it. Text that is no bookmark is +opened as an address or searched for on the web. + +The rest are small filters that read and write bookmark lines: bm-import +turns a browser's bookmarks into bookmark lines, bm-check reports dead links, +bm-html writes a searchable web page, bm-migrate converts the old file +format, bm-title prints a page's title and bm-commit keeps the bookmark +file's history in git. + +Everything is POSIX sh and POSIX utilities. Nothing is compiled. + +%prep +%autosetup + +%build +# Nothing is compiled; the package is a set of sh scripts. + +%install +%make_install PREFIX=%{_prefix} + +# Shipped as documentation, not as configuration: the user copies what they +# want to ~/.local/share/sbm/. +mkdir -p examples +cp -p usertags engines examples/ + +%check +# The suite scripts the menu, the clipboard and curl, so it needs no display +# and no network. +make check + +%files +%doc README TODO examples +%{_bindir}/bm +%{_bindir}/bm-check +%{_bindir}/bm-commit +%{_bindir}/bm-html +%{_bindir}/bm-import +%{_bindir}/bm-migrate +%{_bindir}/bm-title + +%changelog +* Sun Sep 20 2026 Spenser Truex <truex@equwal.com> - 0.3-1 +- Initial package. diff --git a/packaging/scoop/sbm.json b/packaging/scoop/sbm.json new file mode 100644 index 0000000..36b7243 --- /dev/null +++ b/packaging/scoop/sbm.json @@ -0,0 +1,68 @@ +{ + "##": [ + "sbm is POSIX shell. This manifest does not port it to PowerShell: it", + "installs the scripts and generates a .cmd per script that runs them", + "through the sh.exe that comes with Git for Windows. That is why git is", + "a dependency. The menu is fzf; dmenu is X11 only and has no Windows", + "build, so it is neither installed nor mentioned as an alternative.", + "", + "license: upstream has not chosen one yet and ships no LICENSE file.", + "Replace SBM_LICENSE_TBD with the SPDX identifier.", + "hash: no release tag exists yet. Replace SBM_SHA256_TBD with the", + "sha256 of the tarball, or run: scoop checkver sbm <bucket> -u" + ], + "version": "0.3", + "description": "Bookmark manager made of POSIX sh scripts, driven by fzf", + "homepage": "https://github.com/equwal/sbm", + "license": "SBM_LICENSE_TBD", + "depends": [ + "git", + "fzf" + ], + "suggest": { + "JSON processing (bm-import of Chromium bookmark files)": "jq" + }, + "url": "https://github.com/equwal/sbm/archive/refs/tags/v0.3.tar.gz", + "hash": "SBM_SHA256_TBD", + "extract_dir": "sbm-0.3", + "pre_install": [ + "$lines = @(", + " '@echo off',", + " 'setlocal',", + " 'if not defined SBM_COPY set \"SBM_COPY=clip\"',", + " 'if not defined SBM_PASTE set \"SBM_PASTE=powershell -NoProfile -Command Get-Clipboard\"',", + " 'set \"SBM_SH=\"',", + " 'for %%I in (sh.exe) do if not defined SBM_SH if not \"%%~$PATH:I\"==\"\" set \"SBM_SH=%%~$PATH:I\"',", + " 'for %%I in (\"%SCOOP%\\apps\\git\\current\\bin\\sh.exe\" \"%USERPROFILE%\\scoop\\apps\\git\\current\\bin\\sh.exe\" \"%ProgramFiles%\\Git\\bin\\sh.exe\" \"%LOCALAPPDATA%\\Programs\\Git\\bin\\sh.exe\") do if not defined SBM_SH if exist %%I set \"SBM_SH=%%~I\"',", + " 'if not defined SBM_SH echo sbm: no POSIX sh found. Install Git: scoop install git 1>&2',", + " 'if not defined SBM_SH exit /b 127'", + ")", + "foreach ($t in 'bm','bm-migrate','bm-import','bm-check','bm-html','bm-title','bm-commit') {", + " ($lines + ('\"%SBM_SH%\" \"%~dp0' + $t + '\" %*')) | Set-Content -LiteralPath \"$dir\\$t.cmd\" -Encoding ASCII", + "}" + ], + "bin": [ + "bm.cmd", + "bm-migrate.cmd", + "bm-import.cmd", + "bm-check.cmd", + "bm-html.cmd", + "bm-title.cmd", + "bm-commit.cmd" + ], + "notes": [ + "The menu is fzf. dmenu is an X11 program and does not exist here.", + "SBM_COPY and SBM_PASTE default to clip and Get-Clipboard.", + "Set an opener yourself, for example:", + " setx SBM_OPEN \"powershell -NoProfile -Command Start-Process\"", + "Example tag and engine files are in the app directory; copy usertags", + "and engines to ~/.local/share/sbm/ (the HOME that Git Bash uses)." + ], + "checkver": { + "github": "https://github.com/equwal/sbm" + }, + "autoupdate": { + "url": "https://github.com/equwal/sbm/archive/refs/tags/v$version.tar.gz", + "extract_dir": "sbm-$version" + } +} diff --git a/packaging/void/srcpkgs/sbm/template b/packaging/void/srcpkgs/sbm/template new file mode 100644 index 0000000..a7cb217 --- /dev/null +++ b/packaging/void/srcpkgs/sbm/template @@ -0,0 +1,44 @@ +# Template file for 'sbm' +pkgname=sbm +version=0.3 +revision=1 +build_style=gnu-makefile +make_install_args="PREFIX=/usr" +# xbps-src has no "a or b" operator. A menu is required; fzf needs no display +# and is the hard dependency. dmenu is in the tree too: install it as well if +# you run X11. +depends="fzf" +checkdepends="shellcheck" +short_desc="Bookmark manager made of POSIX sh scripts, driven by fzf" +maintainer="Spenser Truex <truex@equwal.com>" +# Upstream has not chosen a licence yet and ships no LICENSE file. Replace +# SBM_LICENSE_TBD with the SPDX identifier and add "vlicense LICENSE" to +# post_install. xlint rejects the token, which is intended. +license="SBM_LICENSE_TBD" +homepage="https://github.com/equwal/sbm" +distfiles="https://github.com/equwal/sbm/archive/refs/tags/v${version}.tar.gz" +# No release tag exists yet, so there is nothing to hash. Replace +# SBM_SHA256_TBD with the output of: xgensum -i srcpkgs/sbm/template +checksum=SBM_SHA256_TBD + +# Optional at runtime, none of them pulled in: +# curl bm-title, bm-check +# jq bm-import of Chromium JSON bookmark files +# git bm-commit +# xclip clipboard under X11 (or xsel, or wl-clipboard under Wayland) +# xdg-utils opening URLs with xdg-open + +do_check() { + # make check runs shellcheck -s sh over every script, then the test + # suite. The suite scripts the menu, the clipboard and curl: no display, + # no network. + make check +} + +post_install() { + vdoc README + vdoc TODO + vmkdir usr/share/examples/sbm + vcopy usertags usr/share/examples/sbm + vcopy engines usr/share/examples/sbm +}