Module: Abqari
- Defined in:
- lib/abqari/version.rb,
lib/abqari.rb,
lib/abqari/cli.rb,
lib/abqari/log.rb,
lib/abqari/feed.rb,
lib/abqari/page.rb,
lib/abqari/site.rb,
lib/abqari/audit.rb,
lib/abqari/folio.rb,
lib/abqari/hooks.rb,
lib/abqari/robots.rb,
lib/abqari/search.rb,
lib/abqari/server.rb,
lib/abqari/cli/new.rb,
lib/abqari/helpers.rb,
lib/abqari/sitemap.rb,
lib/abqari/indieweb.rb,
lib/abqari/llms_txt.rb,
lib/abqari/manifest.rb,
lib/abqari/minifier.rb,
lib/abqari/renderer.rb,
lib/abqari/audit/seo.rb,
lib/abqari/cli/theme.rb,
lib/abqari/http_safe.rb,
lib/abqari/importers.rb,
lib/abqari/page/path.rb,
lib/abqari/paginator.rb,
lib/abqari/path_safe.rb,
lib/abqari/redirects.rb,
lib/abqari/audit/a11y.rb,
lib/abqari/audit/rule.rb,
lib/abqari/audit/links.rb,
lib/abqari/page/bundle.rb,
lib/abqari/page/parser.rb,
lib/abqari/site_config.rb,
lib/abqari/site_loader.rb,
lib/abqari/syndication.rb,
lib/abqari/theme_fonts.rb,
lib/abqari/headers_file.rb,
lib/abqari/security_txt.rb,
lib/abqari/audit/content.rb,
lib/abqari/audit/privacy.rb,
lib/abqari/bundle_assets.rb,
lib/abqari/erbi_template.rb,
lib/abqari/font_pipeline.rb,
lib/abqari/importers/cli.rb,
lib/abqari/taxonomy_page.rb,
lib/abqari/asset_pipeline.rb,
lib/abqari/image_pipeline.rb,
lib/abqari/importers/base.rb,
lib/abqari/render_context.rb,
lib/abqari/visualizations.rb,
lib/abqari/artifact_writer.rb,
lib/abqari/importers/ghost.rb,
lib/abqari/paginated_shard.rb,
lib/abqari/publisher_pages.rb,
lib/abqari/theme_bootstrap.rb,
lib/abqari/importers/jekyll.rb,
lib/abqari/page/incremental.rb,
lib/abqari/plausible_script.rb,
lib/abqari/audit/performance.rb,
lib/abqari/audit/dependencies.rb,
lib/abqari/importers/substack.rb,
lib/abqari/og_image_generator.rb,
lib/abqari/related_index_page.rb,
lib/abqari/syntax_highlighter.rb,
lib/abqari/publication_normaliser.rb,
lib/abqari/speculation_rules_guard.rb,
lib/abqari/importers/support/report.rb,
lib/abqari/render_context/cover_helpers.rb,
lib/abqari/render_context/picture_helpers.rb,
lib/abqari/importers/support/slug_normalizer.rb,
lib/abqari/importers/support/html_to_markdown.rb,
lib/abqari/importers/support/image_downloader.rb,
lib/abqari/render_context/publication_helpers.rb
Overview
The version constant lives alone, in a file with NO requires, because
abqari.gemspec loads it to read Abqari::VERSION.
The gemspec used to require_relative 'lib/abqari' instead, which
pulls in the whole engine — and with it erubi, commonmarker, rouge and
webrick. That works locally (those gems are already installed) but
breaks any git or path source: Bundler evaluates the gemspec BEFORE
installing dependencies, so the requires blow up with
"cannot load such file -- erubi". Published gems are immune (their
spec is pre-serialized into the .gem), which is exactly why the bug
only surfaced on a clean CI/deploy builder.
Keep this file dependency-free.
Defined Under Namespace
Modules: CLI, Helpers, Hooks, HttpSafe, Importers, Indieweb, Log, Minifier, PathSafe, PlausibleScript, PluginLoader, PublicationNormaliser, SiteConfig, SpeculationRulesGuard, Syndication, ThemeBootstrap, ThemeFonts Classes: ArtifactWriter, AssetPipeline, Audit, BundleAssets, ErbiTemplate, Feed, Folio, FontPipeline, HeadersFile, ImagePipeline, LlmsTxt, Manifest, OgImageGenerator, Page, PaginatedShard, Paginator, PublisherIndexPage, PublisherPages, PublisherShowPage, Redirects, RelatedIndexPage, RenderContext, Renderer, Robots, Search, SecurityTxt, Server, Site, SiteLoader, Sitemap, SyntaxHighlighter, TaxonomyPage, UserError, Visualizations, VizPage
Constant Summary collapse
- ROOT =
File.('..', __dir__)
- YAML_PERMITTED_CLASSES =
Classes the engine accepts from any YAML input — site config, data files, frontmatter, Folio cache, audit whitelists. Date + Time so naked dates like
date: 2026-06-15and ISO timestamps round-trip. Anything else (Symbol, ranges, arbitrary classes) raises Psych::DisallowedClass before any deserialised object touches the engine. Keep this set minimal — adding a class here is the security-sensitive equivalent of widening a sandbox. [Date, Time].freeze
- BUILD_OK_SENTINEL =
Marker file written by
Site#buildat the end of a successful build. Deployers (bin/deploy, CI pipelines that rsync_site/) refuse to ship without it; the test harness uses it as the fixture-intact sentinel. Single source of truth so the three readers stay in lockstep. '.abqari-build-ok'- FRONTMATTER_RE =
Jekyll-style YAML frontmatter — opening
---, body, closing---, then everything after.Match groups:
[1] = the YAML body between the `---` markers [2] = everything after the closing `---\n` (page body / layout markup / whatever follows)The YAML group is OPTIONAL (
(?:.*?\n)?) so an EMPTY frontmatter block (---\n---\n) still matches — group [1] is "" (→{}after safe_load), not treated as "no frontmatter" (which rendered the two---lines as visible body text).Used in three places — Page (content files), RenderContext (layout files chaining via
layout:), and Renderer (parent-layout lookup for the dep-mtime walker). Centralised here so the three callers stay in lockstep; previously the regex was duplicated and one copy had drifted (no body capture group), which made consolidation easy to put off. /\A---\s*\n((?:.*?\n)?)---\s*\n(.*)/m.freeze
- VERSION =
'1.1.0'
Class Method Summary collapse
-
.atomic_write(path, content) ⇒ Object
Atomic file write: write to a sibling tempfile, fsync, then rename into place.
- .debug? ⇒ Boolean
-
.run_cli ⇒ Object
Wrap a CLI entry point so failures are presented rather than dumped.
Class Method Details
.atomic_write(path, content) ⇒ Object
Atomic file write: write to a sibling tempfile, fsync, then rename into place. POSIX guarantees the rename is atomic on the same filesystem, so a reader either sees the previous full contents or the new full contents — never a half-written buffer.
Used for state files we re-read on subsequent builds: the POSSE sent log, the webmention sender log, the webmention cache, the etag pointer. Without atomicity, a SIGINT or runner timeout mid-write leaves a truncated YAML / JSON file and the next build either crashes on parse or — worse for the POSSE case — treats every prior send as un-sent and re-posts everything to Mastodon + Bluesky.
77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/abqari.rb', line 77 def self.atomic_write(path, content) dir = File.dirname(path) base = File.basename(path) tmp = File.join(dir, ".#{base}.#{Process.pid}.tmp") File.open(tmp, 'w') do |f| f.write(content) f.flush f.fsync rescue nil end File.rename(tmp, path) ensure File.unlink(tmp) if tmp && File.exist?(tmp) rescue nil end |
.debug? ⇒ Boolean
45 46 47 |
# File 'lib/abqari.rb', line 45 def self.debug? %w[1 true yes].include?(ENV['ABQARI_DEBUG'].to_s.strip.downcase) end |
.run_cli ⇒ Object
Wrap a CLI entry point so failures are presented rather than dumped.
A malformed config/site.yml used to greet the user with ten frames
of Psych internals; the useful part (file, line, column) was there,
just buried at the top. Same for a typo'd flag. Set ABQARI_DEBUG=1
to get the backtrace back when a UserError is hiding something real.
Interrupt is handled here too: Ctrl-C during a build printed a stack trace through the render pool, which reads like a crash rather than "you pressed Ctrl-C". Exit 130 is the shell convention for SIGINT.
33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/abqari.rb', line 33 def self.run_cli yield rescue UserError => e warn e. warn '' if debug? warn e.backtrace.join("\n") if debug? exit 1 rescue Interrupt warn "\nInterrupted." exit 130 end |