wright 0.0.1 → 0.1.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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +2 -2
  3. data/NEWS +8 -0
  4. data/README.md +70 -0
  5. data/Rakefile +19 -0
  6. data/lib/wright/config.rb +64 -0
  7. data/lib/wright/dry_run.rb +33 -0
  8. data/lib/wright/dsl.rb +63 -0
  9. data/lib/wright/logger.rb +73 -0
  10. data/lib/wright/provider/directory.rb +78 -0
  11. data/lib/wright/provider/file.rb +104 -0
  12. data/lib/wright/provider/package/apt.rb +93 -0
  13. data/lib/wright/provider/package.rb +38 -0
  14. data/lib/wright/provider/symlink.rb +86 -0
  15. data/lib/wright/provider.rb +30 -0
  16. data/lib/wright/resource/directory.rb +67 -0
  17. data/lib/wright/resource/file.rb +67 -0
  18. data/lib/wright/resource/package.rb +70 -0
  19. data/lib/wright/resource/symlink.rb +47 -0
  20. data/lib/wright/resource.rb +157 -0
  21. data/lib/wright/util/color.rb +51 -0
  22. data/lib/wright/util/file.rb +258 -0
  23. data/lib/wright/util/file_permissions.rb +129 -0
  24. data/lib/wright/util/recursive_autoloader.rb +91 -0
  25. data/lib/wright/util/stolen_from_activesupport.rb +202 -0
  26. data/lib/wright/util/user.rb +75 -0
  27. data/lib/wright/util.rb +72 -0
  28. data/lib/wright/version.rb +3 -2
  29. data/lib/wright.rb +10 -1
  30. data/spec/config_spec.rb +37 -0
  31. data/spec/dsl_spec.rb +65 -0
  32. data/spec/logger_spec.rb +65 -0
  33. data/spec/provider/directory_spec.rb +114 -0
  34. data/spec/provider/file_spec.rb +130 -0
  35. data/spec/provider/package/apt/apt-get_install_-qy_abcde=2.5.4-1.return +1 -0
  36. data/spec/provider/package/apt/apt-get_install_-qy_abcde=2.5.4-1.stderr +0 -0
  37. data/spec/provider/package/apt/apt-get_install_-qy_abcde=2.5.4-1.stdout +15 -0
  38. data/spec/provider/package/apt/apt-get_install_-qy_htop.return +1 -0
  39. data/spec/provider/package/apt/apt-get_install_-qy_htop.stderr +0 -0
  40. data/spec/provider/package/apt/apt-get_install_-qy_htop.stdout +19 -0
  41. data/spec/provider/package/apt/apt-get_install_-qy_unknown-package.return +1 -0
  42. data/spec/provider/package/apt/apt-get_install_-qy_unknown-package.stderr +1 -0
  43. data/spec/provider/package/apt/apt-get_install_-qy_unknown-package.stdout +3 -0
  44. data/spec/provider/package/apt/apt-get_remove_-qy_abcde.return +1 -0
  45. data/spec/provider/package/apt/apt-get_remove_-qy_abcde.stderr +0 -0
  46. data/spec/provider/package/apt/apt-get_remove_-qy_abcde.stdout +14 -0
  47. data/spec/provider/package/apt/dpkg-query_-s_abcde.return +1 -0
  48. data/spec/provider/package/apt/dpkg-query_-s_abcde.stderr +0 -0
  49. data/spec/provider/package/apt/dpkg-query_-s_abcde.stdout +23 -0
  50. data/spec/provider/package/apt/dpkg-query_-s_htop.return +1 -0
  51. data/spec/provider/package/apt/dpkg-query_-s_htop.stderr +0 -0
  52. data/spec/provider/package/apt/dpkg-query_-s_htop.stdout +19 -0
  53. data/spec/provider/package/apt/dpkg-query_-s_unknown-package.return +1 -0
  54. data/spec/provider/package/apt/dpkg-query_-s_unknown-package.stderr +3 -0
  55. data/spec/provider/package/apt/dpkg-query_-s_unknown-package.stdout +0 -0
  56. data/spec/provider/package/apt/dpkg-query_-s_vlc.return +1 -0
  57. data/spec/provider/package/apt/dpkg-query_-s_vlc.stderr +3 -0
  58. data/spec/provider/package/apt/dpkg-query_-s_vlc.stdout +0 -0
  59. data/spec/provider/package/apt_spec.rb +297 -0
  60. data/spec/provider/package_spec.rb +63 -0
  61. data/spec/provider/symlink_spec.rb +122 -0
  62. data/spec/provider_spec.rb +19 -0
  63. data/spec/recursive_autoloader/foo/bar/baz.rb +12 -0
  64. data/spec/recursive_autoloader/identically_named_dir_and_file/this_should_not_be_loaded.rb +1 -0
  65. data/spec/recursive_autoloader/identically_named_dir_and_file.rb +8 -0
  66. data/spec/recursive_autoloader/loaded_on_demand.rb +8 -0
  67. data/spec/recursive_autoloader/raises_exception.rb +1 -0
  68. data/spec/recursive_autoloader_spec.rb +41 -0
  69. data/spec/resource/directory_spec.rb +187 -0
  70. data/spec/resource/file_spec.rb +213 -0
  71. data/spec/resource/symlink_spec.rb +117 -0
  72. data/spec/resource_spec.rb +184 -0
  73. data/spec/spec_helper.rb +35 -0
  74. data/spec/spec_helpers/fake_capture3.rb +47 -0
  75. data/spec/util/activesupport_spec.rb +24 -0
  76. data/spec/util/file_permissions_spec.rb +141 -0
  77. data/spec/util/file_spec.rb +127 -0
  78. data/spec/util/user_spec.rb +46 -0
  79. data/spec/util_spec.rb +80 -0
  80. metadata +253 -20
  81. data/.gitignore +0 -17
  82. data/Gemfile +0 -3
  83. data/wright.gemspec +0 -16
