fjords 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +14 -0
- data/Rakefile +2 -0
- data/bin/fjords +4 -0
- data/fjords.gemspec +22 -0
- data/lib/fjords/cli/core.rb +459 -0
- data/lib/fjords/cli/runner.rb +176 -0
- data/lib/fjords/cli/usage.rb +57 -0
- data/lib/fjords/version.rb +3 -0
- data/lib/fjords.rb +11 -0
- metadata +126 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem "fjords-client", :path => '~/Sites/fjords/fjords-client'
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in fjords.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
group :development do
|
9
|
+
gem "rake"
|
10
|
+
gem "webmock"
|
11
|
+
gem "rspec"
|
12
|
+
gem "cucumber"
|
13
|
+
gem "aruba"
|
14
|
+
end
|
data/Rakefile
ADDED
data/bin/fjords
ADDED
data/fjords.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/fjords/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Thomas Reynolds"]
|
6
|
+
gem.email = ["me@tdreyno.com"]
|
7
|
+
gem.description = %q{Fjords.cc CLI}
|
8
|
+
gem.summary = %q{Fjords.cc CLI}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "fjords"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Fjords::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency("interact", "0.5.1")
|
19
|
+
gem.add_dependency("highline")
|
20
|
+
gem.add_dependency("progress_bar")
|
21
|
+
gem.add_dependency("fjords-client", "1.0.1")
|
22
|
+
end
|
@@ -0,0 +1,459 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'shellwords'
|
3
|
+
require 'fjords-client'
|
4
|
+
require "highline/import"
|
5
|
+
require 'progress_bar'
|
6
|
+
|
7
|
+
# require "rbconfig"
|
8
|
+
# WINDOWS = !!(RbConfig::CONFIG['host_os'] =~ /mingw|mswin32|cygwin/)
|
9
|
+
|
10
|
+
class Fjords::Cli::Core
|
11
|
+
include Fjords::Cli::Runner
|
12
|
+
include Fjords::Cli::Usage
|
13
|
+
# include Interactive
|
14
|
+
# disable_rewind
|
15
|
+
|
16
|
+
def version
|
17
|
+
return if @help_only
|
18
|
+
say "fjords #{Fjords::VERSION}"
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def help
|
23
|
+
say command_usage
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
27
|
+
def signup
|
28
|
+
return if @help_only
|
29
|
+
|
30
|
+
puts
|
31
|
+
say "This process will create a new account for you."
|
32
|
+
say "Signup requires a valid US credit card which will"
|
33
|
+
say "be charged at a rate of $6 USD per month for basic"
|
34
|
+
say "service. Let's get started."
|
35
|
+
puts
|
36
|
+
|
37
|
+
username = get_unique_username
|
38
|
+
email = ask "Email: "
|
39
|
+
|
40
|
+
password = ask("Password: ") { |q| q.echo = "*" }
|
41
|
+
confirmed_password = ask("Confirm Password: ") { |q| q.echo = "*" }
|
42
|
+
|
43
|
+
if password != confirmed_password
|
44
|
+
say "Passwords do not match"
|
45
|
+
end
|
46
|
+
|
47
|
+
puts
|
48
|
+
say "Great! Now let's get your credit card information."
|
49
|
+
puts
|
50
|
+
|
51
|
+
stripe_token = get_credit_card_information
|
52
|
+
|
53
|
+
say "Creating account..."
|
54
|
+
|
55
|
+
begin
|
56
|
+
Fjords::Client.signup(email, username, password, stripe_token.id)
|
57
|
+
|
58
|
+
say "Success! Your account is ready and you have been logged-in."
|
59
|
+
rescue TooManyConnections
|
60
|
+
say "Sorry, we've reached our max users for this beta period. We're growing slowly, but surely."
|
61
|
+
end
|
62
|
+
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
def sites
|
67
|
+
return if @help_only
|
68
|
+
require_login!
|
69
|
+
|
70
|
+
sites = Fjords::Client.sites
|
71
|
+
|
72
|
+
if sites.length > 0
|
73
|
+
rows = sites.map do |site|
|
74
|
+
cost = "$#{(site['cost'] / 100.00).to_i}"
|
75
|
+
domain = site['internal_name']
|
76
|
+
domain = site['custom_name'] if site['custom_name'] != domain
|
77
|
+
|
78
|
+
d = DateTime.parse(site['created_at'])
|
79
|
+
[
|
80
|
+
domain,
|
81
|
+
site['type'],
|
82
|
+
cost,
|
83
|
+
site['type'] === 'temporary' ? time_to_expiry(d.to_time.to_i + (60 * 60 * 24 * 30)) : 'never'
|
84
|
+
]
|
85
|
+
end
|
86
|
+
|
87
|
+
rows.unshift ["Domain", "Type", "Cost", "Expires"]
|
88
|
+
puts
|
89
|
+
print_table(rows, :indent => 2)
|
90
|
+
else
|
91
|
+
say "You don't currently have any sites."
|
92
|
+
end
|
93
|
+
|
94
|
+
true
|
95
|
+
end
|
96
|
+
|
97
|
+
def info
|
98
|
+
return if @help_only
|
99
|
+
require_login!
|
100
|
+
|
101
|
+
info = Fjords::Client.info
|
102
|
+
a = info["account"]
|
103
|
+
u = info["user"]
|
104
|
+
|
105
|
+
puts
|
106
|
+
print_table([
|
107
|
+
["Username:", u["username"]],
|
108
|
+
["Email:", u["email"]],
|
109
|
+
["Total Cost:", "$#{(a['current_price'] / 100.00).to_i} USD per month"]
|
110
|
+
], :indent => 2)
|
111
|
+
|
112
|
+
puts
|
113
|
+
say "For site information, see: fjords sites"
|
114
|
+
|
115
|
+
true
|
116
|
+
end
|
117
|
+
|
118
|
+
def push
|
119
|
+
return if @help_only
|
120
|
+
require_login!
|
121
|
+
|
122
|
+
path = File.expand_path(@options[:path] || Dir.pwd)
|
123
|
+
domain_file = @options[:domain_file] || "Fjordsfile"
|
124
|
+
full_domain_file_path = File.expand_path(domain_file, path)
|
125
|
+
|
126
|
+
overwrite = @options[:overwrite] || false
|
127
|
+
permanent = @options[:permanent] || nil
|
128
|
+
|
129
|
+
domain = if @options[:domain]
|
130
|
+
@options[:domain]
|
131
|
+
else
|
132
|
+
if File.exists?(full_domain_file_path)
|
133
|
+
overwrite = true
|
134
|
+
File.read(full_domain_file_path).chomp
|
135
|
+
else
|
136
|
+
nil
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
if domain
|
141
|
+
valid = Fjords::Client.validate_domain(domain)
|
142
|
+
if valid === false
|
143
|
+
say "The domain #{domain} is already taken by another account."
|
144
|
+
exit(0)
|
145
|
+
elsif !overwrite && valid["site"]["exists"]
|
146
|
+
unless agree("A site is already live at this domain. Overwrite?")
|
147
|
+
exit(0)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
puts
|
153
|
+
say "Preparing to push: #{path}"
|
154
|
+
|
155
|
+
begin
|
156
|
+
zipfile, changeless, filesize = Fjords::Client.prepare_push(path, valid, domain_file)
|
157
|
+
rescue Fjords::Client::UploadTooLarge
|
158
|
+
say "Sorry, sites cannot be over 50M in size."
|
159
|
+
exit(0)
|
160
|
+
rescue Fjords::Client::NothingToUpload
|
161
|
+
say "There are no changes to push. Checksums match live site."
|
162
|
+
exit(0)
|
163
|
+
end
|
164
|
+
|
165
|
+
say "Compressed site down to #{filesize}"
|
166
|
+
say "Pushing..."
|
167
|
+
|
168
|
+
# seen_log_messages = {}
|
169
|
+
|
170
|
+
if !@options[:no_progress]
|
171
|
+
bar = ::ProgressBar.new(100, :bar, :percentage)
|
172
|
+
end
|
173
|
+
|
174
|
+
first_progress = true
|
175
|
+
|
176
|
+
last_uploaded = 0
|
177
|
+
|
178
|
+
site = Fjords::Client.push(zipfile, changeless, domain, permanent) do |data|
|
179
|
+
# data["site_logs"].each do |log|
|
180
|
+
# if !seen_log_messages[log["id"]]
|
181
|
+
# seen_log_messages[log["id"]] = log
|
182
|
+
# say "* #{log["message"]}"
|
183
|
+
# end
|
184
|
+
# end
|
185
|
+
if first_progress
|
186
|
+
puts
|
187
|
+
say "Deploying..."
|
188
|
+
first_progress = false
|
189
|
+
end
|
190
|
+
|
191
|
+
if !@options[:no_progress] && data["percentage_uploaded"] > last_uploaded
|
192
|
+
bar.count = data["percentage_uploaded"]
|
193
|
+
bar.write
|
194
|
+
last_uploaded = data["percentage_uploaded"]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
if !@options[:no_progress] && last_uploaded < 100
|
199
|
+
bar.count = 100
|
200
|
+
bar.write
|
201
|
+
puts
|
202
|
+
end
|
203
|
+
|
204
|
+
puts
|
205
|
+
if site["site"]["dns_mode"] === 'alias'
|
206
|
+
cname = site["site"]["custom_name"]
|
207
|
+
say "Site is now available at: http://#{cname}"
|
208
|
+
say "Make sure your CNAME points to: #{site["site"]["internal_name"]}"
|
209
|
+
# say "Make sure your Nameservers points to us. See: fjords nameservers"
|
210
|
+
else
|
211
|
+
if site["site"]["dns_mode"] === 'random'
|
212
|
+
cname = site["site"]["internal_name"]
|
213
|
+
say %Q{Site is now available at: http://#{site["site"]["internal_name"]}}
|
214
|
+
elsif site["site"]["dns_mode"] === 'cname'
|
215
|
+
cname = site["site"]["custom_name"]
|
216
|
+
say %Q{Site is now available at: http://#{site["site"]["custom_name"]}}
|
217
|
+
if site["site"]["internal_name"] != site["site"]["custom_name"]
|
218
|
+
say "Make sure your CNAME points to: #{site["site"]["internal_name"]}"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
if !File.exists?(full_domain_file_path)
|
224
|
+
say "Writing #{domain_file} for future pushes."
|
225
|
+
|
226
|
+
File.open(full_domain_file_path, 'w') { |f| f.write(cname) }
|
227
|
+
end
|
228
|
+
|
229
|
+
true
|
230
|
+
end
|
231
|
+
|
232
|
+
# def nameservers
|
233
|
+
# return if @help_only
|
234
|
+
|
235
|
+
# puts
|
236
|
+
# say "To setup a root domain, use our nameservers:"
|
237
|
+
# say "* ns1.fjords.cc"
|
238
|
+
# say "* ns2.fjords.cc"
|
239
|
+
# say "* ns3.fjords.cc"
|
240
|
+
# say "* ns4.fjords.cc"
|
241
|
+
|
242
|
+
# true
|
243
|
+
# end
|
244
|
+
|
245
|
+
def login
|
246
|
+
return if @help_only
|
247
|
+
|
248
|
+
if Fjords::Client.logged_in?
|
249
|
+
puts
|
250
|
+
say "Already logged-in"
|
251
|
+
return true
|
252
|
+
end
|
253
|
+
|
254
|
+
puts
|
255
|
+
username = ask "Username: "
|
256
|
+
password = ask("Password: ") { |q| q.echo = "*" }
|
257
|
+
|
258
|
+
begin
|
259
|
+
puts
|
260
|
+
say "Contacting server..."
|
261
|
+
Fjords::Client.login(username, password)
|
262
|
+
|
263
|
+
puts
|
264
|
+
say "Successfully logged in"
|
265
|
+
|
266
|
+
true
|
267
|
+
rescue Fjords::Client::ResourceNotFound => e
|
268
|
+
puts
|
269
|
+
say "Login Failed"
|
270
|
+
exit(0)
|
271
|
+
rescue Fjords::Client::LoginInvalid => e
|
272
|
+
puts
|
273
|
+
say "Login Failed"
|
274
|
+
exit(0)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def logout
|
279
|
+
return if @help_only
|
280
|
+
|
281
|
+
if !Fjords::Client.logged_in?
|
282
|
+
say "Not logged-in"
|
283
|
+
return true
|
284
|
+
end
|
285
|
+
|
286
|
+
Fjords::Client.logout
|
287
|
+
puts
|
288
|
+
say "Logged Out"
|
289
|
+
|
290
|
+
true
|
291
|
+
end
|
292
|
+
|
293
|
+
def bugreport
|
294
|
+
return if @help_only
|
295
|
+
require_login!
|
296
|
+
|
297
|
+
is_ready = agree("Ready to write your bug report? This will open your system $EDITOR: ") { |q| q.default = "yes" }
|
298
|
+
|
299
|
+
if !is_ready
|
300
|
+
exit(0)
|
301
|
+
end
|
302
|
+
|
303
|
+
body = ask_editor("Write your bug report below, then close your editor.\n----------------\n\n")
|
304
|
+
|
305
|
+
if body && !body.nil?
|
306
|
+
attach = @options[:attach] || nil
|
307
|
+
|
308
|
+
puts
|
309
|
+
say "Sending..."
|
310
|
+
Fjords::Client.bugreport(body, attach)
|
311
|
+
true
|
312
|
+
else
|
313
|
+
exit(0)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def remove(domain)
|
318
|
+
return if @help_only
|
319
|
+
require_login!
|
320
|
+
|
321
|
+
puts
|
322
|
+
if Fjords::Client::delete_site(domain)
|
323
|
+
say %Q{Successfully removed site "#{domain}"}
|
324
|
+
true
|
325
|
+
else
|
326
|
+
say %Q{Error: Could not find site "#{domain}" to remove.}
|
327
|
+
exit(0)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
private
|
332
|
+
|
333
|
+
def available_editor(preferred=nil)
|
334
|
+
[preferred, ENV['EDITOR'], 'mate -w', 'vim', 'vi', 'emacs', 'nano', 'pico'].
|
335
|
+
compact.
|
336
|
+
find {|name| system("hash #{name.split.first} 2>&-") }
|
337
|
+
end
|
338
|
+
|
339
|
+
def ask_editor(input=nil, preferred_editor=nil)
|
340
|
+
editor = available_editor preferred_editor
|
341
|
+
tmpfile = Tempfile.new 'fjords-bugreport'
|
342
|
+
begin
|
343
|
+
tmpfile.write input if input
|
344
|
+
tmpfile.close
|
345
|
+
system("#{editor} #{tmpfile.path.shellescape}") ? IO.read(tmpfile.path) : nil
|
346
|
+
ensure
|
347
|
+
tmpfile.unlink
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def print_table(array, options={})
|
352
|
+
return if array.empty?
|
353
|
+
|
354
|
+
formats, indent, colwidth = [], options[:indent].to_i, options[:colwidth]
|
355
|
+
# options[:truncate] = terminal_width if options[:truncate] == true
|
356
|
+
|
357
|
+
formats << "%-#{colwidth + 2}s" if colwidth
|
358
|
+
start = colwidth ? 1 : 0
|
359
|
+
|
360
|
+
colcount = array.max{|a,b| a.size <=> b.size }.size
|
361
|
+
|
362
|
+
maximas = []
|
363
|
+
|
364
|
+
start.upto(colcount - 1) do |index|
|
365
|
+
maxima = array.map {|row| row[index] ? row[index].to_s.size : 0 }.max
|
366
|
+
maximas << maxima
|
367
|
+
if index == colcount - 1
|
368
|
+
# Don't output 2 trailing spaces when printing the last column
|
369
|
+
formats << "%-s"
|
370
|
+
else
|
371
|
+
formats << "%-#{maxima + 2}s"
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
formats[0] = formats[0].insert(0, " " * indent)
|
376
|
+
formats << "%s"
|
377
|
+
|
378
|
+
array.each do |row|
|
379
|
+
sentence = ""
|
380
|
+
|
381
|
+
row.each_with_index do |column, index|
|
382
|
+
maxima = maximas[index]
|
383
|
+
|
384
|
+
if column.is_a?(Numeric)
|
385
|
+
if index == row.size - 1
|
386
|
+
# Don't output 2 trailing spaces when printing the last column
|
387
|
+
f = "%#{maxima}s"
|
388
|
+
else
|
389
|
+
f = "%#{maxima}s "
|
390
|
+
end
|
391
|
+
else
|
392
|
+
f = formats[index]
|
393
|
+
end
|
394
|
+
sentence << f % column.to_s
|
395
|
+
end
|
396
|
+
|
397
|
+
# sentence = truncate(sentence, options[:truncate]) if options[:truncate]
|
398
|
+
say sentence
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
def require_login!
|
403
|
+
if !Fjords::Client.logged_in?
|
404
|
+
puts
|
405
|
+
say "You must login you can run this command:"
|
406
|
+
say "fjords login"
|
407
|
+
puts
|
408
|
+
say "If you do not have an account, create one with:"
|
409
|
+
say "fjords signup"
|
410
|
+
exit(0)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
def get_unique_username
|
415
|
+
username = ask "Desired Username: "
|
416
|
+
|
417
|
+
if Fjords::Client.username_available?(username)
|
418
|
+
username
|
419
|
+
else
|
420
|
+
say "Sorry, that username (#{username}) is already taken. Please try another."
|
421
|
+
get_unique_username
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
def get_credit_card_information
|
426
|
+
name_on_card = ask "Name on Card: "
|
427
|
+
card_number = ask "Card Number: "
|
428
|
+
exp_month = ask "Expiration Month (MM): "
|
429
|
+
exp_year = ask "Expiration Year (YY): "
|
430
|
+
cvc = ask("Security CVC Number: ") { |q| q.echo = "*" }
|
431
|
+
|
432
|
+
puts
|
433
|
+
say "Verifying information..."
|
434
|
+
|
435
|
+
begin
|
436
|
+
Fjords::Client.get_stripe_token(name_on_card, card_number, exp_month, exp_year, cvc)
|
437
|
+
rescue => e
|
438
|
+
puts
|
439
|
+
say "Sorry, there was an error."
|
440
|
+
say e.message
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
def time_to_expiry(from_time)
|
445
|
+
to_time = DateTime.now.to_time.to_i
|
446
|
+
distance_in_minutes = (((from_time - to_time))/60).round
|
447
|
+
|
448
|
+
case distance_in_minutes
|
449
|
+
when 0..1 then distance_in_minutes == 0 ? "in less than a minute" : "in 1 minute"
|
450
|
+
when 2..44 then "in #{distance_in_minutes} minutes"
|
451
|
+
when 45..89 then "in 1 hour"
|
452
|
+
when 90..1439 then "in #{(distance_in_minutes.to_f / 60.0).round} hours"
|
453
|
+
when 1440..2519 then "in 1 day"
|
454
|
+
when 2520..43199 then "in #{(distance_in_minutes.to_f / 1440.0).round} days"
|
455
|
+
else
|
456
|
+
"already expired"
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Fjords::Cli::Runner
|
4
|
+
def initialize(args=[])
|
5
|
+
@args = args
|
6
|
+
@options = {}
|
7
|
+
@exit_status = true
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse_options!
|
11
|
+
opts_parser = OptionParser.new do |opts|
|
12
|
+
opts.banner = "\nAvailable options:\n\n"
|
13
|
+
|
14
|
+
opts.on('--attach ERROR_FILE') { |attach| @options[:attach] = attach }
|
15
|
+
opts.on('--host PATH') { |host| @options[:host] = host }
|
16
|
+
opts.on('--path PATH') { |path| @options[:path] = path }
|
17
|
+
opts.on('--domain DOMAIN') { |domain| @options[:domain] = domain }
|
18
|
+
opts.on('--overwrite') { |overwrite| @options[:overwrite] = overwrite }
|
19
|
+
opts.on('--no-zip') { |no_zip| @options[:no_zip] = !no_zip }
|
20
|
+
opts.on('--no-progress') { |no_progress| @options[:no_progress] = !no_progress }
|
21
|
+
opts.on('--permanent') { |permanent| @options[:permanent] = permanent }
|
22
|
+
opts.on('--domain-file DOMAIN_FILE') { |domain_file| @options[:domain_file] = domain_file }
|
23
|
+
opts.on('-h', '--help') { puts "#{command_usage}\n"; exit }
|
24
|
+
end
|
25
|
+
|
26
|
+
@args = opts_parser.parse!(@args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_command!
|
30
|
+
verb = @args.shift
|
31
|
+
case verb
|
32
|
+
|
33
|
+
when 'help'
|
34
|
+
help if @args.size == 0
|
35
|
+
@help_only = true
|
36
|
+
parse_command!
|
37
|
+
when 'nameservers'
|
38
|
+
usage('fjords nameservers')
|
39
|
+
nameservers
|
40
|
+
when 'sites'
|
41
|
+
usage('fjords sites')
|
42
|
+
sites
|
43
|
+
when 'push'
|
44
|
+
usage('fjords push [--path PATH] [--domain DOMAIN] [--domain-file DOMAIN_FILE]')
|
45
|
+
push
|
46
|
+
when 'login'
|
47
|
+
usage('fjords login')
|
48
|
+
login
|
49
|
+
when 'logout'
|
50
|
+
usage('fjords logout')
|
51
|
+
logout
|
52
|
+
when 'signup'
|
53
|
+
usage('fjords signup')
|
54
|
+
signup
|
55
|
+
when 'remove'
|
56
|
+
usage('fjords remove DOMAIN')
|
57
|
+
remove(@args[0])
|
58
|
+
when 'bugreport'
|
59
|
+
usage('fjords bugreport [--attach ERROR_FILE]')
|
60
|
+
bugreport
|
61
|
+
when 'info'
|
62
|
+
usage('fjords info')
|
63
|
+
info
|
64
|
+
when 'version'
|
65
|
+
usage('fjords version')
|
66
|
+
version
|
67
|
+
else
|
68
|
+
if verb
|
69
|
+
puts "fjords: Unknown command [#{verb}]"
|
70
|
+
puts basic_usage
|
71
|
+
exit(false)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def save_error_report(e)
|
77
|
+
dir = File.expand_path("~/.fjords-errors")
|
78
|
+
|
79
|
+
FileUtils.mkdir_p(dir)
|
80
|
+
|
81
|
+
filename = File.join(dir, "exception-#{Time.now.to_i}.txt")
|
82
|
+
|
83
|
+
File.open(filename, 'w') do |file|
|
84
|
+
file.write("#{e.to_s}\n\n")
|
85
|
+
|
86
|
+
if e.respond_to?(:report_data)
|
87
|
+
file.write(e.report_data.join("\n"))
|
88
|
+
elsif e.respond_to?(:backtrace)
|
89
|
+
file.write(e.backtrace.join("\n"))
|
90
|
+
else
|
91
|
+
file.write("Unknown exception format")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
filename
|
96
|
+
end
|
97
|
+
|
98
|
+
def run
|
99
|
+
trap('TERM') { print "\nTerminated\n"; exit(false)}
|
100
|
+
|
101
|
+
parse_options!
|
102
|
+
|
103
|
+
if @options[:host]
|
104
|
+
Fjords::Client.host = @options[:host]
|
105
|
+
puts "Using API host: #{Fjords::Client.host}"
|
106
|
+
end
|
107
|
+
|
108
|
+
if @options[:no_zip]
|
109
|
+
Fjords::Client.ruby_zip = @options[:no_zip]
|
110
|
+
puts "Using built-in Ruby Zip"
|
111
|
+
end
|
112
|
+
|
113
|
+
begin
|
114
|
+
res = parse_command!
|
115
|
+
rescue Fjords::Client::PreconditionFailed => e
|
116
|
+
puts
|
117
|
+
puts "Error: Your login token has expired. Please login again with: fjords login"
|
118
|
+
exit(0)
|
119
|
+
rescue Fjords::Client::ConnectionRefused => e
|
120
|
+
puts
|
121
|
+
puts "Error: Could not connect to server"
|
122
|
+
exit(0)
|
123
|
+
rescue => e
|
124
|
+
file_name = save_error_report(e)
|
125
|
+
|
126
|
+
puts
|
127
|
+
puts "Sorry, an unexpected error has occured (#{e.to_s})"
|
128
|
+
puts
|
129
|
+
puts "The details of this error have been logged to: "
|
130
|
+
puts " #{file_name}"
|
131
|
+
puts
|
132
|
+
puts "You can report this bug to the developer by running:"
|
133
|
+
puts
|
134
|
+
puts " fjords bugreport --attach=#{file_name}"
|
135
|
+
|
136
|
+
exit(0)
|
137
|
+
end
|
138
|
+
|
139
|
+
if res
|
140
|
+
|
141
|
+
elsif @help_only || @usage
|
142
|
+
display_usage
|
143
|
+
else
|
144
|
+
puts basic_usage
|
145
|
+
exit(false)
|
146
|
+
end
|
147
|
+
|
148
|
+
rescue OptionParser::InvalidOption => e
|
149
|
+
puts(e.message)
|
150
|
+
puts("\n")
|
151
|
+
puts(basic_usage)
|
152
|
+
@exit_status = false
|
153
|
+
rescue OptionParser::AmbiguousOption => e
|
154
|
+
puts(e.message)
|
155
|
+
puts("\n")
|
156
|
+
puts(basic_usage)
|
157
|
+
@exit_status = false
|
158
|
+
rescue SystemExit => e
|
159
|
+
@exit_status = e.success?
|
160
|
+
rescue SyntaxError => e
|
161
|
+
puts e.message
|
162
|
+
puts e.backtrace
|
163
|
+
@exit_status = false
|
164
|
+
rescue Interrupt => e
|
165
|
+
puts("\nInterrupted")
|
166
|
+
@exit_status = false
|
167
|
+
rescue Exception => e
|
168
|
+
puts e.message
|
169
|
+
puts e.backtrace
|
170
|
+
@exit_status = false
|
171
|
+
ensure
|
172
|
+
puts("\n")
|
173
|
+
@exit_status == true if @exit_status.nil?
|
174
|
+
exit(@exit_status)
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Fjords::Cli::Usage
|
2
|
+
def usage(msg = nil)
|
3
|
+
@usage = msg if msg
|
4
|
+
@usage
|
5
|
+
end
|
6
|
+
|
7
|
+
def usage_error(msg = nil)
|
8
|
+
@usage_error = msg if msg
|
9
|
+
@usage_error
|
10
|
+
end
|
11
|
+
|
12
|
+
def display_usage
|
13
|
+
if @usage
|
14
|
+
puts @usage_error if @usage_error
|
15
|
+
puts "Usage: #{@usage}"
|
16
|
+
return
|
17
|
+
elsif @verb_usage
|
18
|
+
puts @verb_usage
|
19
|
+
return
|
20
|
+
end
|
21
|
+
puts command_usage
|
22
|
+
end
|
23
|
+
|
24
|
+
def basic_usage
|
25
|
+
"Usage: fjords [options] command [<args>] [command_options]\n" +
|
26
|
+
"Try 'fjords help [command]' or 'fjords help options' for more information."
|
27
|
+
end
|
28
|
+
|
29
|
+
def command_usage
|
30
|
+
# nameservers List the nameservers for using a root domain
|
31
|
+
<<-USAGE
|
32
|
+
|
33
|
+
#{basic_usage}
|
34
|
+
|
35
|
+
Currently available af commands are:
|
36
|
+
|
37
|
+
Getting Started
|
38
|
+
login Login to Fjords
|
39
|
+
logout Logout of Fjords
|
40
|
+
signup Create an account
|
41
|
+
info Get your account information, including current plan costs
|
42
|
+
|
43
|
+
Sites
|
44
|
+
sites List deployed sites
|
45
|
+
remove DOMAIN Remove a deployed site
|
46
|
+
|
47
|
+
Site Creation
|
48
|
+
push Push a new site
|
49
|
+
|
50
|
+
Help
|
51
|
+
help [command] Get general help or help on a specific command
|
52
|
+
help options Get help on available options
|
53
|
+
bugreport Send a bug-report
|
54
|
+
USAGE
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
data/lib/fjords.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
FJORDS_CLI_ROOT = File.join(File.expand_path(File.dirname(__FILE__)), 'fjords')
|
2
|
+
|
3
|
+
module Fjords
|
4
|
+
module Cli
|
5
|
+
autoload :Core, "#{FJORDS_CLI_ROOT}/cli/core"
|
6
|
+
autoload :Usage, "#{FJORDS_CLI_ROOT}/cli/usage"
|
7
|
+
autoload :Runner, "#{FJORDS_CLI_ROOT}/cli/runner"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require "#{FJORDS_CLI_ROOT}/version"
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fjords
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas Reynolds
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: interact
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.5.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.5.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: highline
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: progress_bar
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: fjords-client
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - '='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.0.1
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - '='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.0.1
|
78
|
+
description: Fjords.cc CLI
|
79
|
+
email:
|
80
|
+
- me@tdreyno.com
|
81
|
+
executables:
|
82
|
+
- fjords
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- Gemfile
|
88
|
+
- Rakefile
|
89
|
+
- bin/fjords
|
90
|
+
- fjords.gemspec
|
91
|
+
- lib/fjords.rb
|
92
|
+
- lib/fjords/cli/core.rb
|
93
|
+
- lib/fjords/cli/runner.rb
|
94
|
+
- lib/fjords/cli/usage.rb
|
95
|
+
- lib/fjords/version.rb
|
96
|
+
homepage: ''
|
97
|
+
licenses: []
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ! '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
hash: -1246193583979943233
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
segments:
|
118
|
+
- 0
|
119
|
+
hash: -1246193583979943233
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 1.8.23
|
123
|
+
signing_key:
|
124
|
+
specification_version: 3
|
125
|
+
summary: Fjords.cc CLI
|
126
|
+
test_files: []
|