pagoda 0.3.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +33 -24
- data/README.md +68 -0
- data/Rakefile +4 -7
- data/bin/pagoda +100 -8
- data/lib/pagoda/cli/commands/clone.rb +13 -0
- data/lib/pagoda/cli/commands/create.rb +13 -0
- data/lib/pagoda/cli/commands/deploy.rb +12 -0
- data/lib/pagoda/cli/commands/destroy.rb +16 -0
- data/lib/pagoda/cli/commands/info.rb +13 -0
- data/lib/pagoda/cli/commands/init.rb +13 -0
- data/lib/pagoda/cli/commands/list.rb +20 -0
- data/lib/pagoda/cli/commands/rename.rb +17 -0
- data/lib/pagoda/cli/commands/rollback.rb +12 -0
- data/lib/pagoda/cli/commands/ssh_key.rb +27 -0
- data/lib/pagoda/cli/commands/tunnel.rb +18 -0
- data/lib/pagoda/cli/commands.rb +11 -0
- data/lib/pagoda/{helpers.rb → cli/core_ext.rb} +10 -118
- data/lib/pagoda/cli/helpers/app.rb +143 -0
- data/lib/pagoda/cli/helpers/base.rb +199 -0
- data/lib/pagoda/cli/helpers/key.rb +69 -0
- data/lib/pagoda/cli/helpers/tunnel.rb +36 -0
- data/lib/pagoda/cli/helpers.rb +127 -0
- data/lib/pagoda/cli/override.rb +23 -0
- data/lib/pagoda/cli/version.rb +5 -0
- data/lib/pagoda/cli.rb +11 -0
- data/lib/pagoda-cli.rb +1 -0
- data/pagoda.gemspec +20 -24
- data/pagoda.rdoc +139 -0
- data/pkg/newpagoda-0.1.10.gem +0 -0
- data/pkg/newpagoda-0.1.11.gem +0 -0
- data/pkg/newpagoda-0.1.12.gem +0 -0
- data/pkg/newpagoda-0.1.13.gem +0 -0
- data/pkg/newpagoda-0.1.15.gem +0 -0
- data/pkg/newpagoda-0.1.4.gem +0 -0
- data/pkg/newpagoda-0.1.6.gem +0 -0
- data/pkg/newpagoda-0.1.7.gem +0 -0
- data/pkg/newpagoda-0.1.8.gem +0 -0
- data/pkg/newpagoda-0.1.9.gem +0 -0
- data/pkg/newpagoda-0.5.0.gem +0 -0
- data/spec/lib/helper_spec.rb +32 -0
- data/spec/lib/helpers/app_spec.rb +104 -0
- data/spec/lib/helpers/base_spec.rb +27 -0
- data/spec/lib/helpers/key_spec.rb +42 -0
- data/spec/lib/helpers/tunnel_spec.rb +30 -0
- data/spec/spec_helper.rb +17 -0
- metadata +74 -50
- data/.bundle/config +0 -1
- data/README +0 -3
- data/lib/pagoda/client.rb +0 -225
- data/lib/pagoda/command.rb +0 -96
- data/lib/pagoda/commands/app.rb +0 -247
- data/lib/pagoda/commands/auth.rb +0 -149
- data/lib/pagoda/commands/base.rb +0 -184
- data/lib/pagoda/commands/db.rb +0 -18
- data/lib/pagoda/commands/help.rb +0 -100
- data/lib/pagoda/commands/tunnel.rb +0 -49
- data/lib/pagoda/tunnel_proxy.rb +0 -130
- data/lib/pagoda/version.rb +0 -3
- data/lib/pagoda.rb +0 -3
- data/spec/base.rb +0 -21
- data/spec/client_spec.rb +0 -255
- data/spec/command_spec.rb +0 -26
- data/spec/commands/auth_spec.rb +0 -57
@@ -0,0 +1,143 @@
|
|
1
|
+
module Pagoda
|
2
|
+
module Command
|
3
|
+
|
4
|
+
class App < Base
|
5
|
+
|
6
|
+
def list
|
7
|
+
apps = client.app_list
|
8
|
+
unless apps.empty?
|
9
|
+
display
|
10
|
+
display "APPS"
|
11
|
+
display "//////////////////////////////////"
|
12
|
+
display
|
13
|
+
apps.each do |app|
|
14
|
+
display "- #{app[:name]}"
|
15
|
+
end
|
16
|
+
else
|
17
|
+
error ["looks like you haven't launched any apps", "type 'pagoda create' to create this project on pagodabox"]
|
18
|
+
end
|
19
|
+
display
|
20
|
+
end
|
21
|
+
|
22
|
+
def info
|
23
|
+
display
|
24
|
+
info = client.app_info(app)
|
25
|
+
error("What application are you looking for?") unless info.is_a?(Hash)
|
26
|
+
display "INFO - #{info[:name]}"
|
27
|
+
display "//////////////////////////////////"
|
28
|
+
display "name : #{info[:name]}"
|
29
|
+
display "clone url : git@pagodabox.com:#{info[:id]}.git"
|
30
|
+
display
|
31
|
+
display "owner"
|
32
|
+
display " username : #{info[:owner][:username]}"
|
33
|
+
display " email : #{info[:owner][:email]}"
|
34
|
+
display
|
35
|
+
display "collaborators"
|
36
|
+
info[:collaborators].each do |collab|
|
37
|
+
display " username : #{collab[:username]}"
|
38
|
+
display " email : #{collab[:email]}"
|
39
|
+
end
|
40
|
+
display
|
41
|
+
display "ssh_portal : #{info[:ssh] ? 'enabled' : 'disabled'}"
|
42
|
+
display
|
43
|
+
end
|
44
|
+
|
45
|
+
def rename
|
46
|
+
old_name = options[:old] || app
|
47
|
+
new_name = options[:new] || args.first
|
48
|
+
error "I need the new name" unless new_name
|
49
|
+
error "New name and existiong name cannot be the same" if new_name == old_name
|
50
|
+
client.app_update(old_name, {:name => new_name})
|
51
|
+
display "Successfully changed name to #{new_name}"
|
52
|
+
rescue
|
53
|
+
error "Given name was either invalid or already in use"
|
54
|
+
end
|
55
|
+
|
56
|
+
def init
|
57
|
+
id = client.app_info(args.first || app)[:id] rescue error("We could not find the application you were looking for")
|
58
|
+
create_git_remote(id, remote)
|
59
|
+
end
|
60
|
+
|
61
|
+
def clone
|
62
|
+
my_app = args.first || app
|
63
|
+
id = client.app_info(my_app)[:id]
|
64
|
+
display
|
65
|
+
git "clone git@git.pagodabox.com:#{id}.git #{my_app}"
|
66
|
+
Dir.chdir(my_app)
|
67
|
+
git "config --add pagoda.id #{id}"
|
68
|
+
Dir.chdir("..")
|
69
|
+
display
|
70
|
+
display "+> Repo has been added. Navigate to folder #{my_app}."
|
71
|
+
rescue
|
72
|
+
error "We were not able to access that app"
|
73
|
+
end
|
74
|
+
|
75
|
+
def create
|
76
|
+
name = args.first || app
|
77
|
+
if client.app_available?(name)
|
78
|
+
id = client.app_create(name)[:id]
|
79
|
+
display("Creating #{name}...", false)
|
80
|
+
loop_transaction(name)
|
81
|
+
d_remote = create_git_remote(id, remote)
|
82
|
+
display "#{name} created"
|
83
|
+
display "----------------------------------------------------"
|
84
|
+
display
|
85
|
+
display "LIVE URL : http://#{name}.pagodabox.com"
|
86
|
+
display "ADMIN PANEL : http://dashboard.pagodabox.com/apps/#{name}"
|
87
|
+
display
|
88
|
+
display "----------------------------------------------------"
|
89
|
+
display
|
90
|
+
display "+> Use 'git push #{d_remote} --all' to push your code live"
|
91
|
+
else
|
92
|
+
error "App name (#{name}) is already taken"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def deploy
|
97
|
+
display
|
98
|
+
my_app = app
|
99
|
+
if client.app_info(my_app)[:active_transaction_id] == nil
|
100
|
+
begin
|
101
|
+
client.app_deploy(my_app, branch, commit)
|
102
|
+
rescue RestClient::Found => e
|
103
|
+
# do nothing because we found it HURRAY!
|
104
|
+
end
|
105
|
+
display "+> deploying current branch and commit...", true
|
106
|
+
loop_transaction
|
107
|
+
else
|
108
|
+
error "Your app is currently in transaction, Please try again later."
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def rollback
|
113
|
+
display
|
114
|
+
client.app_rollback(app)
|
115
|
+
display "+> undo..."
|
116
|
+
loop_transaction
|
117
|
+
display
|
118
|
+
end
|
119
|
+
|
120
|
+
def destroy
|
121
|
+
display
|
122
|
+
my_app = app
|
123
|
+
dname = display_name(my_app) # Make the app name look better
|
124
|
+
if options[:force]
|
125
|
+
display "+> Destroying #{dname}"
|
126
|
+
client.app_destroy(my_app)
|
127
|
+
display "+> #{dname} has been successfully destroyed. RIP #{dname}."
|
128
|
+
remove_app(my_app)
|
129
|
+
else
|
130
|
+
if confirm ["Are you totally completely sure you want to delete #{dname} forever and ever?", "THIS CANNOT BE UNDONE! (y/n)"]
|
131
|
+
display
|
132
|
+
display "+> Destroying #{dname}"
|
133
|
+
client.app_destroy(my_app)
|
134
|
+
display "+> #{dname} has been successfully destroyed. RIP #{dname}."
|
135
|
+
remove_app(my_app)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
display
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'pagoda-client'
|
2
|
+
|
3
|
+
module Pagoda
|
4
|
+
module Command
|
5
|
+
|
6
|
+
class Base
|
7
|
+
include Pagoda::Helpers
|
8
|
+
|
9
|
+
class << self
|
10
|
+
include Pagoda::Helpers
|
11
|
+
def ask_for_credentials
|
12
|
+
username = ask "Username: "
|
13
|
+
display "Password: ", false
|
14
|
+
password = running_on_windows? ? ask_for_password_on_windows : ask_for_password
|
15
|
+
# api_key = Pagoda::Client.new(user, password).api_key
|
16
|
+
[username, password] # return
|
17
|
+
end
|
18
|
+
|
19
|
+
def ask_for_password
|
20
|
+
echo_off
|
21
|
+
password = ask
|
22
|
+
puts
|
23
|
+
echo_on
|
24
|
+
return password
|
25
|
+
end
|
26
|
+
|
27
|
+
def ask_for_password_on_windows
|
28
|
+
require "Win32API"
|
29
|
+
char = nil
|
30
|
+
password = ''
|
31
|
+
|
32
|
+
while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do
|
33
|
+
break if char == 10 || char == 13 # received carriage return or newline
|
34
|
+
if char == 127 || char == 8 # backspace and delete
|
35
|
+
password.slice!(-1, 1)
|
36
|
+
else
|
37
|
+
# windows might throw a -1 at us so make sure to handle RangeError
|
38
|
+
(password << char.chr) rescue RangeError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
return password
|
42
|
+
end
|
43
|
+
|
44
|
+
def echo_off
|
45
|
+
silently(system("stty -echo"))
|
46
|
+
rescue
|
47
|
+
end
|
48
|
+
|
49
|
+
def echo_on
|
50
|
+
silently(system("stty echo"))
|
51
|
+
rescue
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_reader :client
|
57
|
+
attr_reader :globals
|
58
|
+
attr_reader :options
|
59
|
+
attr_reader :args
|
60
|
+
|
61
|
+
def initialize(globals, options, args)
|
62
|
+
@globals = globals
|
63
|
+
@options = options
|
64
|
+
@args = args
|
65
|
+
end
|
66
|
+
|
67
|
+
def user
|
68
|
+
globals[:username]
|
69
|
+
end
|
70
|
+
|
71
|
+
def password
|
72
|
+
globals[:password]
|
73
|
+
end
|
74
|
+
|
75
|
+
def client
|
76
|
+
@client ||= Pagoda::Client.new(user, password)
|
77
|
+
end
|
78
|
+
|
79
|
+
# protected
|
80
|
+
|
81
|
+
def shell(cmd)
|
82
|
+
FileUtils.cd(Dir.pwd) {|d| return `#{cmd}`}
|
83
|
+
end
|
84
|
+
|
85
|
+
def remote
|
86
|
+
options[:remote] || "pagoda"
|
87
|
+
end
|
88
|
+
|
89
|
+
def app(soft_fail=true)
|
90
|
+
if app = globals[:app] || options[:app]
|
91
|
+
app
|
92
|
+
elsif app = extract_app_from_git_config
|
93
|
+
app
|
94
|
+
elsif app = extract_app_from_remote
|
95
|
+
app
|
96
|
+
else
|
97
|
+
if soft_fail
|
98
|
+
display "I was unable to find your application name."
|
99
|
+
ask "what is the name of your application? "
|
100
|
+
else
|
101
|
+
error "Unable to find the app. please specify using -a or --app="
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def extract_app_from_git_config
|
107
|
+
remote = git("config pagoda.id")
|
108
|
+
if remote =~ /error: More than one value for the key pagoda.id/
|
109
|
+
git("config --unset-all pagoda.id")
|
110
|
+
return nil
|
111
|
+
end
|
112
|
+
remote == "" ? nil : remote
|
113
|
+
end
|
114
|
+
|
115
|
+
def extract_app_from_remote
|
116
|
+
remotes = git_remotes
|
117
|
+
if remotes.length == 1
|
118
|
+
remotes.values.first
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def git_remotes(base_dir=Dir.pwd)
|
123
|
+
remotes = {}
|
124
|
+
original_dir = Dir.pwd
|
125
|
+
Dir.chdir(base_dir)
|
126
|
+
git("remote -v").split("\n").each do |remote|
|
127
|
+
name, url, method = remote.split(/\s/)
|
128
|
+
if url =~ /^git@git.pagodabox.com:([\w\d-]+)\.git$/
|
129
|
+
remotes[name] = $1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
Dir.chdir(original_dir)
|
133
|
+
remotes
|
134
|
+
end
|
135
|
+
|
136
|
+
def branch
|
137
|
+
options[:branch] || find_branch
|
138
|
+
end
|
139
|
+
|
140
|
+
def commit
|
141
|
+
options[:commit] || find_commit
|
142
|
+
end
|
143
|
+
|
144
|
+
def find_branch
|
145
|
+
if git("name-rev --refs=$(git symbolic-ref HEAD) --name-only HEAD") =~ /Could not get/
|
146
|
+
error "Cannot find your branch"
|
147
|
+
else
|
148
|
+
git("name-rev --refs=$(git symbolic-ref HEAD) --name-only HEAD")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def home_dir
|
153
|
+
File.expand_path("~")
|
154
|
+
end
|
155
|
+
|
156
|
+
def find_commit
|
157
|
+
if git("rev-parse --verify HEAD") =~ /Could not get/
|
158
|
+
error "Cannot find your commit"
|
159
|
+
else
|
160
|
+
git("rev-parse --verify HEAD")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def extract_git_clone_url(remote="pagoda")
|
165
|
+
git("config remote.#{remote}.url")
|
166
|
+
end
|
167
|
+
|
168
|
+
def locate_app_root(dir=Dir.pwd)
|
169
|
+
return dir if File.exists? "#{dir}/.git/config"
|
170
|
+
parent = dir.split('/')[0..-2].join('/')
|
171
|
+
return false if parent.empty?
|
172
|
+
locate_app_root(parent)
|
173
|
+
end
|
174
|
+
|
175
|
+
def loop_transaction(app_name = nil)
|
176
|
+
use_app = app_name || app
|
177
|
+
transaction_id = client.app_info(use_app)[:active_transaction_id]
|
178
|
+
if transaction_id
|
179
|
+
log_stream_length = 0
|
180
|
+
display("",true,0)
|
181
|
+
while true
|
182
|
+
start = Time.now
|
183
|
+
active = client.transaction_info(use_app, transaction_id)
|
184
|
+
unless active[:log_stream].length == log_stream_length
|
185
|
+
display( active[:log_stream][log_stream_length..-1].join("\n"),true,0)
|
186
|
+
log_stream_length = active[:log_stream].length
|
187
|
+
end
|
188
|
+
break unless active[:state] == "incomplete"
|
189
|
+
sleep(Time.now - start) if (Time.now - start) > 0
|
190
|
+
end
|
191
|
+
end
|
192
|
+
display('',true,0)
|
193
|
+
display( "Complete!",true,0)
|
194
|
+
display('',true,0)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
module Pagoda
|
3
|
+
module Command
|
4
|
+
|
5
|
+
class Key < Base
|
6
|
+
|
7
|
+
def generate_key_and_push
|
8
|
+
display
|
9
|
+
display "+> Generating a ssh key pair"
|
10
|
+
display
|
11
|
+
if running_on_windows?
|
12
|
+
display "It appears you are running on windows"
|
13
|
+
display "the best way to generate a key is with an external tool"
|
14
|
+
display "We suggest using 'PuTTY'"
|
15
|
+
else
|
16
|
+
(options[:file] ? `ssh-keygen -f #{options[:file]}` : `ssh-keygen`)
|
17
|
+
display
|
18
|
+
push_existing_key
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def push_existing_key
|
23
|
+
if file_path = options[:file] || args.first
|
24
|
+
unless file_path[0] == '/'
|
25
|
+
file_path = Dir.pwd << '/' << file_path
|
26
|
+
end
|
27
|
+
unless file_path.end_with?(".pub")
|
28
|
+
file_path << ".pub"
|
29
|
+
end
|
30
|
+
if File.exists?(file_path)
|
31
|
+
send_key_file(file_path)
|
32
|
+
else
|
33
|
+
error "file given '#{file_path}' does not exist"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
if File.exists?("#{home_dir}/.ssh/id_rsa.pub") || File.exists?("~/.ssh/id_dsa.pub")
|
37
|
+
if File.exists?("#{home_dir}/.ssh/id_rsa.pub")
|
38
|
+
send_key_file("#{home_dir}/.ssh/id_rsa.pub")
|
39
|
+
end
|
40
|
+
|
41
|
+
if File.exists?("#{home_dir}/.ssh/id_dsa.pub")
|
42
|
+
send_key_file("#{home_dir}/.ssh/id_dsa.pub")
|
43
|
+
end
|
44
|
+
else
|
45
|
+
display "It appears you do not have a public key."
|
46
|
+
display "One should be generated with either id-rsa.pub or id-rsa.pub"
|
47
|
+
display "in the #{home_dir}/.ssh folder."
|
48
|
+
display "Or you could specify the file 'pagoda key:gen ~/.ssh/my_awesome_key.pub"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def send_key_file(file)
|
54
|
+
key = File.read(file).strip
|
55
|
+
if key =~ /^ssh-(?:dss|rsa) [A-Za-z0-9+\/]+/
|
56
|
+
client.user_add_key(key)
|
57
|
+
display "+> Pushing ssh key to Pagoda Box"
|
58
|
+
display "+> done"
|
59
|
+
else
|
60
|
+
error "that key is not the correct format"
|
61
|
+
end
|
62
|
+
rescue RestClient::UnprocessableEntity
|
63
|
+
error "It Appears this key is already in use"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'pagoda-tunnel'
|
2
|
+
|
3
|
+
module Pagoda::Command
|
4
|
+
class Tunnel < Base
|
5
|
+
|
6
|
+
def run
|
7
|
+
user_input = options[:component] || args.first
|
8
|
+
component = {}
|
9
|
+
begin
|
10
|
+
if user_input =~ /^(web\d*)|(db\d*)|(cache\d*)|(worker\d*)$/
|
11
|
+
components = client.component_list(app)
|
12
|
+
components.delete_if {|x| x[:cuid] != user_input }
|
13
|
+
component = components[0]
|
14
|
+
else
|
15
|
+
component = client.component_info(app, user_input)
|
16
|
+
end
|
17
|
+
rescue
|
18
|
+
errors = []
|
19
|
+
errors << "Input unrecoginized"
|
20
|
+
errors << "try 'pagoda -a <appname> tunnel <component>'"
|
21
|
+
errors << "ie. 'pagoda -a app tunnel db1'"
|
22
|
+
error errors
|
23
|
+
end
|
24
|
+
if component[:tunnelable]
|
25
|
+
type = component[:_type]
|
26
|
+
component_id = component[:_id]
|
27
|
+
app_id = component[:app_id]
|
28
|
+
Pagoda::Tunnel.new(type, user, password, app_id, component_id).start
|
29
|
+
else
|
30
|
+
error "Either the component is not tunnelable or you do not have access"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Pagoda
|
2
|
+
module Helpers
|
3
|
+
INDENT = " "
|
4
|
+
|
5
|
+
def home_directory
|
6
|
+
running_on_windows? ? ENV['USERPROFILE'] : ENV['HOME']
|
7
|
+
end
|
8
|
+
|
9
|
+
def running_on_windows?
|
10
|
+
RUBY_PLATFORM =~ /mswin32|mingw32/
|
11
|
+
end
|
12
|
+
|
13
|
+
def running_on_a_mac?
|
14
|
+
RUBY_PLATFORM =~ /-darwin\d/
|
15
|
+
end
|
16
|
+
|
17
|
+
def display(msg="", newline=true, level=1)
|
18
|
+
indent = build_indent(level)
|
19
|
+
if newline
|
20
|
+
(running_on_windows?) ? puts("#{indent}#{msg}") : puts("#{indent}#{msg}".green)
|
21
|
+
else
|
22
|
+
(running_on_windows?) ? print("#{indent}#{msg}") : print("#{indent}#{msg}".green)
|
23
|
+
STDOUT.flush
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def format_date(date)
|
28
|
+
date = Time.parse(date) if date.is_a?(String)
|
29
|
+
date.strftime("%Y-%m-%d %H:%M %Z")
|
30
|
+
end
|
31
|
+
|
32
|
+
def ask(message=nil, level=1)
|
33
|
+
(running_on_windows?) ? print("#{build_indent(level)}#{message}") : print("#{build_indent(level)}#{message}".blue)
|
34
|
+
STDOUT.flush
|
35
|
+
STDIN.gets.strip
|
36
|
+
end
|
37
|
+
|
38
|
+
def confirm(message="Are you sure you wish to continue? (y/n)?", level=1)
|
39
|
+
return true if ARGV.include? "-f"
|
40
|
+
case message
|
41
|
+
when Array
|
42
|
+
count = message.length
|
43
|
+
iteration = 0
|
44
|
+
message.each do |m|
|
45
|
+
if iteration == count - 1
|
46
|
+
(running_on_windows?) ? display("#{m} ", false, level) : display("#{m} ".blue, false, level)
|
47
|
+
else
|
48
|
+
(running_on_windows?) ? display("#{m} ", false, level) : display("#{m} ".blue, true, level)
|
49
|
+
end
|
50
|
+
iteration += 1
|
51
|
+
end
|
52
|
+
when String
|
53
|
+
(running_on_windows?) ? display("#{message} ", false, level) : display("#{message} ".blue, false, level)
|
54
|
+
end
|
55
|
+
ask.downcase == 'y'
|
56
|
+
end
|
57
|
+
|
58
|
+
def error(msg, exit=true, level=1)
|
59
|
+
indent = build_indent(level)
|
60
|
+
STDERR.puts
|
61
|
+
case msg
|
62
|
+
when Array
|
63
|
+
(running_on_windows?) ? STDERR.puts("#{indent}** Error:") : STDERR.puts("#{indent}** Error:".red)
|
64
|
+
msg.each do |m|
|
65
|
+
(running_on_windows?) ? STDERR.puts("#{indent}** #{m}") : STDERR.puts("#{indent}** #{m}".red)
|
66
|
+
end
|
67
|
+
when String
|
68
|
+
(running_on_windows?) ? STDERR.puts("#{indent}** Error: #{msg}") : STDERR.puts("#{indent}** Error: #{msg}".red)
|
69
|
+
end
|
70
|
+
STDERR.puts
|
71
|
+
exit 1 if exit
|
72
|
+
end
|
73
|
+
|
74
|
+
def has_git?
|
75
|
+
%x{ git --version }
|
76
|
+
$?.success?
|
77
|
+
end
|
78
|
+
|
79
|
+
def display_name(app)
|
80
|
+
client.app_info(app)[:name]
|
81
|
+
end
|
82
|
+
|
83
|
+
def git(args)
|
84
|
+
return "" unless has_git?
|
85
|
+
flattened_args = [args].flatten.compact.join(" ")
|
86
|
+
%x{ git #{flattened_args} 2>&1 }.strip
|
87
|
+
end
|
88
|
+
|
89
|
+
def create_git_remote(id, remote)
|
90
|
+
error "you do not have git installed on your computer" unless has_git?
|
91
|
+
if git('remote').split("\n").include?(remote)
|
92
|
+
display "Given remote (#{remote}) is already in use on this repo"
|
93
|
+
remote = ask "what would you like to call the new remote? "
|
94
|
+
end
|
95
|
+
unless File.directory?(".git")
|
96
|
+
if confirm "git has not been initialized yet, would you like us to do this for you? (y/n)?"
|
97
|
+
display "git repo is being created in '#{Dir.pwd}'"
|
98
|
+
git "init"
|
99
|
+
else
|
100
|
+
error(["repo has not been initialized." , "try 'git init'"])
|
101
|
+
end
|
102
|
+
end
|
103
|
+
git "remote add #{remote} git@git.pagodabox.com:#{id}.git"
|
104
|
+
git "config --add pagoda.id #{id}"
|
105
|
+
display "Git remote #{remote} added"
|
106
|
+
remote
|
107
|
+
end
|
108
|
+
|
109
|
+
def remove_app(app)
|
110
|
+
remove_git_remote(app)
|
111
|
+
end
|
112
|
+
|
113
|
+
def remove_git_remote(app)
|
114
|
+
git "remote rm pagoda"
|
115
|
+
git "config --unset pagoda.id"
|
116
|
+
end
|
117
|
+
|
118
|
+
def build_indent(level=1)
|
119
|
+
indent = ""
|
120
|
+
level.times do
|
121
|
+
indent += INDENT
|
122
|
+
end
|
123
|
+
indent
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
unless Object.respond_to? :tap
|
2
|
+
class Object
|
3
|
+
def tap
|
4
|
+
yield(self)
|
5
|
+
self
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module GLI
|
11
|
+
def command(*names, &block)
|
12
|
+
command = Command.new([names].flatten,@@next_desc,@@next_arg_name,@@next_long_desc,@@skips_pre,@@skips_post)
|
13
|
+
commands[command.name] = command
|
14
|
+
command.instance_eval(&block)
|
15
|
+
# yield command
|
16
|
+
command.tap do |c|
|
17
|
+
c.desc "Help"
|
18
|
+
c.switch [:h, :help]
|
19
|
+
end
|
20
|
+
clear_nexts
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/lib/pagoda/cli.rb
ADDED
data/lib/pagoda-cli.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'pagoda/cli'
|
data/pagoda.gemspec
CHANGED
@@ -1,29 +1,25 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
require "pagoda/version"
|
2
|
+
require File.expand_path('../lib/pagoda/cli/version', __FILE__)
|
4
3
|
|
5
|
-
Gem::Specification.new do |
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
s.homepage = "http://www.pagodabox.com/"
|
12
|
-
s.summary = %q{Terminal client for interacting with the pagodabox}
|
13
|
-
s.description = %q{Terminal client for interacting with the pagodabox. This client does not contain full api functionality, just functionality that will enhance the workflow experience.}
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Lyon Hill"]
|
6
|
+
gem.email = ["lyon@pagodabox.com"]
|
7
|
+
gem.summary = %q{Pagoda Box CLI}
|
8
|
+
gem.description = %q{Pagoda Box User facing interface to improve workflow with Pagoda Box}
|
9
|
+
gem.homepage = "http://www.pagodabox.com"
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "pagoda"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Pagoda::CLI::VERSION
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
s.add_dependency "json_pure"
|
23
|
-
s.add_dependency "rest-client"
|
18
|
+
gem.add_development_dependency "rspec"
|
19
|
+
gem.add_development_dependency "pry"
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
21
|
+
gem.add_dependency "pagoda-client"
|
22
|
+
gem.add_dependency "pagoda-tunnel"
|
23
|
+
gem.add_dependency "rest-client"
|
24
|
+
gem.add_dependency "gli"
|
25
|
+
end
|