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?