wright 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +10 -3
  3. data/NEWS.md +8 -0
  4. data/README.md +9 -16
  5. data/lib/wright/cli.rb +25 -24
  6. data/lib/wright/config.rb +5 -3
  7. data/lib/wright/dsl.rb +52 -9
  8. data/lib/wright/logger.rb +1 -1
  9. data/lib/wright/provider.rb +8 -5
  10. data/lib/wright/provider/directory.rb +2 -2
  11. data/lib/wright/provider/file.rb +4 -4
  12. data/lib/wright/provider/group.rb +4 -4
  13. data/lib/wright/provider/package.rb +3 -3
  14. data/lib/wright/provider/package/apt.rb +1 -1
  15. data/lib/wright/provider/package/yum.rb +1 -1
  16. data/lib/wright/provider/symlink.rb +2 -2
  17. data/lib/wright/provider/user.rb +8 -8
  18. data/lib/wright/resource.rb +21 -19
  19. data/lib/wright/resource/directory.rb +21 -10
  20. data/lib/wright/resource/file.rb +25 -14
  21. data/lib/wright/resource/group.rb +16 -9
  22. data/lib/wright/resource/package.rb +14 -9
  23. data/lib/wright/resource/symlink.rb +10 -8
  24. data/lib/wright/resource/user.rb +30 -9
  25. data/lib/wright/util.rb +14 -2
  26. data/lib/wright/util/erb_renderer.rb +29 -0
  27. data/lib/wright/util/file.rb +1 -1
  28. data/lib/wright/util/file_owner.rb +8 -3
  29. data/lib/wright/util/file_permissions.rb +14 -12
  30. data/lib/wright/util/file_renderer.rb +50 -0
  31. data/lib/wright/util/mustache_renderer.rb +41 -0
  32. data/lib/wright/util/pencil_mustache.rb +58 -0
  33. data/lib/wright/version.rb +1 -1
  34. data/man/wright.1 +10 -11
  35. data/spec/dsl_spec.rb +72 -7
  36. data/spec/provider/package/apt/{apt-get_--purge_remove_-qy_abcde.return → apt-get_-qy_--purge_remove_abcde.return} +0 -0
  37. data/spec/provider/package/apt/{apt-get_--purge_remove_-qy_abcde.stderr → apt-get_-qy_--purge_remove_abcde.stderr} +0 -0
  38. data/spec/provider/package/apt/{apt-get_--purge_remove_-qy_abcde.stdout → apt-get_-qy_--purge_remove_abcde.stdout} +0 -0
  39. data/spec/provider/package/apt/{apt-get_install_-qy_abcde=2.5.4-1.return → apt-get_-qy_install_abcde=2.5.4-1.return} +0 -0
  40. data/spec/provider/package/apt/{apt-get_install_-qy_abcde=2.5.4-1.stderr → apt-get_-qy_install_abcde=2.5.4-1.stderr} +0 -0
  41. data/spec/provider/package/apt/{apt-get_install_-qy_abcde=2.5.4-1.stdout → apt-get_-qy_install_abcde=2.5.4-1.stdout} +0 -0
  42. data/spec/provider/package/apt/{apt-get_install_-qy_htop.return → apt-get_-qy_install_htop.return} +0 -0
  43. data/spec/provider/package/apt/{apt-get_install_-qy_htop.stderr → apt-get_-qy_install_htop.stderr} +0 -0
  44. data/spec/provider/package/apt/{apt-get_install_-qy_htop.stdout → apt-get_-qy_install_htop.stdout} +0 -0
  45. data/spec/provider/package/apt/{apt-get_install_-qy_not-a-real-package.return → apt-get_-qy_install_not-a-real-package.return} +0 -0
  46. data/spec/provider/package/apt/{apt-get_install_-qy_not-a-real-package.stderr → apt-get_-qy_install_not-a-real-package.stderr} +0 -0
  47. data/spec/provider/package/apt/{apt-get_install_-qy_not-a-real-package.stdout → apt-get_-qy_install_not-a-real-package.stdout} +0 -0
  48. data/spec/provider/package/apt/{apt-get_remove_-qy_abcde.return → apt-get_-qy_remove_abcde.return} +0 -0
  49. data/spec/provider/package/apt/{apt-get_remove_-qy_abcde.stderr → apt-get_-qy_remove_abcde.stderr} +0 -0
  50. data/spec/provider/package/apt/{apt-get_remove_-qy_abcde.stdout → apt-get_-qy_remove_abcde.stdout} +0 -0
  51. data/spec/provider/package/apt_spec.rb +2 -2
  52. data/spec/provider/package/yum/{yum_install_-y_mc-4.8.7-8.el7.return → yum_-y_install_mc-4.8.7-8.el7.return} +0 -0
  53. data/spec/provider/package/yum/{yum_install_-y_mc-4.8.7-8.el7.stderr → yum_-y_install_mc-4.8.7-8.el7.stderr} +0 -0
  54. data/spec/provider/package/yum/{yum_install_-y_mc-4.8.7-8.el7.stdout → yum_-y_install_mc-4.8.7-8.el7.stdout} +0 -0
  55. data/spec/provider/package/yum/{yum_install_-y_nano.return → yum_-y_install_nano.return} +0 -0
  56. data/spec/provider/package/yum/{yum_install_-y_nano.stderr → yum_-y_install_nano.stderr} +0 -0
  57. data/spec/provider/package/yum/{yum_install_-y_nano.stdout → yum_-y_install_nano.stdout} +0 -0
  58. data/spec/provider/package/yum/{yum_install_-y_not-a-real-package.return → yum_-y_install_not-a-real-package.return} +0 -0
  59. data/spec/provider/package/yum/{yum_install_-y_not-a-real-package.stderr → yum_-y_install_not-a-real-package.stderr} +0 -0
  60. data/spec/provider/package/yum/{yum_install_-y_not-a-real-package.stdout → yum_-y_install_not-a-real-package.stdout} +0 -0
  61. data/spec/provider/package/yum/{yum_remove_-y_screen.return → yum_-y_remove_screen.return} +0 -0
  62. data/spec/provider/package/yum/{yum_remove_-y_screen.stderr → yum_-y_remove_screen.stderr} +0 -0
  63. data/spec/provider/package/yum/{yum_remove_-y_screen.stdout → yum_-y_remove_screen.stdout} +0 -0
  64. data/spec/provider/package/yum_spec.rb +1 -1
  65. data/spec/resource/directory_spec.rb +15 -0
  66. data/spec/resource/file_spec.rb +17 -0
  67. data/spec/resource/group_spec.rb +15 -0
  68. data/spec/resource/package_spec.rb +13 -0
  69. data/spec/resource/symlink_spec.rb +11 -0
  70. data/spec/resource/user_spec.rb +32 -0
  71. data/spec/resource_spec.rb +18 -10
  72. data/spec/spec_helper.rb +1 -0
  73. data/spec/spec_helpers/fake_capture3.rb +1 -1
  74. data/spec/util/erb_renderer_spec.rb +23 -0
  75. data/spec/util/file_owner_spec.rb +19 -0
  76. data/spec/util/file_renderer_spec.rb +28 -0
  77. data/spec/util/mustache_renderer_spec.rb +57 -0
  78. data/spec/util/pencil_mustache_spec.rb +15 -0
  79. data/spec/util_spec.rb +17 -3
  80. metadata +90 -64
