diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 6ad4707..624a5ee 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -20,51 +20,80 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.21' + go-version: "1.21" - name: Upload Release Asset uses: https://gitea.com/actions/release-action@main with: files: |- kewt - api_key: '${{secrets.GITEA_TOKEN}}' + packaging/bash/kewt.bash + api_key: "${{secrets.GITEA_TOKEN}}" - name: Push to GitHub Release run: | TAG="${GITHUB_REF#refs/tags/}" - - # Fetch release body from Gitea + RELEASE_BODY=$(curl -sL \ "https://git.krzak.org/api/v1/repos/N0VA/kewt/releases/tags/${TAG}" \ | jq -r '.body // ""') - - # Build JSON payload + PAYLOAD=$(jq -n \ --arg tag "$TAG" \ --arg name "Release $TAG" \ --arg body "$RELEASE_BODY" \ '{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}') - - # Create the release on GitHub + curl -sL -X POST \ -H "Authorization: token ${{ secrets.GH_RELEASE_TOKEN }}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/n0va-bot/kewt/releases" \ -d "$PAYLOAD" || true - - # Get the release ID + RELEASE_ID=$(curl -sL \ -H "Authorization: token ${{ secrets.GH_RELEASE_TOKEN }}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/n0va-bot/kewt/releases/tags/${TAG}" | jq -r '.id') - - # Upload the asset + curl -sL -X POST \ -H "Authorization: token ${{ secrets.GH_RELEASE_TOKEN }}" \ -H "Content-Type: application/octet-stream" \ "https://uploads.github.com/repos/n0va-bot/kewt/releases/${RELEASE_ID}/assets?name=kewt" \ --data-binary @kewt + publish-fedora: + runs-on: local + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install dependencies + run: | + sudo apt-get update || true + sudo apt-get install -y rpm || true + + - name: Build Fedora Assets + run: | + if command -v rpmbuild >/dev/null; then + make srpm + else + echo "rpmbuild not found, generating spec file only" + TAG="${GITHUB_REF#refs/tags/}" + VERSION="${TAG#v}" + sed -e "s/VERSION_PLACEHOLDER/${VERSION}/g" packaging/fedora/kewt.spec.template > packaging/fedora/kewt.spec + fi + + - name: Upload Fedora Assets + uses: https://gitea.com/actions/release-action@main + with: + files: |- + kewt-*.src.rpm + packaging/fedora/kewt.spec + api_key: "${{secrets.GITEA_TOKEN}}" + publish-aur: runs-on: local needs: build @@ -76,21 +105,21 @@ jobs: run: | sudo apt-get update sudo apt-get install -y openssh-client curl jq - + - name: Render PKGBUILD and SRCINFO run: | VERSION=${GITHUB_REF#refs/tags/v} VERSION=${VERSION#refs/tags/} - + curl -sL -o kewt https://git.krzak.org/N0VA/kewt/releases/download/v${VERSION}/kewt - + CHECKSUM=$(sha256sum kewt | awk '{print $1}') - + mkdir -p aur-work sed -e "s/VERSION_PLACEHOLDER/${VERSION}/g" \ -e "s/SHA256SUM_PLACEHOLDER/${CHECKSUM}/g" \ packaging/AUR/PKGBUILD.template > aur-work/PKGBUILD - + sed -e "s/VERSION_PLACEHOLDER/${VERSION}/g" \ -e "s/SHA256SUM_PLACEHOLDER/${CHECKSUM}/g" \ packaging/AUR/.SRCINFO.template > aur-work/.SRCINFO diff --git a/.gitignore b/.gitignore index d2efdfb..4df1170 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ out/ -kewt \ No newline at end of file +kewt diff --git a/Makefile b/Makefile index a281bdd..bbdc1ce 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ PREFIX ?= /usr/local BINDIR = $(PREFIX)/bin ZSHCOMPDIR ?= $(PREFIX)/share/zsh/site-functions +BASHCOMPDIR ?= $(PREFIX)/share/bash-completion/completions all: kewt @@ -12,13 +13,25 @@ install: kewt install -m 755 kewt $(DESTDIR)$(BINDIR)/kewt install -d $(DESTDIR)$(ZSHCOMPDIR) install -m 644 packaging/zsh/_kewt $(DESTDIR)$(ZSHCOMPDIR)/_kewt + install -d $(DESTDIR)$(BASHCOMPDIR) + install -m 644 packaging/bash/kewt.bash $(DESTDIR)$(BASHCOMPDIR)/kewt uninstall: rm -f $(DESTDIR)$(BINDIR)/kewt rm -f $(DESTDIR)$(ZSHCOMPDIR)/_kewt + rm -f $(DESTDIR)$(BASHCOMPDIR)/kewt clean: - rm -f kewt + rm -f kewt kewt-*.tar.gz + +dist: + $(eval VERSION := $(shell git describe --tags --always | sed 's/^v//;s/-/./g')) + tar -czf kewt-$(VERSION).tar.gz --exclude-vcs --exclude=kewt --exclude=kewt-$(VERSION).tar.gz --transform "s|^|kewt-$(VERSION)/|" * + +srpm: dist + $(eval VERSION := $(shell git describe --tags --always | sed 's/^v//;s/-/./g')) + sed -e "s/VERSION_PLACEHOLDER/$(VERSION)/g" packaging/fedora/kewt.spec.template > packaging/fedora/kewt.spec + rpmbuild -bs --define "_sourcedir $(PWD)" --define "_srcrpmdir $(PWD)" packaging/fedora/kewt.spec test: sh tests/test_runner.sh diff --git a/kewt.sh b/kewt.sh index 54bab81..f48308f 100755 --- a/kewt.sh +++ b/kewt.sh @@ -45,6 +45,8 @@ positional_count=0 watch_mode="false" serve_mode="false" serve_port="" +draft_mode="false" +dry_run_mode="false" while [ $# -gt 0 ]; do case "$1" in @@ -89,6 +91,8 @@ _kewt() { '--to[Output directory]:directory:_directories' '(-w --watch)'{-w,--watch}'[Watch for file changes and rebuild automatically]' '(-s --serve)'{-s,--serve}'[Start a local HTTP server after building]::port:' + '(-d --draft)'{-d,--draft}'[Include draft pages in the build]' + '(-)--dry-run[Show what would be built without writing any files]' ) _arguments -S -C $args '*: :_directories' @@ -141,6 +145,12 @@ EOFCOMPS shift fi ;; + --draft|-d) + draft_mode="true" + ;; + --dry-run) + dry_run_mode="true" + ;; --*) die "Unknown option: $1" ;; @@ -201,10 +211,24 @@ refresh_build_context if [ "$clean_mode" = "true" ]; then [ -d "$out" ] && rm -rf "$out" fi + +if [ "$dry_run_mode" = "true" ]; then + dry_run_out="$KEWT_TMPDIR/dry_run_out" + mkdir -p "$dry_run_out" + out="$dry_run_out" +fi + mkdir -p "$out" build_site +if [ "$dry_run_mode" = "true" ]; then + echo "" + echo "Dry run complete. Files that would be generated:" + find "$dry_run_out" -type f | sed "s|^$dry_run_out/||" | sort + exit 0 +fi + if [ "$serve_mode" = "true" ]; then port="${serve_port:-8000}" if command -v python3 >/dev/null 2>&1; then diff --git a/lib/builder.sh b/lib/builder.sh index 565aeb9..9171c7d 100644 --- a/lib/builder.sh +++ b/lib/builder.sh @@ -48,8 +48,10 @@ build_dir_entries_list() { elif [ "${entry%.md}" != "$entry" ]; then entry_rel_path="${entry#"$src"/}" load_manifest_entry "$entry_rel_path" || continue + if [ "${draft_mode:-false}" != "true" ]; then + [ "$manifest_draft" = "true" ] && continue + fi label="${name%.md}" - [ "$manifest_draft" = "true" ] && continue post_h="$manifest_title" @@ -373,7 +375,9 @@ build_files() { if [ "${file%.md}" != "$file" ] && [ "$is_preserved" -eq 0 ]; then load_manifest_entry "$rel_path" || continue - [ "$manifest_draft" = "true" ] && continue + if [ "${draft_mode:-false}" != "true" ]; then + [ "$manifest_draft" = "true" ] && continue + fi is_home="false"; [ "$file" = "$src/index.md" ] && is_home="true" out_file="$out/${rel_path%.md}.html" if needs_rebuild "$file" "$out_file"; then @@ -476,8 +480,15 @@ build_feed() { post_url="$base_url_feed$manifest_url" pub_date=$(format_rfc2822_utc "$post_date" "$post_time") - printf ' \n %s\n %s\n %s\n %s\n \n' \ - "$feed_post_title" "$post_url" "$post_url" "$pub_date" >> "$feed_path" + if [ "$feed_full_content" = "true" ]; then + feed_content_file="$src/$post_rel_path" + feed_content_html=$(ENABLE_HEADER_LINKS="false" CUSTOM_ADMONITIONS="" MARKDOWN_SITE_ROOT="$src" MARKDOWN_FALLBACK_FILE="$script_dir/styles/$style.css" sh "$script_dir/markdown.sh" "$feed_content_file" | sed 's//\>/g') + printf ' \n %s\n %s\n %s\n %s\n %s\n \n' \ + "$feed_post_title" "$post_url" "$post_url" "$pub_date" "$feed_content_html" >> "$feed_path" + else + printf ' \n %s\n %s\n %s\n %s\n \n' \ + "$feed_post_title" "$post_url" "$post_url" "$pub_date" >> "$feed_path" + fi done printf ' \n\n' >> "$feed_path" @@ -606,12 +617,24 @@ build_tags() { } build_error_page() { - [ -n "$error_page" ] && [ ! -f "$out/$error_page" ] || return + [ -n "$error_page" ] || return - temp_404="$KEWT_TMPDIR/404_gen.md" - printf '# 404 - Not Found\n\nThe requested page could not be found.\n' > "$temp_404" - render_markdown "$temp_404" "false" "/$error_page" > "$out/$error_page" - rm -f "$temp_404" + error_base="${error_page%.html}" + error_md="$src/${error_base}.md" + + if [ -f "$error_md" ]; then + if needs_rebuild "$error_md" "$out/$error_page"; then + is_home="false" + current_url="/$error_page" + parse_frontmatter "$error_md" + render_markdown "$error_md" "$is_home" "/$error_page" > "$out/$error_page" + fi + elif [ ! -f "$out/$error_page" ]; then + temp_404="$KEWT_TMPDIR/404_gen.md" + printf '# 404 - Not Found\n\nThe requested page could not be found.\n' > "$temp_404" + render_markdown "$temp_404" "false" "/$error_page" > "$out/$error_page" + rm -f "$temp_404" + fi } build_site() { diff --git a/lib/commands.sh b/lib/commands.sh index 5e2fde1..79dc688 100644 --- a/lib/commands.sh +++ b/lib/commands.sh @@ -22,6 +22,8 @@ Options: --post Create a new empty post file in the configured posts_dir with current date and time as name --generate-template [path] Generate a new template file at (default: template.html) --version Show version information. + --draft, -d Include draft pages in the build. + --dry-run Show what would be built without writing any files. --from Source directory (default: site) --to Output directory (default: out) --watch, -w Watch for file changes and rebuild automatically. diff --git a/lib/config.sh b/lib/config.sh index ca386e7..d3a6e95 100644 --- a/lib/config.sh +++ b/lib/config.sh @@ -34,7 +34,8 @@ tags_dir = "tags" generate_search = false search_in_footer = false search_in_header = false -include_cw_pages_in_search = false' +include_cw_pages_in_search = false +feed_full_content = false' DEFAULT_TMPL=' @@ -129,6 +130,7 @@ _load_conf_line() { search_in_footer) search_in_footer="$_lc_val" ;; search_in_header) search_in_header="$_lc_val" ;; include_cw_pages_in_search) include_cw_pages_in_search="$_lc_val" ;; + feed_full_content) feed_full_content="$_lc_val" ;; esac } diff --git a/lib/manifest.sh b/lib/manifest.sh index 16b980b..eb46b9f 100644 --- a/lib/manifest.sh +++ b/lib/manifest.sh @@ -187,8 +187,10 @@ build_markdown_manifest() { eval "find \"$src\" \( $IGNORE_ARGS -o $HIDE_ARGS -o $PRESERVE_ARGS \) -prune -o -name \"*.md\" -print" | sort | while IFS= read -r visible_file; do visible_rel_path="${visible_file#"$src"/}" load_manifest_entry "$visible_rel_path" || continue - [ "$manifest_draft" = "true" ] && continue - manifest_dir_hidden_by_draft_index "$manifest_dir_rel" && continue + if [ "${draft_mode:-false}" != "true" ]; then + [ "$manifest_draft" = "true" ] && continue + manifest_dir_hidden_by_draft_index "$manifest_dir_rel" && continue + fi printf '%s\n' "$visible_rel_path" >> "$manifest_visible_list" done } diff --git a/packaging/AUR/.SRCINFO.git b/packaging/AUR/.SRCINFO.git index e4272d4..10e9d37 100644 --- a/packaging/AUR/.SRCINFO.git +++ b/packaging/AUR/.SRCINFO.git @@ -1,12 +1,13 @@ pkgbase = kewt-git pkgdesc = A minimalist, 100% POSIX, static site generator inspired by werc and kew - pkgver = r0.0000001 + pkgver = r0.0000002 pkgrel = 1 url = https://kewt.krzak.org arch = any license = ISC makedepends = git depends = sh + optdepends = bash-completion: bash shell completions provides = kewt conflicts = kewt conflicts = kewt-bin diff --git a/packaging/AUR/.SRCINFO.template b/packaging/AUR/.SRCINFO.template index 2c953b4..7d75362 100644 --- a/packaging/AUR/.SRCINFO.template +++ b/packaging/AUR/.SRCINFO.template @@ -6,10 +6,13 @@ pkgbase = kewt-bin arch = any license = ISC depends = sh + optdepends = bash-completion: bash shell completions provides = kewt conflicts = kewt conflicts = kewt-git source = kewt-bin-VERSION_PLACEHOLDER.sh::https://git.krzak.org/N0VA/kewt/releases/download/vVERSION_PLACEHOLDER/kewt + source = kewt-bin-VERSION_PLACEHOLDER.bash::https://git.krzak.org/N0VA/kewt/releases/download/vVERSION_PLACEHOLDER/kewt.bash sha256sums = SHA256SUM_PLACEHOLDER + sha256sums = SKIP pkgname = kewt-bin diff --git a/packaging/AUR/PKGBUILD.git b/packaging/AUR/PKGBUILD.git index fe8b041..1e6312e 100644 --- a/packaging/AUR/PKGBUILD.git +++ b/packaging/AUR/PKGBUILD.git @@ -1,6 +1,6 @@ # Maintainer: n0va pkgname=kewt-git -pkgver=r0.0000001 +pkgver=r0.0000002 pkgrel=1 pkgdesc="A minimalist, 100% POSIX, static site generator inspired by werc and kew" arch=('any') @@ -28,4 +28,5 @@ package() { install -Dm755 kewt "${pkgdir}/usr/bin/kewt" install -d "${pkgdir}/usr/share/zsh/site-functions" "${pkgdir}/usr/bin/kewt" --dump-zsh-completions > "${pkgdir}/usr/share/zsh/site-functions/_kewt" + install -Dm644 packaging/bash/kewt.bash "${pkgdir}/usr/share/bash-completion/completions/kewt" } diff --git a/packaging/AUR/PKGBUILD.template b/packaging/AUR/PKGBUILD.template index 6d7f6bf..b368771 100644 --- a/packaging/AUR/PKGBUILD.template +++ b/packaging/AUR/PKGBUILD.template @@ -9,8 +9,9 @@ license=('ISC') depends=('sh') provides=('kewt') conflicts=('kewt' 'kewt-git') -source=("${pkgname}-${pkgver}.sh::https://git.krzak.org/N0VA/kewt/releases/download/v${pkgver}/kewt") -sha256sums=('SHA256SUM_PLACEHOLDER') +source=("${pkgname}-${pkgver}.sh::https://git.krzak.org/N0VA/kewt/releases/download/v${pkgver}/kewt" + "${pkgname}-${pkgver}.bash::https://git.krzak.org/N0VA/kewt/releases/download/v${pkgver}/kewt.bash") +sha256sums=('SHA256SUM_PLACEHOLDER' 'SKIP') build() { chmod +x "${srcdir}/${pkgname}-${pkgver}.sh" @@ -20,4 +21,5 @@ package() { install -Dm755 "${srcdir}/${pkgname}-${pkgver}.sh" "${pkgdir}/usr/bin/kewt" install -d "${pkgdir}/usr/share/zsh/site-functions" "${pkgdir}/usr/bin/kewt" --dump-zsh-completions > "${pkgdir}/usr/share/zsh/site-functions/_kewt" + install -Dm644 "${srcdir}/${pkgname}-${pkgver}.bash" "${pkgdir}/usr/share/bash-completion/completions/kewt" } diff --git a/packaging/bash/kewt.bash b/packaging/bash/kewt.bash new file mode 100644 index 0000000..a8c87bf --- /dev/null +++ b/packaging/bash/kewt.bash @@ -0,0 +1,37 @@ +_kewt() { + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + opts="--help --new --init --clean --no-clean --update --post --generate-template --version --from --to --watch -w --serve -s --draft --dry-run" + + case "$prev" in + --from|--to) + COMPREPLY=$(compgen -d -- "$cur") + return 0 + ;; + --serve|-s) + COMPREPLY=() + return 0 + ;; + --new|--init|--update) + COMPREPLY=$(compgen -d -- "$cur") + return 0 + ;; + --generate-template) + COMPREPLY=$(compgen -f -- "$cur") + return 0 + ;; + esac + + if [[ "$cur" == -* ]]; then + COMPREPLY=$(compgen -W "$opts" -- "$cur") + return 0 + fi + + COMPREPLY=$(compgen -d -- "$cur") + return 0 +} + +complete -F _kewt kewt diff --git a/packaging/fedora/kewt.spec.template b/packaging/fedora/kewt.spec.template new file mode 100644 index 0000000..9ce87e2 --- /dev/null +++ b/packaging/fedora/kewt.spec.template @@ -0,0 +1,41 @@ +Name: kewt +Version: VERSION_PLACEHOLDER +Release: 1%{?dist} +Summary: A minimalist, 100% POSIX, static site generator inspired by werc + +License: ISC +URL: https://kewt.krzak.org +Source0: https://git.krzak.org/N0VA/kewt/archive/v%{version}.tar.gz + +BuildArch: noarch +BuildRequires: make +Requires: sh +Requires: findutils +Requires: grep +Requires: sed +Requires: gawk +Recommends: python3 +Recommends: bash-completion + +%description +A minimalist, 100% POSIX, static site generator inspired by werc and kew + +%prep +%autosetup + +%build +%make_build + +%install +%make_install PREFIX=%{_prefix} BINDIR=%{_bindir} ZSHCOMPDIR=%{_datadir}/zsh/site-functions BASHCOMPDIR=%{_datadir}/bash-completion/completions + +%files +%license LICENSE +%doc README.md +%{_bindir}/kewt +%{_datadir}/zsh/site-functions/_kewt +%{_datadir}/bash-completion/completions/kewt + +%changelog +* Mon May 20 2024 n0va - VERSION_PLACEHOLDER-1 +- Initial package for Fedora diff --git a/packaging/homebrew/kewt.rb.template b/packaging/homebrew/kewt.rb.template index 1ef7f88..77da40a 100644 --- a/packaging/homebrew/kewt.rb.template +++ b/packaging/homebrew/kewt.rb.template @@ -9,7 +9,7 @@ class Kewt < Formula def install bin.install "kewt" chmod 0755, bin/"kewt" - generate_completions_from_executable(bin/"kewt", "--dump-zsh-completions", shells: [:zsh]) + generate_completions_from_executable(bin/"kewt", "--dump-zsh-completions", shells: [:zsh, :bash]) end test do diff --git a/packaging/zsh/_kewt b/packaging/zsh/_kewt index 4edf5d2..b2d9d8b 100644 --- a/packaging/zsh/_kewt +++ b/packaging/zsh/_kewt @@ -17,6 +17,8 @@ _kewt() { '--to[Output directory]:directory:_directories' '(-w --watch)'{-w,--watch}'[Watch for file changes and rebuild automatically]' '(-s --serve)'{-s,--serve}'[Start a local HTTP server after building]::port:' + '(-d --draft)'{-d,--draft}'[Include draft pages in the build]' + '(-)--dry-run[Show what would be built without writing any files]' ) _arguments -S -C $args '*: :_directories' diff --git a/site/docs/installation.md b/site/docs/installation.md index b419092..798bd3f 100644 --- a/site/docs/installation.md +++ b/site/docs/installation.md @@ -38,6 +38,14 @@ sudo make install brew tap n0va-bot/tap brew install kewt ``` + +### Fedora + +```sh +sudo dnf copr enable n0va-bot/kewt +sudo dnf install kewt +``` + ### bpkg ```sh diff --git a/tests/test_builder.sh b/tests/test_builder.sh new file mode 100644 index 0000000..8590777 --- /dev/null +++ b/tests/test_builder.sh @@ -0,0 +1,185 @@ +test_needs_rebuild_no_output() { + . "$project_dir/lib/config.sh" + . "$project_dir/lib/runtime.sh" + . "$project_dir/lib/builder.sh" + + tmpdir="${TMPDIR:-/tmp}/kewt_test.$$" + mkdir -p "$tmpdir" + echo "test" > "$tmpdir/src.md" + + needs_rebuild "$tmpdir/src.md" "$tmpdir/out.html" + result=$? + assert_eq "0" "$result" "rebuild when output missing" + + rm -rf "$tmpdir" +} + +test_needs_rebuild_output_newer() { + . "$project_dir/lib/config.sh" + . "$project_dir/lib/runtime.sh" + . "$project_dir/lib/builder.sh" + + tmpdir="${TMPDIR:-/tmp}/kewt_test.$$" + mkdir -p "$tmpdir" + echo "test" > "$tmpdir/src.md" + sleep 1 + echo "test" > "$tmpdir/out.html" + + needs_rebuild "$tmpdir/src.md" "$tmpdir/out.html" + result=$? + assert_eq "1" "$result" "no rebuild when output newer" + + rm -rf "$tmpdir" +} + +test_needs_rebuild_source_newer() { + . "$project_dir/lib/config.sh" + . "$project_dir/lib/runtime.sh" + . "$project_dir/lib/builder.sh" + + tmpdir="${TMPDIR:-/tmp}/kewt_test.$$" + mkdir -p "$tmpdir" + echo "old" > "$tmpdir/out.html" + sleep 1 + echo "new" > "$tmpdir/src.md" + + needs_rebuild "$tmpdir/src.md" "$tmpdir/out.html" + result=$? + assert_eq "0" "$result" "rebuild when source newer" + + rm -rf "$tmpdir" +} + +test_escape_html_text() { + . "$project_dir/lib/generator.sh" + + result=$(escape_html_text "