automateit 0.71102 → 0.71103

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.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