dbtools 0.5.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/README.md +333 -0
- data/Thorfile +1 -0
- data/bin/dbtools +5 -0
- data/config/client_secret_dbtools.json +1 -0
- data/config/config.yml +1 -0
- data/config/database_config.yml +12 -0
- data/config/databases.txt +5 -0
- data/config/schedule.rb +8 -0
- data/dbtools.gemspec +37 -0
- data/lib/dbtools.rb +47 -0
- data/lib/dbtools/constants.rb +847 -0
- data/lib/dbtools/converter/csv2rdf_converter.rb +68 -0
- data/lib/dbtools/converter/csv_importer.rb +107 -0
- data/lib/dbtools/converter/excel2csv_converter.rb +40 -0
- data/lib/dbtools/converter/google_drive2_rdf_converter.rb +97 -0
- data/lib/dbtools/database/database_data.rb +146 -0
- data/lib/dbtools/database/db_connection.rb +236 -0
- data/lib/dbtools/database/mysql_connection.rb +78 -0
- data/lib/dbtools/database/postgresql_connection.rb +132 -0
- data/lib/dbtools/database/violation.rb +45 -0
- data/lib/dbtools/google_drive/google_drive_api.rb +211 -0
- data/lib/dbtools/google_drive/google_drive_entity.rb +22 -0
- data/lib/dbtools/google_drive/google_drive_file.rb +10 -0
- data/lib/dbtools/google_drive/google_drive_folder.rb +9 -0
- data/lib/dbtools/plsql_functions/connect_server.sql +30 -0
- data/lib/dbtools/plsql_functions/link.sql +17 -0
- data/lib/dbtools/plsql_functions/unlink.sql +15 -0
- data/lib/dbtools/rdf/rdf_reader.rb +136 -0
- data/lib/dbtools/version.rb +3 -0
- data/lib/rdf/geophy.rb +27 -0
- data/lib/tasks/aws.rb +43 -0
- data/lib/tasks/backup.rb +107 -0
- data/lib/tasks/check.rb +220 -0
- data/lib/tasks/ckan.rb +151 -0
- data/lib/tasks/convert.rb +139 -0
- data/lib/tasks/dump.rb +110 -0
- data/lib/tasks/googledrivetool.rb +252 -0
- data/lib/tasks/import.rb +142 -0
- data/lib/tasks/postgres.rb +29 -0
- metadata +307 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
require 'linkeddata'
|
3
|
+
require 'dbtools/converter/csv2rdf_converter'
|
4
|
+
|
5
|
+
module Dbtools
|
6
|
+
class Convert < Thor
|
7
|
+
package_name "dbtools"
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
# desc 'csv2rdf [csv_file, format, metadata]', 'Converts a csv file to a RDF file. Output file has the same name as input file, with a different extension.'
|
14
|
+
# def csv2rdf(csv_file, format = 'ttl', metadata_file = nil)
|
15
|
+
# if csv_file
|
16
|
+
# # Output as the same file, but with a different extension.
|
17
|
+
# rdf_file = change_filename_extension(csv_file, format)
|
18
|
+
# RDF::Writer.open(rdf_file) do |f|
|
19
|
+
# # Load the csv into rdf graph, and write output to file.
|
20
|
+
# options = {}
|
21
|
+
# options[:metadata] = metadata_file if metadata_file
|
22
|
+
# graph = RDF::Graph.load(csv_file, options)
|
23
|
+
# f << graph
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
|
28
|
+
desc 'excel2csv [excel_file, sheet_index, output_file(optional)]', 'Converts an excel file to CSV file.'
|
29
|
+
long_desc <<-LONGDESC
|
30
|
+
`excel2csv` converts an excel file to csv format. The sheet index should be specified.
|
31
|
+
It will default to the first sheet by default.
|
32
|
+
LONGDESC
|
33
|
+
# option :sheet,
|
34
|
+
def excel2csv(excel_file, sheet_index = 0, output_file = nil)
|
35
|
+
converter = Dbtools::Converter::Excel2csv_converter.new(excel_file)
|
36
|
+
if output_file.nil?
|
37
|
+
STDOUT << converter.sheet2csv(sheet_index)
|
38
|
+
else
|
39
|
+
File.open(output_file, 'a') do |f|
|
40
|
+
f << converter.sheet2csv(sheet_index)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'csv2rdf [csv_file, uri, compressed(optional)]', 'Converts a csv file to a RDF ntriples file.'
|
46
|
+
long_desc <<-LONGDESC
|
47
|
+
`csv2rdf csv_file uri` will convert a csv file to a RDF NTriples file.
|
48
|
+
The URI will be the subject in the resulting RDF file.
|
49
|
+
|
50
|
+
You can optionally specify a third parameter, which will write
|
51
|
+
the output to a file. You can also specify a fourth parameter to compress
|
52
|
+
the file to .gz format.
|
53
|
+
|
54
|
+
Example:
|
55
|
+
\x5$ dbtools convert csv2rdf data.csv http://geophy.io output.nt
|
56
|
+
|
57
|
+
Resulting triples will look like:
|
58
|
+
<http://geophy.io#ROWNUMBER> <http://geophy.io/COLUMNNAME> VALUE .
|
59
|
+
<http://geophy.io#1> <http://geophy.io/name> "Bob" .
|
60
|
+
|
61
|
+
LONGDESC
|
62
|
+
def csv2rdf(csv_file, uri, output_file=nil, compressed=false)
|
63
|
+
csv_rdf = Dbtools::Converter::Csv2rdf_converter.new(csv_file, uri)
|
64
|
+
if output_file.nil?
|
65
|
+
csv_rdf.each_triple do |triple|
|
66
|
+
puts triple
|
67
|
+
end
|
68
|
+
else
|
69
|
+
begin
|
70
|
+
file = if compressed
|
71
|
+
Zlib::GzipWriter.open(output_file + '.gz')
|
72
|
+
else
|
73
|
+
File.open(output_file, 'w')
|
74
|
+
end
|
75
|
+
csv_rdf.each_triple do |triple|
|
76
|
+
file.write(triple << "\n")
|
77
|
+
end
|
78
|
+
ensure
|
79
|
+
file.close unless file.nil?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
desc 'googledrive2rdf [file_id]', 'Converts a csv file from Google Drive to a RDF ntriples file. '
|
85
|
+
long_desc <<-LONGDESC
|
86
|
+
`googledrive2rdf file_id` will download a file from Google Drive and
|
87
|
+
convert that file to a RDF NTriples file.
|
88
|
+
The Google Drive file id will be the subject in the resulting RDF file.
|
89
|
+
|
90
|
+
You can optionally specify a second parameter, which will write
|
91
|
+
the output to a file. To compress the file to .gz, you can specify a third parameter.
|
92
|
+
|
93
|
+
Example:
|
94
|
+
\x5$ dbtools convert googledrive2rdf 0Byv6wMVo_JE4WGR6QWc2S3NiQjg output.nt true
|
95
|
+
LONGDESC
|
96
|
+
def googledrive2rdf(file_id, output_file=nil, compressed=false)
|
97
|
+
output_dir = File.join('/tmp', 'dbtools_googledrive/')
|
98
|
+
file_path = invoke("dbtools:google_drive:download", [file_id, output_dir])
|
99
|
+
uri = "https://drive.google.com/open?id=" << file_id
|
100
|
+
invoke "dbtools:convert:csv2rdf", [file_path, uri, output_file, compressed]
|
101
|
+
ensure
|
102
|
+
FileUtils.remove_entry_secure(output_dir)
|
103
|
+
end
|
104
|
+
|
105
|
+
# desc 'excel2rdf [excel_file, format, metadata]', 'Converts an excel file to an RDF file. Output file has the same name as input file, with a different extension.'
|
106
|
+
# def excel2rdf(excel_file, format = 'ttl', metadata_file = nil)
|
107
|
+
# if excel_file
|
108
|
+
# # Use tmp dir to output csv files.
|
109
|
+
# output_dir = File.join('/tmp', 'excel2csv')
|
110
|
+
# files = Dbtools::Import.new.excel2csv(excel_file, output_dir)
|
111
|
+
# # Output as the same file, but with a different extension.
|
112
|
+
# rdf_file = change_filename_extension(excel_file, format)
|
113
|
+
# RDF::Writer.open(rdf_file) do |f|
|
114
|
+
# options = {}
|
115
|
+
# # Use metadata file for mapping if specified.
|
116
|
+
# options[:metadata] = metadata_file if metadata_file
|
117
|
+
# graph = RDF::Graph.new
|
118
|
+
# files.each do |sheetname, csv_file|
|
119
|
+
# # Load all sheets in the graph.
|
120
|
+
# graph.load(csv_file, options)
|
121
|
+
# end
|
122
|
+
# f << graph
|
123
|
+
# end
|
124
|
+
# # Remove tmp dir
|
125
|
+
# FileUtils.remove_entry_secure(output_dir)
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
|
129
|
+
|
130
|
+
private
|
131
|
+
# Change the extension of the given filename with the new extension
|
132
|
+
def change_filename_extension(file, extension)
|
133
|
+
# Strip current extension from file name
|
134
|
+
file_extless = File.join(File.dirname(file), File.basename(file, ".*"))
|
135
|
+
ext = extension.delete(".")
|
136
|
+
return file_extless << "." << ext
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/lib/tasks/dump.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'thor'
|
3
|
+
require 'rdf'
|
4
|
+
require 'sparql/client'
|
5
|
+
|
6
|
+
module Dbtools
|
7
|
+
class Dump < Thor
|
8
|
+
package_name "dbtools"
|
9
|
+
|
10
|
+
# Backs up a rdf graph at a sparql endpoint
|
11
|
+
desc 'rdf [sparql_endpoint, filename]', 'Dumps a rdf database to a file.'
|
12
|
+
long_desc <<-LONGDESC
|
13
|
+
`rdf [sparql_endpoint, filename]` will write all ntriple statements
|
14
|
+
located in the RDF repository to the specified file.
|
15
|
+
|
16
|
+
Example:
|
17
|
+
\x5$ dbtools dump rdf http://localhost:9999/blazegraph/namespace/test/sparql /tmp/repository.nt --compress=false
|
18
|
+
\x5$ dbtools dump rdf http://localhost:9999/blazegraph/namespace/test/sparql /tmp/repository.nt.gz --compress
|
19
|
+
LONGDESC
|
20
|
+
option :compress, :default => false, :type => :boolean
|
21
|
+
def rdf(sparql_endpoint, filename)
|
22
|
+
repo = SPARQL::Client::Repository.new(uri: sparql_endpoint)
|
23
|
+
|
24
|
+
# Use temp name when compressing
|
25
|
+
if options[:compress]
|
26
|
+
target = filename + '_tmp.nt'
|
27
|
+
STDERR.puts %q[Warning: compress option is selected, but filename doesn't end with .gz.
|
28
|
+
You should change the name to end in .gz if you want to open it.] if File.extname(filename) != '.gz'
|
29
|
+
else
|
30
|
+
target = filename
|
31
|
+
end
|
32
|
+
|
33
|
+
RDF::Writer.open(target, format: :ntriples) do |w|
|
34
|
+
repo.each {|stmt| w << stmt}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Zlib::GzipWriter can't wrap around RDF::Writer, because RDF::Writer is not a IO-like object...
|
38
|
+
if options[:compress]
|
39
|
+
# Compress the file using gz
|
40
|
+
Zlib::GzipWriter.open(filename) do |gz|
|
41
|
+
# Write in chunks.
|
42
|
+
File.open(target) do |fp|
|
43
|
+
while chunk = fp.read(16 * 1024) do
|
44
|
+
gz.write chunk
|
45
|
+
end
|
46
|
+
end
|
47
|
+
gz.close
|
48
|
+
end
|
49
|
+
# Delete the original file after generating the compressed version.
|
50
|
+
File.delete(target) if File.exists?(target)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'blazegraph [url, file]', 'Dumps a blazegraph database to a jnl file.'
|
55
|
+
long_desc <<-LONGDESC
|
56
|
+
`blazegraph [url, file]` will create a backup of a blazegraph database,
|
57
|
+
using the built in backup function, and output it to the specified file.
|
58
|
+
It is recommended to use absolute filepaths.
|
59
|
+
|
60
|
+
Note: the resulting file will reside on the same server as where blazegraph
|
61
|
+
is running.
|
62
|
+
|
63
|
+
Example:
|
64
|
+
\x5$ dbtools backup blazegraph http://localhost:9999/blazegraph/backup /tmp/dump.jnl
|
65
|
+
LONGDESC
|
66
|
+
option :compress, :default => false, :type => :boolean
|
67
|
+
def blazegraph(url, file)
|
68
|
+
uri = URI(url)
|
69
|
+
params = { :compress => options[:compress],
|
70
|
+
:file => file }
|
71
|
+
uri.query = URI.encode_www_form(params)
|
72
|
+
res = Net::HTTP.get_response(uri)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Creates a schema dump of the database. Specify the database with an url.
|
77
|
+
desc 'schema URL PATH', 'Creates a schema dump of the database. Specify the database with an url.'
|
78
|
+
def schema(url, path)
|
79
|
+
adapter, user, password, host, database = url.match("^([a-zA-Z0-9]+):\/\/(.+):(.+)@(.+)\/(.+)").captures
|
80
|
+
case adapter
|
81
|
+
when "mysql2"
|
82
|
+
dump_mysql_schema(user, password, database, host, path)
|
83
|
+
when "postgres"
|
84
|
+
dump_postgresql_schema(user, password, database, host, path)
|
85
|
+
else
|
86
|
+
puts "Not supported database"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
# Dumps a mysql database schema to a file.
|
92
|
+
def dump_mysql_schema(user, password, database, host, path)
|
93
|
+
dump_path = File.join(path, 'mysql', host)
|
94
|
+
FileUtils::mkdir_p(dump_path)
|
95
|
+
dump_file_name = File.join(dump_path, "#{database}_schema.sql")
|
96
|
+
puts "Dumping schema to #{dump_file_name}"
|
97
|
+
system "mysqldump -u #{user} -p#{password} -h #{host} --no-data #{database} > #{dump_file_name}"
|
98
|
+
end
|
99
|
+
|
100
|
+
# Dumps a postgres database schema to a file.
|
101
|
+
def dump_postgresql_schema(user, password, database, host, path)
|
102
|
+
dump_path = File.join(path, "postgres", host)
|
103
|
+
FileUtils::mkdir_p(dump_path)
|
104
|
+
dump_file_name = File.join(dump_path, "#{database}_schema.sql")
|
105
|
+
puts "Dumping schema to #{dump_file_name}"
|
106
|
+
system "pg_dump -h #{host} --dbname=#{database} --username=#{user} --schema-only > #{dump_file_name}"
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,252 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'thor'
|
3
|
+
require 'find'
|
4
|
+
require 'dbtools/rdf/rdf_reader'
|
5
|
+
require 'dbtools/constants'
|
6
|
+
require 'dbtools/converter/csv_importer'
|
7
|
+
require 'dbtools/converter/google_drive2_rdf_converter'
|
8
|
+
require 'dbtools/converter/excel2csv_converter'
|
9
|
+
require 'dbtools/database/mysql_connection'
|
10
|
+
require 'dbtools/database/postgresql_connection'
|
11
|
+
require 'dbtools/google_drive/google_drive_api'
|
12
|
+
require 'fileutils'
|
13
|
+
|
14
|
+
require 'googleauth'
|
15
|
+
require 'googleauth/stores/file_token_store'
|
16
|
+
require 'google/apis/drive_v3'
|
17
|
+
|
18
|
+
module Dbtools
|
19
|
+
class FormatNotSupportedError < StandardError; end
|
20
|
+
|
21
|
+
class Google_drive < Thor
|
22
|
+
|
23
|
+
def initialize(*args)
|
24
|
+
super
|
25
|
+
@gdrive = Google_Drive::Google_drive_api.new(auth=authorize)
|
26
|
+
@service = @gdrive.service
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
desc 'export [File_id, format, target_dest(optional)]', 'Exports a file stored on Google Drive. Like Google Spreadsheets etc. For regular files, use download. If no target directory is specified, it will print the contents. Supported export formats: https://developers.google.com/drive/v3/web/manage-downloads#downloading_a_file'
|
31
|
+
long_desc <<-LONGDESC
|
32
|
+
`export` will download a Google document stored on Google Drive, like Google Spreadsheets, Google slides etc.
|
33
|
+
You need to specify the export format. The supported conversion formats can be found here:
|
34
|
+
https://developers.google.com/drive/v3/web/manage-downloads#downloading_a_file
|
35
|
+
|
36
|
+
An optional target directory can be given. This will download the file into the directory,
|
37
|
+
using the same name as on Google Drive.
|
38
|
+
If no target directory is given, the file will be streamed to STDOUT.
|
39
|
+
|
40
|
+
Examples:
|
41
|
+
\x5$ dbtools google_drive export 0B67ew1eLtcXxeUVmTndialhTRTA 'text/plain' /tmp/target_dir/"
|
42
|
+
\x5$ dbtools google_drive export 0B67ew1eLtcXxeUVmTndialhTRTA 'application/pdf' > /tmp/test.pdf"
|
43
|
+
|
44
|
+
LONGDESC
|
45
|
+
def export(file_id, target_format, target_dest = nil)
|
46
|
+
if target_dest.nil?
|
47
|
+
@service.export_file(file_id, target_format, download_dest: STDOUT)
|
48
|
+
else
|
49
|
+
file = @service.get_file(file_id)
|
50
|
+
FileUtils.mkdir_p(target_dest)
|
51
|
+
extension_mapping = { 'text/html' => '.html',
|
52
|
+
'text/plain' => '.txt',
|
53
|
+
'application/rtf' => '.rtf',
|
54
|
+
'application/vnd.oasis.opendocument.text' => '.odt',
|
55
|
+
'application/pdf' => '.pdf',
|
56
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => '.docx',
|
57
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => '.xlsx',
|
58
|
+
'application/x-vnd.oasis.opendocument.spreadsheet' => '.ods',
|
59
|
+
'text/csv' => '.csv',
|
60
|
+
'image/jpeg' => '.jpg',
|
61
|
+
'image/png' => '.png',
|
62
|
+
'image/svg+xml' => '.svg',
|
63
|
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation' => '.pptx',
|
64
|
+
'application/vnd.google-apps.script+json' => '.json' }
|
65
|
+
extension_mapping.default = ''
|
66
|
+
extension = extension_mapping[target_format]
|
67
|
+
destination = File.join(target_dest, file.name + extension)
|
68
|
+
@service.export_file(file_id, target_format, download_dest: destination)
|
69
|
+
return destination
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
desc 'download [File_id, target_dest(optional)]', 'Downloads a file stored on google drive. Regular files, no Google Spreadsheets etc. For Google documents, use export. If no target directory is specified, it will print the contents. '
|
74
|
+
long_desc <<-LONGDESC
|
75
|
+
`download` will download a file stored on Google Drive.
|
76
|
+
An optional target directory can be given. This will download the file into the directory,
|
77
|
+
using the same name as on Google Drive. If a Google Doc file is given, it will automatically
|
78
|
+
export it to the most commonly used format.
|
79
|
+
If no target directory is given, the file will be streamed to STDOUT.
|
80
|
+
|
81
|
+
Examples:
|
82
|
+
\x5$ dbtools google_drive download 0B67ew1eLtcXxeUVmTndialhTRTA /tmp/target_destination/"
|
83
|
+
\x5$ dbtools google_drive download 0B67ew1eLtcXxeUVmTndialhTRTA > /tmp/image.jpg"
|
84
|
+
|
85
|
+
LONGDESC
|
86
|
+
def download(file_id, target_dest = nil)
|
87
|
+
metadata = @service.get_file(file_id)
|
88
|
+
if metadata.mime_type.index('application/vnd.google-apps')
|
89
|
+
# Default conversion formats
|
90
|
+
googledoc_format_conversion = { 'application/vnd.google-apps.document' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
91
|
+
'application/vnd.google-apps.presentation' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
92
|
+
'application/vnd.google-apps.spreadsheet' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
93
|
+
'application/vnd.google-apps.drawing' => 'image/png' }
|
94
|
+
target_format = googledoc_format_conversion[metadata.mime_type]
|
95
|
+
raise FormatNotSupportedError.new("Mimetype #{metadata.mime_type} is not supported. If you know the target conversion format, try using the `export` task.") if target_format.nil?
|
96
|
+
return export(file_id, target_format, target_dest)
|
97
|
+
end
|
98
|
+
|
99
|
+
if target_dest.nil?
|
100
|
+
@service.get_file(file_id, download_dest: STDOUT)
|
101
|
+
else
|
102
|
+
destination = target_dest
|
103
|
+
if target_dest.is_a?(String)
|
104
|
+
FileUtils.mkdir_p(target_dest)
|
105
|
+
destination = File.join(target_dest, metadata.name)
|
106
|
+
end
|
107
|
+
@service.get_file(file_id, download_dest: destination)
|
108
|
+
return destination
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
desc 'serialize_rdf [target_file]', 'Serializes the entire Google Drive to a RDF representation. '
|
113
|
+
long_desc <<-LONGDESC
|
114
|
+
`serialize_rdf` will serialize the entire Google Drive to a RDF representation. When no target file
|
115
|
+
is specified, it will output the results to STDOUT.
|
116
|
+
|
117
|
+
An optional `query` parameter can be given, to only serialize matching results.
|
118
|
+
See the `Search for files` guide from the Google Drive API for supported syntax.
|
119
|
+
|
120
|
+
Example:
|
121
|
+
\x5$ dbtools google_drive serialize_rdf output.nt --query="name contains 'Data Lake'"
|
122
|
+
LONGDESC
|
123
|
+
option :query, :option => '', :type => :string
|
124
|
+
option :verbose, :default => false, :type => :boolean
|
125
|
+
def serialize_rdf(target_file = nil)
|
126
|
+
f = if target_file.nil? then STDOUT else File.open(target_file, 'w') end
|
127
|
+
begin
|
128
|
+
print_progress = options[:verbose]
|
129
|
+
files = @gdrive.get_tree(optional_query=options[:query], verbose: print_progress)
|
130
|
+
googledrive2rdf_converter = Dbtools::Converter::GoogleDrive2RDFConverter.new
|
131
|
+
googledrive2rdf_converter.serialize_as_rdf(files=files, verbose: print_progress) do |statement|
|
132
|
+
f << statement
|
133
|
+
end
|
134
|
+
ensure
|
135
|
+
if f != STDOUT
|
136
|
+
f.flush
|
137
|
+
f.close
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
desc 'upload [file]', 'Upload a file to Google Drive'
|
143
|
+
long_desc <<-LONGDESC
|
144
|
+
`upload` will load a file stored on Google Drive. You can specify the target directory by
|
145
|
+
providing the --folder argument with the folder id. If no argument is given, the file will
|
146
|
+
be placed in the root directory.
|
147
|
+
|
148
|
+
Note: Google Drive allows the same file to be placed in multiple directories, similar to
|
149
|
+
symlinking a file. To place the uploaded file in multiple directories, pass an
|
150
|
+
array of folder ids to the --folder argument.
|
151
|
+
|
152
|
+
Examples:
|
153
|
+
\x5$ dbtools google_drive upload file.txt --folder=0B1ptxcLvq-tCNHlQMzU0ZFcyZjQ
|
154
|
+
|
155
|
+
LONGDESC
|
156
|
+
method_option :folder, :type => :array
|
157
|
+
method_option :filename, :type => :string
|
158
|
+
def upload(file)
|
159
|
+
mime_type = `file --mime-type -b #{file}`.chomp
|
160
|
+
file_metadata = {
|
161
|
+
name: File.basename(file),
|
162
|
+
mime_type: mime_type,
|
163
|
+
}
|
164
|
+
file_metadata.merge!({ parents: options[:folder] }) if options[:folder]
|
165
|
+
file_metadata.merge!({ name: options[:filename] }) if options[:filename]
|
166
|
+
|
167
|
+
result = @service.create_file(file_metadata, upload_source: file,
|
168
|
+
content_type: mime_type, options: { retries: 3 } )
|
169
|
+
return result
|
170
|
+
end
|
171
|
+
|
172
|
+
desc 'changes_as_rdf [page_token, target_file]', 'Queries all changes to the Google Drive from a starting point defined by the page token.'
|
173
|
+
def changes_as_rdf(start_page_token, target_file=nil)
|
174
|
+
# Check if it's not empty.
|
175
|
+
if start_page_token.nil? || start_page_token.to_s.empty?
|
176
|
+
STDERR.puts "Start page token cannot be nil. "
|
177
|
+
return
|
178
|
+
end
|
179
|
+
f = if target_file.nil?
|
180
|
+
STDOUT
|
181
|
+
else
|
182
|
+
File.open(target_file, 'w')
|
183
|
+
end
|
184
|
+
begin
|
185
|
+
changed_files, removed_files, new_start_page_token = @gdrive.get_changes(page_token=start_page_token)
|
186
|
+
googledrive2rdf = Dbtools::Converter::GoogleDrive2RDFConverter.new
|
187
|
+
googledrive2rdf.serialize_as_rdf(files=changed_files) do |statement|
|
188
|
+
f << statement
|
189
|
+
end
|
190
|
+
ensure
|
191
|
+
if f != STDOUT
|
192
|
+
f.flush
|
193
|
+
f.close
|
194
|
+
end
|
195
|
+
end
|
196
|
+
STDERR.puts "New page token: #{new_start_page_token}"
|
197
|
+
return changed_files, removed_files, new_start_page_token
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
desc 'list [file_id]', 'Lists all files in the folder.'
|
202
|
+
def list(file_id)
|
203
|
+
folder = @service.get_file(file_id)
|
204
|
+
puts @gdrive.print_child_files(folder)
|
205
|
+
end
|
206
|
+
|
207
|
+
no_commands do
|
208
|
+
def get_file(file_id, download_dest: nil)
|
209
|
+
@service.get_file(file_id, download_dest: download_dest)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
|
215
|
+
OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
|
216
|
+
CLIENT_SECRETS_PATH = Dbtools::Google_Drive::Google_drive_api::CLIENT_SECRETS_PATH
|
217
|
+
CREDENTIALS_PATH = Dbtools::Google_Drive::Google_drive_api::CREDENTIALS_PATH
|
218
|
+
SCOPE = Google::Apis::DriveV3::AUTH_DRIVE
|
219
|
+
|
220
|
+
# Ensure valid credentials, either by restoring from the saved credentials
|
221
|
+
# files or intitiating an OAuth2 authorization. If authorization is required,
|
222
|
+
# the user's default browser will be launched to approve the request.
|
223
|
+
#
|
224
|
+
# @return [Google::Auth::UserRefreshCredentials] OAuth2 credentials
|
225
|
+
def authorize
|
226
|
+
unless File.exist?(CLIENT_SECRETS_PATH)
|
227
|
+
puts "#{CLIENT_SECRETS_PATH} not found."
|
228
|
+
puts "Create Google Drive API OAuth 2.0 credentials to allow access. "
|
229
|
+
exit(1)
|
230
|
+
end
|
231
|
+
|
232
|
+
FileUtils.mkdir_p(File.dirname(CREDENTIALS_PATH))
|
233
|
+
client_id = Google::Auth::ClientId.from_file(CLIENT_SECRETS_PATH)
|
234
|
+
token_store = Google::Auth::Stores::FileTokenStore.new(file: CREDENTIALS_PATH)
|
235
|
+
authorizer = Google::Auth::UserAuthorizer.new(
|
236
|
+
client_id, SCOPE, token_store)
|
237
|
+
user_id = 'default'
|
238
|
+
credentials = authorizer.get_credentials(user_id)
|
239
|
+
if credentials.nil?
|
240
|
+
url = authorizer.get_authorization_url(
|
241
|
+
base_url: OOB_URI)
|
242
|
+
puts url
|
243
|
+
code = ask("Open the following URL in the browser and enter the " +
|
244
|
+
"resulting code after authorization: ")
|
245
|
+
credentials = authorizer.get_and_store_credentials_from_code(
|
246
|
+
user_id: user_id, code: code, base_url: OOB_URI)
|
247
|
+
end
|
248
|
+
credentials
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
252
|
+
end
|