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 ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + "/../lib/appli"
3
+ Appli.run(ARGV.shift, ARGV)
@@ -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
+