appli 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+