@@ -6,17 +6,19 @@ module Wright
6
6
  # Symlink resource, represents a symlink.
7
7
  #
8
8
  # @example
9
- # link = Wright::Resource::Symlink.new('/tmp/fstab')
10
- # link.to = '/etc/fstab'
9
+ # link = Wright::Resource::Symlink.new('/tmp/fstab', to: '/etc/fstab')
11
10
  # link.create
12
11
  class Symlink < Wright::Resource
13
12
  # Initializes a Symlink.
14
13
  #
15
14
  # @param name [String] the symlink's name
16
- def initialize(name)
15
+ # @param args [Hash] the arguments
16
+ # @option args [Symbol] :action (:create) the action
17
+ # @option args [String] :to the symlink's target
18
+ def initialize(name, args = {})
17
19
  super
18
- @to = nil
19
- @action = :create
20
+ @action = args.fetch(:action, :create)
21
+ @to = args.fetch(:to, nil)
20
22
  end
21
23
 
22
24
  # @return [String] the symlink's intended target
@@ -27,9 +29,9 @@ module Wright
27
29
  # @return [Bool] true if the symlink was updated and false
28
30
  # otherwise
29
31
  def create
30
- fail ArgumentError, 'Symlink target undefined' unless @to
32
+ fail ArgumentError, 'Symlink target undefined' unless to
31
33
  might_update_resource do
