class Tumugi::Plugin::GoogleDrive::FileSystem

Constants

MIME_TYPE_FOLDER

Public Class Methods

new(config) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 13
def initialize(config)
  save_config(config)
end

Public Instance Methods

copy(src_file_id, dest_name, dest_parents: nil) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 62
def copy(src_file_id, dest_name, dest_parents: nil)
  dest_parents = [dest_parents] if dest_parents.is_a?(String)
  dest_file_metadata = Google::Apis::DriveV3::File.new({
    name: dest_name,
    parents: dest_parents
  })
  file = client.copy_file(src_file_id, dest_file_metadata, options: request_options)
  wait_until { exist?(file.id) }
  file
rescue
  process_error($!)
end
directory?(file_id) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 49
def directory?(file_id)
  file = get_file_metadata(file_id)
  file.mime_type == MIME_TYPE_FOLDER
rescue
  process_error($!)
end
download(file_id, download_path: nil, mode: 'r', mime_type: nil, &block) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 95
def download(file_id, download_path: nil, mode: 'r', mime_type: nil, &block)
  if !exist?(file_id)
    raise Tumugi::FileSystemError.new("#{file_id} does not exist")
  end

  if download_path.nil?
    download_path = Tempfile.new('tumugi_google_drive_file_system').path
  end

  file = get_file_metadata(file_id)
  if google_drive_document?(file.mime_type)
    # If file is Google Drive Document, use export_file
    # https://developers.google.com/drive/v3/web/manage-downloads#downloading_google_documents
    if mime_type.nil?
      raise Tumugi::FileSystemError.new("mime_type is required because file #{file_id} is Google Drive Document")
    end
    client.export_file(file_id, mime_type, download_dest: download_path, options: request_options)
  else
    # If file is not Google Drive Document, use get_file
    # https://developers.google.com/drive/v3/web/manage-downloads#downloading_a_file
    client.get_file(file_id, download_dest: download_path, options: request_options)
  end

  wait_until { File.exist?(download_path) }

  if block_given?
    File.open(download_path, mode, &block)
  else
    File.open(download_path, mode)
  end
  file
rescue
  process_error($!)
end
exist?(file_id) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 17
def exist?(file_id)
  get_file_metadata(file_id, fields: 'id')
  true
rescue => e
  return false if e.respond_to?(:status_code) && e.status_code == 404
  process_error(e)
end
generate_file_id() click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 130
def generate_file_id
  client.generate_file_ids(count: 1, options: request_options).ids.first
rescue
  process_error($!)
end
get_file_metadata(file_id, fields: "*") click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 144
def get_file_metadata(file_id, fields: "*")
  client.get_file(file_id, fields: fields, options: request_options)
end
google_drive_document?(mime_type) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 148
def google_drive_document?(mime_type)
  !!(mime_type && mime_type.start_with?("application/vnd.google-apps."))
end
list_files(query:, order_by: "name", spaces: "drive", fields: "next_page_token, files(id, name, parents, mime_type)", page_size: 100, page_token: nil) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 136
def list_files(query:, order_by: "name", spaces: "drive", fields: "next_page_token, files(id, name, parents, mime_type)", page_size: 100, page_token: nil)
  # https://developers.google.com/drive/v3/reference/files/list
  # https://developers.google.com/drive/v3/web/search-parameters
  client.list_files(q: query, order_by: order_by, spaces: spaces, fields: fields, page_size: page_size, page_token: page_token)
rescue
  process_error($!)
end
mkdir(name, folder_id: nil, parents: nil) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 35
def mkdir(name, folder_id: nil, parents: nil)
  file_metadata = Google::Apis::DriveV3::File.new({
    name: name,
    mime_type: MIME_TYPE_FOLDER,
    parents: parents,
    id: folder_id
  })
  file = client.create_file(file_metadata, fields: "*", options: request_options)
  wait_until { exist?(file.id) }
  file
rescue
  process_error($!)
end
move(src_file_id, dest_name, dest_parents: nil) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 56
def move(src_file_id, dest_name, dest_parents: nil)
  file = copy(src_file_id, dest_name, dest_parents: dest_parents)
  remove(src_file_id)
  file
end
put_string(contents, name, content_type: 'text/plain', file_id: nil, parents: nil) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 90
def put_string(contents, name, content_type: 'text/plain', file_id: nil, parents: nil)
  media = StringIO.new(contents)
  upload(media, name, content_type: content_type, file_id: file_id, parents: parents)
end
remove(file_id) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 25
def remove(file_id)
  return unless exist?(file_id)

  client.delete_file(file_id, options: request_options)
  wait_until { !exist?(file_id) }
  file_id
rescue
  process_error($!)
end
upload(media, name, content_type: nil, file_id: nil, parents: nil, mime_type: nil) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 75
def upload(media, name, content_type: nil, file_id: nil, parents: nil, mime_type: nil)
  parents = [parents] if parents.is_a?(String)
  file_metadata = Google::Apis::DriveV3::File.new({
    id: file_id,
    name: name,
    parents: parents,
    mime_type: mime_type
  })
  file = client.create_file(file_metadata, fields: "*", upload_source: media, content_type: content_type, options: request_options)
  wait_until { exist?(file.id) }
  file
rescue
  process_error($!)
end

Private Instance Methods

client() click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 171
def client
  return @cached_client if @cached_client && @cached_client_expiration > Time.now

  client = Google::Apis::DriveV3::DriveService.new
  scope = Google::Apis::DriveV3::AUTH_DRIVE

  if @key[:client_email] && @key[:private_key]
    options = {
      json_key_io: StringIO.new(JSON.generate(@key)),
      scope: scope
    }
    auth = Google::Auth::ServiceAccountCredentials.make_creds(options)
  else
    auth = Google::Auth.get_application_default([scope])
  end
  auth.fetch_access_token!
  client.authorization = auth

  @cached_client_expiration = Time.now + (auth.expires_in / 2)
  @cached_client = client
end
process_error(err) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 199
def process_error(err)
  if err.respond_to?(:body)
    begin
      if err.body.nil?
        reason = err.status_code.to_s
        errors = "HTTP Status: #{err.status_code}, Headers: #{err.header.inspect}"
      else
        jobj = JSON.parse(err.body)
        error = jobj["error"]
        errors = "HTTP Status: #{err.status_code}, Headers: #{err.header.inspect}, Body: "
        if error["errors"]
          reason = error["errors"].map{|e| e["reason"]}.join(",")
          errors += error["errors"].map{|e| e["message"] }.join(". ")
        else
          errors += error["message"]
        end
      end
    rescue JSON::ParserError
      reason = err.status_code.to_s
      errors = "HTTP Status: #{err.status_code}, Headers: #{err.header.inspect}, Body: #{err.body}"
    end
    raise Tumugi::FileSystemError.new(errors, reason)
  else
    raise err
  end
end
request_options() click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 226
def request_options
  {
    retries: 5,
    timeout_sec: 60
  }
end
save_config(config) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 154
def save_config(config)
  if config.private_key_file.nil?
    @project_id = config.project_id
    client_email = config.client_email
    private_key = config.private_key
  elsif config.private_key_file
    json = JSON.parse(File.read(config.private_key_file))
    @project_id = json['project_id']
    client_email = json['client_email']
    private_key = json['private_key']
  end
  @key = {
    client_email: client_email,
    private_key: private_key
  }
end
wait_until(&block) click to toggle source
# File lib/tumugi/plugin/google_drive/file_system.rb, line 193
def wait_until(&block)
  while not block.call
    sleep 3
  end
end