automateit 0.71102 → 0.71103

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
@@ -1,2 +1 @@
1
- h�ɋ��r ��b6���\�Dn�U��&R�U2˘��ǣQ (}��& ��J���}2���"��u�4�/)\ŒJ̽6�����OA�e
2
- �Z���3Ǩ��1P��{��q5��ʚ��s�NN"v����>`�w�p.�F����ر~�z0����#j
1
+ V]�2� �0��Y����� L�������%^6&]�Ǎ���k�կY��
@@ -1,3 +1,17 @@
1
+ 0.71103:
2
+ Date: Sat, 03 Nov 2007 01:26:13 -0700
3
+ Desc:
4
+ - (+) Added "aissh" command, provides an easy way to run commands on a group of hosts. For example, see if there's a Rails process running on all hosts matching the "rails_servers" tag: "aissh -p . rails_servers 'ps -ef | grep rails'"
5
+ - Improved PackageManager, it can now accept package names as Symbols.
6
+ - Improved AccountManager spec with additional examples for checking password changes.
7
+ - Improved AccountManager::NSCD with refactoring and additional tests.
8
+ - Improved AddressManager spec with additional tests for address conversion routines and code generation helpers.
9
+ - Improved Plugin spec with more checks against invalid managers and drivers, and unavailable dependencies.
10
+ - Improved ShellManager spec with more checks against hard links and symbolic links; for #cp when contents, modes or ownership changes; for #rm with :force option: for #umask with and without block, and with caught exceptions.
11
+ - Added spec for String#shell_escape.
12
+ - Added spec for Object's extensions for #unique_methods and #args_and_opts.
13
+ - Added spec for NestedError.
14
+
1
15
  0.71102:
2
16
  Date: Fri, 02 Nov 2007 02:59:41 -0700
3
17
  Desc:
data/Rakefile CHANGED
@@ -82,50 +82,35 @@ class Numeric
82
82
  def commify() (s=self.to_s;x=s.length;s).rjust(x+(3-(x%3))).gsub(/(\d)(?=\d{3}+(\.\d*)?$)/,'\1,').strip end
83
83
  end
84
84
 
