automate-it 0.9.0

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.
Files changed (137) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.hgignore +10 -0
  4. data/.loadpath +5 -0
  5. data/.project +17 -0
  6. data/CHANGES.txt +314 -0
  7. data/Hoe.rake +40 -0
  8. data/Manifest.txt +164 -0
  9. data/README.txt +40 -0
  10. data/Rakefile +256 -0
  11. data/TESTING.txt +57 -0
  12. data/TODO.txt +50 -0
  13. data/TUTORIAL.txt +391 -0
  14. data/automate-it.gemspec +25 -0
  15. data/bin/ai +3 -0
  16. data/bin/aifield +75 -0
  17. data/bin/aissh +93 -0
  18. data/bin/aitag +134 -0
  19. data/bin/automateit +133 -0
  20. data/docs/friendly_errors.txt +50 -0
  21. data/docs/previews.txt +86 -0
  22. data/examples/basic/Rakefile +26 -0
  23. data/examples/basic/config/automateit_env.rb +16 -0
  24. data/examples/basic/config/fields.yml +3 -0
  25. data/examples/basic/config/tags.yml +7 -0
  26. data/examples/basic/dist/README.txt +9 -0
  27. data/examples/basic/dist/myapp_server.erb +30 -0
  28. data/examples/basic/install.log +15 -0
  29. data/examples/basic/lib/README.txt +10 -0
  30. data/examples/basic/recipes/README.txt +4 -0
  31. data/examples/basic/recipes/install.rb +61 -0
  32. data/examples/basic/recipes/uninstall.rb +6 -0
  33. data/gpl.txt +674 -0
  34. data/helpers/cpan_wrapper.pl +220 -0
  35. data/helpers/which.cmd +7 -0
  36. data/lib/automateit.rb +55 -0
  37. data/lib/automateit/account_manager.rb +114 -0
  38. data/lib/automateit/account_manager/base.rb +138 -0
  39. data/lib/automateit/account_manager/etc.rb +128 -0
  40. data/lib/automateit/account_manager/nscd.rb +33 -0
  41. data/lib/automateit/account_manager/passwd_expect.rb +40 -0
  42. data/lib/automateit/account_manager/passwd_pty.rb +69 -0
  43. data/lib/automateit/account_manager/posix.rb +138 -0
  44. data/lib/automateit/address_manager.rb +88 -0
  45. data/lib/automateit/address_manager/base.rb +171 -0
  46. data/lib/automateit/address_manager/bsd.rb +28 -0
  47. data/lib/automateit/address_manager/freebsd.rb +59 -0
  48. data/lib/automateit/address_manager/linux.rb +42 -0
  49. data/lib/automateit/address_manager/openbsd.rb +66 -0
  50. data/lib/automateit/address_manager/portable.rb +37 -0
  51. data/lib/automateit/address_manager/sunos.rb +34 -0
  52. data/lib/automateit/cli.rb +85 -0
  53. data/lib/automateit/common.rb +65 -0
  54. data/lib/automateit/constants.rb +35 -0
  55. data/lib/automateit/download_manager.rb +48 -0
  56. data/lib/automateit/edit_manager.rb +321 -0
  57. data/lib/automateit/error.rb +10 -0
  58. data/lib/automateit/field_manager.rb +103 -0
  59. data/lib/automateit/interpreter.rb +631 -0
  60. data/lib/automateit/package_manager.rb +257 -0
  61. data/lib/automateit/package_manager/apt.rb +27 -0
  62. data/lib/automateit/package_manager/cpan.rb +101 -0
  63. data/lib/automateit/package_manager/dpkg.rb +54 -0
  64. data/lib/automateit/package_manager/egg.rb +64 -0
  65. data/lib/automateit/package_manager/gem.rb +201 -0
  66. data/lib/automateit/package_manager/pear.rb +95 -0
  67. data/lib/automateit/package_manager/pecl.rb +80 -0
  68. data/lib/automateit/package_manager/portage.rb +69 -0
  69. data/lib/automateit/package_manager/yum.rb +65 -0
  70. data/lib/automateit/platform_manager.rb +49 -0
  71. data/lib/automateit/platform_manager/darwin.rb +30 -0
  72. data/lib/automateit/platform_manager/debian.rb +26 -0
  73. data/lib/automateit/platform_manager/freebsd.rb +29 -0
  74. data/lib/automateit/platform_manager/gentoo.rb +26 -0
  75. data/lib/automateit/platform_manager/lsb.rb +44 -0
  76. data/lib/automateit/platform_manager/openbsd.rb +28 -0
  77. data/lib/automateit/platform_manager/struct.rb +80 -0
  78. data/lib/automateit/platform_manager/sunos.rb +39 -0
  79. data/lib/automateit/platform_manager/uname.rb +29 -0
  80. data/lib/automateit/platform_manager/windows.rb +40 -0
  81. data/lib/automateit/plugin.rb +7 -0
  82. data/lib/automateit/plugin/base.rb +32 -0
  83. data/lib/automateit/plugin/driver.rb +256 -0
  84. data/lib/automateit/plugin/manager.rb +224 -0
  85. data/lib/automateit/project.rb +493 -0
  86. data/lib/automateit/root.rb +17 -0
  87. data/lib/automateit/service_manager.rb +93 -0
  88. data/lib/automateit/service_manager/chkconfig.rb +39 -0
  89. data/lib/automateit/service_manager/rc_update.rb +37 -0
  90. data/lib/automateit/service_manager/sysv.rb +139 -0
  91. data/lib/automateit/service_manager/update_rcd.rb +35 -0
  92. data/lib/automateit/shell_manager.rb +316 -0
  93. data/lib/automateit/shell_manager/base_link.rb +67 -0
  94. data/lib/automateit/shell_manager/link.rb +24 -0
  95. data/lib/automateit/shell_manager/portable.rb +523 -0
  96. data/lib/automateit/shell_manager/symlink.rb +32 -0
  97. data/lib/automateit/shell_manager/which_base.rb +30 -0
  98. data/lib/automateit/shell_manager/which_unix.rb +16 -0
  99. data/lib/automateit/shell_manager/which_windows.rb +20 -0
  100. data/lib/automateit/tag_manager.rb +127 -0
  101. data/lib/automateit/tag_manager/struct.rb +121 -0
  102. data/lib/automateit/tag_manager/tag_parser.rb +93 -0
  103. data/lib/automateit/tag_manager/yaml.rb +29 -0
  104. data/lib/automateit/template_manager.rb +56 -0
  105. data/lib/automateit/template_manager/base.rb +181 -0
  106. data/lib/automateit/template_manager/erb.rb +17 -0
  107. data/lib/ext/metaclass.rb +17 -0
  108. data/lib/ext/object.rb +18 -0
  109. data/lib/ext/shell_escape.rb +7 -0
  110. data/lib/hashcache.rb +22 -0
  111. data/lib/helpful_erb.rb +63 -0
  112. data/lib/inactive_support.rb +53 -0
  113. data/lib/inactive_support/basic_object.rb +6 -0
  114. data/lib/inactive_support/clean_logger.rb +127 -0
  115. data/lib/inactive_support/core_ext/array/extract_options.rb +19 -0
  116. data/lib/inactive_support/core_ext/blank.rb +50 -0
  117. data/lib/inactive_support/core_ext/class/attribute_accessors.rb +48 -0
  118. data/lib/inactive_support/core_ext/class/inheritable_attributes.rb +140 -0
  119. data/lib/inactive_support/core_ext/enumerable.rb +63 -0
  120. data/lib/inactive_support/core_ext/hash/keys.rb +54 -0
  121. data/lib/inactive_support/core_ext/module/aliasing.rb +70 -0
  122. data/lib/inactive_support/core_ext/numeric/time.rb +91 -0
  123. data/lib/inactive_support/core_ext/string/inflections.rb +153 -0
  124. data/lib/inactive_support/core_ext/symbol.rb +14 -0
  125. data/lib/inactive_support/core_ext/time/conversions.rb +96 -0
  126. data/lib/inactive_support/duration.rb +96 -0
  127. data/lib/inactive_support/inflections.rb +53 -0
  128. data/lib/inactive_support/inflector.rb +282 -0
  129. data/lib/nested_error.rb +33 -0
  130. data/lib/nitpick.rb +33 -0
  131. data/lib/queued_logger.rb +68 -0
  132. data/lib/tempster.rb +250 -0
  133. data/misc/index_gem_repository.rb +304 -0
  134. data/misc/setup_egg.rb +12 -0
  135. data/misc/setup_gem_dependencies.sh +6 -0
  136. data/misc/setup_rubygems.sh +21 -0
  137. metadata +279 -0
