summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilip McGrath <philip@philipmcgrath.com>2022-07-25 08:16:33 -0400
committerLudovic Courtès <ludo@gnu.org>2022-08-04 12:05:52 +0200
commit14a50b62d4e8765b794861226d79f6872d6c434c (patch)
treeef1d26387edd7e4e1f699021b4e0892e6e66f080
parentbc2de56572872eefdc2992b34cce69c77deb485a (diff)
downloadguix-14a50b62d4e8765b794861226d79f6872d6c434c.tar.gz
gnu: ruby-anystyle: Initialize dictionary files.
For the GDBM and Marshal dictionary adapters to be useful with their
default settings, we must initialize their data files during the package
build: upstream would initialize them lazily, but that doesn't work with
an immutable installation directory (at least, not without more complex
patches). Otherwise, we would always end up rebuilding the dictionary at
startup, which is “slow” and “not recommended”.

* gnu/packages/patches/ruby-anystyle-fix-dictionary-populate.patch: New
patch.
* gnu/local.mk (dist_patch_DATA): Add it.
* gnu/packages/ruby.scm (ruby-anystyle)[patches]: Use it.
[arguments]<#:phases>: Add 'populate-dictionaries' phase.

Signed-off-by: Ludovic Courtès <ludo@gnu.org>
-rw-r--r--gnu/local.mk1
-rw-r--r--gnu/packages/patches/ruby-anystyle-fix-dictionary-populate.patch94
-rw-r--r--gnu/packages/ruby.scm31
3 files changed, 125 insertions, 1 deletions
diff --git a/gnu/local.mk b/gnu/local.mk
index 32ee102943..0e8b7b0447 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1783,6 +1783,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/rocm-opencl-runtime-4.3-noclinfo.patch \
   %D%/packages/patches/rocm-opencl-runtime-4.3-noopencl.patch \
   %D%/packages/patches/ruby-anystyle-data-immutable-install.patch	\
+  %D%/packages/patches/ruby-anystyle-fix-dictionary-populate.patch	\
   %D%/packages/patches/ruby-latex-decode-fix-test.patch		\
   %D%/packages/patches/ruby-mustache-1.1.1-fix-race-condition-tests.patch \
   %D%/packages/patches/ruby-sanitize-system-libxml.patch	\
