toss 0.0.4 → 0.0.5

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/toss CHANGED
@@ -1,3 +1,52 @@
1
1
  #!/usr/bin/env ruby
2
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
3
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
2
4
 
3
- puts "toss"
5
+ require 'rubygems'
6
+ require 'toss'
7
+
8
+ puts "#{Toss::NAME} #{Toss::VERSION}"
9
+
10
+ $options = Toss::Options.load
11
+
12
+ # set environment
13
+ set :env, $options[:environment]
14
+
15
+ # load preset
16
+ $options[:pre_set].each do |name, value|
17
+ set name, value
18
+ end
19
+
20
+ # load recipe
21
+ if $options[:recipes].count > 0
22
+ $options[:recipes].each do |file|
23
+ require file
24
+ end
25
+ else
26
+ require "#{Dir.pwd}/Tossfile.rb"
27
+ end
28
+
29
+ # load set
30
+ $options[:set].each do |name, value|
31
+ set name, value
32
+ end
33
+
34
+ if ARGV.count.to_i > 0
35
+ @steps = []
36
+ ARGV.each do |func|
37
+ step func
38
+ end
39
+ end
40
+
41
+ # run steps
42
+ steps && steps.each_with_index do |toss_step, index|
43
+ @step_index = index
44
+ puts "== " + cyan(cap_words(toss_step[0].to_s.gsub("_", " "))) + " =="
45
+ if method(toss_step[0]).call == false
46
+ rollback_steps
47
+ exit(1)
48
+ end
49
+ end
50
+
51
+ # close any open ssh sessions
52
+ close_sessions
@@ -1,5 +1,37 @@
1
+ require "toss/options"
1
2
  require "toss/version"
3
+ require "toss/meta"
4
+ require "toss/ssh"
5
+ require "toss/color"
6
+ require "toss/server"
2
7
 
3
- module Toss
4
- # Your code goes here...
8
+ include Toss::Meta
9
+ include Toss::Ssh
10
+
11
+ @step_index ||= 0
12
+
13
+ def steps
14
+ @steps ||= []
15
+ end
16
+
17
+ def step(step_name, options={})
18
+ steps << [step_name, options]
5
19
  end