@@ -0,0 +1,220 @@
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).
3
+
4
+ =head1 NAME
5
+
6
+ CpanWrapper - Provides a simpler wrapper for the CPAN package manager.
7
+
8
+ =head1 DESCRIPTION
9
+
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;
25
+
26
+ =head1 CLASS VARIABLES
27
+
28
+ =item $CpanWrapper::DRYRUN
29
+
30
+ Should actions really happen? E.g., in dry-run mode, the uninstall will only
31
+ pretend to delete files.
32
+
33
+ =cut
34
+
35
+ our $DRYRUN = 0;
36
+
37
+ =head1 CLASS METHODS
38
+
39
+ =item CpanWrapper->query($module_name)
40
+
41
+ Query the module and return 1 if it's installed, 0 if not.
42
+
43
+ =cut
44
+ sub query {
45
+ my($class, $module) = @_;
46
+ no warnings;
47
+ my $result = $CPAN::META->has_inst($module);
48
+ use warnings "all";
49
+ return $result;
50
+ }
51
+
52
+ =item CpanWrapper->uninstall($module_name)
53
+
54
+ Uninstall the module. Returns an array of files removed.
55
+
56
+ =cut
57
+ sub uninstall {
58
+ # /usr/local/lib/perl/5.8.8/auto/ack/.packlist
59
+ my($class, $module) = @_;
60
+ my $packlists = ExtUtils::Installed->new;
61
+ my @result;
62
+ foreach my $file ($packlists->files($module)) {
63
+ push(@result, $file);
64
+ unlink $file unless $DRYRUN;
65
+ }
66
+ my $packlist = $packlists->packlist($module)->packlist_file();
67
+ push(@result, $packlist);
68
+ unlink $packlist unless $DRYRUN;
69
+ return @result;
70
+ }
71
+
72
+ =item CpanWrapper->install($module_name)
73
+
74
+ Install the module. Returns 0 if can't find module.
75
+
76
+ =cut
77
+ sub install {
78
+ no warnings;
79
+ my($class, $module) = @_;
80
+ tie *NO, 'NoHandle';
81
+ open(SAVEIN, ">&STDIN");
82
+ open(STDIN, ">&NO"); # TODO why isn't this enough?
83
+ *STDIN = *NO;
84
+ my $result;
85
+ if (my $module_ref = CPAN::Shell->expand('Module', $module)) {
86
+ $module_ref->install unless $DRYRUN;
87
+ $result = 1;
88
+ } else {
89
+ $result = 0;
90
+ }
91
+ open(STDIN, ">&SAVEIN");
92
+ close NO;
93
+ use warnings "all";
94
+ return $result;
95
+ }
96
+
97
+ =item NoHandle
98
+
99
+ File handle that responds with "no" to all readline queries. This is used
100
+ during the install process to reject CPAN's unreasonable defaults.
101
+
102
+ =cut
103
+ package NoHandle;
104
+ sub TIEHANDLE { my $self; bless \$self, shift }
105
+ sub WRITE { die }
106
+ sub PRINT { die }
107
+ sub PRINTF { die }
108
+ sub READ { die }
109
+ sub READLINE { print "no\n"; return "no\n" }
110
+ sub GETC { die }
111
+ sub CLOSE { }
112
+ sub OPEN { }
113
+ sub BINMODE { }
114
+ sub EOF { 0 }
115
+ sub TELL { }
116
+ sub DESTROY { }
117
+
118
+ #===[ command-line usage ]==============================================
119
+
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
+ }
219
+
220
+ 1;
data/helpers/which.cmd ADDED
@@ -0,0 +1,7 @@
1
+ @ rem "which" workalike for Windows. Searches current directory and PATH for all extensions, stops after first match, and returns meaningful exit value for "system" or "ERRORLEVEL" checks.
2
+ @setlocal
3
+ @set P2=.;%PATH%
4
+ @for %%e in (%PATHEXT%) do @for %%i in (%1%%e) do @if NOT "%%~$P2:i"=="" echo %%~$P2:i && goto end
5
+ @rem REM This exits the shell on failure, so don't use it directly
6
+ @exit 1
7
+ :end
data/lib/automateit.rb ADDED
@@ -0,0 +1,55 @@
1
+ # == Dependencies
2
+
3
+ # Standard libraries
4
+ require 'etc'
5
+ require 'fileutils'
6
+ require 'find'
7
+ require 'logger'
8
+ require 'open3'
9
+ require 'pp'
10
+ require 'pathname'
11
+ require 'resolv'
12
+ require 'set'
13
+ require 'socket'
14
+ require 'yaml'
15
+
16
+ # Gems
17
+ require 'rubygems'
18
+ require 'erb'
19
+
20
+ # Extensions
21
+ require 'inactive_support'
22
+ require 'ext/object.rb'
23
+ require 'ext/metaclass.rb'
24
+ require 'ext/shell_escape.rb'
25
+
26
+ # Helpers
27
+ require 'hashcache'
28
+ require 'queued_logger'
29
+ require 'tempster'
30
+ require 'helpful_erb'
31
+ require 'nested_error'
32
+ require 'nitpick'
33
+
34
+ # Core
35
+ require 'automateit/root'
36
+ require 'automateit/constants'
37
+ require 'automateit/error'
38
+ require 'automateit/common'
39
+ require 'automateit/interpreter'
40
+ require 'automateit/plugin'
41
+ require 'automateit/cli'
42
+ require 'automateit/project'
43
+
44
+ # Plugins which must be loaded early
45
+ require 'automateit/shell_manager'
46
+ require 'automateit/platform_manager' # requires shell
47
+ require 'automateit/address_manager' # requires shell
48
+ require 'automateit/tag_manager' # requires address, platform
49
+ require 'automateit/field_manager' # requires shell
50
+ require 'automateit/service_manager' # requires shell
51
+ require 'automateit/package_manager' # requires shell
52
+ require 'automateit/template_manager'
53
+ require 'automateit/edit_manager'
54
+ require 'automateit/account_manager'
55
+ require 'automateit/download_manager'
@@ -0,0 +1,114 @@
1
+ # == AccountManager
2
+ #
3
+ # The AccountManager provides a way of managing system accounts, such as Unix
4
+ # users and groups.
5
+ class AutomateIt::AccountManager < AutomateIt::Plugin::Manager
6
+ # Invalidate system cache for +database+. The +database+ can be either :users
7
+ # or :groups. This is necessary on operating systems that lack logic to
8
+ # notify their caching system that an entry changed. If the OS doesn't need
9
+ # invalidation, will do nothing and return false.
10
+ #
11
+ # This method is primarily for the sake of driver authors, recipe authors
12
+ # will probably never need to use this.
13
+ def invalidate(database) dispatch_safely(database) end
14
+
15
+ #-----------------------------------------------------------------------
16
+
17
+ # Find a user account. Method returns a query helper which takes a
18
+ # +username+ as an index argument and returns a Struct::Passwd entry as
19
+ # described in Etc::getpwent if the user exists or a nil if not.
20
+ #
21
+ # Example:
22
+ # users["root"] # => #<struct Struct::Passwd name="root"...
23
+ #
24
+ # users["does_not_exist"] # => nil
25
+ def users() dispatch() end
26
+
27
+ # Add the +username+ if not already created.
28
+ #
29
+ # Options:
30
+ # * :description -- User's full name. Defaults to username.
31
+ # * :home -- Path to user's home directory. If not specified, uses system
32
+ # default like "/home/username".
33
+ # * :create_home -- Create homedir. Defaults to true.
34
+ # * :groups -- Array of group names to add this user to.
35
+ # * :shell -- Path to login shell. If not specified, uses system default
36
+ # like "/bin/bash".
37
+ # * :uid -- Fixnum user ID for user. Default chooses an unused id.
38
+ # * :gid -- Fixnum group ID for user. Default chooses same gid as uid.
39
+ #
40
+ # Example:
41
+ # add_user("bob", :description => "Bob Smith")
42
+ def add_user(username, opts={}) dispatch(username, opts) end
43
+
44
+ # TODO AccountManager#update_user -- implement
45
+ ### def update_user(username, opts={}) dispatch(username, opts) end
46
+
47
+ # Remove the +username+ if present.
48
+ #
49
+ # Options:
50
+ # * :remove_home -- Delete user's home directory and mail spool. Default is
51
+ # true.
52
+ def remove_user(username, opts={}) dispatch(username, opts) end
53
+
54
+ # Is +user+ present?
55
+ def has_user?(user) dispatch(user) end
56
+
57
+ # Add +groups+ (array of groupnames) to +user+.
58
+ def add_groups_to_user(groups, user) dispatch(groups, user) end
59
+
60
+ # Remove +groups+ (array of groupnames) from +user+.
61
+ def remove_groups_from_user(groups, user) dispatch(groups, user) end
62
+
63
+ # Change the +password+ for the +user+.
64
+ def passwd(user, password, opts={}) dispatch(user, password, opts) end
65
+
66
+ #.......................................................................
67
+
68
+ # Find a group. Method returns a query helper which takes a
69
+ # +groupname+ as an index argument and returns a Struct::Group entry as
70
+ # described in Etc::getgrent if the group exists or a nil if not.
71
+ #
72
+ # Example:
73
+ # groups["root"] # => #<struct Struct::Group name="root"...
74
+ #
75
+ # groups["does_not_exist"] # => nil
76
+ def groups() dispatch() end
77
+
78
+ # Add +groupname+ if it doesn't exist. Options:
79
+ # * :members -- Array of usernames to add as members.
80
+ # * :gid -- Group ID to use. Default is to find an unused id.
81
+ def add_group(groupname, opts={}) dispatch(groupname, opts) end
82
+
83
+ # TODO AccountManager#update_group -- implement
84
+ ### def update_group(groupname, opts={}) dispatch(groupname, opts) end
85
+
86
+ # Remove +groupname+ if it exists.
87
+ def remove_group(groupname, opts={}) dispatch(groupname, opts) end
88
+
89
+ # Does +group+ exist?
90
+ def has_group?(group) dispatch(group) end
91
+
92
+ # Add +users+ (array of usernames) to +group+.
93
+ def add_users_to_group(users, group) dispatch(users, group) end
94
+
95
+ # Remove +users+ (array of usernames) from +group+.
96
+ def remove_users_from_group(users, group) dispatch(users, group) end
97
+
98
+ # Array of groupnames this user is a member of.
99
+ def groups_for_user(query) dispatch(query) end
100
+
101
+ # Array of usernames in group.
102
+ def users_for_group(query) dispatch(query) end
103
+
104
+ # Hash of usernames and the groupnames they're members of.
105
+ def users_to_groups() dispatch() end
106
+ end # class AccountManager
107
+
108
+ # Drivers
109
+ require 'automateit/account_manager/base'
110
+ require 'automateit/account_manager/passwd_pty'
111
+ require 'automateit/account_manager/passwd_expect'
112
+ require 'automateit/account_manager/nscd'
113
+ require 'automateit/account_manager/etc'
114
+ require 'automateit/account_manager/posix'
@@ -0,0 +1,138 @@
1
+ # == AccountManager::BaseDriver
2
+ #
3
+ # Base class for all AccountManager drivers.
4
+ class ::AutomateIt::AccountManager::BaseDriver < ::AutomateIt::Plugin::Driver
5
+ protected
6
+
7
+ def _passwd_helper(user, password, opts={}, &block)
8
+ users = manager.users
9
+
10
+ unless users[user]
11
+ if preview?
12
+ log.info(PNOTE+"Setting password for user: #{user}")
13
+ return true
14
+ else
15
+ raise ArgumentError.new("No such user: #{user}")
16
+ end
17
+ end
18
+
19
+ case user
20
+ when Symbol
21
+ user = user.to_s
22
+ when Integer
23
+ user = users[user]
24
+ when String
25
+ # leave it alone
26
+ else
27
+ raise TypeError.new("Unknown user type: #{user.class}")
28
+ end
29
+
30
+ return block.call(user, password, opts)
31
+ end
32
+
33
+ def _add_user_helper(username, opts={}, &block)
34
+ return false if has_user?(username)
35
+
36
+ # Create group first, then the user. Necessary because some OSes can't add users with non-existent groups.
37
+
38
+ if opts[:personal_group].nil? and not opts[:group] and not opts[:gid]
39
+ opts[:personal_group] = true
40
+ end
41
+
42
+ # FIXME how to default personal_group to false?
43
+ # FIXME what if want to add user to a specific group, rather than creating?
44
+ # FIXME what if want or not want to crease user group?
45
+ # FIXME how to find an unused gid/uid combo?
46
+
47
+ unless opts[:group] == false
48
+ groupname = opts[:group] || username
49
+ unless has_group?(groupname)
50
+ if not opts[:uid] and not opts[:gid] and group = add_group(groupname, opts)
51
+ opts[:uid] = opts[:gid] = group.gid
52
+ end
53
+ end
54
+ end
55
+
56
+ block.call(username, opts)
57
+ manager.invalidate(:passwd)
58
+
59
+ passwd_opts = {:quiet => opts[:quiet]}
60
+ manager.passwd(username, opts[:passwd], passwd_opts) if opts[:passwd]
61
+
62
+ manager.invalidate(:passwd)
63
+ return users[username]
64
+ end
65
+
66
+ def _remove_user_helper(username, opts={}, &block)
67
+ return false unless has_user?(username)
68
+
69
+ block.call(username, opts)
70
+ manager.invalidate(:passwd)
71
+ remove_group(username) if has_group?(username)
72
+
73
+ return true
74
+ end
75
+
76
+ def _add_groups_to_user_helper(groups, username, &block)
77
+ groups = [groups].flatten
78
+ present = groups_for_user(username)
79
+ missing = groups - present
80
+ return false if missing.empty?
81
+
82
+ block.call(missing, username)
83
+ manager.invalidate(:group)
84
+
85
+ return missing
86
+ end
87
+
88
+ def _remove_groups_from_user_helper(groups, username, &block)
89
+ groups = [groups].flatten
90
+ matched = groups_for_user(username)
91
+ present = groups & matched
92
+ return false if present.empty?
93
+
94
+ block.call(present, username)
95
+ manager.invalidate(:group)
96
+
97
+ return present
98
+ end
99
+
100
+ def _add_users_to_group_helper(users, groupname, &block)
101
+ users = [users].flatten
102
+ # XXX Include pwent.gid?
103
+ grent = groups[groupname]
104
+ missing = \
105
+ if writing? and not grent
106
+ raise ArgumentError.new("no such group: #{groupname}")
107
+ elsif writing? or grent
108
+ users - grent.mem
109
+ else
110
+ users
111
+ end
112
+ return false if missing.empty?
113
+
114
+ block.call(missing, groupname)
115
+ manager.invalidate(:groups)
116
+
117
+ return missing
118
+ end
119
+
120
+ def _remove_users_from_group_helper(users, groupname, &block)
121
+ users = [users].flatten
122
+ grent = groups[groupname]
123
+ present = \
124
+ if writing? and not grent
125
+ raise ArgumentError.new("no such group: #{groupname}")
126
+ elsif writing? or grent
127
+ grent.mem & users
128
+ else
129
+ users
130
+ end
131
+ return false if present.empty?
132
+
133
+ block.call(present, groupname)
134
+ manager.invalidate(:groups)
135
+
136
+ return present
137
+ end
138
+ end