github_cli 0.3.1 → 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.
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +20 -22
- data/README.md +29 -4
- data/bin/ghc +1 -1
- data/features/download.feature +11 -0
- data/features/email.feature +9 -0
- data/features/errors.feature +10 -0
- data/features/event.feature +14 -0
- data/features/executable.feature +44 -17
- data/features/follower.feature +11 -0
- data/features/fork.feature +13 -0
- data/features/hook.feature +12 -0
- data/features/label.feature +16 -0
- data/features/member.feature +18 -0
- data/features/milestone.feature +11 -0
- data/features/organization.feature +9 -0
- data/features/reference.feature +11 -0
- data/features/repositories.feature +16 -7
- data/features/tag.feature +8 -0
- data/features/team.feature +18 -0
- data/features/tree.feature +8 -0
- data/features/user.feature +8 -0
- data/ghc_logo.png +0 -0
- data/github_cli.gemspec +2 -2
- data/lib/github_cli/api.rb +14 -11
- data/lib/github_cli/apis/follower.rb +40 -0
- data/lib/github_cli/apis/member.rb +52 -0
- data/lib/github_cli/apis/organization.rb +28 -0
- data/lib/github_cli/apis/team.rb +89 -0
- data/lib/github_cli/apis/user.rb +22 -0
- data/lib/github_cli/apis.rb +5 -0
- data/lib/github_cli/cli.rb +11 -4
- data/lib/github_cli/command.rb +40 -28
- data/lib/github_cli/commands/followers.rb +50 -0
- data/lib/github_cli/commands/members.rb +70 -0
- data/lib/github_cli/commands/organizations.rb +42 -0
- data/lib/github_cli/commands/teams.rb +148 -0
- data/lib/github_cli/commands/users.rb +26 -0
- data/lib/github_cli/commands.rb +5 -0
- data/lib/github_cli/editor.rb +27 -0
- data/lib/github_cli/errors.rb +6 -1
- data/lib/github_cli/formatter.rb +47 -0
- data/lib/github_cli/formatters/csv.rb +8 -8
- data/lib/github_cli/formatters/table.rb +237 -11
- data/lib/github_cli/pager.rb +66 -0
- data/lib/github_cli/subcommands.rb +15 -0
- data/lib/github_cli/system.rb +33 -0
- data/lib/github_cli/terminal.rb +60 -30
- data/lib/github_cli/thor_ext.rb +15 -0
- data/lib/github_cli/ui.rb +8 -0
- data/lib/github_cli/util.rb +55 -12
- data/lib/github_cli/version.rb +1 -1
- data/lib/github_cli.rb +3 -0
- data/spec/github_cli/pager_spec.rb +69 -0
- data/spec/github_cli/util_spec.rb +14 -4
- metadata +64 -14
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module GithubCLI
|
4
|
+
# This class determines editor to use to open the output.
|
5
|
+
class Editor
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
end
|
9
|
+
|
10
|
+
def editor
|
11
|
+
editors = [ ENV['GHC_EDITOR'], ENV['VISUAL'], ENV['EDITOR'], 'vi' ]
|
12
|
+
editor = GithubCLI.config['editor']
|
13
|
+
editor ||= editors.find { |e| !e.nil? && !e.empty? }
|
14
|
+
end
|
15
|
+
|
16
|
+
def open(name)
|
17
|
+
if editor
|
18
|
+
command = "#{editor} #{name}"
|
19
|
+
success = system(command)
|
20
|
+
GithubCLI.ui.info "Could not run '#{command}'" unless success
|
21
|
+
else
|
22
|
+
GithubCLI.info("To open output, set $EDITOR or $VISUL")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end # Editor
|
27
|
+
end # GithubCLI
|
data/lib/github_cli/errors.rb
CHANGED
@@ -8,6 +8,10 @@ module GithubCLI
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
+
class ApiError < GithubCLIError
|
12
|
+
status_code 5
|
13
|
+
end
|
14
|
+
|
11
15
|
# Raised when a configuration file is corrupt or missing.
|
12
16
|
class ConfigFileNotFound < GithubCLIError
|
13
17
|
status_code 10
|
@@ -30,8 +34,9 @@ module GithubCLI
|
|
30
34
|
status_code 13
|
31
35
|
|
32
36
|
def initialize(format)
|
33
|
-
super %{Unrecognized formatting options: #{format}
|
37
|
+
super %{Unrecognized formatting options: #{format}}
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
41
|
+
|
37
42
|
end # GithubCLI
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module GithubCLI
|
4
|
+
# This is the main entry point for formatting output.
|
5
|
+
# It delegates to other objects like Formatter::Table
|
6
|
+
# to perform actual rendering.
|
7
|
+
class Formatter
|
8
|
+
attr_reader :response, :format
|
9
|
+
|
10
|
+
def initialize(response, options={})
|
11
|
+
@response = response
|
12
|
+
@format = options[:format]
|
13
|
+
end
|
14
|
+
|
15
|
+
def render_output
|
16
|
+
render_status
|
17
|
+
Terminal.paged_output
|
18
|
+
determine_output_formatter
|
19
|
+
end
|
20
|
+
|
21
|
+
def determine_output_formatter
|
22
|
+
case format.to_s
|
23
|
+
when 'table', /table:v.*/, /table:h.*/
|
24
|
+
formatter = Formatters::Table.new(response,
|
25
|
+
:transform => format.to_s.split(':').last
|
26
|
+
)
|
27
|
+
formatter.format
|
28
|
+
when 'csv'
|
29
|
+
formatter = Formatters::CSV.new(response)
|
30
|
+
formatter.format
|
31
|
+
when 'json'
|
32
|
+
'json output'
|
33
|
+
else
|
34
|
+
raise UnknownFormatError, format
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Render status code
|
39
|
+
def render_status
|
40
|
+
if response.respond_to? :status
|
41
|
+
Terminal.line "Response Status: #{response.status}\n"
|
42
|
+
Terminal.newline
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end # Formatter
|
47
|
+
end # GithubCLi
|
@@ -14,24 +14,24 @@ module GithubCLI
|
|
14
14
|
render_headers @response.first
|
15
15
|
@response.each_with_index do |item, indx|
|
16
16
|
render_line indx, item
|
17
|
-
|
17
|
+
Terminal.newline
|
18
18
|
end
|
19
|
-
|
19
|
+
when Hash
|
20
20
|
render_headers @response
|
21
21
|
render_line 1, @response
|
22
|
+
else
|
23
|
+
Terminal.line "#{@response}\n"
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
27
|
def render_headers(response)
|
26
|
-
output =
|
27
|
-
|
28
|
-
puts "Index," + output.keys.join(',')
|
28
|
+
output = GithubCLI::Util.flatten_hash(response.to_hash)
|
29
|
+
Terminal.line "Index,#{output.keys.join(',')}\n"
|
29
30
|
end
|
30
31
|
|
31
32
|
def render_line(index, item)
|
32
|
-
output =
|
33
|
-
|
34
|
-
printf "%d,%s", index, output.values.join(',')
|
33
|
+
output = GithubCLI::Util.flatten_hash(item.to_hash)
|
34
|
+
$stdout.printf "%d,%s", index, output.values.join(',')
|
35
35
|
end
|
36
36
|
|
37
37
|
end # CSV
|
@@ -1,34 +1,260 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require 'ostruct'
|
4
|
+
require 'forwardable'
|
5
|
+
|
3
6
|
module GithubCLI
|
4
7
|
module Formatters
|
5
8
|
class Table
|
9
|
+
include GithubCLI::Util
|
10
|
+
include Enumerable
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
OPTIONS = {
|
14
|
+
:border => {
|
15
|
+
'top' => '━',
|
16
|
+
'top_mid' => '┳',
|
17
|
+
'top_left' => '┏',
|
18
|
+
'top_right' => '┓',
|
19
|
+
'bottom' => '━',
|
20
|
+
'bottom_mid' => '┻',
|
21
|
+
'bottom_left' => '┗',
|
22
|
+
'bottom_right' => '┛',
|
23
|
+
'left' => '┃',
|
24
|
+
'left_mid' => '┣',
|
25
|
+
'mid' => '━',
|
26
|
+
'mid_mid' => '╋',
|
27
|
+
'right' => '┃',
|
28
|
+
'right_mid' => '┫'
|
29
|
+
},
|
30
|
+
:truncate => '…',
|
31
|
+
:style => {
|
32
|
+
:padding_left => 1,
|
33
|
+
:padding_right => 1,
|
34
|
+
:align => :left,
|
35
|
+
:head => ['cyan'],
|
36
|
+
:compact => false
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
attr_reader :response, :transform, :output_array, :total_records
|
41
|
+
|
42
|
+
# Subset of safe methods that both Array and Hash implement
|
43
|
+
def_delegators(:@output_array, :[], :assoc, :each, :empty?, :flatten,
|
44
|
+
:include?, :index, :inspect, :length, :select, :size, :to_a, :values_at,
|
45
|
+
:pretty_print, :rassoc)
|
46
|
+
|
47
|
+
def initialize(response, options={})
|
48
|
+
@total_records = 1
|
49
|
+
@transform = determine_layout(options[:transform])
|
50
|
+
@response = response
|
51
|
+
@output_array = build_output
|
52
|
+
end
|
53
|
+
|
54
|
+
def determine_layout(layout)
|
55
|
+
( !layout.nil? && layout.index('h') ) ? :horizontal : :vertical
|
56
|
+
end
|
6
57
|
|
7
|
-
def
|
8
|
-
|
58
|
+
def options
|
59
|
+
OPTIONS
|
60
|
+
end
|
61
|
+
|
62
|
+
def border
|
63
|
+
OpenStruct.new OPTIONS[:border]
|
64
|
+
end
|
65
|
+
|
66
|
+
def style
|
67
|
+
OpenStruct.new OPTIONS[:style]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Builds output array from response hash
|
71
|
+
#
|
72
|
+
def build_output
|
73
|
+
case response
|
74
|
+
when Array
|
75
|
+
case transform
|
76
|
+
when :horizontal
|
77
|
+
array = [flatten_hash(response[0].to_hash).keys]
|
78
|
+
response.each do |item|
|
79
|
+
array << convert_values(flatten_hash(item.to_hash).values)
|
80
|
+
end
|
81
|
+
array
|
82
|
+
when :vertical
|
83
|
+
response.inject([]) do |array, item|
|
84
|
+
output = flatten_hash(item.to_hash)
|
85
|
+
rows = output.keys.zip(convert_values(output.values))
|
86
|
+
rows.each {|row| array << row }
|
87
|
+
@total_records = rows.size
|
88
|
+
array
|
89
|
+
end
|
90
|
+
end
|
91
|
+
when Hash
|
92
|
+
output = flatten_hash(response)
|
93
|
+
case transform
|
94
|
+
when :horizontal
|
95
|
+
array = [output.keys]
|
96
|
+
array << convert_values(output.values)
|
97
|
+
when :vertical
|
98
|
+
output.keys.zip(convert_values(output.values))
|
99
|
+
end
|
100
|
+
else
|
101
|
+
[response]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def column_widths
|
106
|
+
@column_widths ||= begin
|
107
|
+
array = case transform
|
108
|
+
when :horizontal
|
109
|
+
field_len = (
|
110
|
+
(Terminal.width - (output_array[0].size)).to_f / output_array[0].size.to_f
|
111
|
+
).round
|
112
|
+
Array.new(output_array[0].size, field_len)
|
113
|
+
when :vertical
|
114
|
+
start = 0
|
115
|
+
maximas = []
|
116
|
+
colcount = output_array.max{ |a,b| a.size <=> b.size }.size
|
117
|
+
|
118
|
+
start.upto(colcount - 1) do |index|
|
119
|
+
maxima = output_array.map do |row|
|
120
|
+
row[index] ? (style.padding_left+ row[index].to_s.size + style.padding_right) : 0
|
121
|
+
end.max
|
122
|
+
maximas << maxima
|
123
|
+
end
|
124
|
+
maximas
|
125
|
+
end
|
126
|
+
array
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def column_width(index)
|
131
|
+
width = column_widths[index] || 0
|
132
|
+
end
|
133
|
+
|
134
|
+
def columns
|
135
|
+
column_widths.size
|
136
|
+
end
|
137
|
+
|
138
|
+
def total_width
|
139
|
+
column_widths.reduce(0, :+).round + column_widths.size + border.right.length
|
9
140
|
end
|
10
141
|
|
11
142
|
def format
|
12
|
-
case
|
143
|
+
case response
|
13
144
|
when Array
|
14
|
-
|
15
|
-
|
16
|
-
|
145
|
+
render_top_line
|
146
|
+
output_array.each_with_index do |row, indx|
|
147
|
+
render_row row
|
148
|
+
if (output_array.size - 1 != indx) && ((indx + 1) % total_records == 0)
|
149
|
+
render_middle_line
|
150
|
+
end
|
151
|
+
end
|
152
|
+
render_bottom_line
|
153
|
+
when Hash
|
154
|
+
render_top_line
|
155
|
+
output_array.each_with_index do |row, indx|
|
156
|
+
render_row row
|
157
|
+
if transform == :horizontal && output_array.size - 1 != indx
|
158
|
+
render_middle_line
|
159
|
+
end
|
17
160
|
end
|
161
|
+
render_bottom_line
|
18
162
|
else
|
19
|
-
|
163
|
+
Terminal.line "#{response}\n"
|
20
164
|
end
|
21
165
|
end
|
22
166
|
|
23
167
|
def render_vertical(item)
|
24
|
-
output =
|
25
|
-
GithubCLI::Util.flatten_hash(item.to_hash, output)
|
168
|
+
output = GithubCLI::Util.flatten_hash(item.to_hash)
|
26
169
|
GithubCLI.ui.print_table(
|
27
|
-
output.keys.zip(GithubCLI::Util.convert_values(output.values))
|
170
|
+
output.keys.zip(GithubCLI::Util.convert_values(output.values)),
|
171
|
+
:truncate => true
|
172
|
+
)
|
173
|
+
end
|
174
|
+
|
175
|
+
def render_horizontal(item)
|
176
|
+
output = GithubCLI::Util.flatten_hash(item.to_hash)
|
177
|
+
GithubCLI.ui.print_table(
|
178
|
+
[GithubCLI::Util.convert_values(output.values)],
|
179
|
+
:truncate => true
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
def render_line(line, left, right, intersection)
|
184
|
+
line = left + (line * (total_width - 2)) + right
|
185
|
+
width = 0
|
186
|
+
|
187
|
+
column_widths.each_with_index do |col_width, indx|
|
188
|
+
# Skip last column
|
189
|
+
if indx != (column_widths.size - 1)
|
190
|
+
width += col_width + 1
|
191
|
+
line = line[0...width] + intersection + line[width+1..-1]
|
192
|
+
else
|
193
|
+
width += col_width - 1
|
194
|
+
line = line[0...width] + right
|
195
|
+
end
|
196
|
+
end
|
197
|
+
Terminal.line line + "\n"
|
198
|
+
end
|
199
|
+
|
200
|
+
def render_top_line
|
201
|
+
render_line(
|
202
|
+
border.top,
|
203
|
+
border.top_left || border.top,
|
204
|
+
border.top_right || border.top,
|
205
|
+
border.top_mid
|
28
206
|
)
|
29
207
|
end
|
30
208
|
|
31
|
-
def
|
209
|
+
def render_middle_line
|
210
|
+
render_line(
|
211
|
+
border.mid,
|
212
|
+
border.left_mid || border.mid,
|
213
|
+
border.right_mid || border.mid,
|
214
|
+
border.mid_mid
|
215
|
+
)
|
216
|
+
end
|
217
|
+
|
218
|
+
def render_bottom_line
|
219
|
+
render_line(
|
220
|
+
border.bottom,
|
221
|
+
border.bottom_left || border.bottom,
|
222
|
+
border.bottom_right || border.top,
|
223
|
+
border.bottom_mid
|
224
|
+
)
|
225
|
+
end
|
226
|
+
|
227
|
+
def render_cell(field, indx)
|
228
|
+
width = column_widths[indx] -
|
229
|
+
(style.padding_left || 0) -
|
230
|
+
(style.padding_right || 0)
|
231
|
+
|
232
|
+
if (indx == (column_widths.size - 1))
|
233
|
+
# Don't output 2 trailing spaces when printing last column
|
234
|
+
width = width - 2 if width > 3 # Ensure sensible width
|
235
|
+
end
|
236
|
+
field = if field.length == width
|
237
|
+
field
|
238
|
+
elsif field.length < width
|
239
|
+
pad(field.to_s, width, :align => style.align)
|
240
|
+
else
|
241
|
+
truncate(field.to_s, width)
|
242
|
+
end
|
243
|
+
|
244
|
+
string = ''
|
245
|
+
string << ' ' * (style.padding_left || 0)
|
246
|
+
string << "#{field}"
|
247
|
+
string << ' ' * (style.padding_right || 0)
|
248
|
+
string << "#{border.right}"
|
249
|
+
string
|
250
|
+
end
|
251
|
+
|
252
|
+
def render_row(fields, options={})
|
253
|
+
columns = []
|
254
|
+
fields.each_with_index do |field, indx|
|
255
|
+
columns << render_cell(field, indx)
|
256
|
+
end
|
257
|
+
Terminal.line border.left + columns.join + "\n"
|
32
258
|
end
|
33
259
|
|
34
260
|
end # Table
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module GithubCLI
|
4
|
+
# This class provides pagining of terminal output.
|
5
|
+
class Pager
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def pager_command(*cmds)
|
9
|
+
@pager_command = (!@pager_command.nil? && cmds.empty?) || begin
|
10
|
+
commands = [
|
11
|
+
ENV['GIT_PAGER'], `git config --get-all core.pager`.split.first,
|
12
|
+
ENV['PAGER'], 'less -isr', 'more', 'cat', 'pager'
|
13
|
+
]
|
14
|
+
commands = cmds + commands
|
15
|
+
commands.compact.uniq.find { |cmd| System.command? cmd }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Indicates if pager is enabled
|
20
|
+
def enabled?
|
21
|
+
@enabled && true
|
22
|
+
end
|
23
|
+
|
24
|
+
def enable
|
25
|
+
@enabled = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def disable
|
29
|
+
@enabled = false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(options={})
|
34
|
+
@pager_command = options[:pager_command] if options[:pager_command]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Pages output using configured pager.
|
38
|
+
def page
|
39
|
+
return if not $stdout.tty? or System.windows?
|
40
|
+
|
41
|
+
read_io, write_io = IO.pipe
|
42
|
+
|
43
|
+
if Kernel.fork
|
44
|
+
$stdin.reopen(read_io)
|
45
|
+
read_io.close
|
46
|
+
write_io.close
|
47
|
+
|
48
|
+
# Don't page if the input is short enough
|
49
|
+
ENV['LESS'] = 'FSRX'
|
50
|
+
|
51
|
+
# Wait until we have input before we start the pager
|
52
|
+
Kernel.select [$stdin]
|
53
|
+
|
54
|
+
pager = Pager.pager_command
|
55
|
+
|
56
|
+
Kernel.exec pager rescue Kernel.exec "/bin/sh", "-c", pager
|
57
|
+
else
|
58
|
+
# Child process
|
59
|
+
$stdout.reopen(write_io)
|
60
|
+
$stderr.reopen(write_io) if $stderr.tty?
|
61
|
+
write_io.close
|
62
|
+
read_io.close
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end # System
|
66
|
+
end # GithubCLI
|
@@ -24,6 +24,9 @@ module GithubCLI
|
|
24
24
|
desc "event <command>", "Leverage Events API"
|
25
25
|
subcommand "event", GithubCLI::Commands::Events
|
26
26
|
|
27
|
+
desc "follower <command>", "Leverage Followers API"
|
28
|
+
subcommand "follower", GithubCLI::Commands::Followers
|
29
|
+
|
27
30
|
desc "fork <command>", "Leverage Forks API"
|
28
31
|
subcommand "fork", GithubCLI::Commands::Forks
|
29
32
|
|
@@ -42,9 +45,15 @@ module GithubCLI
|
|
42
45
|
desc "label <command>", "Leverage Labels API"
|
43
46
|
subcommand "label", GithubCLI::Commands::Labels
|
44
47
|
|
48
|
+
desc "member <command>", "Leverage Members API"
|
49
|
+
subcommand "member", GithubCLI::Commands::Members
|
50
|
+
|
45
51
|
desc "milestone <command>", "Leverage Milestones API"
|
46
52
|
subcommand "milestone", GithubCLI::Commands::Milestones
|
47
53
|
|
54
|
+
desc "org <command>", "Leverage Organizations API"
|
55
|
+
subcommand "org", GithubCLI::Commands::Organizations
|
56
|
+
|
48
57
|
desc "pull <command>", "Leverage Pull Requests API"
|
49
58
|
subcommand "pull", GithubCLI::Commands::PullRequests
|
50
59
|
|
@@ -57,9 +66,15 @@ module GithubCLI
|
|
57
66
|
desc "tag <command>", "Leverage Tags API"
|
58
67
|
subcommand "tag", GithubCLI::Commands::Tags
|
59
68
|
|
69
|
+
desc "team <command>", "Leverage Teams API"
|
70
|
+
subcommand "team", GithubCLI::Commands::Teams
|
71
|
+
|
60
72
|
desc "tree <command>", "Leverage Trees API"
|
61
73
|
subcommand "tree", GithubCLI::Commands::Trees
|
62
74
|
|
75
|
+
desc "user <command>", "Leverage Users API"
|
76
|
+
subcommand "user", GithubCLI::Commands::Users
|
77
|
+
|
63
78
|
desc "watch <command>", "Leverage Watching API"
|
64
79
|
subcommand "watch", GithubCLI::Commands::Watching
|
65
80
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module GithubCLI
|
4
|
+
# This class provides methods for reading system settings.
|
5
|
+
class System
|
6
|
+
class << self
|
7
|
+
|
8
|
+
# Checks if windows platform.
|
9
|
+
def windows?
|
10
|
+
require 'rbconfig'
|
11
|
+
RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw|windows/
|
12
|
+
end
|
13
|
+
|
14
|
+
# Finds executable in $PATH.
|
15
|
+
def which(command)
|
16
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
17
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
18
|
+
exts.each do |ext|
|
19
|
+
exe = "#{path}/#{command}#{ext}"
|
20
|
+
return exe if File.executable? exe
|
21
|
+
end
|
22
|
+
end
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# Checks if command exists.
|
27
|
+
def command?(name)
|
28
|
+
!which(name).nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end # System
|
33
|
+
end # GithubCLI
|
data/lib/github_cli/terminal.rb
CHANGED
@@ -3,38 +3,44 @@
|
|
3
3
|
module GithubCLI
|
4
4
|
# Responsible for display and size detection.
|
5
5
|
class Terminal
|
6
|
-
DEFAULT_WIDTH
|
6
|
+
DEFAULT_WIDTH = 80
|
7
7
|
DEFAULT_HEIGHT = 40
|
8
8
|
|
9
9
|
class << self
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
formatter.format
|
18
|
-
when 'csv'
|
19
|
-
formatter = Formatters::CSV.new(response)
|
20
|
-
formatter.format
|
21
|
-
when 'json'
|
22
|
-
'json output'
|
23
|
-
else
|
24
|
-
raise UnknownFormatError, options[:format]
|
25
|
-
end
|
10
|
+
|
11
|
+
def default_width
|
12
|
+
DEFAULT_WIDTH
|
13
|
+
end
|
14
|
+
|
15
|
+
def width
|
16
|
+
GithubCLI.ui.terminal_width
|
26
17
|
end
|
27
18
|
|
28
|
-
|
29
|
-
|
30
|
-
puts "Response Status: #{response.status}"
|
31
|
-
puts
|
19
|
+
def line(text)
|
20
|
+
$stdout.print text
|
32
21
|
end
|
33
22
|
|
34
|
-
def
|
23
|
+
def newline
|
24
|
+
$stdout.print "\n"
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def paged_output
|
29
|
+
if Pager.enabled?
|
30
|
+
pager.page
|
31
|
+
true
|
32
|
+
else
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def pager
|
38
|
+
@pager ||= Pager.new
|
35
39
|
end
|
36
40
|
|
37
41
|
def print_commands(pattern=nil)
|
42
|
+
Terminal.line "\n" + GithubCLI.program_name + "\n"
|
43
|
+
Terminal.newline
|
38
44
|
GithubCLI.ui.info "Commands:"
|
39
45
|
|
40
46
|
commands = Command.all.select do |cmd|
|
@@ -63,23 +69,47 @@ module GithubCLI
|
|
63
69
|
GithubCLI.ui.info "ghc: '#{cmd}' is not a ghc command. See 'ghc --help'."
|
64
70
|
end
|
65
71
|
|
66
|
-
def
|
72
|
+
def print_usage(flags, command='<command>')
|
67
73
|
GithubCLI.ui.info <<-TEXT
|
68
74
|
|
69
|
-
|
75
|
+
#{GithubCLI.program_name}
|
76
|
+
|
77
|
+
Usage: ghc #{format_usage(flags, command, :indent => 11)}
|
70
78
|
|
71
79
|
TEXT
|
72
80
|
end
|
73
81
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
82
|
+
# Options
|
83
|
+
# indent - Indent the line with by indent value. Assumes that the first
|
84
|
+
# the first line is already filled in with other padding.
|
85
|
+
# length - Line length, otherwise the default terminal width is assumed.
|
86
|
+
def format_usage(flags, command, options={})
|
87
|
+
synopsis = "#{flags} #{command} <subcommand> [<args>]"
|
88
|
+
indent = options[:indent] || 0
|
89
|
+
padding = sprintf("%#{indent}s",'')
|
90
|
+
length = options[:length] || default_width
|
91
|
+
wrap synopsis, length, indent, padding
|
92
|
+
end
|
79
93
|
|
80
|
-
|
94
|
+
# Wraps text at the given line length using given indent value.
|
95
|
+
def wrap(text, length, indent=0, padding=0)
|
96
|
+
if text.length > length - indent
|
97
|
+
paragraphs = []
|
98
|
+
line = ''
|
99
|
+
text.split(/\s+/).map(&:chomp).reject(&:empty?).each do |fragment|
|
100
|
+
if line.length < length - indent
|
101
|
+
line << fragment + ' '
|
102
|
+
else
|
103
|
+
paragraphs << line
|
104
|
+
line = padding + fragment + ' '
|
105
|
+
end
|
106
|
+
end
|
107
|
+
paragraphs << line
|
108
|
+
text = paragraphs.join("\n")
|
81
109
|
end
|
110
|
+
text
|
82
111
|
end
|
112
|
+
|
83
113
|
end
|
84
114
|
|
85
115
|
end # Terminal
|
data/lib/github_cli/thor_ext.rb
CHANGED
@@ -12,12 +12,27 @@ class Thor
|
|
12
12
|
end
|
13
13
|
list.sort!{ |a,b| a[0] <=> b[0] }
|
14
14
|
|
15
|
+
GithubCLI::Terminal.print_usage global_flags, GithubCLI::Command.command_to_show(list[0][0])
|
16
|
+
|
15
17
|
shell.say "Commands:"
|
16
18
|
shell.print_table(list, :indent => 2, :truncate => true)
|
17
19
|
shell.say
|
18
20
|
class_options_help(shell)
|
19
21
|
end
|
20
22
|
|
23
|
+
# String representation of all available global flags
|
24
|
+
def global_flags
|
25
|
+
return if class_options.empty?
|
26
|
+
|
27
|
+
all_options = ''
|
28
|
+
class_options.each do |key, val|
|
29
|
+
all_options << '[' + val.switch_name
|
30
|
+
all_options << (!val.aliases.empty? ? ('|' + val.aliases.join('|')) : '')
|
31
|
+
all_options << '] '
|
32
|
+
end
|
33
|
+
all_options
|
34
|
+
end
|
35
|
+
|
21
36
|
def subcommand_help(cmd)
|
22
37
|
desc "help <command>", "Describe subcommands or one specific subcommand"
|
23
38
|
class_eval <<-RUBY
|