wright 0.4.4 → 0.5.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 (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