32
- @provider.create
34
+ provider.create
33
35
  end
34
36
  end
35
37
 
@@ -39,7 +41,7 @@ module Wright
39
41
  # otherwise
40
42
  def remove
41
43
  might_update_resource do
42
- @provider.remove
44
+ provider.remove
43
45
  end
44
46
  end
45
47
  end
@@ -6,8 +6,7 @@ module Wright
6
6
  # User resource, represents a user.
7
7
  #
8
8
  # @example
9
- # johndoe = Wright::Resource::User.new('johndoe')
10
- # johndoe.home = '/home/johndoe'
9
+ # johndoe = Wright::Resource::User.new('johndoe', home: '/home/johndoe')
11
10
  # johndoe.create
12
11
  class User < Wright::Resource
13
12
  # @return [Integer] the user's intended user id
@@ -37,10 +36,26 @@ module Wright
37
36
  # Initializes a user.
38
37
  #
39
38
  # @param name [String] the user's name
40
- def initialize(name)
39
+ # @param args [Hash] the arguments
40
+ # @option args [Symbol] :action (:create) the action
41
+ # @option args [Integer] :uid the user's uid
42
+ # @option args [String] :full_name the user's full name
43
+ # @option args [Array<String>] :groups the user's groups
44
+ # @option args [String] :shell the user's shell
45
+ # @option args [String] :home the user's home directory
46
+ # @option args [String] :primary_group the user's primary group
47
+ # @option args [Bool] :system (false) denotes whether the user
48
+ # should be a system user or not
49
+ def initialize(name, args = {})
41
50
  super
42
- @action = :create
43
- @system = false
51
+ @action = args.fetch(:action, :create)
52
+ @uid = args.fetch(:uid, nil)
53
+ @full_name = args.fetch(:full_name, nil)
54
+ @groups = args.fetch(:groups, nil)
55
+ @shell = args.fetch(:shell, nil)
56
+ @home = fetch_last(args, [:home, :homedir], nil)
57
+ @primary_group = fetch_last(args, [:primary_group, :login_group], nil)
58
+ @system = args.fetch(:system, false)
44
59
  end
45
60
 
46
61
  # Creates or updates the user.
@@ -49,7 +64,7 @@ module Wright
49
64
  # otherwise
50
65
  def create
51
66
  might_update_resource do
52
- @provider.create
67
+ provider.create
53
68
  end
54
69
  end
55
70
 
@@ -59,9 +74,15 @@ module Wright
59
74
  # otherwise
60
75
  def remove
61
76
  might_update_resource do
62
- @provider.remove
77
+ provider.remove
63
78
  end
64
79
  end
80
+
81
+ private
82
+
83
+ def fetch_last(hash, candidate_keys, default = nil)
84
+ Wright::Util.fetch_last(hash, candidate_keys, default)
85
+ end
65
86
  end
66
87
  end
67
88
  end
@@ -70,9 +91,9 @@ Wright::DSL.register_resource(Wright::Resource::User)
70
91
 
