appli 0.0.1
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/bin/appli +3 -0
- data/lib/appli/command.rb +126 -0
- data/lib/appli.rb +166 -0
- data/lib/commands/gems.rb +57 -0
- data/lib/commands/system.rb +40 -0
- metadata +68 -0
data/bin/appli
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
module Appli
|
2
|
+
class Command
|
3
|
+
|
4
|
+
def initialize(block)
|
5
|
+
(class << self;self end).send :define_method, :command, &block
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(options, *args)
|
9
|
+
@options = options
|
10
|
+
arity = method(:command).arity
|
11
|
+
args << nil while args.size < arity
|
12
|
+
send :command, *args
|
13
|
+
rescue Error => e
|
14
|
+
puts "An error occured while excuting your command...\n#{e.message}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def use_hirb
|
18
|
+
begin
|
19
|
+
require 'hirb'
|
20
|
+
extend Hirb::Console
|
21
|
+
rescue LoadError
|
22
|
+
puts "Hirb is not installed. Install hirb using '[sudo] gem install hirb' to get cool ASCII tables"
|
23
|
+
Process.exit(1)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def application
|
28
|
+
return nil if @options[:application].nil?
|
29
|
+
@application ||= get("applications/#{@options[:application]}")['application']
|
30
|
+
rescue
|
31
|
+
puts "Application not found with identifier '#{@options[:application]}'"
|
32
|
+
Process.exit(1)
|
33
|
+
end
|
34
|
+
|
35
|
+
def options
|
36
|
+
@options || Hash.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def execute_commands(array)
|
40
|
+
for command in array
|
41
|
+
puts "\e[44;33m" + command + "\e[0m"
|
42
|
+
exit_code = 0
|
43
|
+
IO.popen(command) do |f|
|
44
|
+
output = f.read
|
45
|
+
exit_code = Process.waitpid2(f.pid)[1]
|
46
|
+
end
|
47
|
+
if exit_code != 0
|
48
|
+
$stderr.puts "An error occured running: #{command}"
|
49
|
+
Process.exit(1)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def git_config_variable(name)
|
55
|
+
if name.is_a?(Symbol)
|
56
|
+
r = `git config appli.#{name.to_s}`.chomp
|
57
|
+
else
|
58
|
+
r = `git config #{name.to_s}`.chomp
|
59
|
+
end
|
60
|
+
r.empty? ? nil : r
|
61
|
+
end
|
62
|
+
|
63
|
+
def api_request(url, username, password, data = nil)
|
64
|
+
require 'uri'
|
65
|
+
require 'net/http'
|
66
|
+
require 'net/https'
|
67
|
+
uri = URI.parse(url)
|
68
|
+
if data
|
69
|
+
req = Net::HTTP::Post.new(uri.path)
|
70
|
+
else
|
71
|
+
req = Net::HTTP::Get.new(uri.path)
|
72
|
+
end
|
73
|
+
req.basic_auth(username, password)
|
74
|
+
req.add_field("Accept", "application/json")
|
75
|
+
req.add_field("Content-type", "application/json")
|
76
|
+
res = Net::HTTP.new(uri.host, uri.port)
|
77
|
+
if url.include?('https://')
|
78
|
+
res.use_ssl = true
|
79
|
+
res.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
80
|
+
end
|
81
|
+
res = res.request(req, data)
|
82
|
+
case res
|
83
|
+
when Net::HTTPSuccess
|
84
|
+
return res.body
|
85
|
+
when Net::HTTPServiceUnavailable
|
86
|
+
puts "The API is currently unavailable. Please check your codebase account has been enabled for API access."
|
87
|
+
Process.exit(1)
|
88
|
+
when Net::HTTPForbidden, Net::HTTPUnauthorized
|
89
|
+
puts "Access Denied. Ensure you have correctly configured your local Gem installation using the 'cb setup' command."
|
90
|
+
Process.exit(1)
|
91
|
+
else
|
92
|
+
@errors = res.body
|
93
|
+
return false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def errors
|
98
|
+
@errors || nil
|
99
|
+
end
|
100
|
+
|
101
|
+
def get(path)
|
102
|
+
JSON.parse(api(path))
|
103
|
+
end
|
104
|
+
|
105
|
+
def api(path, data = nil)
|
106
|
+
api_request("http://#{domain}/#{path}", git_config_variable(:username), git_config_variable(:apikey), data)
|
107
|
+
end
|
108
|
+
|
109
|
+
def api_on_api(path, data = nil)
|
110
|
+
api("applications/#{git_config_variable(:app)}/#{path}", data)
|
111
|
+
end
|
112
|
+
|
113
|
+
def domain
|
114
|
+
git_config_variable(:domain) || 'applihq.com'
|
115
|
+
end
|
116
|
+
|
117
|
+
def get_from_ssh(command)
|
118
|
+
`ssh -p #{application['ssh_port']} app@mercury.uk.applihq.com \"#{command}\"`
|
119
|
+
end
|
120
|
+
|
121
|
+
def ssh(command, filter = //)
|
122
|
+
puts get_from_ssh(command).gsub(filter, '')
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
data/lib/appli.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require 'appli/command'
|
7
|
+
|
8
|
+
trap("INT") { puts; exit }
|
9
|
+
|
10
|
+
module Appli
|
11
|
+
extend self
|
12
|
+
|
13
|
+
class Error < RuntimeError; end
|
14
|
+
class NotConfiguredError < StandardError; end
|
15
|
+
class MustBeInRepositoryError < StandardError; end
|
16
|
+
|
17
|
+
VERSION = "4.0.0"
|
18
|
+
|
19
|
+
def run(command, args = [])
|
20
|
+
load_commands
|
21
|
+
command = 'help' if command.nil?
|
22
|
+
application = nil
|
23
|
+
commands_array = @global_commands
|
24
|
+
|
25
|
+
if @global_commands[command]
|
26
|
+
## nothing to do...
|
27
|
+
elsif @application_commands[args.first]
|
28
|
+
application = command
|
29
|
+
command = args.shift
|
30
|
+
commands_array = @application_commands
|
31
|
+
elsif !command.empty?
|
32
|
+
puts "usage: appli #{command} {command}\n\n"
|
33
|
+
command = 'help'
|
34
|
+
else
|
35
|
+
puts "Command not found. Check 'cb help' for full information."
|
36
|
+
Process.exit(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
options = parse_options(args)
|
40
|
+
if args.size < commands_array[command][:required_args].to_i
|
41
|
+
puts "error: #{commands_array[command][:usage]}"
|
42
|
+
puts "See 'cb help #{command}' for usage."
|
43
|
+
Process.exit(1)
|
44
|
+
end
|
45
|
+
options.merge!({:application => application})
|
46
|
+
commands_array[command][:block].call(options, *args)
|
47
|
+
end
|
48
|
+
|
49
|
+
def command(command, options = {}, &block)
|
50
|
+
hash = Hash.new
|
51
|
+
hash[:description] = @next_description
|
52
|
+
hash[:usage] = @next_usage
|
53
|
+
hash[:flags] = @next_flags
|
54
|
+
hash[:required_args] = (options[:required_args] || 0)
|
55
|
+
hash[:block] = Command.new(block)
|
56
|
+
|
57
|
+
@global_commands = Hash.new if @global_commands.nil?
|
58
|
+
@application_commands = Hash.new if @application_commands.nil?
|
59
|
+
|
60
|
+
if options[:global]
|
61
|
+
@global_commands[command] = hash
|
62
|
+
else
|
63
|
+
@application_commands[command] = hash
|
64
|
+
end
|
65
|
+
|
66
|
+
@next_usage, @next_description, @next_flags = nil, nil, nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def global_commands
|
70
|
+
@global_commands
|
71
|
+
end
|
72
|
+
|
73
|
+
def application_commands
|
74
|
+
@application_commands
|
75
|
+
end
|
76
|
+
|
77
|
+
def desc(value)
|
78
|
+
@next_description = Array.new if @next_description.nil?
|
79
|
+
@next_description << value
|
80
|
+
end
|
81
|
+
|
82
|
+
def usage(value)
|
83
|
+
@next_usage = value
|
84
|
+
end
|
85
|
+
|
86
|
+
def flags(key, value)
|
87
|
+
@next_flags = Hash.new if @next_flags.nil?
|
88
|
+
@next_flags[key] = value
|
89
|
+
end
|
90
|
+
|
91
|
+
def load_commands
|
92
|
+
Dir[File.join(File.dirname(__FILE__), 'commands', '*.rb')].each do |path|
|
93
|
+
Appli.module_eval File.read(path), path
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def parse_options(args)
|
98
|
+
idx = 0
|
99
|
+
args.clone.inject({}) do |memo, arg|
|
100
|
+
case arg
|
101
|
+
when /^--(.+?)=(.*)/
|
102
|
+
args.delete_at(idx)
|
103
|
+
memo.merge($1.to_sym => $2)
|
104
|
+
when /^--(.+)/
|
105
|
+
args.delete_at(idx)
|
106
|
+
memo.merge($1.to_sym => true)
|
107
|
+
when "--"
|
108
|
+
args.delete_at(idx)
|
109
|
+
return memo
|
110
|
+
else
|
111
|
+
idx += 1
|
112
|
+
memo
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
Appli.desc "Displays this help message"
|
119
|
+
Appli.usage "cb help [command]"
|
120
|
+
Appli.command "help", :global => true do |command|
|
121
|
+
if command.nil?
|
122
|
+
puts "The Appli Gem allows you to easily access your Appli account functions from the"
|
123
|
+
puts "command line. The functions below outline the options which are currently available."
|
124
|
+
puts
|
125
|
+
puts "Global Commands"
|
126
|
+
puts
|
127
|
+
for key, command in Appli.global_commands.sort_by{|k,v| k}
|
128
|
+
puts " #{key.ljust(15)} #{command[:description].first}"
|
129
|
+
end
|
130
|
+
puts
|
131
|
+
puts "Application Specific Commands"
|
132
|
+
puts "The following commands can be executed by running 'appli [app identifier] {command}'"
|
133
|
+
puts
|
134
|
+
for key, command in Appli.application_commands.sort_by{|k,v| k}
|
135
|
+
puts " #{key.ljust(15)} #{command[:description].first}"
|
136
|
+
end
|
137
|
+
|
138
|
+
puts
|
139
|
+
puts "For more information see http://www.applihq.com/gem"
|
140
|
+
puts "See 'appli help [command]' for usage information."
|
141
|
+
else
|
142
|
+
if c = Appli.global_commands[command]
|
143
|
+
puts c[:description]
|
144
|
+
if c[:usage]
|
145
|
+
puts
|
146
|
+
puts "Usage:"
|
147
|
+
puts " #{c[:usage]}"
|
148
|
+
end
|
149
|
+
if c[:flags]
|
150
|
+
puts
|
151
|
+
puts "Options:"
|
152
|
+
for key, value in c[:flags]
|
153
|
+
puts " #{key.ljust(15)} #{value}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
else
|
157
|
+
puts "Command Not Found. Check 'appli help' for a full list of commands available to you."
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
Appli.desc "Displays the current version number"
|
163
|
+
Appli.usage "cb version"
|
164
|
+
Appli.command "version", :global => true do
|
165
|
+
puts "Appli Gem Version #{Appli::VERSION}"
|
166
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class FakeGemfile
|
2
|
+
attr_reader :gems, :sources
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@sources, @gems = [], []
|
6
|
+
end
|
7
|
+
|
8
|
+
def gem(name, version = nil, options = {})
|
9
|
+
@gems << {:name => name, :version => version, :options => options}
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(name, *values, &block)
|
13
|
+
yield block if block_given?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Read in the specified Gemfile and install all the required gems on your application"
|
18
|
+
usage "appli gems:import"
|
19
|
+
command "gems:import" do |file|
|
20
|
+
file_to_import = File.expand_path(file || 'Gemfile')
|
21
|
+
unless File.exist?(file_to_import)
|
22
|
+
raise Error, "Gemfile was not found at #{file_to_import}"
|
23
|
+
end
|
24
|
+
|
25
|
+
puts "Importing gems from #{file_to_import}"
|
26
|
+
gem_details = FakeGemfile.new
|
27
|
+
gem_details.instance_eval(File.read(file_to_import), file_to_import)
|
28
|
+
|
29
|
+
puts "There are #{gem_details.gems.size} gem(s) to install on your application."
|
30
|
+
for g in gem_details.gems[0,4]
|
31
|
+
puts "Installing #{g[:name]} (#{g[:version] || 'latest'})"
|
32
|
+
data = {:ruby_gem => {:name => g[:name], :version => g[:version]}}.to_json
|
33
|
+
if api_on_api "ruby_gems", data
|
34
|
+
puts "=> Installed successfully"
|
35
|
+
else
|
36
|
+
puts "=> Installation failed"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Install the named gem"
|
42
|
+
usage "appli gems:install [gem name] [version]"
|
43
|
+
command "gems:install" do |name, version|
|
44
|
+
puts "Installing #{name} (#{version || 'latest'})"
|
45
|
+
data = {:ruby_gem => {:name => name, :version => version || ''}}.to_json
|
46
|
+
if a = api_on_api("ruby_gems", data)
|
47
|
+
puts "=> Installed"
|
48
|
+
else
|
49
|
+
puts "=> Install failed"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "List all installed gems on your application"
|
54
|
+
usage "appli gems"
|
55
|
+
command "gems" do
|
56
|
+
ssh "gem list"
|
57
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
desc "Display system memory usage"
|
2
|
+
usage "appli mem:system"
|
3
|
+
command "mem:system" do
|
4
|
+
puts get_from_ssh("free -m").split("\n")[0,2].join("\n")
|
5
|
+
end
|
6
|
+
|
7
|
+
desc 'Display passenger memory statistics'
|
8
|
+
usage "appli mem:passenger"
|
9
|
+
command "mem:passenger" do
|
10
|
+
ssh "passenger-memory-stats", /^\*\*\* WARNING\:(.*)$/
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Display your current disk space usage'
|
14
|
+
usage "appli diskusage"
|
15
|
+
command "diskusage" do
|
16
|
+
output = get_from_ssh("df -h").split("\n")[1]
|
17
|
+
output = output.split(/\s+/)
|
18
|
+
fs, size, usage, available, usage_percent, mountpoint = output
|
19
|
+
puts "You are using #{usage} (including system files)."
|
20
|
+
puts
|
21
|
+
puts "You are not billed for system file usage - only files & gems which"
|
22
|
+
puts "you place within your hosting area."
|
23
|
+
puts
|
24
|
+
puts "Your system is limited to #{size} however if you need additional"
|
25
|
+
puts "space, please just contact support."
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Display the current settings"
|
29
|
+
command "settings", :global => true do
|
30
|
+
puts "Username........: #{git_config_variable(:username) || 'unknown'}"
|
31
|
+
puts "API Key.........: #{git_config_variable(:apikey) || 'unknown'}"
|
32
|
+
puts "Domain..........: #{git_config_variable(:domain) || 'unknown'}"
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
desc 'SSH to the named server'
|
37
|
+
usage "appli [application] ssh"
|
38
|
+
command "ssh" do
|
39
|
+
exec "ssh -p #{application['ssh_port']} app@mercury.uk.applihq.com"
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: appli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Cooke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-04 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: json
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.1.5
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: adam@atechmedia.com
|
27
|
+
executables:
|
28
|
+
- appli
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- bin/appli
|
35
|
+
- lib/appli/command.rb
|
36
|
+
- lib/appli.rb
|
37
|
+
- lib/commands/gems.rb
|
38
|
+
- lib/commands/system.rb
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://www.atechmedia.com
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.3.5
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: Gem for Appli shared Ruby hosting management
|
67
|
+
test_files: []
|
68
|
+
|