dbtools 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|