71
92
  user_providers = {
72
93
  'debian' => 'Wright::Provider::User::GnuPasswd',
73
- 'rhel' => 'Wright::Provider::User::GnuPasswd',
74
94
  'fedora' => 'Wright::Provider::User::GnuPasswd',
75
- 'macosx' => 'Wright::Provider::User::DarwinDirectoryService'
95
+ 'rhel' => 'Wright::Provider::User::GnuPasswd',
96
+ 'osx' => 'Wright::Provider::User::DarwinDirectoryService'
76
97
  }
77
98
  Wright::Config[:resources][:user] ||= {}
78
99
  Wright::Config[:resources][:user][:provider] ||=
@@ -56,7 +56,7 @@ module Wright
56
56
  # # => "debian"
57
57
  # @example
58
58
  # Wright::Util.os_family
59
- # # => "macosx"
59
+ # # => "osx"
60
60
  #
61
61
  # @return [String] the system's OS family (base distribution for
62
62
  # GNU/Linux systems) or 'other' for unknown operating systems
@@ -64,7 +64,7 @@ module Wright
64
64
  system_arch = RbConfig::CONFIG['target_os']
65
65
  case system_arch
66
66
  when /darwin/
67
- 'macosx'
67
+ 'osx'
68
68
  when /linux/
69
69
  distro
70
70
  else
@@ -85,5 +85,17 @@ module Wright
85
85
  yield
86
86
  end
87
87
  end
88
+
89
+ # Fetches the value of the candidate key that occurs last in a hash.
90
+ #
91
+ # @param hash [Hash] the hash
92
+ # @param candidate_keys [Array<Object>] the candidate keys
93
+ # @param default [Object] the default value
94
+ # @return [Object] the value of the candidate key that occurs last in
95
+ # the hash or +default+ if none of the candidate keys can be found
96
+ def self.fetch_last(hash, candidate_keys, default = nil)
97
+ candidates = hash.select { |k, _v| candidate_keys.include?(k) }
98
+ candidates.empty? ? default : candidates.values.last
99
+ end
88
100
  end
89
101
  end
@@ -0,0 +1,29 @@
1
+ require 'erb'
2
+
3
+ module Wright
4
+ module Util
5
+ # ERB renderer.
6
+ #
7
+ # @example
8
+ # template = "foo is <%= foo %>."
9
+ # hash = { foo: :bar }
10
+ # Wright::Util::ErbRenderer.new(hash).render(template)
11
+ # # => "foo is bar."
12
+ class ErbRenderer
13
+ def initialize(hash)
14
+ hash.each do |k, v|
15
+ instance_var = "@#{k}"
16
+ instance_variable_set(instance_var, v)
17
+ define_singleton_method(k) { instance_variable_get(instance_var) }
18
+ end
19
+ end
20
+
21
+ # Renders an ERB template.
22
+ # @param template [String] the template
23
+ # @return [String] the rendered template
24
+ def render(template)
25
+ ERB.new(template).result(binding)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -54,7 +54,7 @@ module Wright
54
54
  private_constant :MODE_MAP
55
55
 
56
56
  def self.mode_mask(mode, is_directory)
57
- mode.gsub!('X', 'x') if is_directory
57
+ mode.tr!('X', 'x') if is_directory
58
58
  mode.chars.reduce(0) { |a, e| a | MODE_MAP[e].to_i }
59
59
  end
60
60
  private_class_method :mode_mask
@@ -9,9 +9,14 @@ module Wright
9
9
  # @return [String, Integer] the group's name or gid
10
10
  attr_accessor :group
11
11
 
12
+ def initialize(user_and_group = nil, group = nil)
13
+ self.user_and_group = user_and_group
14
+ self.group = group if group
15
+ end
16
+
12
17
  # Sets user and group simultaneously.
13
18
  #
14
- # @param [String, Integer] user_and_group a user in +user:group+
19
+ # @param user_and_group [String, Integer] a user in +user:group+
15
20
  # notation or a uid
16
21
  #
17
22
  # @example
@@ -38,8 +43,8 @@ module Wright
38
43
  # one colon