diff --git a/gnu/packages/patches/ruby-anystyle-fix-dictionary-populate.patch b/gnu/packages/patches/ruby-anystyle-fix-dictionary-populate.patch
new file mode 100644
index 0000000000..b2e0498e8d
--- /dev/null
+++ b/gnu/packages/patches/ruby-anystyle-fix-dictionary-populate.patch
@@ -0,0 +1,94 @@
+From fae622c8b77feebac66a538d76e4211de8bd8eb3 Mon Sep 17 00:00:00 2001
+From: Philip McGrath <philip@philipmcgrath.com>
+Date: Sun, 24 Jul 2022 21:50:44 -0400
+Subject: [PATCH] fix saving `AnyStyle::Dictionary` after `populate!`
+
+Some of these fixes are more generally applicable.
+
+A more robust solution might find data files using
+e.g. `Gem.find_files()`.
+---
+ lib/anystyle/dictionary/gdbm.rb    |  6 ++++++
+ lib/anystyle/dictionary/marshal.rb | 31 ++++++++++++++++++++++++------
+ 2 files changed, 31 insertions(+), 6 deletions(-)
+
+diff --git a/lib/anystyle/dictionary/gdbm.rb b/lib/anystyle/dictionary/gdbm.rb
+index 754903c..c814df2 100644
+--- a/lib/anystyle/dictionary/gdbm.rb
++++ b/lib/anystyle/dictionary/gdbm.rb
+@@ -1,5 +1,6 @@
+ module AnyStyle
+   require 'gdbm'
++  require 'fileutils'
+ 
+   class Dictionary
+     class GDBM < Dictionary
+@@ -17,8 +18,13 @@ module AnyStyle
+ 
+       def open
+         close
++        FileUtils.mkdir_p(File.dirname(options[:path]))
+         @db = ::GDBM.new(*options.values_at(:path, :mode, :flags))
+         self
++      rescue Errno::EACCES
++        # GDBM.new tries this if :flags is nil, but not necessarily otherwise
++        @db = ::GDBM.new(options[:path],options[:mode],::GDBM::READER)
++        self
+       ensure
+         populate! if empty?
+       end
+diff --git a/lib/anystyle/dictionary/marshal.rb b/lib/anystyle/dictionary/marshal.rb
+index 761ca36..b9529d0 100644
+--- a/lib/anystyle/dictionary/marshal.rb
++++ b/lib/anystyle/dictionary/marshal.rb
+@@ -1,4 +1,6 @@
+ module AnyStyle
++  require 'fileutils'
++  require 'tempfile'
+   class Dictionary
+     class Marshal < Dictionary
+       @defaults = {
+@@ -10,17 +12,34 @@ module AnyStyle
+       end
+ 
+       def open
+-        if File.exists?(options[:path])
+-          @db = ::Marshal.load(File.open(options[:path]))
+-        else
+-          @db = {}
++        File.open(options[:path]) do |file|
++          @db = ::Marshal.load(file)
+         end
+         self
++      rescue Errno::ENOENT
++        @db = {}
++        self
+       ensure
+         if empty?
+           populate!
+-          if File.writable?(options[:path])
+-            ::Marshal.dump(db, File.open(options[:path], 'wb'))
++          tmp = nil
++          begin
++            FileUtils.mkdir_p(File.dirname(options[:path]))
++            tmp = Tempfile.create(File.basename(options[:path]),
++                                  File.dirname(options[:path]),
++                                  mode: File::Constants::BINARY)
++            pth = tmp.path()
++            ::Marshal.dump(db, tmp)
++            tmp.close()
++            File.rename(tmp.path, options[:path]) # will overwrite if exists
++            tmp = nil
++          rescue SystemCallError => e
++            warn(e.message)
++          ensure
++            if tmp then
++              tmp.close()
++              tmp.unlink()
++            end
+           end
+         end
+       end
+-- 
+2.32.0
+
diff --git a/gnu/packages/ruby.scm b/gnu/packages/ruby.scm
index 6e0b2dd14c..0b558de6db 100644
--- a/gnu/packages/ruby.scm
+++ b/gnu/packages/ruby.scm
@@ -13516,6 +13516,9 @@ the power of the built-in @code{OptionParser}.")
                      (substitute* "spec/anystyle/parser_spec.rb"
                        (("language: 'en'," orig)
                         (string-append "# " orig " # no lanugage_detector")))))
+                (patches
+                 (search-patches
+                  "ruby-anystyle-fix-dictionary-populate.patch"))
                 (file-name (git-file-name name version))))
       (build-system ruby-build-system)
       (propagated-inputs
@@ -13545,7 +13548,33 @@ the power of the built-in @code{OptionParser}.")
               (lambda args
                 (substitute* "anystyle.gemspec"
                   (("`git ls-files spec`")
-                   "`find spec -type f | sort`")))))))
+                   "`find spec -type f | sort`"))))
+            (add-after 'wrap 'populate-dictionaries
+              (lambda args
+                ;; We must initiallize these files here, or they will never be
+                ;; usable with the default settings. A more flexible approach
+                ;; might use something like `Gem.find_files()` or
+                ;; XDG_DATA_DIRS.
+                (with-output-to-file "initialize-dictionaries.rb"
+                  (lambda ()
+                    (display "
+require 'anystyle/dictionary' # must come before 'anystyle/data'
+require 'anystyle/data'
+[:marshal, :gdbm].each do |adapter|
+  AnyStyle::Dictionary.create({adapter: adapter}).open().close()
+end
+")))
+                (let* ((old-gems (getenv "GEM_PATH"))
+                       (new-gems (string-append #$output
+                                                "/lib/ruby/vendor_ruby:"
+                                                old-gems)))
+                  (dynamic-wind
+                    (lambda ()
+                      (setenv "GEM_PATH" new-gems))
+                    (lambda ()
+                      (invoke "ruby" "initialize-dictionaries.rb"))
+                    (lambda ()
+                      (setenv "GEM_PATH" old-gems)))))))))
       (home-page "https://anystyle.io")
       (synopsis "Fast and smart citation reference parsing (Ruby library)")
       (description