Class: Relaton::Index::FileIO

Inherits:
Object
  • Object
show all
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.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir, url, filename, id_keys, pubid_class = nil) ⇒ FileIO

Initialize FileIO

Parameters:

  • dir (String)

    falvor specific local directory in ~/.relaton to store index

  • url (String, Boolean, nil)

    if String then the URL is used to fetch an index from a Git repository

    and save it to the storage (if not exists, or older than 24 hours)
    

    if true then the index is read from the storage (used to remove index file) if nil then the fiename is used to read and write file (used to create indes in GH actions)

  • pubid (Pubid::Core::Identifier::Base)

    class for deserialization



22
23
24
25
26
27
28
# File 'lib/relaton/index/file_io.rb', line 22

def initialize(dir, url, filename, id_keys, pubid_class = nil)
  @dir = dir
  @url = url
  @filename = filename
  @id_keys = id_keys || []
  @pubid_class = pubid_class
end

Instance Attribute Details

#pubid_classObject (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

#urlObject (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



84
85
86
87
88
89
# File 'lib/relaton/index/file_io.rb', line 84

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_fileArray<Hash>?

Check if index file exists and is not older than 24 hours

Returns:

  • (Array<Hash>, nil)

    index or nil



66
67
68
69
70
71
# File 'lib/relaton/index/file_io.rb', line 66

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

Parameters:

  • index (Array<Hash>)

    index to check

Returns:

  • (Boolean)

    <description>



80
81
82
# File 'lib/relaton/index/file_io.rb', line 80

def check_format(index)
  check_basic_format(index) && check_id_format(index)
end

#check_id_format(index) ⇒ Object



91
92
93
94
95
96
97
98
# File 'lib/relaton/index/file_io.rb', line 91

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



112
113
114
115
116
# File 'lib/relaton/index/file_io.rb', line 112

def deserialize_pubid(index)
  return index unless @pubid_class

  index.map { |r| { id: @pubid_class.create(**r[:id]), file: r[:file] } }
end

#fetch_and_saveArray<Hash>

Fetch index from external repository and save it to storage

Returns:

  • (Array<Hash>)

    index



154
155
156
157
158
159
160
161
# File 'lib/relaton/index/file_io.rb', line 154

def fetch_and_save
  resp = StringIO.new(URI(url).read)
  zip = Zip::InputStream.new resp
  entry = zip.get_next_entry
  yaml = entry.get_input_stream.read
  Util.info "Downloaded index from `#{url}`", progname
  load_index(yaml, save = true)
end

#fileObject



48
49
50
# File 'lib/relaton/index/file_io.rb', line 48

def file
  @file ||= url ? path_to_local_file : @filename
end

#load_index(yaml, save = false) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/relaton/index/file_io.rb', line 132

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

Returns:

  • (<Type>)

    <description>



57
58
59
# File 'lib/relaton/index/file_io.rb', line 57

def path_to_local_file
  File.join(Index.config.storage_dir, ".relaton", @dir, @filename)
end

#prognameObject



128
129
130
# File 'lib/relaton/index/file_io.rb', line 128

def progname
  @progname ||= "relaton-#{@dir}"
end

#readArray<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.

Returns:

  • (Array<Hash>)

    index



39
40
41
42
43
44
45
46
# File 'lib/relaton/index/file_io.rb', line 39

def read
  case url
  when String
    check_file || fetch_and_save
  else
    read_file || []
  end
end

#read_fileArray<Hash>

Read index from storage

Returns:

  • (Array<Hash>)

    index



105
106
107
108
109
110
# File 'lib/relaton/index/file_io.rb', line 105

def read_file
  yaml = Index.config.storage.read(file)
  return unless yaml

  load_index(yaml) || []
end

#removeArray

Remove index file from storage

Returns:

  • (Array)


186
187
188
189
# File 'lib/relaton/index/file_io.rb', line 186

def remove
  Index.config.storage.remove file
  []
end

#save(index) ⇒ void

This method returns an undefined value.

Save index to storage

Parameters:

  • index (Array<Hash>)

    index to save



176
177
178
179
# File 'lib/relaton/index/file_io.rb', line 176

def save(index)
  Index.config.storage.write file,
    index.map { |item| item.transform_values { |value| value.is_a?(Pubid::Core::Identifier::Base) ? value.to_h : value } }.to_yaml
end

#warn_local_index_error(reason) ⇒ Object



118
119
120
121
122
123
124
125
126
# File 'lib/relaton/index/file_io.rb', line 118

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



163
164
165
166
167
# File 'lib/relaton/index/file_io.rb', line 163

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