39
44
  def user_and_group=(user_and_group)
40
45
  user, group = split_user_and_group(user_and_group)
41
- @user = user
42
- @group = group if group
46
+ self.user = user
47
+ self.group = group if group
43
48
  end
44
49
 
45
50
  private
@@ -60,8 +60,8 @@ module Wright
60
60
 
61
61
  mode_i = File.numeric_mode_to_i(mode)
62
62
  unless mode_i
63
- base_mode_i = ::File.exist?(@filename) ? current_mode : default_mode
64
- mode_i = File.symbolic_mode_to_i(mode, base_mode_i, @filetype)
63
+ base_mode_i = ::File.exist?(filename) ? current_mode : default_mode
64
+ mode_i = File.symbolic_mode_to_i(mode, base_mode_i, filetype)
65
65
  end
66
66
  @mode = mode_i
67
67
  end
@@ -70,7 +70,7 @@ module Wright
70
70
  # @return [Bool] +true+ if the file is up to date, +false+
71
71
  # otherwise
72
72
  def uptodate?
73
- if ::File.exist?(@filename)
73
+ if ::File.exist?(filename)
74
74
  uid_uptodate? && gid_uptodate? && mode_uptodate?
75
75
  else
76
76
  false
@@ -81,41 +81,43 @@ module Wright
81
81
  #
82
82
  # @return [void]
83
83
  def update
84
- ::File.chmod(@mode, @filename) if @mode
85
- ::File.chown(@uid, @gid, @filename) if @uid || @gid
84
+ ::File.chmod(mode, filename) if mode
85
+ ::File.chown(uid, gid, filename) if uid || gid
86
86
  end
87
87
 
88
88
  # @return [Integer] the file's current mode
89
89
  def current_mode
90
- Wright::Util::File.file_mode(@filename)
90
+ Wright::Util::File.file_mode(filename)
91
91
  end
92
92
 
93
93
  # @return [Integer] the file's current owner's uid
94
94
  def current_uid
95
- Wright::Util::File.file_owner(@filename)
95
+ Wright::Util::File.file_owner(filename)
96
96
  end
97
97
 
98
98
  # @return [Integer] the file's current group's gid
99
99
  def current_gid
100
- Wright::Util::File.file_group(@filename)
100
+ Wright::Util::File.file_group(filename)
101
101
  end
102
102
 
103
103
  private
104
104
 
105
+ attr_reader :filetype
106
+
105
107
  def uid_uptodate?
106
- @uid.nil? || current_uid == @uid
108
+ uid.nil? || current_uid == uid
107
109
  end
108
110
 
109
111
  def gid_uptodate?
110
- @gid.nil? || current_gid == @gid
112
+ gid.nil? || current_gid == gid
111
113
  end
112
114
 
113
115
  def mode_uptodate?
114
- @mode.nil? || current_mode == @mode
116
+ mode.nil? || current_mode == mode
115
117
  end
116
118
 
117
119
  def default_mode
118
- case @filetype
120
+ case filetype
119
121
  when :file
120
122
  ~::File.umask & 0666
121
123
  when :directory
