commit 2daced25baec9fe9c60548dd4437db6ab9d84dec
parent 6679c317a86c1bfa293499892be11495ace8aca9
Author: mtmn <miro@haravara.org>
Date: Mon, 6 Jul 2026 10:37:10 +0200
void: fix otterb
Diffstat:
2 files changed, 216 insertions(+), 212 deletions(-)
diff --git a/hosts/void/overlays/bin/otterb b/hosts/void/overlays/bin/otterb
@@ -0,0 +1,216 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require "fileutils"
+require "open3"
+require "etc"
+
+class Builder
+ REPO = "https://repo-default.voidlinux.org/current"
+ DEPS = %w[
+ cmake
+ make
+ gcc
+ qt5-devel
+ qt5-svg-devel
+ qt5-multimedia-devel
+ qt5-declarative-devel
+ qt5-webengine
+ qt5-webengine-devel
+ qt5-webkit-devel
+ qt5-webchannel-devel
+ qt5-location-devel
+ hunspell-devel
+ gstreamer1-devel
+ libxml2-devel
+ qt5-tools
+ ]
+ .freeze
+
+ def initialize(argv)
+ @outdir = nil
+ @chroot = "/var/chroot/otter-build"
+ @keep = false
+ @quiet = false
+ parse(argv)
+ validate
+ end
+
+ def run
+ bootstrap
+ mount_vfs
+ prep_chroot
+ install_deps
+ build
+ extract
+ ensure
+ unmount_vfs
+ remove_chroot unless @keep
+ msg("done.")
+ end
+
+ private
+
+ def parse(argv)
+ i = 0
+ while i < argv.length
+ case argv[i]
+ when "-o"
+ @outdir = argv[i += 1]
+ when "-c"
+ @chroot = argv[i += 1]
+ when "-k"
+ @keep = true
+ when "-q"
+ @quiet = true
+ when "-h", "--help"
+ usage(code: 0)
+ else
+ usage
+ end
+
+ i += 1
+ end
+ end
+
+ def usage_lines
+ [
+ "Usage: #{File.basename($0)} [-o DIR] [-c DIR] [-k] [-q]",
+ " -o DIR output directory (default: invoking user home)",
+ " -c DIR chroot directory (default: /var/chroot/otter-build)",
+ " -k keep chroot after build",
+ " -q quiet"
+ ]
+ end
+
+ def usage(code: 1)
+ usage_lines.each { |l| puts(l) }
+ exit(code)
+ end
+
+ def validate
+ unless Process.uid.zero?
+ usage_lines.each { |l| puts(l) }
+ die("must run as root")
+ end
+
+ @src = Dir.pwd
+ die("no CMakeLists.txt in #{@src}") unless File.file?(File.join(@src, "CMakeLists.txt"))
+
+ inv = ENV["SUDO_USER"] || ENV["DOAS_USER"]
+ if inv
+ @pw = Etc.getpwnam(inv) rescue nil
+ die("cannot resolve user #{inv}") unless @pw
+ @outdir ||= @pw.dir
+ else
+ @outdir ||= File.expand_path("~")
+ end
+ end
+
+ def msg(s) = puts(s) unless @quiet
+
+ def die(s)
+ $stderr.puts("#{File.basename($0)}: #{s}")
+ exit(1)
+ end
+
+ def run_cmd(cmd, fatal: true)
+ msg(cmd)
+ _o, e, st = Open3.capture3(cmd)
+ die("#{cmd}: #{e.strip}") if !st.success? && fatal
+ st.success?
+ end
+
+ def chroot_cmd(script)
+ msg("chroot #{@chroot} /bin/bash -c '#{script}'")
+ die("chroot command failed") unless system("chroot #{@chroot} /bin/bash -c '#{script}'")
+ end
+
+ def bootstrap
+ FileUtils.mkdir_p(@chroot)
+ return if File.executable?(File.join(@chroot, "bin/bash"))
+
+ msg("bootstrapping chroot...")
+ kdir = File.join(@chroot, "var/db/xbps/keys")
+ FileUtils.mkdir_p(kdir)
+ Dir.glob("/var/db/xbps/keys/*").each { |f| FileUtils.cp(f, kdir) }
+
+ run_cmd("xbps-install -Syu -R #{REPO} -r #{@chroot} base-voidstrap", fatal: false)
+ die("bootstrap failed") unless File.executable?(File.join(@chroot, "bin/bash"))
+ msg("bootstrap ok")
+ end
+
+ def mount_vfs
+ mounts = {
+ File.join(@chroot, "proc") => ["-t", "proc", "proc"],
+ File.join(@chroot, "sys") => ["-t", "sysfs", "sys"],
+ File.join(@chroot, "dev") => ["--bind", "/dev"]
+ }
+ mounts.each do |dst, opts|
+ FileUtils.mkdir_p(dst)
+ next if system("mountpoint -q #{dst} 2>/dev/null")
+ system("mount #{opts.join(" ")} #{dst}")
+ end
+ end
+
+ def unmount_vfs
+ %w[dev sys proc].each { |n| system("umount #{File.join(@chroot, n)} 2>/dev/null") }
+ end
+
+ def prep_chroot
+ FileUtils.cp("/etc/resolv.conf", File.join(@chroot, "etc/resolv.conf"))
+ kdir = File.join(@chroot, "var/db/xbps/keys")
+ FileUtils.mkdir_p(kdir)
+ Dir.glob("/var/db/xbps/keys/*").each { |f| FileUtils.cp(f, kdir) }
+ end
+
+ def install_deps
+ chroot_cmd("xbps-install -Syu")
+ chroot_cmd("xbps-install -S #{DEPS.join(" ")}")
+ end
+
+ def build
+ dst = File.join(@chroot, "src/otter-browser")
+ FileUtils.rm_rf(dst)
+ FileUtils.mkdir_p(File.dirname(dst))
+ system("cp -a #{@src} #{dst}") || die("copy failed")
+
+ cm = File.join(dst, "CMakeLists.txt")
+ txt = File.read(cm)
+ unless txt.include?("FATAL_ON_MISSING_REQUIRED_PACKAGES")
+ die("CMakeLists.txt: FATAL_ON_MISSING_REQUIRED_PACKAGES not found")
+ end
+
+ txt.gsub!("FATAL_ON_MISSING_REQUIRED_PACKAGES", "")
+ File.write(cm, txt)
+
+ script = "set -e; cd /src/otter-browser; rm -rf build; mkdir build; cd build; cmake -DENABLE_QT5=ON ../; make -j$(nproc)"
+ chroot_cmd(script)
+ end
+
+ def extract
+ bin = File.join(@chroot, "src/otter-browser/build/otter-browser")
+ die("binary not found") unless File.file?(bin)
+
+ out = File.join(@outdir, "otter-browser")
+ system("cp #{bin} #{out}") || die("copy binary failed")
+ FileUtils.chmod("+x", out)
+
+ if @pw
+ begin
+ File.chown(@pw.uid, @pw.gid, out)
+ rescue => e
+ msg("chown failed: #{e}")
+ end
+ end
+
+ msg("binary: #{out}")
+ end
+
+ def remove_chroot
+ msg("removing #{@chroot}...")
+ FileUtils.rm_rf(@chroot)
+ end
+end
+
+Builder.new(ARGV).run
diff --git a/hosts/void/overlays/bin/xbps-otterb-build b/hosts/void/overlays/bin/xbps-otterb-build
@@ -1,212 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require "fileutils"
-require "open3"
-require "etc"
-
-class Builder
- REPO = "https://repo-default.voidlinux.org/current"
- DEPS = %w[
- cmake
- make
- gcc
- qt5-devel
- qt5-svg-devel
- qt5-multimedia-devel
- qt5-declarative-devel
- qt5-webkit-devel
- hunspell-devel
- gstreamer1-devel
- libxml2-devel
- qt5-tools
- ]
- .freeze
-
- def initialize(argv)
- @outdir = nil
- @chroot = "/var/chroot/otter-build"
- @keep = false
- @quiet = false
- parse(argv)
- validate
- end
-
- def run
- bootstrap
- mount_vfs
- prep_chroot
- install_deps
- build
- extract
- ensure
- unmount_vfs
- remove_chroot unless @keep
- msg("done.")
- end
-
- private
-
- def parse(argv)
- i = 0
- while i < argv.length
- case argv[i]
- when "-o"
- @outdir = argv[i += 1]
- when "-c"
- @chroot = argv[i += 1]
- when "-k"
- @keep = true
- when "-q"
- @quiet = true
- when "-h", "--help"
- usage(code: 0)
- else
- usage
- end
-
- i += 1
- end
- end
-
- def usage_lines
- [
- "Usage: #{File.basename($0)} [-o DIR] [-c DIR] [-k] [-q]",
- " -o DIR output directory (default: invoking user home)",
- " -c DIR chroot directory (default: /var/chroot/otter-build)",
- " -k keep chroot after build",
- " -q quiet"
- ]
- end
-
- def usage(code: 1)
- usage_lines.each { |l| puts(l) }
- exit(code)
- end
-
- def validate
- unless Process.uid.zero?
- usage_lines.each { |l| puts(l) }
- die("must run as root")
- end
-
- @src = Dir.pwd
- die("no CMakeLists.txt in #{@src}") unless File.file?(File.join(@src, "CMakeLists.txt"))
-
- inv = ENV["SUDO_USER"] || ENV["DOAS_USER"]
- if inv
- @pw = Etc.getpwnam(inv) rescue nil
- die("cannot resolve user #{inv}") unless @pw
- @outdir ||= @pw.dir
- else
- @outdir ||= File.expand_path("~")
- end
- end
-
- def msg(s) = puts(s) unless @quiet
-
- def die(s)
- $stderr.puts("#{File.basename($0)}: #{s}")
- exit(1)
- end
-
- def run_cmd(cmd, fatal: true)
- msg(cmd)
- _o, e, st = Open3.capture3(cmd)
- die("#{cmd}: #{e.strip}") if !st.success? && fatal
- st.success?
- end
-
- def chroot_cmd(script)
- msg("chroot #{@chroot} /bin/bash -c '#{script}'")
- die("chroot command failed") unless system("chroot #{@chroot} /bin/bash -c '#{script}'")
- end
-
- def bootstrap
- FileUtils.mkdir_p(@chroot)
- return if File.executable?(File.join(@chroot, "bin/bash"))
-
- msg("bootstrapping chroot...")
- kdir = File.join(@chroot, "var/db/xbps/keys")
- FileUtils.mkdir_p(kdir)
- Dir.glob("/var/db/xbps/keys/*").each { |f| FileUtils.cp(f, kdir) }
-
- run_cmd("xbps-install -Syu -R #{REPO} -r #{@chroot} base-voidstrap", fatal: false)
- die("bootstrap failed") unless File.executable?(File.join(@chroot, "bin/bash"))
- msg("bootstrap ok")
- end
-
- def mount_vfs
- mounts = {
- File.join(@chroot, "proc") => ["-t", "proc", "proc"],
- File.join(@chroot, "sys") => ["-t", "sysfs", "sys"],
- File.join(@chroot, "dev") => ["--bind", "/dev"]
- }
- mounts.each do |dst, opts|
- FileUtils.mkdir_p(dst)
- next if system("mountpoint -q #{dst} 2>/dev/null")
- system("mount #{opts.join(" ")} #{dst}")
- end
- end
-
- def unmount_vfs
- %w[dev sys proc].each { |n| system("umount #{File.join(@chroot, n)} 2>/dev/null") }
- end
-
- def prep_chroot
- FileUtils.cp("/etc/resolv.conf", File.join(@chroot, "etc/resolv.conf"))
- kdir = File.join(@chroot, "var/db/xbps/keys")
- FileUtils.mkdir_p(kdir)
- Dir.glob("/var/db/xbps/keys/*").each { |f| FileUtils.cp(f, kdir) }
- end
-
- def install_deps
- chroot_cmd("xbps-install -Syu")
- chroot_cmd("xbps-install -S #{DEPS.join(" ")}")
- end
-
- def build
- dst = File.join(@chroot, "src/otter-browser")
- FileUtils.rm_rf(dst)
- FileUtils.mkdir_p(File.dirname(dst))
- system("cp -a #{@src} #{dst}") || die("copy failed")
-
- cm = File.join(dst, "CMakeLists.txt")
- txt = File.read(cm)
- unless txt.include?("FATAL_ON_MISSING_REQUIRED_PACKAGES")
- die("CMakeLists.txt: FATAL_ON_MISSING_REQUIRED_PACKAGES not found")
- end
-
- txt.gsub!("FATAL_ON_MISSING_REQUIRED_PACKAGES", "")
- File.write(cm, txt)
-
- script = "set -e; cd /src/otter-browser; rm -rf build; mkdir build; cd build; cmake -DENABLE_QT5=ON ../; make -j$(nproc)"
- chroot_cmd(script)
- end
-
- def extract
- bin = File.join(@chroot, "src/otter-browser/build/otter-browser")
- die("binary not found") unless File.file?(bin)
-
- out = File.join(@outdir, "otter-browser")
- system("cp #{bin} #{out}") || die("copy binary failed")
- FileUtils.chmod("+x", out)
-
- if @pw
- begin
- File.chown(@pw.uid, @pw.gid, out)
- rescue => e
- msg("chown failed: #{e}")
- end
- end
-
- msg("binary: #{out}")
- end
-
- def remove_chroot
- msg("removing #{@chroot}...")
- FileUtils.rm_rf(@chroot)
- end
-end
-
-Builder.new(ARGV).run