automateit 0.71226.1 → 0.71230
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGES.txt +13 -1
- data/Hoe.rake +1 -2
- data/Rakefile +13 -9
- data/TODO.txt +4 -1
- data/bin/aifield +0 -11
- data/bin/aitag +16 -23
- data/helpers/cpan_wrapper.pl +138 -16
- data/lib/automateit.rb +1 -15
- data/lib/automateit/account_manager/base.rb +8 -4
- data/lib/automateit/address_manager/freebsd.rb +6 -3
- data/lib/automateit/address_manager/openbsd.rb +6 -3
- data/lib/automateit/edit_manager.rb +13 -5
- data/lib/automateit/package_manager.rb +16 -8
- data/lib/automateit/package_manager/cpan.rb +4 -6
- data/lib/automateit/platform_manager/lsb.rb +15 -11
- data/lib/automateit/root.rb +1 -1
- data/lib/automateit/service_manager/sysv.rb +6 -3
- data/lib/automateit/template_manager/base.rb +30 -26
- data/lib/inactive_support.rb +50 -0
- data/lib/inactive_support/basic_object.rb +5 -0
- data/lib/inactive_support/clean_logger.rb +127 -0
- data/lib/inactive_support/core_ext/array/extract_options.rb +19 -0
- data/lib/inactive_support/core_ext/blank.rb +50 -0
- data/lib/inactive_support/core_ext/class/attribute_accessors.rb +48 -0
- data/lib/inactive_support/core_ext/class/inheritable_attributes.rb +140 -0
- data/lib/inactive_support/core_ext/enumerable.rb +63 -0
- data/lib/inactive_support/core_ext/hash/keys.rb +54 -0
- data/lib/inactive_support/core_ext/module/aliasing.rb +70 -0
- data/lib/inactive_support/core_ext/numeric/time.rb +91 -0
- data/lib/inactive_support/core_ext/string/inflections.rb +153 -0
- data/lib/inactive_support/core_ext/symbol.rb +14 -0
- data/lib/inactive_support/core_ext/time/conversions.rb +94 -0
- data/lib/inactive_support/duration.rb +96 -0
- data/lib/inactive_support/inflections.rb +53 -0
- data/lib/inactive_support/inflector.rb +282 -0
- data/lib/nitpick.rb +8 -4
- data/spec/integration/package_manager_spec.rb +1 -1
- data/spec/integration/platform_manager_spec.rb +0 -16
- data/spec/unit/edit_manager_spec.rb +1 -0
- data/spec/unit/package_manager_spec.rb +1 -0
- metadata +19 -23
- metadata.gz.sig +0 -0
- data/helpers/cpan_install.pl +0 -59
- data/helpers/cpan_is_installed.pl +0 -37
- data/helpers/cpan_uninstall.pl +0 -58
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGES.txt
CHANGED
@@ -1,7 +1,19 @@
|
|
1
|
+
0.71230:
|
2
|
+
Date: Sun, 30 Dec 2007 14:05:31 -0800
|
3
|
+
Desc:
|
4
|
+
- (!) Removed all code that relied on the ActiveSupport and Builder libraries. The new, AutomateIt-specific replacements for these libraries are guaranteed to work correctly and load much more quickly.
|
5
|
+
- (!) Removed the "--to-xml" option from "aitag" and "aifield". If anyone relied on this functionality, post to the mailing list and I'll write a replacement.
|
6
|
+
- (%) Fixed PlatformManager::LSB, it no longer converts OS release versions like "7.10" into "7.1".
|
7
|
+
- (%) Fixed "aitags" with "--tags" options, it now returns a sorted array instead of a set.
|
8
|
+
- (%) Fixed case/when statements to work with Ruby 1.9.
|
9
|
+
- (%) Fixed TemplateManager#render, it now only runs file-related checks when rendering to a file.
|
10
|
+
- Improved PackageManager::CPAN's "cpan_wrapper.pl". It's now just a single file that can be used as both a command and library.
|
11
|
+
- Improved EditManager. In preview mode, it now checks to make sure the file is readable, rather than failing due to permission denied errors.
|
12
|
+
|
1
13
|
0.71226.1:
|
2
14
|
Date: Wed, 26 Dec 2007 11:45:03 -0800
|
3
15
|
Desc:
|
4
|
-
- Same as previous version. Something went wrong with Rubyforge and the gem was only partially uploaded, so trying again.
|
16
|
+
- Same as previous version. Something went wrong with Rubyforge and the gem was only partially uploaded, so trying again.
|
5
17
|
|
6
18
|
0.71226:
|
7
19
|
Date: Wed, 26 Dec 2007 11:41:03 -0800
|
data/Hoe.rake
CHANGED
@@ -25,8 +25,7 @@ Hoe.new("AutomateIt", AutomateIt::VERSION.to_s) do |s|
|
|
25
25
|
s.changes = s.paragraphs_of('CHANGES.txt', 0).join("\n")
|
26
26
|
s.description = slogan
|
27
27
|
s.email = "igal@pragmaticraft.com"
|
28
|
-
|
29
|
-
s.extra_deps = [["activesupport", ">= 1.4"], ["builder", ">= 2.0"], ["open4", ">= 0.9"]]
|
28
|
+
s.extra_deps = [["open4", ">= 0.9"]]
|
30
29
|
s.name = "automateit"
|
31
30
|
s.summary = slogan
|
32
31
|
s.url = "http://automateit.org/"
|
data/Rakefile
CHANGED
@@ -98,8 +98,7 @@ namespace :loc do
|
|
98
98
|
|
99
99
|
desc "Display lines of churn"
|
100
100
|
task :churn do
|
101
|
-
|
102
|
-
require 'active_support'
|
101
|
+
automateit # Load libraries
|
103
102
|
puts "%s lines of Hg churn" % (`hg churn`.scan(/^[^\s]+\s+(\d+)\s/).flatten.map(&:to_i).sum).commify
|
104
103
|
end
|
105
104
|
|
@@ -143,8 +142,7 @@ end
|
|
143
142
|
|
144
143
|
desc "RFC-822 time for right now, optional D=x where x is delta like '1.day' ago"
|
145
144
|
task :now do
|
146
|
-
|
147
|
-
require 'activesupport'
|
145
|
+
automateit # Loads libraries
|
148
146
|
time = Time.now
|
149
147
|
if delta = ENV["D"]
|
150
148
|
time = eval "time - #{delta}"
|
@@ -154,8 +152,7 @@ end
|
|
154
152
|
|
155
153
|
desc "RFC-822 time for yesterday"
|
156
154
|
task :yesterday do
|
157
|
-
|
158
|
-
require 'active_support'
|
155
|
+
automateit # Loads libraries
|
159
156
|
time = Time.now - 1.day
|
160
157
|
puts time.to_s(:rfc822)
|
161
158
|
end
|
@@ -174,7 +171,7 @@ end
|
|
174
171
|
|
175
172
|
desc "Publish to RubyForge"
|
176
173
|
task :publish do
|
177
|
-
automateit
|
174
|
+
automateit # Loads libraries
|
178
175
|
hoe("release VERSION=#{AutomateIt::VERSION}")
|
179
176
|
Rake::Task[:after].invoke
|
180
177
|
end
|
@@ -243,7 +240,7 @@ namespace :rdoc do
|
|
243
240
|
desc "Generate documentation"
|
244
241
|
task :make do
|
245
242
|
# Uses Jamis Buck's RDoc template from http://weblog.jamisbuck.org/2005/4/8/rdoc-template
|
246
|
-
sh "rdoc --template=jamis --main
|
243
|
+
sh "rdoc --op doc --template=jamis --main README.txt --promiscuous --accessor class_inheritable_accessor=R --inline-source --line-numbers --title 'AutomateIt: Open source server automation' README.txt TUTORIAL.txt TESTING.txt lib docs/*.txt"
|
247
244
|
# Create a tutorial index
|
248
245
|
File.open("doc/tutorial.html", "w+") do |writer|
|
249
246
|
writer.write(File.read("doc/index.html").sub(/README_txt.html/, 'TUTORIAL_txt.html'))
|
@@ -297,7 +294,14 @@ namespace :rdoc do
|
|
297
294
|
end
|
298
295
|
end
|
299
296
|
|
300
|
-
|
297
|
+
desc "Generate Rdoc"
|
298
|
+
task :rdoc do
|
299
|
+
# TODO Something is broke in rdoc recently. It decides to only generate rdocs for newer files, which is very bad because if you re-run "rdoc" without deleting the "doc" directory, it'll can end up creating a set of documentation that only contains the single file you changed. This sucks.
|
300
|
+
sh "rm -rf doc" if File.exist?("doc")
|
301
|
+
|
302
|
+
Rake::Task["rdoc:make"].invoke
|
303
|
+
Rake::Task["rdoc:rewrite"].invoke
|
304
|
+
end
|
301
305
|
|
302
306
|
desc "List aliased_methods for inclusion into rdoc"
|
303
307
|
task :aliased_methods do
|
data/TODO.txt
CHANGED
@@ -12,9 +12,12 @@ KEY: Important? Urgent? Easy? 1=yes, 0=no
|
|
12
12
|
111 AccountManager::NSCD -- Uses "ps -ef", needs abstraction
|
13
13
|
|
14
14
|
#---[ Design issues ]---------------------------------------------------
|
15
|
-
|
15
|
+
??? PackageManager -- How to specify interpreter? E.g. reuse CPAN driver's approach?
|
16
|
+
??? PackageManager -- How to have driver check against instance variables, such as the particular interpreter requested? Needed to work around things like 'gem1.8', 'python2.5.1' and '/usr/local/bin/perl'.
|
17
|
+
??? PackageManager -- What's a reasonable way to leave out the ':with' option when using a hash argument to install? E.g., sudo ai -e "package_manager.install({'swiftfox-prescott' => '/tmp/swiftfox_3.0b3pre-1_prescott.deb'}, :with => :dpkg)"
|
16
18
|
|
17
19
|
#---[ Development ]-----------------------------------------------------
|
20
|
+
111 Shell or ServiceManager -- Add pgrep/pmatch methods and import them
|
18
21
|
111 Shell -- Write #su(user, *command) as a wrapper around #sh
|
19
22
|
101 Shell -- Expand glob patterns, e.g. chown_R(500, 500, "*")
|
20
23
|
100 Edit -- Display summary of edits, return with :details as [rv, list]
|
data/bin/aifield
CHANGED
@@ -29,9 +29,6 @@ Examples:
|
|
29
29
|
# Dump the 'myapp' hash contents as YAML
|
30
30
|
#{PROG} -y myapp#user
|
31
31
|
|
32
|
-
# Dump the 'myapp' hash contents as XML
|
33
|
-
#{PROG} -x myapp#user
|
34
|
-
|
35
32
|
Options:
|
36
33
|
EOB
|
37
34
|
parser.on("-p", "--project PATH", "Set project path") do |v|
|
@@ -42,10 +39,6 @@ EOB
|
|
42
39
|
opts[:yaml] = v
|
43
40
|
end
|
44
41
|
|
45
|
-
parser.on("-X", "--xml", "Dump as XML") do |v|
|
46
|
-
opts[:xml] = v
|
47
|
-
end
|
48
|
-
|
49
42
|
parser.on("-a", "--add TAGS", "Add list of space separated tags") do |v|
|
50
43
|
opts[:tags] = [v.split].flatten
|
51
44
|
end
|
@@ -75,10 +68,6 @@ EOB
|
|
75
68
|
exit 1
|
76
69
|
elsif opts[:yaml]
|
77
70
|
puts result.to_yaml
|
78
|
-
elsif opts[:xml]
|
79
|
-
require 'active_support/core_ext/hash'
|
80
|
-
require 'active_support/core_ext/array'
|
81
|
-
puts result.to_xml
|
82
71
|
else
|
83
72
|
puts result.is_a?(String) ? result : result.inspect
|
84
73
|
end
|
data/bin/aitag
CHANGED
@@ -19,11 +19,11 @@ OptionParser.new do |parser|
|
|
19
19
|
Usage: #{PROG} [options] [arguments...]
|
20
20
|
|
21
21
|
IMPORTANT:
|
22
|
-
#{PROG} can only match against tags specified in tags.yml. It cannot
|
22
|
+
#{PROG} can only match against tags specified in tags.yml. It cannot
|
23
23
|
match against automatically generated tags like the OS, architecture and such
|
24
24
|
which are created at runtime by PlatformManager or AddressManager. So if you
|
25
25
|
want to run a command against all Ubuntu servers, you must define them
|
26
|
-
explicitly in tags.yml.
|
26
|
+
explicitly in tags.yml.
|
27
27
|
|
28
28
|
Examples:
|
29
29
|
# Load 'myproject' and see if it's tagged with 'apache' or 'svn':
|
@@ -38,13 +38,10 @@ Examples:
|
|
38
38
|
# Dump the results of a query as YAML
|
39
39
|
#{PROG} -Y myapp#user
|
40
40
|
|
41
|
-
# Dump the results of a query as XML
|
42
|
-
#{PROG} -X myapp#user
|
43
|
-
|
44
41
|
Options:
|
45
42
|
EOB
|
46
43
|
parser.on("-s", "--tags", "List tags for this host") do |v|
|
47
|
-
opts[:
|
44
|
+
opts[:list_tags] = v
|
48
45
|
end
|
49
46
|
|
50
47
|
parser.on("-f", "--tags_for HOST", "List tags for a specific host") do |v|
|
@@ -67,12 +64,8 @@ EOB
|
|
67
64
|
opts[:yaml] = v
|
68
65
|
end
|
69
66
|
|
70
|
-
parser.on("-X", "--xml", "Dump as XML") do |v|
|
71
|
-
opts[:xml] = v
|
72
|
-
end
|
73
|
-
|
74
67
|
parser.on("-a", "--add TAGS", "Add list of space separated tags") do |v|
|
75
|
-
opts[:
|
68
|
+
opts[:add_tags] = [v.split].flatten
|
76
69
|
end
|
77
70
|
|
78
71
|
parser.on("-v", "--version", "Display version") do |v|
|
@@ -93,11 +86,11 @@ EOB
|
|
93
86
|
|
94
87
|
interpreter = AutomateIt.new(
|
95
88
|
:project => opts[:project],
|
96
|
-
:tags => opts[:
|
89
|
+
:tags => opts[:add_tags]
|
97
90
|
)
|
98
91
|
result = nil
|
99
92
|
|
100
|
-
unless opts[:
|
93
|
+
unless opts[:list_tags] or opts[:tags_for] or opts[:tagged?] or opts[:hosts_tagged_with]
|
101
94
|
if args.first
|
102
95
|
opts[:tagged?] = args.first
|
103
96
|
else
|
@@ -108,8 +101,8 @@ EOB
|
|
108
101
|
end
|
109
102
|
|
110
103
|
result = \
|
111
|
-
if opts[:
|
112
|
-
interpreter.tags
|
104
|
+
if opts[:list_tags]
|
105
|
+
interpreter.tags.to_a.sort
|
113
106
|
elsif opts[:tags_for]
|
114
107
|
interpreter.tags_for(opts[:tags_for])
|
115
108
|
elsif opts[:tagged?]
|
@@ -123,16 +116,16 @@ EOB
|
|
123
116
|
result.inspect
|
124
117
|
elsif opts[:yaml]
|
125
118
|
result.to_yaml
|
126
|
-
elsif opts[:xml]
|
127
|
-
require 'active_support/core_ext/hash'
|
128
|
-
require 'active_support/core_ext/array'
|
129
|
-
result.to_xml
|
130
119
|
else
|
131
120
|
case result
|
132
|
-
when String
|
133
|
-
|
134
|
-
when
|
135
|
-
|
121
|
+
when String
|
122
|
+
result
|
123
|
+
when Set
|
124
|
+
result.sort.to_a.join(' ')
|
125
|
+
when Array
|
126
|
+
result.sort.join(' ')
|
127
|
+
else
|
128
|
+
result.inspect
|
136
129
|
end
|
137
130
|
end
|
138
131
|
)
|
data/helpers/cpan_wrapper.pl
CHANGED
@@ -1,21 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
use ExtUtils::Packlist;
|
4
|
-
use ExtUtils::Installed;
|
1
|
+
# This file can be used as both a Perl library (read the POD below) and a
|
2
|
+
# stand-alone program (run it with "--help" for instructions).
|
5
3
|
|
6
4
|
=head1 NAME
|
7
5
|
|
8
|
-
CpanWrapper - Provides a simpler wrapper for CPAN package
|
6
|
+
CpanWrapper - Provides a simpler wrapper for the CPAN package manager.
|
9
7
|
|
10
8
|
=head1 DESCRIPTION
|
11
9
|
|
12
|
-
This module provides easy-to-use methods for
|
13
|
-
|
10
|
+
This module provides easy-to-use methods for installing, uninstalling and
|
11
|
+
querying the status of CPAN modules.
|
12
|
+
|
13
|
+
=over
|
14
|
+
|
15
|
+
=cut
|
16
|
+
|
17
|
+
use warnings "all";
|
18
|
+
|
19
|
+
package CpanWrapper;
|
20
|
+
|
21
|
+
require CPAN;
|
22
|
+
require ExtUtils::Packlist;
|
23
|
+
require ExtUtils::Installed;
|
24
|
+
require Tie::Handle;
|
14
25
|
|
15
26
|
=head1 CLASS VARIABLES
|
16
27
|
|
17
28
|
=item $CpanWrapper::DRYRUN
|
18
|
-
|
29
|
+
|
19
30
|
Should actions really happen? E.g., in dry-run mode, the uninstall will only
|
20
31
|
pretend to delete files.
|
21
32
|
|
@@ -23,24 +34,28 @@ pretend to delete files.
|
|
23
34
|
|
24
35
|
our $DRYRUN = 0;
|
25
36
|
|
26
|
-
=
|
37
|
+
=head1 CLASS METHODS
|
27
38
|
|
28
|
-
|
39
|
+
=item CpanWrapper->query($module_name)
|
29
40
|
|
30
|
-
|
41
|
+
Query the module and return 1 if it's installed, 0 if not.
|
31
42
|
|
32
|
-
CpanWrapper->is_installed('App::Ack')
|
33
43
|
=cut
|
34
|
-
sub
|
44
|
+
sub query {
|
35
45
|
my($class, $module) = @_;
|
36
|
-
|
46
|
+
no warnings;
|
47
|
+
my $result = $CPAN::META->has_inst($module);
|
48
|
+
use warnings "all";
|
49
|
+
return $result;
|
37
50
|
}
|
38
51
|
|
39
52
|
=item CpanWrapper->uninstall($module_name)
|
40
53
|
|
41
54
|
Uninstall the module. Returns an array of files removed.
|
55
|
+
|
42
56
|
=cut
|
43
57
|
sub uninstall {
|
58
|
+
# /usr/local/lib/perl/5.8.8/auto/ack/.packlist
|
44
59
|
my($class, $module) = @_;
|
45
60
|
my $packlists = ExtUtils::Installed->new;
|
46
61
|
my @result;
|
@@ -48,14 +63,19 @@ sub uninstall {
|
|
48
63
|
push(@result, $file);
|
49
64
|
unlink $file unless $DRYRUN;
|
50
65
|
}
|
66
|
+
my $packlist = $packlists->packlist($module)->packlist_file();
|
67
|
+
push(@result, $packlist);
|
68
|
+
unlink $packlist unless $DRYRUN;
|
51
69
|
return @result;
|
52
70
|
}
|
53
71
|
|
54
72
|
=item CpanWrapper->install($module_name)
|
55
73
|
|
56
74
|
Install the module. Returns 0 if can't find module.
|
75
|
+
|
57
76
|
=cut
|
58
77
|
sub install {
|
78
|
+
no warnings;
|
59
79
|
my($class, $module) = @_;
|
60
80
|
tie *NO, 'NoHandle';
|
61
81
|
open(SAVEIN, ">&STDIN");
|
@@ -70,15 +90,16 @@ sub install {
|
|
70
90
|
}
|
71
91
|
open(STDIN, ">&SAVEIN");
|
72
92
|
close NO;
|
93
|
+
use warnings "all";
|
73
94
|
return $result;
|
74
95
|
}
|
75
96
|
|
76
97
|
=item NoHandle
|
77
98
|
|
78
99
|
File handle that responds with "no" to all readline queries. This is used
|
79
|
-
during the install process to reject CPAN's
|
100
|
+
during the install process to reject CPAN's unreasonable defaults.
|
101
|
+
|
80
102
|
=cut
|
81
|
-
require Tie::Handle;
|
82
103
|
package NoHandle;
|
83
104
|
sub TIEHANDLE { my $self; bless \$self, shift }
|
84
105
|
sub WRITE { die }
|
@@ -93,6 +114,107 @@ sub BINMODE { }
|
|
93
114
|
sub EOF { 0 }
|
94
115
|
sub TELL { }
|
95
116
|
sub DESTROY { }
|
117
|
+
|
118
|
+
#===[ command-line usage ]==============================================
|
119
|
+
|
96
120
|
package main;
|
121
|
+
if ($0 eq __FILE__) {
|
122
|
+
sub usage {
|
123
|
+
my($message) = @_;
|
124
|
+
print <<HERE;
|
125
|
+
USAGE: cpan_wrapper.pl [OPTIONS] ACTION module [modules...]
|
126
|
+
|
127
|
+
OPTIONS:
|
128
|
+
--help
|
129
|
+
Show this help
|
130
|
+
--quiet
|
131
|
+
Don't print anything other than what CPAN generates
|
132
|
+
--dryrun
|
133
|
+
Don't actually perform actions, just pretend to
|
134
|
+
|
135
|
+
ACTIONS:
|
136
|
+
|
137
|
+
--install
|
138
|
+
Install modules
|
139
|
+
--uninstall
|
140
|
+
Uninstall modules
|
141
|
+
--query
|
142
|
+
Display which packages are installed and which aren't
|
143
|
+
HERE
|
144
|
+
|
145
|
+
if ($message) {
|
146
|
+
print "ERROR: $message\n";
|
147
|
+
exit 1;
|
148
|
+
} else {
|
149
|
+
exit 0;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
use Getopt::Long;
|
154
|
+
our $quiet = 0;
|
155
|
+
our $dryrun = 0;
|
156
|
+
our $help = 0;
|
157
|
+
our $install = 0;
|
158
|
+
our $uninstall = 0;
|
159
|
+
our $query = 0;
|
160
|
+
GetOptions(
|
161
|
+
'quiet' => \$quiet,
|
162
|
+
'dryrun' => \$dryrun,
|
163
|
+
'n' => \$dryrun,
|
164
|
+
'help' => \$help,
|
165
|
+
'install' => \$install,
|
166
|
+
'uninstall' => \$uninstall,
|
167
|
+
'query' => \$query,
|
168
|
+
'q' => \$query
|
169
|
+
);
|
170
|
+
my @modules = @ARGV;
|
171
|
+
|
172
|
+
usage(0) if 1 == $help;
|
173
|
+
usage("No action specified") unless $install or $uninstall or $query;
|
174
|
+
usage("No modules specified") unless $#modules >= 0;
|
175
|
+
|
176
|
+
if ($install) {
|
177
|
+
foreach my $module (@modules) {
|
178
|
+
if (CpanWrapper->install($module)) {
|
179
|
+
print "* Installed: $module\n" unless $quiet;
|
180
|
+
} else {
|
181
|
+
print "! Can't find CPAN module: $module\n";
|
182
|
+
exit 1
|
183
|
+
}
|
184
|
+
}
|
185
|
+
} elsif ($uninstall) {
|
186
|
+
foreach my $module (@modules) {
|
187
|
+
print "* Uninstalling module: $module\n" unless $quiet;
|
188
|
+
|
189
|
+
my(@files) = CpanWrapper->uninstall($module);
|
190
|
+
foreach my $file (@files) {
|
191
|
+
print "- $file\n" unless $quiet;
|
192
|
+
}
|
193
|
+
}
|
194
|
+
} elsif ($query) {
|
195
|
+
my @available;
|
196
|
+
my @unavailable;
|
197
|
+
foreach my $module (@modules) {
|
198
|
+
if (CpanWrapper->query($module)) {
|
199
|
+
push(@available, $module);
|
200
|
+
} else {
|
201
|
+
push(@unavailable, $module);
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
sub print_contents {
|
206
|
+
my($name, @modules) = @_;
|
207
|
+
return if $#modules < 0;
|
208
|
+
print "$name:\n";
|
209
|
+
foreach my $module (@modules) {
|
210
|
+
print " - $module\n";
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
print "--- %YAML:1.0\n";
|
215
|
+
print_contents 'available', @available;
|
216
|
+
print_contents 'unavailable', @unavailable;
|
217
|
+
}
|
218
|
+
}
|
97
219
|
|
98
220
|
1;
|