@@ -0,0 +1,50 @@
1
+ require 'wright/util/erb_renderer'
2
+ require 'wright/util/mustache_renderer'
3
+
4
+ module Wright
5
+ module Util
6
+ # File renderer.
7
+ #
8
+ # @example
9
+ # filename = 'template.erb'
10
+ # template = "foo is <%= foo %>."
11
+ # hash = { foo: :bar }
12
+ # File.write(filename, template)
13
+ # renderer = Wright::Util::FileRenderer.new(hash)
14
+ # renderer.render(filename)
15
+ # # => "foo is bar."
16
+ class FileRenderer
17
+ # Initializes a FileTemplate.
18
+ # @param hash [Hash] the attribute hash of the template
19
+ def initialize(hash)
20
+ @hash = hash
21
+ end
22
+
23
+ # Renders a template file.
24
+ # @param filename [String] the filename of the template
25
+ # @raise [ArgumentError] if the given file type is not supported
26
+ def render(filename)
27
+ renderer = renderer_for_file(filename)
28
+ template = ::File.read(::File.expand_path(filename))
29
+ renderer.render(template)
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :hash
35
+
36
+ FILE_RENDERERS = {
37
+ '.erb' => ErbRenderer,
38
+ '.mustache' => MustacheRenderer
39
+ }
40
+
41
+ def renderer_for_file(filename)
42
+ file_extension = ::File.extname(filename)
43
+ rendering_class = FILE_RENDERERS[file_extension]
44
+ unknown_template_type = "unknown template type '#{file_extension}'"
45
+ fail ArgumentError, unknown_template_type unless rendering_class
46
+ rendering_class.new(hash)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,41 @@
1
+ begin
2
+ require 'mustache'
3
+ rescue LoadError # rubocop:disable Lint/HandleExceptions
4
+ end
5
+
6
+ require 'wright/util/pencil_mustache'
7
+
8
+ module Wright
9
+ module Util
10
+ # Mustache renderer.
11
+ #
12
+ # @example
13
+ # template = "foo is {{foo}}."
14
+ # hash = { foo: :bar }
15
+ # Wright::Util::MustacheRenderer.new(hash).render(template)
16
+ # # => "foo is bar."
17
+ class MustacheRenderer
18
+ def initialize(hash)
19
+ @hash = hash
20
+ @mustache = select_mustache
21
+ end
22
+
23
+ # Renders a Mustache template.
24
+ # @param template [String] the template
25
+ # @return [String] the rendered template
26
+ def render(template)
27
+ @mustache.render(template, @hash)
28
+ end
29
+
30
+ private
31
+
32
+ def select_mustache
33
+ return PencilMustache.new unless defined?(Mustache)
34
+
35
+ mustache = Mustache.new
36
+ mustache.raise_on_context_miss = true
37
+ mustache
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,58 @@
1
+ # The code in this file is largely copied from PencilMustache by
2
+ # Benjamin Oakes. The original code can be found at
3
+ # https://github.com/benjaminoakes/pencil_mustache.
4
+ #
5
+ # The following is a verbatim copy of the original license (MIT):
6
+ #
7
+ # Copyright (c) 2012 Benjamin Oakes
8
+ #
9
+ # Permission is hereby granted, free of charge, to any person obtaining
10
+ # a copy of this software and associated documentation files (the
11
+ # "Software"), to deal in the Software without restriction, including
12
+ # without limitation the rights to use, copy, modify, merge, publish,
13
+ # distribute, sublicense, and/or sell copies of the Software, and to
14
+ # permit persons to whom the Software is furnished to do so, subject to
15
+ # the following conditions:
16
+ #
17
+ # The above copyright notice and this permission notice shall be
18
+ # included in all copies or substantial portions of the Software.
19
+ #
20
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+
28
+ module Wright
29
+ module Util
30
+ # PencilMustache class.
31
+ #
32
+ # @example
33
+ # pencil_mustache = Wright::Util::PencilMustache.new
34
+ # template = "foo is {{foo}}."
35
+ # hash = { foo: :bar }
36
+ # pencil_mustache.render(template, hash)
37
+ # # => "foo is bar."
38
+ class PencilMustache
39
+ # Renders a Mustache template using the supplied hash.
40
+ # @param template [String] the template
41
+ # @param hash [Hash] the hash
42
+ # @return [String] the rendered template
43
+ # @todo Raise NameError if necessary.
44
+ # @todo Add support for triple whiskers.
45
+ def render(template, hash)
46
+ template.gsub(/{{.*?}}/, add_whiskers(hash))
47
+ end
48
+
49
+ private
50
+
51
+ def add_whiskers(doc)
52
+ with_whiskers = {}
53
+ doc.keys.each { |k| with_whiskers["{{#{k}}}"] = doc[k] }
54
+ with_whiskers
55
+ end
56
+ end
57
+ end
58
+ end