lib/relaton/db_cache.rb in relaton-1.6.0 vs lib/relaton/db_cache.rb in relaton-1.7.pre7
- old
+ new
@@ -1,6 +1,7 @@
require "fileutils"
+require "timeout"
module Relaton
class DbCache
# @return [String]
attr_reader :dir
@@ -12,10 +13,30 @@
FileUtils::mkdir_p @dir
# file_version = "#{@dir}/version"
# set_version # unless File.exist? file_version
end
+ # Move caches to anothe dir
+ # @param new_dir [String, nil]
+ # @return [String, nil]
+ def mv(new_dir)
+ return unless new_dir && @ext == "xml"
+
+ if File.exist? new_dir
+ warn "[relaton] WARNING: target directory exists \"#{new_dir}\""
+ return
+ end
+
+ FileUtils.mv dir, new_dir
+ @dir = new_dir
+ end
+
+ # Clear database
+ def clear
+ FileUtils.rm_rf Dir.glob "#{dir}/*" if @ext == "xml" # unless it's static DB
+ end
+
# Save item
# @param key [String]
# @param value [String] Bibitem xml serialization
def []=(key, value)
if value.nil?
@@ -24,11 +45,11 @@
end
prefix_dir = "#{@dir}/#{prefix(key)}"
FileUtils::mkdir_p prefix_dir unless Dir.exist? prefix_dir
set_version prefix_dir
- File.write "#{filename(key)}.#{ext(value)}", value, encoding: "utf-8"
+ file_safe_write "#{filename(key)}.#{ext(value)}", value
end
# @param value [String]
# @return [String]
def ext(value)
@@ -63,23 +84,24 @@
# @return [String]
def fetched(key)
value = self[key]
return unless value
- if value =~ /^not_found/
+ if value.match? /^not_found/
value.match(/\d{4}-\d{2}-\d{2}/).to_s
else
doc = Nokogiri::XML value
doc.at("/bibitem/fetched|bibdata/fetched")&.text
end
end
# Returns all items
# @return [Array<String>]
def all
- Dir.glob("#{@dir}/**/*.xml").sort.map do |f|
- File.read(f, encoding: "utf-8")
+ Dir.glob("#{@dir}/**/*.{xml,yml,yaml}").sort.map do |f|
+ content = File.read(f, encoding: "utf-8")
+ block_given? ? yield(f, content) : content
end
end
# Delete item
# @param key [String]
@@ -104,11 +126,11 @@
# @param fdir [String] dir pathe to flover cache
# @return [Relaton::DbCache]
def set_version(fdir)
file_version = "#{fdir}/version"
unless File.exist? file_version
- File.write file_version, grammar_hash(fdir), encoding: "utf-8"
+ file_safe_write file_version, grammar_hash(fdir)
end
self
end
# if cached reference is undated, expire it after 60 days
@@ -157,11 +179,11 @@
# @param key [String]
# @return [String]
def filename(key)
prefcode = key.downcase.match /^(?<prefix>[^\(]+)\((?<code>[^\)]+)/
fn = if prefcode
- "#{prefcode[:prefix]}/#{prefcode[:code].gsub(/[-:\s\/\()]/, '_').squeeze("_")}"
+ "#{prefcode[:prefix]}/#{prefcode[:code].gsub(/[-:\s\/\()]/, '_').squeeze('_')}"
else
key.gsub(/[-:\s]/, "_")
end
"#{@dir}/#{fn.sub(/(,|_$)/, '')}"
end
@@ -187,10 +209,19 @@
# @return [String]
def prefix(key)
key.downcase.match(/^[^\(]+(?=\()/).to_s
end
+ # @param file [String]
+ # @content [String]
+ def file_safe_write(file, content)
+ File.open file, File::RDWR | File::CREAT, encoding: "UTF-8" do |f|
+ Timeout.timeout(10) { f.flock File::LOCK_EX }
+ f.write content
+ end
+ end
+
class << self
private
def global_bibliocache_name
"#{Dir.home}/.relaton/cache"
@@ -207,10 +238,10 @@
# Initialse and return relaton instance, with local and global cache names
# local_cache: local cache name; none created if nil; "relaton" created
# if empty global_cache: boolean to create global_cache
# flush_caches: flush caches
- def init_bib_caches(opts)
+ def init_bib_caches(opts) # rubocop:disable Metrics/CyclomaticComplexity
globalname = global_bibliocache_name if opts[:global_cache]
localname = local_bibliocache_name(opts[:local_cache])
localname = "relaton" if localname&.empty?
if opts[:flush_caches]
FileUtils.rm_rf globalname unless globalname.nil?