@@ -0,0 +1,35 @@
1
+ require_relative 'spec_helpers/fake_capture3'
2
+
3
+ require 'ostruct'
4
+ require 'fakefs/safe'
5
+ require 'wright/logger'
6
+
7
+ begin
8
+ require 'simplecov'
9
+ if ENV['COVERAGE']
10
+ SimpleCov.start do
11
+ add_filter '/spec/'
12
+ add_filter '/vendor/'
13
+ add_filter '/.bundle/'
14
+ end
15
+ end
16
+ end
17
+
18
+ module Wright
19
+ # extend Wright::Config to pass on clear for tests
20
+ class Config
21
+ class << self
22
+ attr_accessor :config_hash
23
+ end
24
+ end
25
+ end
26
+
27
+ def reset_logger(log_level = Wright::Logger::DEBUG)
28
+ Wright.log = Wright::Logger.new
29
+ Wright.log.formatter = Wright::Logger::Formatter.new
30
+ Wright.log.level = log_level
31
+ end
32
+
33
+ reset_logger(Wright::Logger::FATAL)
34
+
35
+ require 'minitest/autorun'
@@ -0,0 +1,47 @@
1
+ require 'minitest/mock'
2
+ require 'open3'
3
+
4
+ # Open3::capture3 replacement that reads stdout, stderr and return
5
+ # values from the filesystem
6
+ class FakeCapture3
7
+ def initialize(basedir, env)
8
+ @basedir = basedir
9
+ @env = env
10
+ @mock_open3 = Minitest::Mock.new
11
+ @capture3_stub = lambda do |stub_env, stub_command|
12
+ @mock_open3.capture3(stub_env, stub_command)
13
+ end
14
+ end
15
+
16
+ def expect(command)
17
+ @mock_open3.expect(:capture3, return_values(command), [@env, command])
18
+ end
19
+
20
+ def stub
21
+ Open3.stub :capture3, @capture3_stub do
22
+ yield if block_given?
23
+ end
24
+ @mock_open3.verify
25
+ end
26
+
27
+ private
28
+
29
+ def return_values(command)
30
+ filename = command.gsub(' ', '_')
31
+ command_stdout = File.read("#{@basedir}/#{filename}.stdout")
32
+ command_stderr = File.read("#{@basedir}/#{filename}.stderr")
33
+ command_status = File.read("#{@basedir}/#{filename}.return").chomp == '0'
34
+ [command_stdout, command_stderr, FakeProcessStatus.new(command_status)]
35
+ end
36
+
37
+ # fake Process::Status replacement
38
+ class FakeProcessStatus
39
+ def initialize(success)
40
+ @success = success
41
+ end
42
+
43
+ def success?
44
+ @success
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../spec_helper'
2
+
3
+ require 'wright/util/stolen_from_activesupport'
4
+
5
+ include Wright
6
+
7
+ describe Util::ActiveSupport do
8
+ it 'should camelize underscored words' do
9
+ Util::ActiveSupport.camelize('foo_bar').must_equal 'FooBar'
10
+ end
11
+
12
+ it 'should underscore CamelCase words' do
13
+ Util::ActiveSupport.underscore('FooBar').must_equal 'foo_bar'
14
+ Util::ActiveSupport.underscore('FooBar::Baz').must_equal 'foo_bar/baz'
15
+ end
16
+
17
+ it 'should find constants with a given name' do
18
+ nonexistent = 'ThisConstant::DoesNotExist'
19
+
20
+ Util::ActiveSupport.constantize('Wright::Util').must_equal Wright::Util
21
+ -> { Util::ActiveSupport.constantize(nonexistent) }.must_raise(NameError)
22
+ Util::ActiveSupport.safe_constantize(nonexistent).must_be_nil
23
+ end
24
+ end
@@ -0,0 +1,141 @@
1
+ require_relative '../spec_helper'
2
+
3
+ require 'wright/util/file_permissions'
4
+
5
+ include Wright::Util
6
+
7
+ describe FilePermissions do
8
+ before(:each) do
9
+ @file_permissions = FilePermissions.new('somefile', :file)
10
+ @dir_permissions = FilePermissions.new('somedir', :directory)
11
+ end
12
+
13
+ after(:each) { FakeFS::FileSystem.clear }
14
+
15
+ describe 'initialize' do
16
+ it 'should raise exceptions for incorrect file types' do
17
+ lambda do
18
+ FilePermissions.new(@filename, :invalid_file_type)
19
+ end.must_raise ArgumentError
20
+ end
21
+ end
22
+
23
+ describe '#uptodate?' do
24
+ it 'should return false for non-existent files' do
25
+ FakeFS do
26
+ @file_permissions.uptodate?.must_equal false
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#update' do
32
+ it 'should update file modes when using integer modes' do
33
+ FakeFS do
34
+ FileUtils.touch(@file_permissions.filename)
35
+ FileUtils.chmod(0600, @file_permissions.filename)
36
+ @file_permissions.uptodate?.must_equal true
37
+ @file_permissions.mode = 0666
38
+ @file_permissions.uptodate?.must_equal false
39
+ @file_permissions.update
40
+ @file_permissions.current_mode.must_equal 0666
41
+ @file_permissions.uptodate?.must_equal true
42
+ end
43
+ end
44
+
45
+ it 'should not change file modes when using no-op mode strings' do
46
+ FakeFS do
47
+ FileUtils.touch(@file_permissions.filename)
48
+ FileUtils.chmod(0600, @file_permissions.filename)
49
+ @file_permissions.mode = 'ugo+'
50
+ @file_permissions.uptodate?.must_equal true
51
+ @file_permissions.update
52
+ @file_permissions.current_mode.must_equal 0600
53
+ @file_permissions.uptodate?.must_equal true
54
+ end
55
+ end
56
+
57
+ it 'should update file modes when using symbolic mode strings' do
58
+ FakeFS do
59
+ FileUtils.touch(@file_permissions.filename)
60
+ FileUtils.chmod(0600, @file_permissions.filename)
61
+ @file_permissions.mode = 'u+rwx,g=rx,o=rX'
62
+ @file_permissions.uptodate?.must_equal false
63
+ @file_permissions.update
64
+ @file_permissions.current_mode.must_equal 0754
65
+ @file_permissions.uptodate?.must_equal true
66
+ end
67
+ end
68
+
69
+ it 'should update directory modes when using symbolic mode strings' do
70
+ FakeFS do
71
+ FileUtils.mkdir(@dir_permissions.filename)
72
+ FileUtils.chmod(0600, @dir_permissions.filename)
73
+ @dir_permissions.mode = 'u+rwx,g=rx,o=rX'
74
+ @dir_permissions.update
75
+ @dir_permissions.current_mode.must_equal 0755
76
+ end
77
+ end
78
+
79
+ it 'should update file owners' do
80
+ user1 = Etc.getpwent
81
+ user2 = Etc.getpwent
82
+ FakeFS do
83
+ FileUtils.touch(@file_permissions.filename)
84
+ FileUtils.chown(user1.name, nil, @file_permissions.filename)
85
+ @file_permissions.current_owner.must_equal user1.uid
86
+ @file_permissions.owner = user2.name
87
+ @file_permissions.uptodate?.must_equal false
88
+ @file_permissions.update
89
+ @file_permissions.uptodate?.must_equal true
90
+ @file_permissions.current_owner.must_equal user2.uid
91
+ end
92
+ end
93
+
94
+ it 'should update file groups' do
95
+ group1 = Etc.getgrent
96
+ group2 = Etc.getgrent
97
+ FakeFS do
98
+ FileUtils.touch(@file_permissions.filename)
99
+ FileUtils.chown(nil, group1.name, @file_permissions.filename)
100
+ @file_permissions.current_group.must_equal group1.gid
101
+ @file_permissions.group = group2.name
102
+ @file_permissions.uptodate?.must_equal false
103
+ @file_permissions.update
104
+ @file_permissions.uptodate?.must_equal true
105
+ @file_permissions.current_group.must_equal group2.gid
106
+ end
107
+ end
108
+
109
+ it 'should respect the current umask for relative file modes' do
110
+ begin
111
+ old_umask = File.umask
112
+
113
+ File.umask(0000)
114
+ @file_permissions.mode = 'o='
115
+ @file_permissions.mode.must_equal 0660
116
+
117
+ File.umask(0246)
118
+ @file_permissions.mode = 'o='
119
+ @file_permissions.mode.must_equal 0420
120
+ ensure
121
+ File.umask(old_umask)
122
+ end
123
+ end
124
+
125
+ it 'should respect the current umask for relative directory modes' do
126
+ begin
127
+ old_umask = File.umask
128
+
129
+ File.umask(0000)
130
+ @dir_permissions.mode = 'o='
131
+ @dir_permissions.mode.must_equal 0770
132
+
133
+ File.umask(0246)
134
+ @dir_permissions.mode = 'o='
135
+ @dir_permissions.mode.must_equal 0530
136
+ ensure
137
+ File.umask(old_umask)
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,127 @@
1
+ require_relative '../spec_helper'
2
+
3
+ require 'wright/util/file'
4
+
5
+ include Wright
6
+
7
+ describe Util::File do
8
+ before(:each) do
9
+ @file = 'somefile'
10
+ @dir = 'somedir'
11
+ end
12
+
13
+ after(:each) { FakeFS::FileSystem.clear }
14
+
15
+ describe 'file_mode' do
16
+ it 'should return the correct mode for a given file' do
17
+ FakeFS do
18
+ FileUtils.touch(@file)
19
+ FileUtils.chmod(0644, @file)
20
+ Util::File.file_mode(@file).must_equal 0644
21
+ end
22
+ end
23
+
24
+ it 'should return nil for non-existing files' do
25
+ FakeFS { Util::File.file_mode(@file).must_be_nil }
26
+ end
27
+ end
28
+
29
+ describe 'file_owner' do
30
+ it 'should return the correct owner for a given file' do
31
+ FakeFS do
32
+ FileUtils.touch(@file)
33
+ pwent = Etc.getpwent
34
+ File.chown(pwent.uid, pwent.gid, @file)
35
+ Util::File.file_owner(@file).must_equal pwent.uid
36
+ end
37
+ end
38
+
39
+ it 'should return nil for non-existing files' do
40
+ FakeFS { Util::File.file_mode(@file).must_be_nil }
41
+ end
42
+ end
43
+
44
+ describe 'file_group' do
45
+ it 'should return the correct group for a given file' do
46
+ FakeFS do
47
+ FileUtils.touch(@file)
48
+ pwent = Etc.getpwent
49
+ File.chown(pwent.uid, pwent.gid, @file)
50
+ Util::File.file_group(@file).must_equal pwent.gid
51
+ end
52
+ end
53
+
54
+ it 'should return nil for non-existing files' do
55
+ FakeFS { Util::File.file_group(@file).must_be_nil }
56
+ end
57
+ end
58
+
59
+ describe 'numeric_mode_to_i' do
60
+ it 'should not change octal integer modes' do
61
+ Util::File.numeric_mode_to_i(0644).must_equal 0644
62
+ end
63
+
64
+ it 'should convert numeric string modes' do
65
+ Util::File.numeric_mode_to_i('0644').must_equal 0644
66
+ Util::File.numeric_mode_to_i('644').must_equal 0644
67
+ end
68
+
69
+ it 'should return nil for non-numeric mode strings' do
70
+ Util::File.numeric_mode_to_i('banana').must_equal nil
71
+ end
72
+ end
73
+
74
+ describe 'symbolic_mode_to_i' do
75
+ it 'should convert symbolic modes for files' do
76
+ type = :file
77
+ mode = 00644
78
+ FakeFS do
79
+ FileUtils.touch(@file)
80
+ FileUtils.chmod(mode, @file)
81
+ Util::File.symbolic_mode_to_i('u=rw,go=r', mode, type).must_equal 0644
82
+ Util::File.symbolic_mode_to_i('u=r,go+w', mode, type).must_equal 0466
83
+ Util::File.symbolic_mode_to_i('+x', mode, type).must_equal 0755
84
+ Util::File.symbolic_mode_to_i('+X', mode, type).must_equal 0644
85
+ Util::File.symbolic_mode_to_i('a-r', mode, type).must_equal 0200
86
+ Util::File.symbolic_mode_to_i('+s', mode, type).must_equal 06644
87
+ Util::File.symbolic_mode_to_i('+t', mode, type).must_equal 01644
88
+ end
89
+ end
90
+
91
+ it 'should convert symbolic modes for directories' do
92
+ type = :directory
93
+ mode = 00644
94
+ FakeFS do
95
+ FileUtils.mkdir(@dir)
96
+ FileUtils.chmod(mode, @dir)
97
+ Util::File.symbolic_mode_to_i('u=rw,go=r', mode, type).must_equal 0644
98
+ Util::File.symbolic_mode_to_i('+x', mode, type).must_equal 0755
99
+ Util::File.symbolic_mode_to_i('+X', mode, type).must_equal 0755
100
+ end
101
+ end
102
+
103
+ it 'should raise an exception for invalid symbolic modes' do
104
+ lambda do
105
+ Util::File.symbolic_mode_to_i('this is not a mode string', nil, :file)
106
+ end.must_raise ArgumentError
107
+ end
108
+ end
109
+
110
+ describe 'expand_tilde_path' do
111
+ it 'should expand tilde paths' do
112
+ expected = File.join(Etc.getpwnam('root').dir, 'foo')
113
+ actual = Wright::Util::File.expand_tilde_path('~root/foo')
114
+ actual.must_equal expected
115
+ end
116
+
117
+ it 'should not expand anything but the first path element' do
118
+ expected = File.join(Etc.getpwnam('root').dir, 'foo', '..')
119
+ actual = Wright::Util::File.expand_tilde_path('~root/foo/..')
120
+ actual.must_equal expected
121
+ end
122
+
123
+ it 'should not expand non-tilde paths' do
124
+ Wright::Util::File.expand_tilde_path('../foo/bar').must_equal '../foo/bar'
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,46 @@
1
+ require_relative '../spec_helper'
2
+
3
+ require 'wright/util/user'
4
+
5
+ include Wright
6
+
7
+ describe Util::User do
8
+ describe 'user_to_uid' do
9
+ it 'should leave integer uids alone' do
10
+ Util::User.user_to_uid(42).must_equal 42
11
+ end
12
+
13
+ it 'should convert user names to uids' do
14
+ user = Etc.getpwent
15
+ Util::User.user_to_uid(user.name).must_equal user.uid
16
+ end
17
+ end
18
+
19
+ describe 'group_to_gid' do
20
+ it 'should leave integer gids alone' do
21
+ Util::User.group_to_gid(42).must_equal 42
22
+ end
23
+
24
+ it 'should convert group names to gids' do
25
+ group = Etc.getgrent
26
+ Util::User.group_to_gid(group.name).must_equal group.gid
27
+ end
28
+ end
29
+
30
+ describe 'owner_to_owner_group' do
31
+ it 'should return non-string owners unmodified' do
32
+ Util::User.owner_to_owner_group(23).must_equal [23, nil]
33
+ end
34
+
35
+ it 'should convert owner strings to [owner, group] arrays' do
36
+ Util::User.owner_to_owner_group('foo').must_equal ['foo', nil]
37
+ Util::User.owner_to_owner_group('foo:bar').must_equal %w(foo bar)
38
+ end
39
+
40
+ it 'should raise exceptions for invalid owner strings' do
41
+ lambda do
42
+ Util::User.owner_to_owner_group('foo:bar:baz')
43
+ end.must_raise ArgumentError
44
+ end
45
+ end
46
+ end
data/spec/util_spec.rb ADDED
@@ -0,0 +1,80 @@
1
+ require_relative 'spec_helper'
2
+
3
+ require 'minitest/stub_const'
4
+ require 'wright/util'
5
+
6
+ def stub_os(target_os)
7
+ RbConfig.stub_const(:CONFIG, 'target_os' => target_os) do
8
+ yield
9
+ end
10
+ end
11
+
12
+ describe Wright::Util do
13
+ describe 'filename_to_classname' do
14
+ it 'should convert filenames to class names' do
15
+ classname = Wright::Util.filename_to_classname('foo_bar/baz')
16
+ classname.must_equal 'FooBar::Baz'
17
+ end
18
+ end
19
+
20
+ describe 'class_to_resource_name' do
21
+ it 'should convert classes to resource names' do
22
+ resource_name = Wright::Util.class_to_resource_name(Object)
23
+ resource_name.must_equal 'object'
24
+ end
25
+ end
26
+
27
+ describe 'os_family' do
28
+ before(:each) do
29
+ @debian_os_release = <<EOS
30
+ PRETTY_NAME="Debian GNU/Linux 7 (wheezy)"
31
+ NAME="Debian GNU/Linux"
32
+ VERSION_ID="7"
33
+ VERSION="7 (wheezy)"
34
+ ID=debian
35
+ ANSI_COLOR="1;31"
36
+ HOME_URL="http://www.debian.org/"
37
+ SUPPORT_URL="http://www.debian.org/support/"
38
+ BUG_REPORT_URL="http://bugs.debian.org/"
39
+ EOS
40
+ @ubuntu_os_release = <<EOS
41
+ NAME="Ubuntu"
42
+ VERSION="12.04.4 LTS, Precise Pangolin"
43
+ ID=ubuntu
44
+ ID_LIKE=debian
45
+ PRETTY_NAME="Ubuntu precise (12.04.4 LTS)"
46
+ VERSION_ID="12.04"
47
+ EOS
48
+ end
49
+
50
+ after(:each) { FakeFS::FileSystem.clear }
51
+
52
+ it 'should detect MacOS X' do
53
+ stub_os('darwin13') do
54
+ Wright::Util.os_family.must_equal 'macosx'
55
+ end
56
+ end
57
+
58
+ it 'should detect GNU/Linux distributions' do
59
+ stub_os('linux') do
60
+ FakeFS do
61
+ FileUtils.mkdir('/etc')
62
+ FileUtils.touch('/etc/os-release')
63
+ Wright::Util.os_family.must_equal 'linux'
64
+
65
+ File.write('/etc/os-release', @debian_os_release)
66
+ Wright::Util.os_family.must_equal 'debian'
67
+
68
+ File.write('/etc/os-release', @ubuntu_os_release)
69
+ Wright::Util.os_family.must_equal 'debian'
70
+ end
71
+ end
72
+ end
73
+
74
+ it 'should detect other operating systems' do
75
+ stub_os('and now for something completely different') do
76
+ Wright::Util.os_family.must_equal 'other'
77
+ end
78
+ end
79
+ end
80
+ end