backup-googledrive 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/backup-googledrive.rb +6 -0
- data/lib/storage/googledrive.rb +149 -0
- metadata +46 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 6909a4f268118492f668382203b3c332e19a80c8
|
|
4
|
+
data.tar.gz: eac80a0ce6a50a9314f253a86f93c9c2b9b083ae
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c0b37e31e8bf83fde792b284d30b564426425b3603596b73c89ef71426574b5e99b25d5bb058a73b1a9b865d20d5688d8e0a93bacf795675d34abda55c3fb116
|
|
7
|
+
data.tar.gz: 9a3693d57cb08c8d594b0903a075e919db6184f00196a56ab26118a16cd1e73d9abbbeda94739827af671b5239d3d3047e7c301b719702b79bb3f450c39fb078
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Storage
|
|
5
|
+
class GoogleDrive < Base
|
|
6
|
+
|
|
7
|
+
include Storage::Cycler
|
|
8
|
+
class Error < Backup::Error; end
|
|
9
|
+
|
|
10
|
+
# This adapter uses gdrive (https://github.com/prasmussen/gdrive) to handle all API interactions.
|
|
11
|
+
# Fortunately for us gdrive handles things like timeouts, error retries and large file chunking, too!
|
|
12
|
+
# I found gdrive's defaults to be acceptable, but should be easy to add accessors to customize if needed
|
|
13
|
+
|
|
14
|
+
# Path to gdrive executable
|
|
15
|
+
attr_accessor :gdrive_exe
|
|
16
|
+
|
|
17
|
+
# Use the gdrive executable to obtain a refresh token. Add that token to your backup model.
|
|
18
|
+
# The gdrive exe will handle refresing the access tokens
|
|
19
|
+
attr_accessor :refresh_token
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# Creates a new instance of the storage object
|
|
23
|
+
def initialize(model, storage_id = nil)
|
|
24
|
+
super
|
|
25
|
+
|
|
26
|
+
@path ||= 'backups'
|
|
27
|
+
path.sub!(/^\//, '')
|
|
28
|
+
|
|
29
|
+
required = %w{ refresh_token }
|
|
30
|
+
raise Error, "Configuration Error: a refresh_token is required" if refresh_token.nil?
|
|
31
|
+
|
|
32
|
+
raise Error, "Configuration Error: gdrive executable is required." if gdrive_exe.nil?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# private
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# Transfer each of the package files to Dropbox in chunks of +chunk_size+.
|
|
40
|
+
# Each chunk will be retried +chunk_retries+ times, pausing +retry_waitsec+
|
|
41
|
+
# between retries, if errors occur.
|
|
42
|
+
def transfer!
|
|
43
|
+
package.filenames.each do |filename|
|
|
44
|
+
src = File.join(Config.tmp_path, filename)
|
|
45
|
+
dest = File.join(remote_path, filename)
|
|
46
|
+
Logger.info "Storing '#{ dest }'..."
|
|
47
|
+
|
|
48
|
+
parent_id = find_id_from_path(remote_path)
|
|
49
|
+
gdrive_upload(src, parent_id)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# # Called by the Cycler.
|
|
54
|
+
# # Any error raised will be logged as a warning.
|
|
55
|
+
def remove!(package)
|
|
56
|
+
Logger.info "Removing backup package dated #{ package.time }..."
|
|
57
|
+
id = find_id_from_path(remote_path_for(package), false)
|
|
58
|
+
if id.to_s.empty?
|
|
59
|
+
raise Error, "Backup packge #{ package.time } not found in Google Drive"
|
|
60
|
+
else
|
|
61
|
+
gdrive_delete(id)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def find_id_from_path(path = remote_path, create = true)
|
|
66
|
+
parent = nil
|
|
67
|
+
path.split('/').each do |path_part|
|
|
68
|
+
id = get_folder_id(path_part, parent)
|
|
69
|
+
if id.to_s.empty? && create
|
|
70
|
+
id = gdrive_mkdir(path_part, parent)
|
|
71
|
+
end
|
|
72
|
+
parent = id
|
|
73
|
+
end
|
|
74
|
+
return parent
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_folder_id(name, parent = nil)
|
|
79
|
+
parent = parent ? parent : 'root'
|
|
80
|
+
gdrive_list("name = '#{name}' and '#{parent}' in parents")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def gdrive_list(query)
|
|
84
|
+
unless query.empty?
|
|
85
|
+
cmd = "gdrive --refresh-token '#{refresh_token}' list --no-header -q \"#{query}\""
|
|
86
|
+
output = `#{cmd}`
|
|
87
|
+
if output.downcase.include? "error"
|
|
88
|
+
raise Error, "Could not list or find the object with query string '#{query}'. gdrive output: #{output}"
|
|
89
|
+
elsif output.empty?
|
|
90
|
+
return nil
|
|
91
|
+
else
|
|
92
|
+
begin
|
|
93
|
+
return /^([^ ]*).*/.match(output)[1] # will return an empty string on no match
|
|
94
|
+
rescue => err
|
|
95
|
+
return nil
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
raise Error, "A search query is required to list/find a file or folder"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def gdrive_mkdir(name, parent = nil)
|
|
104
|
+
unless name.empty?
|
|
105
|
+
parent = parent ? parent : 'root'
|
|
106
|
+
cmd = "gdrive --refresh-token '#{refresh_token}' mkdir -p '#{parent}' '#{name}'"
|
|
107
|
+
output = `#{cmd}`
|
|
108
|
+
if output.downcase.include? "error"
|
|
109
|
+
raise Error, "Could not create the directory '#{name}' with parent '#{parent}'. gdrive output: #{output}"
|
|
110
|
+
else
|
|
111
|
+
id = /^Directory (.*?) created/.match(output)[1]
|
|
112
|
+
raise Error, "Could not determine ID of newly created folder. See gdrive output: #{output}" if id.to_s.empty?
|
|
113
|
+
Logger.info "Created folder #{name} successfully with id '#{id}'"
|
|
114
|
+
return id
|
|
115
|
+
end
|
|
116
|
+
else
|
|
117
|
+
raise Error, "Name parameter is required to make a directory"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def gdrive_upload(src, parent = nil)
|
|
122
|
+
parent = parent ? parent : 'root'
|
|
123
|
+
cmd = "gdrive --refresh-token '#{refresh_token}' upload -p '#{parent}' '#{src}'"
|
|
124
|
+
output = `#{cmd}`
|
|
125
|
+
if ( ["error", "failed"].any? {|s| output.downcase.include? s } )
|
|
126
|
+
raise Error, "Could not upload file. See gdrive output: #{output}"
|
|
127
|
+
else
|
|
128
|
+
begin
|
|
129
|
+
id = /.*Uploaded (.*?) .*/.match(output)[1]
|
|
130
|
+
raise Error, "empty id" if id.to_s.empty?
|
|
131
|
+
Logger.info "Uploaded #{src} into parent folder '#{parent}' successfully. Google Drive file_id: #{ id }"
|
|
132
|
+
rescue => err
|
|
133
|
+
raise Error.wrap(err, "Could not determine ID of newly created folder. See gdrive output: #{output}")
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def gdrive_delete(id, recursive = true)
|
|
139
|
+
cmd = "gdrive --refresh-token '#{refresh_token}' delete #{'-r' if recursive} '#{id}'"
|
|
140
|
+
output = `#{cmd}`
|
|
141
|
+
if output.downcase.include? "error"
|
|
142
|
+
raise Error, "Could not delete object with id: #{id}. See gdrive output: #{output}"
|
|
143
|
+
else
|
|
144
|
+
Logger.info output
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: backup-googledrive
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.2
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Joseph Rafferty
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-10-10 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Adds the GoogleDrive storage engine to the Backup ruby gem.
|
|
14
|
+
email: oraff@gmail.comj
|
|
15
|
+
executables: []
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- lib/backup-googledrive.rb
|
|
20
|
+
- lib/storage/googledrive.rb
|
|
21
|
+
homepage: http://github.com/joraff/backup-googledrive
|
|
22
|
+
licenses:
|
|
23
|
+
- MIT
|
|
24
|
+
metadata: {}
|
|
25
|
+
post_install_message:
|
|
26
|
+
rdoc_options: []
|
|
27
|
+
require_paths:
|
|
28
|
+
- lib
|
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - '>='
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - '>='
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0'
|
|
39
|
+
requirements: []
|
|
40
|
+
rubyforge_project:
|
|
41
|
+
rubygems_version: 2.0.14.1
|
|
42
|
+
signing_key:
|
|
43
|
+
specification_version: 4
|
|
44
|
+
summary: GoogleDrive storage engine to Backup
|
|
45
|
+
test_files: []
|
|
46
|
+
has_rdoc:
|