85
- desc "Display the lines of source code and how many lines were changed in the repository"
86
- task :loc => [:loclines, :locdiff, :locchurn, :sloc]
87
-
88
- desc "Display the lines of source code"
89
- task :loclines do
90
- require 'find'
91
- lines = 0
92
- bytes = 0
93
- Find.find(*%w(bin lib spec Rakefile ../web/Rakefile ../web/src )) do |path|
94
- Find.prune if path.match(/.*(\b(.hg|.svn|CVS)\b|(.sw.?|.pyc)$)/)
95
- next if File.directory?(path)
96
- if path.match(/(\bbin\b|.*\.(env|pl|py|rb|rake|java|sql|ftl|jsp|xml|properties|css|rcss|html|rhtml|erb|po|haml|sass)$)/)
97
- data = File.read(path)
98
- bytes += data.size
99
- ### lines += data.scan(/^.*\w.*$/).size # Skip spaces
100
- lines += data.scan(/^\s*(?!#)\w.*$/).size # Skip blanks and comments
101
- end
85
+ namespace :loc do
86
+ desc "Display lines of code using loccount"
87
+ task :count do
88
+ sh "loccount bin/* lib/ spec/ examples/ *.rake"
102
89
  end
103
- puts "Lines: "+lines.commify
104
- puts "Bytes: "+bytes.commify
105
- end
106
90
 
107
- task :loccount do
108
- sh ""
109
- end
91
+ desc "Display the lines of code changed in the repository"
92
+ task :diff do
93
+ if File.directory?(".hg")
94
+ puts "%s lines added and removed through SCM operations" % `hg log --patch`.scan(/^[+-][^+-].+/).size.commify
95
+ else
96
+ raise NotImplementedError.new("Sorry, this only works for a Mercurial checkout")
97
+ end
98
+ end
110
99
 
111
- desc "Display the lines of code changed in the repository"
112
- task :locdiff do
113
- if File.directory?(".hg")
114
- puts "%s lines added and removed through SCM operations" % `hg log --patch`.scan(/^[+-][^+-].+/).size.commify
115
- else
116
- raise NotImplementedError.new("Sorry, this only works for a Mercurial checkout")
100
+ desc "Display lines of churn"
101
+ task :churn do
102
+ require 'active_support'
103
+ puts "%s lines of Hg churn" % (`hg churn`.scan(/^[^\s]+\s+(\d+)\s/).flatten.map(&:to_i).sum).commify
117
104
  end
118
- end
119
105
 
120
- desc "Display lines of churn"
121
- task :locchurn do
122
- require 'active_support'
123
- puts "%s lines of Hg churn" % (`hg churn`.scan(/^[^\s]+\s+(\d+)\s/).flatten.map(&:to_i).sum).commify
106
+ desc "Display lines of code based on sloccount"
107
+ task :sloc do
108
+ sh "sloccount lib spec misc examples bin"
109
+ end
124
110
  end
125
111
 
126
- task :sloc do
127
- sh "sloccount lib spec misc examples bin"
128
- end
112
+ desc "Display the lines of source code and how many lines were changed in the repository"
113
+ task :loc => ["loc:count", "loc:diff", "loc:churn", "loc:sloc"]
129
114
 
130
115
  #---[ RubyGems ]--------------------------------------------------------
131
116
 
@@ -172,22 +157,26 @@ namespace :gem do
172
157
  end
173
158
  end
174
159
 
160
+ desc "Create a gem"
175
161
  task :gem do
176
162
  hoe(:gem)
177
163
  end
178
164
 
165
+ desc "Publish to RubyForge"
179
166
  task :publish do
180
167
  automateit
181
168
  hoe("release VERSION=#{AutomateIt::VERSION}")
182
169
  Rake::Task[:after].invoke
183
170
  end
184
171
 
172
+ desc "Tag a stable release"
185
173
  task :tag do
186
174
  automateit
187
175
  sh "hg tag #{AutomateIt::VERSION}"
188
176
  sh "hg tag -f stable"
189
177
  end
190
178
 
179
+ desc "Push a stable release"
191
180
  task :push do
192
181
  sh "hg push -r stable ../app_stable"
193
182
  end
@@ -233,6 +222,7 @@ namespace :install do
233
222
  end
234
223
  end
235
224
 
225
+ desc "Uninstall automateit gem"
236
226
  task :uninstall do
237
227
  automateit.package_manager.uninstall "automateit", :with => :gem
238
228
  end
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # XXX What can go wrong with this loading approach?
4
+ libdir = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
5
+ if File.directory?(libdir) and File.exists?(File.join(libdir, "automateit.rb"))
6
+ $LOAD_PATH.unshift(libdir)
7
+ end
8
+
9
+ require 'rubygems'
10
+ require 'optparse'
11
+ require 'automateit'
12
+ include AutomateIt::Constants
13
+
14
+ OptionParser.new do |parser|
15
+ PROG = File.basename($0)
16
+ opts = {}
17
+ parser.banner = <<EOB
18
+ #{PROG} - tool for running command via SSH on hosts matching AutomateIt tags
19
+
20
+ Usage: #{PROG} [options] [arguments...]
21
+
22
+ IMPORTANT:
23
+ #{PROG} can only match against tags specified in tags.yml. It cannot
24
+ match against automatically generated tags like the OS, architecture and such
25
+ which are created at runtime by PlatformManager or AddressManager. So if you
26
+ want to run a command against all Ubuntu servers, you must define them
27
+ explicitly in tags.yml.
28
+
29
+ Examples:
30
+ # Read tags from project in current directory and run "ls" on all hosts
31
+ # tagged with "apache_servers" or "rails_servers":
32
+ #{PROG} --project . 'apache_servers | rails_servers' ls
33
+
34
+ # Preview SSH commands needed to run "ls" on "apache_servers":
35
+ #{PROG} -p . -n apache_servers ls
36
+
37
+ # Pass arguments to "ls", rather than #{PROG}:
38
+ #{PROG} -p . -n apache_servers -- ls -la
39
+
40
+ # Same as previous but using a quoted string:
41
+ #{PROG} -p . -n apache_servers 'ls -la'
42
+
43
+ # Execute a command which requires the target server to redirect output:
44
+ #{PROG} -p . -n apache_servers 'ps -ef | grep apache'
45
+
46
+ Options:
47
+ EOB
48
+ parser.on("-n", "--preview", "Preview without executing commands") do |v|
49
+ opts[:preview] = v
50
+ end
51
+
52
+ parser.on("-p", "--project PATH", "Set project path") do |v|
53
+ opts[:project] = v
54
+ end
55
+
56
+ parser.on("-q", "--quiet", "Don't display commands executed") do |v|
57
+ opts[:verbosity] = Logger::ERROR
58
+ end
59
+
60
+ parser.on("-v", "--version", "Display version") do |v|
61
+ puts AutomateIt::VERSION
62
+ exit 0
63
+ end
64
+
65
+ parser.on("-h", "--help", "Display this help message") do |v|
66
+ puts parser
67
+ exit
68
+ end
69
+
70
+ args = parser.parse!.dup
71
+ query = args.shift
72
+ commands = args
73
+
74
+ if commands.blank?
75
+ puts parser
76
+ puts "\nERROR: No commands specified"
77
+ exit 1
78
+ end
79
+
80
+ interpreter = AutomateIt.new(
81
+ :project => opts[:project],
82
+ :verbosity => opts[:verbosity]
83
+ )
84
+
85
+ interpreter.preview true if opts[:preview]
86
+
87
+ for host in interpreter.hosts_tagged_with(query).sort
88
+ cmd = "ssh %s %s" % [host, commands.join(" ").shell_escape]
89
+ interpreter.sh(cmd)
90
+ end
91
+
92
+ exit 0
93
+ end
data/bin/aitag CHANGED
@@ -18,6 +18,13 @@ OptionParser.new do |parser|
18
18
 
19
19
  Usage: #{PROG} [options] [arguments...]
20
20
 
21
+ IMPORTANT:
22
+ #{PROG} can only match against tags specified in tags.yml. It cannot
23
+ match against automatically generated tags like the OS, architecture and such
24
+ which are created at runtime by PlatformManager or AddressManager. So if you
25
+ want to run a command against all Ubuntu servers, you must define them
26
+ explicitly in tags.yml.
27
+
21
28
  Examples:
22
29
  # Load 'myproject' and see if it's tagged with 'apache' or 'svn':
23
30
  #{PROG} -p myproject 'apache || svn'
@@ -35,6 +35,7 @@ Hash.module_eval{include ActiveSupport::CoreExtensions::Hash::Keys}
35
35
  # Extensions
36
36
  require 'ext/object.rb'
37
37
  require 'ext/metaclass.rb'
38
+ require 'ext/shell_escape.rb'
38
39
 
39
40
  # Helpers
40
41
  require 'hashcache'
@@ -42,6 +43,7 @@ require 'queued_logger'
42
43
  require 'tempster'
43
44
  require 'helpful_erb'
44
45
  require 'nested_error'
46
+ require 'nitpick'
45
47
 
46
48
  # Core
47
49
  require 'automateit/root'
@@ -15,8 +15,8 @@ class ::AutomateIt::AccountManager::Etc< ::AutomateIt::AccountManager::BaseDrive
15
15
  # the 'etc' module?
16
16
  def self.has_etc?
17
17
  begin
18
- require './spec/integration/account_manager_spec.rb:1etc'
19
- return defined?(Etc)
18
+ require 'etc'
19
+ return defined?(::Etc)
20
20
  rescue LoadError
21
21
  return false
22
22
  end
@@ -24,7 +24,7 @@ class ::AutomateIt::AccountManager::Etc< ::AutomateIt::AccountManager::BaseDrive
24
24
 
25
25
  # Alias for AccountManager::Etc.has_etc?
26
26
  def has_etc?
27
- self.has_etc?
27
+ self.class.has_etc?
28
28
  end
29
29
 
30
30
  #.......................................................................
@@ -3,7 +3,7 @@
3
3
  # AccountManager driver for invalidating records stored in the NSCD, Name
4
4
  # Service Cache Daemon, found on Unix-like systems.
5
5
  class ::AutomateIt::AccountManager::NSCD < ::AutomateIt::AccountManager::BaseDriver
6
- depends_on :programs => %w(nscd ps),
6
+ depends_on :programs => %w(nscd ps),
7
7
  :callbacks => [lambda{`ps -ef`.match(%r{/usr/sbin/nscd$})}]
8
8
 
9
9
  def suitability(method, *args) # :nodoc:
@@ -11,18 +11,21 @@ class ::AutomateIt::AccountManager::NSCD < ::AutomateIt::AccountManager::BaseDri
11
11
  return available? ? 5 : 0
12
12
  end
13
13
 
14
+ # Returns the NSCD database for the specified shorthand +query+.
15
+ def database_for(query)
16
+ case query.to_sym
17
+ when :user, :users, :passwd, :password
18
+ :passwd
19
+ when :group, :groups
20
+ :group
21
+ else
22
+ raise ArgumentError.new("Unknown cache database: #{query}")
23
+ end
24
+ end
25
+
14
26
  def invalidate(database)
15
27
  return false unless available?
16
28
 
17
- name = \
18
- case database.to_sym
19
- when :user, :users, :passwd
20
- :passwd
21
- when :group, :groups
22
- :group
23
- else
24
- raise ArgumentError.new("Unknown cache database: #{database}")
25
- end
26
- interpreter.sh("nscd -i #{name}")
29
+ interpreter.sh("nscd -i #{database_for(database)}")
27
30
  end
28
31
  end
@@ -155,7 +155,7 @@ class AutomateIt::AddressManager::BaseDriver< AutomateIt::Plugin::Driver
155
155
  ipcmd = "ifconfig"
156
156
  ipcmd << " " << _interface_and_label(opts)
157
157
  if helper_opts[:prepend]
158
- ipcmd << " " << helper_opts[:prepend].join(" ")
158
+ ipcmd << " " << [helper_opts[:prepend]].flatten.join(" ")
159
159
  end
160
160
  ipcmd << " %s" % opts[:address]
161
161
  ipcmd << " netmask %s" % opts[:mask] if opts[:mask]
@@ -164,7 +164,7 @@ class AutomateIt::AddressManager::BaseDriver< AutomateIt::Plugin::Driver
164
164
  ipcmd << " down" if action == :del
165
165
  end
166
166
  if helper_opts[:append]
167
- ipcmd << " " << helper_opts[:append].join(" ")
167
+ ipcmd << " " << [helper_opts[:append]].flatten.join(" ")
168
168
  end
169
169
  return ipcmd
170
170
  end
@@ -82,6 +82,8 @@ module AutomateIt
82
82
  # how to more easily dispatch commands from your program to the Interpreter
83
83
  # instance.
84
84
  class Interpreter < Common
85
+ include Nitpick
86
+
85
87
  # Plugin instance that instantiated the Interpreter.
86
88
  attr_accessor :parent
87
89
  private :parent
@@ -627,24 +629,5 @@ module AutomateIt
627
629
  text = ::HelpfulERB.new(template).result(binding)
628
630
  object.instance_eval(text)
629
631
  end
630
-
631
- # Use to manage nitpick message for debugging AutomateIt internals.
632
- #
633
- # Arguments:
634
- # * nil -- Returns boolean of whether nitpick messages will be displayed.
635
- # * Boolean -- Sets nitpick state.
636
- # * String or Symbol -- Displays nitpick message if state is on.
637
- #
638
- # Example:
639
- # nitpick true
640
- # nitpick "I'm nitpicking"
641
- def nitpick(value=nil)
642
- case value
643
- when NilClass: @nitpick
644
- when TrueClass, FalseClass: @nitpick = value
645
- when String, Symbol: puts "%% #{value}" if @nitpick
646
- else raise TypeError.new("Unknown nitpick type: #{value.class}")
647
- end
648
- end
649
632
  end
650
633
  end
@@ -222,6 +222,8 @@ class AutomateIt::PackageManager::BaseDriver < AutomateIt::Plugin::Driver
222
222
  result = packages.map(&:to_s).grep(LIST_NORMALIZER_RE)
223
223
  when Hash
224
224
  result = packages.stringify_keys
225
+ when Symbol, String
226
+ result = packages.to_s
225
227
  else
226
228
  raise TypeError.new("Unknown input type: #{packages.class}")
227
229
  end
@@ -185,7 +185,7 @@ module AutomateIt
185
185
  when :callbacks
186
186
  item.call() ? true : false
187
187
  else
188
- raise "unknown kind: #{kind}"
188
+ raise TypeError.new("Unknown kind: #{kind}")
189
189
  end
190
190
  unless present
191
191
  all_present = false
@@ -199,12 +199,7 @@ module AutomateIt
199
199
  # instance found, else raises a NotImplementedError if no suitable driver
200
200
  # is found.
201
201
  def driver_for(method, *args, &block)
202
- begin
203
- driver, level = driver_suitability_levels_for(method, *args, &block).sort_by{|k,v| v}.last
204
- rescue IndexError
205
- driver = nil
206
- level = -1
207
- end
202
+ driver, level = driver_suitability_levels_for(method, *args, &block).sort_by{|k,v| v}.last
208
203
  if driver and level > 0
209
204
  return @drivers[driver]
210
205
  else
@@ -1,7 +1,7 @@
1
1
  # See AutomateIt::Interpreter for usage information.
2
2
  module AutomateIt # :nodoc:
3
3
  # AutomateIt version
4
- VERSION=Gem::Version.new("0.71102")
4
+ VERSION=Gem::Version.new("0.71103")
5
5
 
6
6
  # Instantiates a new Interpreter. See documentation for
7
7
  # Interpreter#setup.
@@ -2,13 +2,13 @@
2
2
  #
3
3
  # Helper class for parsing tags. Not useful for users -- for internal use only.
4
4
  class AutomateIt::TagManager::TagParser
5
+ include Nitpick
6
+
5
7
  attr_accessor :struct
6
- attr_accessor :is_trace # FIXME replace is_trace with nitpick
7
8
 
8
9
  # Create a parser for the +struct+, a hash of tag keys to values with arrays of items.
9
- def initialize(struct, is_trace=false)
10
+ def initialize(struct)
10
11
  self.struct = struct
11
- self.is_trace = is_trace
12
12
  normalize!
13
13
  end
14
14
 
@@ -33,11 +33,6 @@ class AutomateIt::TagManager::TagParser
33
33
  end
34
34
  end
35
35
 
36
- # Display debugging information if +is_trace+ is enabled.
37
- def trace(msg)
38
- puts msg if is_trace
39
- end
40
-
41
36
  HOSTS_FOR_VALUE = /(.+?)/
42
37
  HOSTS_FOR_INCLUDE_TAG_RE = /^INCLUDE_TAG #{HOSTS_FOR_VALUE}$/
43
38
  HOSTS_FOR_EXCLUDE_TAG_RE = /^EXCLUDE_TAG #{HOSTS_FOR_VALUE}$/
@@ -45,27 +40,29 @@ class AutomateIt::TagManager::TagParser
45
40
 
46
41
  # Return array of hosts for the +tag+.
47
42
  def hosts_for(tag)
48
- raise IndexError.new("Unknown tag - #{tag}") unless struct[tag]
49
- trace "\nAA %s" % tag
43
+ raise IndexError.new("Unknown tag - #{tag}") unless struct.has_key?(tag)
44
+ return [] if struct[tag].nil? # Tag has no leaves
45
+
46
+ nitpick "\nAA %s" % tag
50
47
  hosts = Set.new
51
48
  for item in struct[tag]
52
49
  case item
53
50
  when HOSTS_FOR_INCLUDE_TAG_RE
54
- trace "+g %s" % $1
51
+ nitpick "+g %s" % $1
55
52
  hosts.merge(hosts_for($1))
56
53
  when HOSTS_FOR_EXCLUDE_TAG_RE
57
- trace "-g %s" % $1
54
+ nitpick "-g %s" % $1
58
55
  hosts.subtract(hosts_for($1))
59
56
  when HOSTS_FOR_EXCLUDE_HOST_RE
60
- trace "-h %s" % $1
57
+ nitpick "-h %s" % $1
61
58
  hosts.delete($1)
62
59
  else
63
- trace "+h %s" % item
60
+ nitpick "+h %s" % item
64
61
  hosts << item
65
62
  end
66
63
  end
67
64
  result = hosts.to_a
68
- trace "ZZ %s for %s" % [result.inspect, tag]
65
+ nitpick "ZZ %s for %s" % [result.inspect, tag]
69
66
  return result
70
67
  end
71
68
 
@@ -90,7 +87,7 @@ class AutomateIt::TagManager::TagParser
90
87
  end
91
88
 
92
89
  # Expand the +struct+.
93
- def self.expand(struct, is_trace=false)
94
- self.new(struct, is_trace).expand
90
+ def self.expand(struct)
91
+ self.new(struct).expand
95
92
  end
96
93
  end