gdsh 0.4.0
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/.gitignore +21 -0
- data/.rspec +1 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/bin/gdsh +10 -0
- data/document.txt +2 -0
- data/gdsh.gemspec +28 -0
- data/lib/gdsh.rb +61 -0
- data/lib/gdsh/clear.rb +20 -0
- data/lib/gdsh/command_factory.rb +32 -0
- data/lib/gdsh/command_mixin.rb +46 -0
- data/lib/gdsh/commands.rb +53 -0
- data/lib/gdsh/drive.rb +113 -0
- data/lib/gdsh/error.rb +7 -0
- data/lib/gdsh/get_file.rb +65 -0
- data/lib/gdsh/help.rb +20 -0
- data/lib/gdsh/list_files.rb +78 -0
- data/lib/gdsh/mime.rb +52 -0
- data/lib/gdsh/query_revision.rb +106 -0
- data/lib/gdsh/quit.rb +23 -0
- data/lib/gdsh/remove.rb +34 -0
- data/lib/gdsh/revision_diff.rb +87 -0
- data/lib/gdsh/share.rb +65 -0
- data/lib/gdsh/share_read_only.rb +18 -0
- data/lib/gdsh/share_read_write.rb +18 -0
- data/lib/gdsh/unrecognized.rb +12 -0
- data/lib/gdsh/upload_template.rb +52 -0
- data/lib/gdsh/version.rb +6 -0
- data/spec/commands_spec.rb +41 -0
- metadata +175 -0
data/lib/gdsh/error.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require_relative 'commands'
|
2
|
+
require_relative 'query_revision'
|
3
|
+
|
4
|
+
module Commands
|
5
|
+
##
|
6
|
+
# Downloads Files/Revisions
|
7
|
+
#
|
8
|
+
class GetFile < QueryRevision
|
9
|
+
def self.command_name
|
10
|
+
'get_txt'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.parameters
|
14
|
+
'(<file_id>[,<revision_number>])'
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.function
|
18
|
+
'Downloads a specific revision of a file if <revision_number> is ' \
|
19
|
+
'specified; downloads all revisions otherwise.'
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(client, params)
|
23
|
+
super(client, params)
|
24
|
+
@revision = (params.length == 3) ? params[2] : nil
|
25
|
+
@file_id = @params[1]
|
26
|
+
end
|
27
|
+
|
28
|
+
def puts_downloading_banner(url)
|
29
|
+
puts 'Downloading '.colorize(:cyan) + "#{url} ...".colorize(:light_yellow)
|
30
|
+
end
|
31
|
+
|
32
|
+
def download(url)
|
33
|
+
return unless @client
|
34
|
+
|
35
|
+
puts_downloading_banner(url)
|
36
|
+
result = @client.execute(uri: url)
|
37
|
+
if result.status == 200
|
38
|
+
result.body
|
39
|
+
else
|
40
|
+
puts drive_error_string
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def download_revision_as_txt(rev)
|
45
|
+
download(txt_link(rev))
|
46
|
+
end
|
47
|
+
|
48
|
+
def write_to_file(revision)
|
49
|
+
filename = generate_filename_from_revision(revision)
|
50
|
+
File.write(filename, download_revision_as_txt(revision))
|
51
|
+
end
|
52
|
+
|
53
|
+
def generate_filename_from_revision(revision)
|
54
|
+
@file_id + '_rev_' + revision + '.txt'
|
55
|
+
end
|
56
|
+
|
57
|
+
def execute
|
58
|
+
if @revision.nil?
|
59
|
+
revisions.each { |r| write_to_file(r['id']) }
|
60
|
+
else
|
61
|
+
write_to_file(@revision)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/gdsh/help.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'commands'
|
2
|
+
|
3
|
+
module Commands
|
4
|
+
##
|
5
|
+
# Help command
|
6
|
+
#
|
7
|
+
class Help < Command
|
8
|
+
def self.command_name
|
9
|
+
'help'
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.function
|
13
|
+
'Returns this usage information.'
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute
|
17
|
+
Commands.usage
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative 'commands'
|
2
|
+
|
3
|
+
module Commands
|
4
|
+
##
|
5
|
+
# List all files accessible by the application.
|
6
|
+
#
|
7
|
+
class ListFiles < Command
|
8
|
+
def self.command_name
|
9
|
+
'ls'
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.function
|
13
|
+
'List files accessible by this application.'
|
14
|
+
end
|
15
|
+
|
16
|
+
def retrieve_file_by_page_token(pagetoken)
|
17
|
+
parameters = pagetoken.to_s.empty? ? {} : { pageToken: pagetoken }
|
18
|
+
drive = @client.discovered_api('drive', 'v2')
|
19
|
+
@client.execute(
|
20
|
+
api_method: drive.files.list,
|
21
|
+
parameters: parameters)
|
22
|
+
end
|
23
|
+
|
24
|
+
def puts_banner
|
25
|
+
puts 'Retrieving list of files accessible...'.colorize(:green)
|
26
|
+
end
|
27
|
+
|
28
|
+
def filelist
|
29
|
+
puts_banner
|
30
|
+
|
31
|
+
result = []
|
32
|
+
page_token = nil
|
33
|
+
|
34
|
+
loop do
|
35
|
+
api_result = retrieve_file_by_page_token(page_token)
|
36
|
+
|
37
|
+
if api_result.status == 200
|
38
|
+
files = api_result.data
|
39
|
+
result.concat(files.items)
|
40
|
+
page_token = files.next_page_token
|
41
|
+
else
|
42
|
+
drive_error_string
|
43
|
+
page_token = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
break if page_token.to_s.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
def title_label
|
53
|
+
'Title: '.colorize(:light_magenta)
|
54
|
+
end
|
55
|
+
|
56
|
+
def id_label
|
57
|
+
'id: '.colorize(:light_magenta)
|
58
|
+
end
|
59
|
+
|
60
|
+
def created_at_label
|
61
|
+
'created at: '.colorize(:light_magenta)
|
62
|
+
end
|
63
|
+
|
64
|
+
def puts_file_info(f)
|
65
|
+
puts title_label + "#{f['title']}"
|
66
|
+
puts id_label + "#{f['id']}"
|
67
|
+
puts created_at_label + "#{f['createdDate']}"
|
68
|
+
puts ''
|
69
|
+
end
|
70
|
+
|
71
|
+
def execute
|
72
|
+
filelist.each do |f|
|
73
|
+
next if f['labels']['trashed']
|
74
|
+
puts_file_info(f)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/gdsh/mime.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
##
|
2
|
+
# MIME types supported by Google Drive.
|
3
|
+
#
|
4
|
+
module Mime
|
5
|
+
def html
|
6
|
+
'text/html'
|
7
|
+
end
|
8
|
+
|
9
|
+
def txt
|
10
|
+
'text/plain'
|
11
|
+
end
|
12
|
+
|
13
|
+
def rtf
|
14
|
+
'application/rtf'
|
15
|
+
end
|
16
|
+
|
17
|
+
def odt
|
18
|
+
'application/vnd.oasis.opendocument.text'
|
19
|
+
end
|
20
|
+
|
21
|
+
def pdf
|
22
|
+
'application/pdf'
|
23
|
+
end
|
24
|
+
|
25
|
+
def docx
|
26
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
27
|
+
end
|
28
|
+
|
29
|
+
def xlsx
|
30
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
31
|
+
end
|
32
|
+
|
33
|
+
def ods
|
34
|
+
'application/x-vnd.oasis.opendocument.spreadsheet'
|
35
|
+
end
|
36
|
+
|
37
|
+
def jpeg
|
38
|
+
'image/jpeg'
|
39
|
+
end
|
40
|
+
|
41
|
+
def png
|
42
|
+
'image/png'
|
43
|
+
end
|
44
|
+
|
45
|
+
def svg
|
46
|
+
'image/svg+xml'
|
47
|
+
end
|
48
|
+
|
49
|
+
def pptx
|
50
|
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require_relative 'commands'
|
2
|
+
require_relative 'mime'
|
3
|
+
|
4
|
+
module Commands
|
5
|
+
##
|
6
|
+
# Queries all revisions of a file.
|
7
|
+
#
|
8
|
+
class QueryRevision < Command
|
9
|
+
include Mime
|
10
|
+
|
11
|
+
def self.command_name
|
12
|
+
'query'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.parameters
|
16
|
+
'(<file_id>)'
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.function
|
20
|
+
'Queries all revisions of a file.'
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(client, params)
|
24
|
+
super(client, params)
|
25
|
+
@file_id = params[1]
|
26
|
+
end
|
27
|
+
|
28
|
+
def revisions
|
29
|
+
drive = @client.discovered_api('drive', 'v2')
|
30
|
+
api_result = @client.execute(
|
31
|
+
api_method: drive.revisions.list,
|
32
|
+
parameters: { 'fileId' => @file_id })
|
33
|
+
if api_result.status == 200
|
34
|
+
api_result.data.items
|
35
|
+
else
|
36
|
+
puts drive_error_string
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def puts_banner
|
41
|
+
puts 'Revisions'.colorize(:magenta)
|
42
|
+
puts '---------'.colorize(:magenta)
|
43
|
+
end
|
44
|
+
|
45
|
+
def revision_id_label
|
46
|
+
'Revision id: '.colorize(:magenta)
|
47
|
+
end
|
48
|
+
|
49
|
+
def modified_date_label
|
50
|
+
'Modified: '.colorize(:magenta)
|
51
|
+
end
|
52
|
+
|
53
|
+
def modifying_user_label
|
54
|
+
'Modifying User: '.colorize(:magenta)
|
55
|
+
end
|
56
|
+
|
57
|
+
def pdf_link_label
|
58
|
+
'Download pdf: '.colorize(:magenta)
|
59
|
+
end
|
60
|
+
|
61
|
+
def docx_link_label
|
62
|
+
'Download docx: '.colorize(:magenta)
|
63
|
+
end
|
64
|
+
|
65
|
+
def txt_link_label
|
66
|
+
'Download txt: '.colorize(:magenta)
|
67
|
+
end
|
68
|
+
|
69
|
+
def puts_download_links(revision)
|
70
|
+
puts pdf_link_label + "#{revision['exportLinks'][pdf]}"
|
71
|
+
puts docx_link_label + "#{revision['exportLinks'][docx]}"
|
72
|
+
puts txt_link_label + "#{revision['exportLinks'][txt]}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def puts_revision_info(revision)
|
76
|
+
puts revision_id_label + "#{revision['id']}"
|
77
|
+
puts modified_date_label + "#{revision['modifiedDate']}"
|
78
|
+
puts modifying_user_label + "#{revision['lastModifyingUserName']}"
|
79
|
+
puts_download_links
|
80
|
+
puts ''
|
81
|
+
end
|
82
|
+
|
83
|
+
def execute
|
84
|
+
return if revisions.nil?
|
85
|
+
|
86
|
+
puts_banner
|
87
|
+
revisions.each do |r|
|
88
|
+
puts_revision_info(r)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def txt_link(revision)
|
93
|
+
rev = revisions.select { |r| r['id'] == revision }
|
94
|
+
# should only have one element if revision exists
|
95
|
+
rev.first['exportLinks'][txt] unless rev.empty?
|
96
|
+
end
|
97
|
+
|
98
|
+
def modifying_users
|
99
|
+
modifying_hash = {}
|
100
|
+
revisions.each do |r|
|
101
|
+
modifying_hash[r['id']] = r['lastModifyingUserName']
|
102
|
+
end
|
103
|
+
modifying_hash
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/gdsh/quit.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'commands'
|
2
|
+
|
3
|
+
module Commands
|
4
|
+
##
|
5
|
+
# Quit command.
|
6
|
+
#
|
7
|
+
class Quit < Command
|
8
|
+
def self.command_name
|
9
|
+
'quit'
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.function
|
13
|
+
'Exit the application.'
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.terminal?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/gdsh/remove.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative 'commands'
|
2
|
+
|
3
|
+
module Commands
|
4
|
+
class Remove < Command
|
5
|
+
def self.command_name
|
6
|
+
'rm'
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.parameters
|
10
|
+
'(<file_id>)'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.function
|
14
|
+
'Removes the file.'
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(client, params)
|
18
|
+
super(client, params)
|
19
|
+
@file_id = @params[1]
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute
|
23
|
+
drive = @client.discovered_api('drive', 'v2')
|
24
|
+
result = @client.execute(
|
25
|
+
api_method: drive.files.trash,
|
26
|
+
parameters: { fileId: @file_id })
|
27
|
+
if result.status != 200
|
28
|
+
puts drive_error_string
|
29
|
+
else
|
30
|
+
puts 'Deleted.'.colorize(:green)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'differ'
|
2
|
+
|
3
|
+
require_relative 'commands'
|
4
|
+
require_relative 'get_file'
|
5
|
+
|
6
|
+
module Commands
|
7
|
+
##
|
8
|
+
# Summarizes changes between revisions
|
9
|
+
#
|
10
|
+
class RevisionDiff < GetFile
|
11
|
+
def self.command_name
|
12
|
+
'diff'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.parameters
|
16
|
+
'(<file_id>[, <rev_1>, <rev_2>])'
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.function
|
20
|
+
'Compares and summarizes the changes between two revisions. If no ' \
|
21
|
+
'revision numbers are provided, a consolidated summary is returned.'
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(client, params)
|
25
|
+
super(client, params)
|
26
|
+
init_revisions
|
27
|
+
end
|
28
|
+
|
29
|
+
def init_revisions
|
30
|
+
@low_rev = (@params.length == 4) ? @params[2] : nil
|
31
|
+
@high_rev = (@params.length == 4) ? @params[3] : nil
|
32
|
+
@all = @low_rev.nil? && @high_rev.nil?
|
33
|
+
return if @all || order_is_correct
|
34
|
+
@low_rev, @high_rev = @high_rev, @low_rev
|
35
|
+
end
|
36
|
+
|
37
|
+
def order_is_correct
|
38
|
+
@high_rev.to_i > @low_rev.to_i
|
39
|
+
end
|
40
|
+
|
41
|
+
def consecutive_revisions
|
42
|
+
return unless @all
|
43
|
+
keys = modifying_users.keys.sort_by { |x| x.to_i }
|
44
|
+
len = keys.length
|
45
|
+
keys.first(len - 1).zip(keys.last(len - 1))
|
46
|
+
end
|
47
|
+
|
48
|
+
def compare_two_revs(low, high)
|
49
|
+
first = download_revision_as_txt(low)
|
50
|
+
second = download_revision_as_txt(high)
|
51
|
+
Differ.diff_by_word(first, second)
|
52
|
+
end
|
53
|
+
|
54
|
+
def print_summary_of_changes(changes)
|
55
|
+
puts "#{changes.change_count} words changed, ".colorize(:green) +
|
56
|
+
"#{changes.insert_count} inserts, ".colorize(:green) +
|
57
|
+
"#{changes.delete_count} deletes.".colorize(:green)
|
58
|
+
end
|
59
|
+
|
60
|
+
def compare_and_print_change_count(low, high)
|
61
|
+
changes = compare_two_revs(low, high)
|
62
|
+
print_summary_of_changes(changes)
|
63
|
+
end
|
64
|
+
|
65
|
+
def puts_diff_note
|
66
|
+
puts "Note: 'ab' -> 'ac' counts as both an insert and".colorize(:green) +
|
67
|
+
' a delete but counts as only one change.'.colorize(:green)
|
68
|
+
end
|
69
|
+
|
70
|
+
def diff_author(pair)
|
71
|
+
"From rev #{pair[0]} to rev #{pair[1]} ".colorize(:green) +
|
72
|
+
"modified by #{modifying_users[pair[0]]}".colorize(:green)
|
73
|
+
end
|
74
|
+
|
75
|
+
def execute
|
76
|
+
puts_diff_note
|
77
|
+
if @all
|
78
|
+
consecutive_revisions.each do |pair|
|
79
|
+
puts diff_author(pair)
|
80
|
+
compare_and_print_change_count(pair[0], pair[1])
|
81
|
+
end
|
82
|
+
else
|
83
|
+
compare_and_print_change_count(@low_rev, @high_rev)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|