20
+
21
+ def rollback_steps
22
+ @step_index.downto(0) do |index|
23
+ m = method(steps[index][0])
24
+ if m.arity == -1
25
+ puts "== " + red("Rolling Back") + " " + bwhite(cap_words(steps[index][0].to_s.gsub("_", " "))) + " =="
26
+
27
+ if m.call(true) == false
28
+ puts "here"
29
+ exit(1)
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def cap_words(str)
36
+ str.split(" ").each{|word| word.capitalize!}.join(" ")
37
+ end
@@ -0,0 +1,86 @@
1
+ def colorize(str, beginColor, endColor = 0)
2
+ return str unless STDOUT.isatty
3
+
4
+ begin
5
+ require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32/
6
+ rescue LoadError
7
+ raise 'You must gem install win32console to use colorize on Windows'
8
+ end
9
+
10
+ "\e[#{beginColor}m#{str}\e[#{endColor}m"
11
+ end
12
+
13
+ #30 Black
14
+ def black(str)
15
+ colorize(str, "30")
16
+ end
17
+
18
+ #31 Red
19
+ def red(str)
20
+ colorize(str, "31")
21
+ end
22
+
23
+ #31 Bright Red
24
+ def bred(str)
25
+ colorize(str, "1;31")
26
+ end
27
+
28
+ #32 Green
29
+ def green(str)
30
+ colorize(str, "32")
31
+ end
32
+
33
+ #32 Bright Green
34
+ def bgreen(str)
35
+ colorize(str, "1;32")
36
+ end
37
+
38
+ #33 Yellow
39
+ def yellow(str)
40
+ colorize(str, "33")
41
+ end
42
+
43
+ #33 Bright Yellow
44
+ def byellow(str)
45
+ colorize(str, "1;33")
46
+ end
47
+
48
+ #34 Blue
49
+ def blue(str)
50
+ colorize(str, "34")
51
+ end
52
+
53
+ #34 Bright Blue
54
+ def bblue(str)
55
+ colorize(str, "1;34")
56
+ end
57
+
58
+ #35 Magenta
59
+ def magenta(str)
60
+ colorize(str, "35")
61
+ end
62
+
63
+ #35 Bright Magenta
64
+ def bmagenta(str)
65
+ colorize(str, "1;35")
66
+ end
67
+
68
+ #36 Cyan
69
+ def cyan(str)
70
+ colorize(str, "36")
71
+ end
72
+
73
+ #36 Bright Cyan
74
+ def bcyan(str)
75
+ colorize(str, "1;36")
76
+ end
77
+
78
+ #37 White
79
+ def white(str)
80
+ colorize(str, "37")
81
+ end
82
+
83
+ #37 Bright White
84
+ def bwhite(str)
85
+ colorize(str, "1;37")
86
+ end
@@ -0,0 +1,34 @@
1
+ module Toss
2
+ module Meta
3
+ module ClassMethods
4
+ end
5
+
6
+ module InstanceMethods
7
+ def set(name, value)
8
+ create_accessor(name)
9
+ Object.send("#{name}=", value)
10
+ end
11
+
12
+ def create_method(name, &block)
13
+ Object.send(:define_method, name, &block)
14
+ end
15
+
16
+ def create_accessor(name)
17
+ create_method("#{name}=") do |value|
18
+ $globals = $globals || {}
19
+ $globals[name] = value
20
+ end
21
+ create_method(name.to_sym) do
22
+ $globals = $globals || {}
23
+ $globals[name]
24
+ end
25
+ end
26
+ end
27
+
28
+ def self.included(receiver)
29
+ receiver.extend ClassMethods
30
+ receiver.send :include, InstanceMethods
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,50 @@
1
+ require 'optparse'
2
+
3
+ module Toss
4
+ module Options
5
+
6
+ def self.load
7
+ options = { :recipes => [], :pre_set => {}, :set => {}, :verbose => false }
8
+
9
+ optparse = OptionParser.new do |opts|
10
+ opts.on('-e', '--environment ENVIRONMENT', 'Environment to deploy as') do |environment|
11
+ options[:environment] = environment
12
+ end
13
+
14
+ opts.on('-f', '--file FILE', 'A recipe file to run. Option may be used more than once.') do |file|
15
+ options[:recipes] << value
16
+ end
17
+
18
+ opts.on("-S", "--set-before NAME=VALUE", "Set a variable before the recipes are loaded.") do |name_value|
19
+ name, value = name_value.split("=", 2)
20
+ options[:pre_set][name.to_sym] = value
21
+ end
22
+
23
+ opts.on("-s", "--set NAME=VALUE", "Set a variable after the recipes are loaded.") do |name_value|
24
+ name, value = name_value.split("=", 2)
25
+ options[:set][name.to_sym] = value
26
+ end
27
+
28
+ opts.on('-v', '--verbose', 'Show more information about the process') do
29
+ options[:verbose] = true
30
+ end
31
+
32
+ opts.on('-h', '--help', 'Display this screen') do
33
+ puts opts
34
+ exit
35
+ end
36
+ end
37
+
38
+ begin
39
+ optparse.parse!
40
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
41
+ puts $!.to_s
42
+ puts optparse
43
+ exit
44
+ end
45
+
46
+ options
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,78 @@
1
+ def server(properties)
2
+ return Server.new(properties)
3
+ end
4
+
5
+ def with(obj, &block)
6
+ obj.instance_eval &block
7
+ end
8
+
9
+ class Server
10
+
11
+ attr_accessor :host, :user, :password, :type
12
+ attr_accessor :working_directory
13
+ attr_accessor :ssh
14
+
15
+ def initialize(properties)
16
+ @host = properties[:host]
17
+ @user = properties[:user]
18
+ @password = properties[:password]
19
+ @type = properties[:type]
20
+ end
21
+
22
+ def run(command='', &block)
23
+ if block_given?
24
+ self.instance_eval &block
25
+ else
26
+ result = exec(command, false)
27
+ return result.first
28
+ end
29
+ end
30
+
31
+ def exec(command, quiet=false)
32
+ ssh = open_sessions[host] || start_session(self)
33
+ # capture all stderr and stdout output from a remote process
34
+
35
+ if $options[:verbose]
36
+ puts "#{bwhite host} executing: #{command}"
37
+ end
38
+
39
+ if !working_directory.nil? && working_directory != ""
40
+ command = "cd #{working_directory} && " + command
41
+ end
42
+
43
+ stdout_data, stderr_data, exit_code, exit_signal = ssh_exec! ssh, command
44
+
45
+ if !quiet
46
+ puts "#{bwhite host} said: #{red stderr_data.strip!}" if !stderr_data.nil? && stderr_data != ""
47
+ puts "#{bwhite host} said: #{stdout_data.strip!}" if !stdout_data.nil? && stdout_data != ""
48
+ end
49
+
50
+ return exit_code, stdout_data, stderr_data, exit_signal
51
+ end
52
+
53
+ def exists?(path)
54
+ exit_code = run("[ -e #{path} ] && exit 0 || exit 1")
55
+ return exit_code == 0
56
+ end
57
+
58
+ def cd(path)
59
+ if $options[:verbose]
60
+ puts "#{bwhite host} cd to: #{path}"
61
+ end
62
+ if block_given?
63
+ previous_path = @working_directory
64
+ @working_directory = path
65
+ yield
66
+ @working_directory = previous_path
67
+ else
68
+ @working_directory = path
69
+ end
70
+ end
71
+
72
+ def delete(path)
73
+ if exists? "#{path}"
74
+ return run "unlink #{path}"
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,65 @@
1
+ require "net/ssh"
2
+ require "net/scp"
3
+
4
+ module Toss
5
+ module Ssh
6
+ module ClassMethods
7
+ end
8
+
9
+ module InstanceMethods
10
+ def open_sessions
11
+ @open_sessions ||= {}
12
+ end
13
+
14
+ def start_session(server)
15
+ puts "Starting ssh session to #{server.host}"
16
+ open_sessions[server.host] = Net::SSH.start(server.host, server.user, :password => server.password)
17
+ open_sessions[server.host]
18
+ end
19
+
20
+ def close_sessions
21
+ open_sessions.each.each do |target_host,session|
22
+ puts "Closing ssh session for #{target_host}"
23
+ session.close
24
+ open_sessions.delete(target_host)
25
+ end
26
+ end
27
+
28
+ def ssh_exec!(ssh, command)
29
+ stdout_data = ""
30
+ stderr_data = ""
31
+ exit_code = nil
32
+ exit_signal = nil
33
+ ssh.open_channel do |channel|
34
+ channel.exec(command) do |ch, success|
35
+ unless success
36
+ abort "FAILED: couldn't execute command (ssh.channel.exec)"
37
+ end
38
+ channel.on_data do |ch,data|
39
+ stdout_data+=data
40
+ end
41
+
42
+ channel.on_extended_data do |ch,type,data|
43
+ stderr_data+=data
44
+ end
45
+
46
+ channel.on_request("exit-status") do |ch,data|
47
+ exit_code = data.read_long
48
+ end
49
+
50
+ channel.on_request("exit-signal") do |ch, data|
51
+ exit_signal = data.read_long
52
+ end
53
+ end
54
+ end
55
+ ssh.loop
56
+ [stdout_data, stderr_data, exit_code, exit_signal]
57
+ end
58
+ end
59
+
60
+ def self.included(receiver)
61
+ receiver.extend ClassMethods
62
+ receiver.send :include, InstanceMethods
63
+ end
64
+ end
65
+ end
@@ -1,3 +1,4 @@
1
1
  module Toss
