Class: Relaton::Index::FileIO
- Inherits:
-
Object
- Object
- Relaton::Index::FileIO
- Defined in:
- lib/relaton/index/file_io.rb
Overview
File IO class is used to read and write index files. In searh mode url is used to fetch index from external repository and save it to storage. In index mode url should be nil.
Constant Summary collapse
- @@file_locks =
{}
- @@file_locks_mutex =
Mutex.new
Instance Attribute Summary collapse
-
#pubid_class ⇒ Object
readonly
Returns the value of attribute pubid_class.
-
#sorted ⇒ Object
Returns the value of attribute sorted.
-
#url ⇒ Object
readonly
Returns the value of attribute url.
Instance Method Summary collapse
- #check_basic_format(index) ⇒ Object
-
#check_file ⇒ Array<Hash>?
Check if index file exists and is not older than 24 hours.
-
#check_format(index) ⇒ Boolean
Check if index has correct format.
- #check_id_format(index) ⇒ Object
- #deserialize_pubid(index) ⇒ Object
-
#fetch_and_save ⇒ Array<Hash>
Fetch index from external repository and save it to storage.
- #file ⇒ Object
- #get_id_number(id) ⇒ Object
-
#initialize(dir, url, filename, id_keys, pubid_class = nil) ⇒ FileIO
constructor
Initialize FileIO.
- #load_index(yaml, save = false) ⇒ Object
-
#path_to_local_file ⇒ <Type>
Create path to local file.
- #progname ⇒ Object
-
#read ⇒ Array<Hash>
If url is String, check if index file exists and is not older than 24 hours.
-
#read_file ⇒ Array<Hash>
Read index from storage.
-
#remove ⇒ Array
Remove index file from storage.
-
#save(index) ⇒ void
Save index to storage.
- #sort_structured_index(index) ⇒ Object
- #warn_local_index_error(reason) ⇒ Object
- #warn_remote_index_error(reason) ⇒ Object
Constructor Details
#initialize(dir, url, filename, id_keys, pubid_class = nil) ⇒ FileIO
Initialize FileIO
26 27 28 29 30 31 32 33 |
# File 'lib/relaton/index/file_io.rb', line 26 def initialize(dir, url, filename, id_keys, pubid_class = nil) @dir = dir @url = url @filename = filename @id_keys = id_keys || [] @pubid_class = pubid_class @sorted = false end |
Instance Attribute Details
#pubid_class ⇒ Object (readonly)
Returns the value of attribute pubid_class.
9 10 11 |
# File 'lib/relaton/index/file_io.rb', line 9 def pubid_class @pubid_class end |
#sorted ⇒ Object
Returns the value of attribute sorted.
10 11 12 |
# File 'lib/relaton/index/file_io.rb', line 10 def sorted @sorted end |
#url ⇒ Object (readonly)
Returns the value of attribute url.
9 10 11 |
# File 'lib/relaton/index/file_io.rb', line 9 def url @url end |
Instance Method Details
#check_basic_format(index) ⇒ Object
91 92 93 94 95 96 |
# File 'lib/relaton/index/file_io.rb', line 91 def check_basic_format(index) return false unless index.is_a? Array keys = %i[file id] index.all? { |item| item.respond_to?(:keys) && item.keys.sort == keys } end |
#check_file ⇒ Array<Hash>?
Check if index file exists and is not older than 24 hours
73 74 75 76 77 78 |
# File 'lib/relaton/index/file_io.rb', line 73 def check_file ctime = Index.config.storage.ctime(file) return unless ctime && ctime > Time.now - 86400 read_file end |
#check_format(index) ⇒ Boolean
Check if index has correct format
87 88 89 |
# File 'lib/relaton/index/file_io.rb', line 87 def check_format(index) check_basic_format(index) && check_id_format(index) end |
#check_id_format(index) ⇒ Object
98 99 100 101 102 103 104 105 |
# File 'lib/relaton/index/file_io.rb', line 98 def check_id_format(index) return true if @id_keys.empty? keys = index.each_with_object(Set.new) do |item, acc| acc.merge item[:id].keys if item[:id].is_a?(Hash) end keys.none? { |k| !@id_keys.include? k } end |
#deserialize_pubid(index) ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/relaton/index/file_io.rb', line 119 def deserialize_pubid(index) return index unless @pubid_class @sorted = true prev_number = nil index.map do |r| id = @pubid_class.create(**(r[:id] || {})) num = get_id_number id @sorted = false if prev_number && prev_number > num prev_number = num { id: id, file: r[:file] } end end |
#fetch_and_save ⇒ Array<Hash>
Fetch index from external repository and save it to storage
170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/relaton/index/file_io.rb', line 170 def fetch_and_save uri = URI.parse(url) body = Net::HTTP.get(uri) yaml = nil Zip::File.open_buffer(body) do |zip| entry = zip.entries.first yaml = entry.get_input_stream.read end Util.info "Downloaded index from `#{url}`", progname load_index(yaml, true) end |
#file ⇒ Object
55 56 57 |
# File 'lib/relaton/index/file_io.rb', line 55 def file @file ||= url ? path_to_local_file : @filename end |
#get_id_number(id) ⇒ Object
210 211 212 |
# File 'lib/relaton/index/file_io.rb', line 210 def get_id_number(id) id.respond_to?(:base) && id.base ? id.base.number.to_s : id.number.to_s end |
#load_index(yaml, save = false) ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/relaton/index/file_io.rb', line 147 def load_index(yaml, save = false) index = YAML.safe_load(yaml, permitted_classes: [Symbol]) save index if save return deserialize_pubid(index) if check_format index if save warn_remote_index_error "Wrong structure of" else warn_local_index_error "Wrong structure of" end rescue Psych::SyntaxError if save warn_remote_index_error "YAML parsing error when reading" else warn_local_index_error "YAML parsing error when reading" end end |
#path_to_local_file ⇒ <Type>
Create path to local file
64 65 66 |
# File 'lib/relaton/index/file_io.rb', line 64 def path_to_local_file File.join(Index.config.storage_dir, ".relaton", @dir, @filename) end |
#progname ⇒ Object
143 144 145 |
# File 'lib/relaton/index/file_io.rb', line 143 def progname @progname ||= "relaton-#{@dir}" end |
#read ⇒ Array<Hash>
If url is String, check if index file exists and is not older than 24
hours. If not, fetch index from external repository and save it to
storage.
If url is true, read index from path to local file. If url is nil, read index from filename.
44 45 46 47 48 49 50 51 52 53 |
# File 'lib/relaton/index/file_io.rb', line 44 def read case url when String with_file_lock do check_file || fetch_and_save end else read_file || [] end end |
#read_file ⇒ Array<Hash>
Read index from storage
112 113 114 115 116 117 |
# File 'lib/relaton/index/file_io.rb', line 112 def read_file yaml = Index.config.storage.read(file) return unless yaml load_index(yaml) || [] end |
#remove ⇒ Array
Remove index file from storage
219 220 221 222 |
# File 'lib/relaton/index/file_io.rb', line 219 def remove Index.config.storage.remove file [] end |
#save(index) ⇒ void
This method returns an undefined value.
Save index to storage
195 196 197 198 199 200 |
# File 'lib/relaton/index/file_io.rb', line 195 def save(index) yaml = sort_structured_index(index).map do |item| item.transform_values { |value| value.is_a?(Pubid::Core::Identifier::Base) ? value.to_h : value } end.to_yaml Index.config.storage.write file, yaml end |
#sort_structured_index(index) ⇒ Object
202 203 204 205 206 207 208 |
# File 'lib/relaton/index/file_io.rb', line 202 def sort_structured_index(index) if @pubid_class && index.first&.dig(:id).is_a?(Pubid::Core::Identifier::Base) index.sort_by { |item| get_id_number item[:id] } else index end end |
#warn_local_index_error(reason) ⇒ Object
133 134 135 136 137 138 139 140 141 |
# File 'lib/relaton/index/file_io.rb', line 133 def warn_local_index_error(reason) Util.info "#{reason} file `#{file}`", progname if url.is_a? String Util.info "Considering `#{file}` file corrupt, re-downloading from `#{url}`", progname else Util.info "Considering `#{file}` file corrupt, removing it.", progname remove end end |
#warn_remote_index_error(reason) ⇒ Object
182 183 184 185 186 |
# File 'lib/relaton/index/file_io.rb', line 182 def warn_remote_index_error(reason) Util.info "#{reason} newly downloaded file `#{file}` at `#{url}`, " \ "the remote index seems to be invalid. Please report this " \ "issue at https://github.com/relaton/relaton-cli.", progname end |