2
- VERSION = "0.0.4"
2
+ NAME = "Toss"
3
+ VERSION = "0.0.5"
3
4
  end
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Tim Santeford"]
10
10
  s.email = ["tsantef@gmail.com"]
11
- s.homepage = "https://github.com/tsantef/toss"
11
+ s.homepage = %q{https://github.com/tsantef/toss}
12
12
  s.default_executable = %q{toss}
13
13
  s.summary = %q{toss - Simple deployment}
14
14
  s.description = %q{toss - Simple deployment}
@@ -20,7 +20,8 @@ Gem::Specification.new do |s|
20
20
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
21
  s.require_paths = ["lib"]
22
22
 
23
- # specify any dependencies here; for example:
24
- # s.add_development_dependency "rspec"
25
- # s.add_runtime_dependency "rest-client"
23
+ s.add_dependency(%q<net-ssh>, [">= 2.0.14"])
24
+ s.add_dependency(%q<net-scp>, [">= 1.0.0"])
25
+ s.add_dependency(%q<highline>, [">= 0"])
26
+
26
27
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toss
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 4
10
- version: 0.0.4
9
+ - 5
10
+ version: 0.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Tim Santeford
@@ -15,9 +15,54 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-02-04 00:00:00 Z
19
- dependencies: []
20
-
18
+ date: 2012-03-06 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: net-ssh
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 19
29
+ segments:
30
+ - 2
31
+ - 0
32
+ - 14
33
+ version: 2.0.14
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: net-scp
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 23
45
+ segments:
46
+ - 1
47
+ - 0
48
+ - 0
49
+ version: 1.0.0
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: highline
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ type: :runtime
65
+ version_requirements: *id003
21
66
  description: toss - Simple deployment
22
67
  email:
23
68
  - tsantef@gmail.com
@@ -34,6 +79,11 @@ files:
34
79
  - Rakefile
35
80
  - bin/toss
36
81
  - lib/toss.rb
82
+ - lib/toss/color.rb
83
+ - lib/toss/meta.rb
84
+ - lib/toss/options.rb
85
+ - lib/toss/server.rb
86
+ - lib/toss/ssh.rb
37
87
  - lib/toss/version.rb
38
88
  - toss.gemspec
39
89
  homepage: https://github.com/tsantef/toss