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.
- checksums.yaml +7 -0
- data/LICENSE +2 -2
- data/NEWS +8 -0
- data/README.md +70 -0
- data/Rakefile +19 -0
- data/lib/wright/config.rb +64 -0
- data/lib/wright/dry_run.rb +33 -0
- data/lib/wright/dsl.rb +63 -0
- data/lib/wright/logger.rb +73 -0
- data/lib/wright/provider/directory.rb +78 -0
- data/lib/wright/provider/file.rb +104 -0
- data/lib/wright/provider/package/apt.rb +93 -0
- data/lib/wright/provider/package.rb +38 -0
- data/lib/wright/provider/symlink.rb +86 -0
- data/lib/wright/provider.rb +30 -0
- data/lib/wright/resource/directory.rb +67 -0
- data/lib/wright/resource/file.rb +67 -0
- data/lib/wright/resource/package.rb +70 -0
- data/lib/wright/resource/symlink.rb +47 -0
- data/lib/wright/resource.rb +157 -0
- data/lib/wright/util/color.rb +51 -0
- data/lib/wright/util/file.rb +258 -0
- data/lib/wright/util/file_permissions.rb +129 -0
- data/lib/wright/util/recursive_autoloader.rb +91 -0
- data/lib/wright/util/stolen_from_activesupport.rb +202 -0
- data/lib/wright/util/user.rb +75 -0
- data/lib/wright/util.rb +72 -0
- data/lib/wright/version.rb +3 -2
- data/lib/wright.rb +10 -1
- data/spec/config_spec.rb +37 -0
- data/spec/dsl_spec.rb +65 -0
- data/spec/logger_spec.rb +65 -0
- data/spec/provider/directory_spec.rb +114 -0
- data/spec/provider/file_spec.rb +130 -0
- data/spec/provider/package/apt/apt-get_install_-qy_abcde=2.5.4-1.return +1 -0
- data/spec/provider/package/apt/apt-get_install_-qy_abcde=2.5.4-1.stderr +0 -0
- data/spec/provider/package/apt/apt-get_install_-qy_abcde=2.5.4-1.stdout +15 -0
- data/spec/provider/package/apt/apt-get_install_-qy_htop.return +1 -0
- data/spec/provider/package/apt/apt-get_install_-qy_htop.stderr +0 -0
- data/spec/provider/package/apt/apt-get_install_-qy_htop.stdout +19 -0
- data/spec/provider/package/apt/apt-get_install_-qy_unknown-package.return +1 -0
- data/spec/provider/package/apt/apt-get_install_-qy_unknown-package.stderr +1 -0
- data/spec/provider/package/apt/apt-get_install_-qy_unknown-package.stdout +3 -0
- data/spec/provider/package/apt/apt-get_remove_-qy_abcde.return +1 -0
- data/spec/provider/package/apt/apt-get_remove_-qy_abcde.stderr +0 -0
- data/spec/provider/package/apt/apt-get_remove_-qy_abcde.stdout +14 -0
- data/spec/provider/package/apt/dpkg-query_-s_abcde.return +1 -0
- data/spec/provider/package/apt/dpkg-query_-s_abcde.stderr +0 -0
- data/spec/provider/package/apt/dpkg-query_-s_abcde.stdout +23 -0
- data/spec/provider/package/apt/dpkg-query_-s_htop.return +1 -0
- data/spec/provider/package/apt/dpkg-query_-s_htop.stderr +0 -0
- data/spec/provider/package/apt/dpkg-query_-s_htop.stdout +19 -0
- data/spec/provider/package/apt/dpkg-query_-s_unknown-package.return +1 -0
- data/spec/provider/package/apt/dpkg-query_-s_unknown-package.stderr +3 -0
- data/spec/provider/package/apt/dpkg-query_-s_unknown-package.stdout +0 -0
- data/spec/provider/package/apt/dpkg-query_-s_vlc.return +1 -0
- data/spec/provider/package/apt/dpkg-query_-s_vlc.stderr +3 -0
- data/spec/provider/package/apt/dpkg-query_-s_vlc.stdout +0 -0
- data/spec/provider/package/apt_spec.rb +297 -0
- data/spec/provider/package_spec.rb +63 -0
- data/spec/provider/symlink_spec.rb +122 -0
- data/spec/provider_spec.rb +19 -0
- data/spec/recursive_autoloader/foo/bar/baz.rb +12 -0
- data/spec/recursive_autoloader/identically_named_dir_and_file/this_should_not_be_loaded.rb +1 -0
- data/spec/recursive_autoloader/identically_named_dir_and_file.rb +8 -0
- data/spec/recursive_autoloader/loaded_on_demand.rb +8 -0
- data/spec/recursive_autoloader/raises_exception.rb +1 -0
- data/spec/recursive_autoloader_spec.rb +41 -0
- data/spec/resource/directory_spec.rb +187 -0
- data/spec/resource/file_spec.rb +213 -0
- data/spec/resource/symlink_spec.rb +117 -0
- data/spec/resource_spec.rb +184 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/spec_helpers/fake_capture3.rb +47 -0
- data/spec/util/activesupport_spec.rb +24 -0
- data/spec/util/file_permissions_spec.rb +141 -0
- data/spec/util/file_spec.rb +127 -0
- data/spec/util/user_spec.rb +46 -0
- data/spec/util_spec.rb +80 -0
- metadata +253 -20
- data/.gitignore +0 -17
- data/Gemfile +0 -3
- data/wright.gemspec +0 -16
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4644d39c9505dda9fce4adb9a0a5bd5a5e0dfe0a
|
4
|
+
data.tar.gz: 33c6ed57fc54bff76b3cfd9c91f2969f8b978d1e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 350373a47cdcd38005c8deb56ab835130c2a946aaf69751344318765797e388f4785d8be34b79fbfccdb85d3cae878312f531d30912b1d6d022f86c77fe5c284
|
7
|
+
data.tar.gz: 63e0cff72088b5d73174c3dd75f26dbb7ad48b97bede920c2625b7c63746a8873c01c46da1c25a9bfa9363494ee255a4b4e8ba3926989855efe01bb7be438932
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2013 Sebastian Boehm
|
1
|
+
Copyright (c) 2012, 2013, 2014, 2015 Sebastian Boehm
|
2
2
|
|
3
3
|
MIT License
|
4
4
|
|
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/NEWS
ADDED
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
wright
|
2
|
+
======
|
3
|
+
|
4
|
+
Lightweight configuration management.
|
5
|
+
|
6
|
+
Requirements
|
7
|
+
------------
|
8
|
+
|
9
|
+
- Ruby ≥1.9
|
10
|
+
|
11
|
+
Documentation
|
12
|
+
-------------
|
13
|
+
|
14
|
+
There is not too much useful documentation that is targeted towards
|
15
|
+
users at the moment.
|
16
|
+
|
17
|
+
Run `bundle exec rake rdoc` to generate HTML docs for wright
|
18
|
+
developers.
|
19
|
+
|
20
|
+
Hacking
|
21
|
+
-------
|
22
|
+
|
23
|
+
To get started with wright, simply install the development
|
24
|
+
dependencies via bundler:
|
25
|
+
|
26
|
+
- `bundle install --path .bundle`
|
27
|
+
- `bundle exec rake test`
|
28
|
+
|
29
|
+
All tests should pass.
|
30
|
+
|
31
|
+
Getting Started
|
32
|
+
---------------
|
33
|
+
|
34
|
+
To start a wright IRB session, simply run:
|
35
|
+
|
36
|
+
$ bundle console
|
37
|
+
|
38
|
+
In order to create some resources using the wright DSL:
|
39
|
+
|
40
|
+
extend Wright::DSL
|
41
|
+
|
42
|
+
foo_dir = directory '/tmp/foo'
|
43
|
+
fstab = symlink '/tmp/foo/fstab' do |s|
|
44
|
+
s.to = '/etc/fstab'
|
45
|
+
end
|
46
|
+
|
47
|
+
puts File.directory? '/tmp/foo'
|
48
|
+
puts File.symlink? '/tmp/foo/fstab'
|
49
|
+
|
50
|
+
fstab.remove
|
51
|
+
foo_dir.remove
|
52
|
+
|
53
|
+
If you don't want to use the DSL:
|
54
|
+
|
55
|
+
foo_dir = Wright::Resource::Directory.new('/tmp/foo')
|
56
|
+
foo_dir.create
|
57
|
+
fstab = Wright::Resource::Symlink.new('/tmp/foo/fstab')
|
58
|
+
fstab.to = '/etc/fstab'
|
59
|
+
fstab.create
|
60
|
+
|
61
|
+
puts File.directory? '/tmp/foo'
|
62
|
+
puts File.symlink? '/tmp/foo/fstab'
|
63
|
+
|
64
|
+
fstab.remove
|
65
|
+
foo_dir.remove
|
66
|
+
|
67
|
+
Copyright
|
68
|
+
---------
|
69
|
+
|
70
|
+
Copyright (c) 2012-2015 Sebastian Boehm. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,2 +1,21 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
require 'bundler/gem_tasks'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rdoc/task'
|
5
|
+
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.pattern = 'spec/**/*_spec.rb'
|
8
|
+
end
|
9
|
+
|
10
|
+
RDoc::Task.new(clobber_rdoc: 'rdoc:clobber',
|
11
|
+
rerdoc: 'rdoc:force') do |t|
|
12
|
+
t.rdoc_files.include('lib/**/*.rb')
|
13
|
+
t.options << '--markup=tomdoc'
|
14
|
+
end
|
15
|
+
|
16
|
+
namespace :rdoc do
|
17
|
+
desc 'Show RDoc coverage report'
|
18
|
+
task :coverage do
|
19
|
+
exec 'rdoc --markup=tomdoc --coverage-report lib/'
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Wright
|
4
|
+
# Public: Configuration container, wraps a regular Ruby hash.
|
5
|
+
#
|
6
|
+
# Useful for getting and setting configuration values, such as
|
7
|
+
# logging verbosity, colour output and provider configuration.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# Wright::Config[:foo] = { bar: :baz }
|
12
|
+
# Wright::Config[:foo][:bar]
|
13
|
+
# # => :baz
|
14
|
+
class Config
|
15
|
+
@config_hash = {}
|
16
|
+
class << self
|
17
|
+
extend Forwardable
|
18
|
+
def_delegators :@config_hash, :[], :[]=, :size
|
19
|
+
end
|
20
|
+
private_class_method :new
|
21
|
+
|
22
|
+
# Public: Check if a (nested) configuration value is set.
|
23
|
+
#
|
24
|
+
# path - The configuration item as an argument list.
|
25
|
+
#
|
26
|
+
# Examples
|
27
|
+
#
|
28
|
+
# Wright::Config[:foo] = { bar: :baz }
|
29
|
+
# Wright::Config.nested_key?(:foo, :bar)
|
30
|
+
# # => true
|
31
|
+
#
|
32
|
+
# Wright::Config.nested_key?(:this, :doesnt, :exist)
|
33
|
+
# # => false
|
34
|
+
#
|
35
|
+
# Returns true if the configuration value is set and false
|
36
|
+
# otherwise.
|
37
|
+
def self.nested_key?(*path)
|
38
|
+
last_key = path.pop
|
39
|
+
last_hash = path.reduce(@config_hash) do |hash, key|
|
40
|
+
return false unless hash.respond_to?(:fetch)
|
41
|
+
hash.fetch(key, {})
|
42
|
+
end
|
43
|
+
last_hash.respond_to?(:key?) && last_hash.key?(last_key)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Public: Retrieve a (nested) configuration value.
|
47
|
+
#
|
48
|
+
# path - The configuration item as an argument list.
|
49
|
+
#
|
50
|
+
# Examples
|
51
|
+
#
|
52
|
+
# Wright::Config[:foo] = { bar: :baz }
|
53
|
+
# Wright::Config.nested_value(:foo, :bar)
|
54
|
+
# # => :baz
|
55
|
+
#
|
56
|
+
# Wright::Config.nested_value(:this, :doesnt, :exist)
|
57
|
+
# # => nil
|
58
|
+
#
|
59
|
+
# Returns the configuration value or nil if the value is not set.
|
60
|
+
def self.nested_value(*path)
|
61
|
+
nested_key?(*path) ? path.reduce(@config_hash) { |a, e| a[e] } : nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Wright # rubocop:disable Documentation
|
2
|
+
@dry_run = false
|
3
|
+
|
4
|
+
# Public: Checks if dry-run mode is currently active.
|
5
|
+
#
|
6
|
+
# Examples
|
7
|
+
#
|
8
|
+
# puts 'Just a dry-run...' if Wright.dry_run?
|
9
|
+
#
|
10
|
+
# Returns true if dry-run mode is currently active and false otherwise.
|
11
|
+
def self.dry_run?
|
12
|
+
@dry_run
|
13
|
+
end
|
14
|
+
|
15
|
+
# Public: Runs a block in dry-run mode.
|
16
|
+
#
|
17
|
+
# Examples
|
18
|
+
#
|
19
|
+
# Wright.dry_run do
|
20
|
+
# symlink '/tmp/fstab' do |s|
|
21
|
+
# s.to = '/etc/fstab'
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# Returns the block's return value.
|
26
|
+
def self.dry_run
|
27
|
+
saved_dry_run = @dry_run
|
28
|
+
@dry_run = true
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
@dry_run = saved_dry_run
|
32
|
+
end
|
33
|
+
end
|
data/lib/wright/dsl.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'wright/util'
|
2
|
+
|
3
|
+
module Wright
|
4
|
+
# Public: Includable Wright script DSL.
|
5
|
+
#
|
6
|
+
# Contains resource methods for all registered resources.
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# # define a new resource at runtime
|
11
|
+
# class KitchenSink < Wright::Resource; end
|
12
|
+
#
|
13
|
+
# # register the resource
|
14
|
+
# Wright::DSL.register_resource KitchenSink
|
15
|
+
#
|
16
|
+
# extend Wright::DSL
|
17
|
+
#
|
18
|
+
# kitchen_sink "I don't do anything"
|
19
|
+
#
|
20
|
+
# # resource methods accept blocks
|
21
|
+
# kitchen_sink 'I am sooo useful' do |k|
|
22
|
+
# puts k.name
|
23
|
+
# end
|
24
|
+
# # output: I am sooo useful
|
25
|
+
#
|
26
|
+
# # save resource for later use
|
27
|
+
# a_sink_to_remember = kitchen_sink 'Me too, me too!'
|
28
|
+
# a_sink_to_remember.class
|
29
|
+
# # => KitchenSink
|
30
|
+
module DSL
|
31
|
+
# Public: Register a class as a resource.
|
32
|
+
#
|
33
|
+
# Creates a resource method in the DSL module. Uses the
|
34
|
+
# snake-cased class name as method name.
|
35
|
+
#
|
36
|
+
# resource_class - The resource class. Usually a subclass of
|
37
|
+
# Wright::Resource. Will be initialized with the
|
38
|
+
# resource's name as an argument.
|
39
|
+
#
|
40
|
+
# Returns nothing.
|
41
|
+
def self.register_resource(resource_class)
|
42
|
+
method_name = Util.class_to_resource_name(resource_class)
|
43
|
+
this_module = self
|
44
|
+
define_method(method_name) do |name = nil, &block|
|
45
|
+
this_module.yield_resource(resource_class, name, &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Internal: Instantiate a resource_class object and perform its
|
50
|
+
# default action.
|
51
|
+
#
|
52
|
+
# Implicitly invoking a block from within another block does not
|
53
|
+
# work: http://blog.sidu.in/2007/11/ruby-blocks-gotchas.html
|
54
|
+
#
|
55
|
+
# Returns nothing.
|
56
|
+
def self.yield_resource(resource_class, name)
|
57
|
+
r = resource_class.new(name)
|
58
|
+
yield(r) if block_given?
|
59
|
+
r.run_action if r.respond_to?(:run_action)
|
60
|
+
r
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
require 'wright/config'
|
4
|
+
require 'wright/util/color'
|
5
|
+
|
6
|
+
module Wright # rubocop:disable Documentation
|
7
|
+
# Public: Default logger for Wright.
|
8
|
+
class Logger < ::Logger
|
9
|
+
# Public: Default formatter for Wright log messages.
|
10
|
+
class Formatter < ::Logger::Formatter
|
11
|
+
# Internal: Called by Wright::Logger to format log messages.
|
12
|
+
#
|
13
|
+
# severity - The String log severity.
|
14
|
+
# time - The time for the log entry. Ignored.
|
15
|
+
# progname - The program name for the log entry. Ignored.
|
16
|
+
# message - The actual log message.
|
17
|
+
#
|
18
|
+
# Returns the formatted String log entry.
|
19
|
+
def call(severity, _time, _progname, message)
|
20
|
+
log_entry = "#{severity}: #{message}\n"
|
21
|
+
if Wright::Config[:log][:colorize]
|
22
|
+
colorize(log_entry, severity)
|
23
|
+
else
|
24
|
+
log_entry
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Internal: ANSI-Colorize a log message according to its
|
31
|
+
# severity.
|
32
|
+
#
|
33
|
+
# string - The String log message to be colorized.
|
34
|
+
# severity - The String severity of the log message.
|
35
|
+
#
|
36
|
+
# Returns the colorized String.
|
37
|
+
def colorize(string, severity)
|
38
|
+
case severity
|
39
|
+
when 'ERROR', 'FATAL'
|
40
|
+
Wright::Util::Color.red(string)
|
41
|
+
when 'WARN'
|
42
|
+
Wright::Util::Color.yellow(string)
|
43
|
+
when 'INFO'
|
44
|
+
string
|
45
|
+
else
|
46
|
+
string
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Public: Initialize a Logger.
|
52
|
+
#
|
53
|
+
# Enables log colorization if the log device is a TTY and
|
54
|
+
# colorization was not disabled before initialization.
|
55
|
+
#
|
56
|
+
# logdev - The log device used by the Logger.
|
57
|
+
def initialize(logdev = $stdout)
|
58
|
+
super
|
59
|
+
Wright::Config[:log] ||= {}
|
60
|
+
return unless Wright::Config[:log][:colorize].nil?
|
61
|
+
|
62
|
+
Wright::Config[:log][:colorize] = logdev.tty?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class << self
|
67
|
+
# Public: Get/Set Wright's Logger.
|
68
|
+
attr_accessor :log
|
69
|
+
end
|
70
|
+
@log = Wright::Logger.new
|
71
|
+
@log.formatter = Wright::Logger::Formatter.new
|
72
|
+
@log.level = Wright::Logger::INFO
|
73
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'wright/provider'
|
3
|
+
require 'wright/util/file'
|
4
|
+
require 'wright/util/user'
|
5
|
+
require 'wright/util/file_permissions'
|
6
|
+
|
7
|
+
module Wright
|
8
|
+
class Provider
|
9
|
+
# Public: Directory provider. Used as a Provider for Resource::Directory.
|
10
|
+
class Directory < Wright::Provider
|
11
|
+
# Public: Create or update the directory.
|
12
|
+
#
|
13
|
+
# Returns nothing.
|
14
|
+
def create
|
15
|
+
if ::File.directory?(dirname) && permissions.uptodate?
|
16
|
+
Wright.log.debug "directory already created: '#{@resource.name}'"
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
fail Errno::EEXIST, dirname if regular_file?
|
21
|
+
create_directory
|
22
|
+
@updated = true
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public: Remove the directory.
|
26
|
+
#
|
27
|
+
# Returns nothing.
|
28
|
+
def remove
|
29
|
+
if ::File.exist?(dirname) && !::File.directory?(dirname)
|
30
|
+
fail "'#{dirname}' exists but is not a directory"
|
31
|
+
end
|
32
|
+
|
33
|
+
if ::File.directory?(dirname)
|
34
|
+
remove_directory
|
35
|
+
@updated = true
|
36
|
+
else
|
37
|
+
Wright.log.debug "directory already removed: '#{@resource.name}'"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def permissions
|
44
|
+
Wright::Util::FilePermissions.create_from_resource(@resource,
|
45
|
+
:directory)
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_directory
|
49
|
+
dir_permissions = permissions
|
50
|
+
|
51
|
+
if Wright.dry_run?
|
52
|
+
Wright.log.info "(would) create directory: '#{@resource.name}'"
|
53
|
+
else
|
54
|
+
Wright.log.info "create directory: '#{@resource.name}'"
|
55
|
+
FileUtils.mkdir_p(dirname)
|
56
|
+
dir_permissions.update
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove_directory
|
61
|
+
if Wright.dry_run?
|
62
|
+
Wright.log.info "(would) remove directory: '#{@resource.name}'"
|
63
|
+
else
|
64
|
+
Wright.log.info "remove directory: '#{@resource.name}'"
|
65
|
+
FileUtils.rmdir(dirname)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def regular_file?
|
70
|
+
::File.exist?(dirname) && !::File.directory?(dirname)
|
71
|
+
end
|
72
|
+
|
73
|
+
def dirname
|
74
|
+
::File.expand_path(@resource.name)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'wright/provider'
|
2
|
+
require 'wright/util/file_permissions'
|
3
|
+
require 'wright/util/user'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'digest'
|
6
|
+
require 'tempfile'
|
7
|
+
require 'tmpdir'
|
8
|
+
|
9
|
+
module Wright
|
10
|
+
class Provider
|
11
|
+
# Public: File provider. Used as a Provider for Resource::File.
|
12
|
+
class File < Wright::Provider
|
13
|
+
# Public: Create or update the File.
|
14
|
+
#
|
15
|
+
# Returns nothing.
|
16
|
+
def create
|
17
|
+
fail Errno::EISDIR, filename if ::File.directory?(filename)
|
18
|
+
|
19
|
+
if uptodate?
|
20
|
+
Wright.log.debug "file already created: '#{@resource.name}'"
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
create_file
|
25
|
+
@updated = true
|
26
|
+
end
|
27
|
+
|
28
|
+
# Public: Remove the File.
|
29
|
+
#
|
30
|
+
# Returns nothing.
|
31
|
+
def remove
|
32
|
+
fail Errno::EISDIR, filename if ::File.directory?(filename)
|
33
|
+
|
34
|
+
if ::File.exist?(filename) || ::File.symlink?(filename)
|
35
|
+
remove_file
|
36
|
+
@updated = true
|
37
|
+
else
|
38
|
+
Wright.log.debug "file already removed: '#{@resource.name}'"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def create_file
|
45
|
+
file_permissions = permissions
|
46
|
+
|
47
|
+
if Wright.dry_run?
|
48
|
+
Wright.log.info "(would) create file: '#{@resource.name}'"
|
49
|
+
else
|
50
|
+
Wright.log.info "create file: '#{@resource.name}'"
|
51
|
+
write_content_to_file
|
52
|
+
file_permissions.update
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def write_content_to_file
|
57
|
+
tempfile = Tempfile.new(::File.basename(filename))
|
58
|
+
tempfile.write(@resource.content) if @resource.content
|
59
|
+
move_tempfile(tempfile)
|
60
|
+
ensure
|
61
|
+
tempfile.close!
|
62
|
+
end
|
63
|
+
|
64
|
+
def move_tempfile(tempfile)
|
65
|
+
# do not overwrite existing files if content was not specified
|
66
|
+
return if @resource.content.nil? && ::File.exist?(filename)
|
67
|
+
FileUtils.mv(tempfile.path, filename)
|
68
|
+
end
|
69
|
+
|
70
|
+
def remove_file
|
71
|
+
if Wright.dry_run?
|
72
|
+
Wright.log.info "(would) remove file: '#{@resource.name}'"
|
73
|
+
else
|
74
|
+
Wright.log.info "remove file: '#{@resource.name}'"
|
75
|
+
FileUtils.rm(filename)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def permissions
|
80
|
+
Wright::Util::FilePermissions.create_from_resource(@resource, :file)
|
81
|
+
end
|
82
|
+
|
83
|
+
def checksum(content)
|
84
|
+
Digest::SHA256.hexdigest(content)
|
85
|
+
end
|
86
|
+
|
87
|
+
def content_uptodate?
|
88
|
+
return false unless ::File.exist?(filename)
|
89
|
+
content = @resource.content || ''
|
90
|
+
target_checksum = checksum(content)
|
91
|
+
current_checksum = checksum(::File.read(filename))
|
92
|
+
current_checksum == target_checksum
|
93
|
+
end
|
94
|
+
|
95
|
+
def uptodate?
|
96
|
+
content_uptodate? && permissions.uptodate?
|
97
|
+
end
|
98
|
+
|
99
|
+
def filename
|
100
|
+
::File.expand_path(@resource.name)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
require 'wright/dry_run'
|
4
|
+
require 'wright/provider'
|
5
|
+
require 'wright/provider/package'
|
6
|
+
|
7
|
+
module Wright
|
8
|
+
class Provider
|
9
|
+
class Package
|
10
|
+
# Public: AptPackage provider. Used as a Provider for
|
11
|
+
# Resource::Package on Debian-based systems.
|
12
|
+
class Apt < Wright::Provider::Package
|
13
|
+
# Public: Get the installed package version.
|
14
|
+
#
|
15
|
+
# Returns an array of installed package version Strings.
|
16
|
+
def installed_versions
|
17
|
+
cmd = "dpkg-query -s #{@resource.name}"
|
18
|
+
cmd_stdout, _cmd_stderr, cmd_status = Open3.capture3(env, cmd)
|
19
|
+
installed_re = /^Status: install ok installed$/
|
20
|
+
|
21
|
+
if cmd_status.success? && installed_re =~ cmd_stdout
|
22
|
+
/^Version: (?<version>.*)$/ =~ cmd_stdout
|
23
|
+
[version]
|
24
|
+
else
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Public: Install the package.
|
30
|
+
#
|
31
|
+
# Returns nothing.
|
32
|
+
def install
|
33
|
+
if uptodate?(:install)
|
34
|
+
Wright.log.debug "package already installed: '#{@resource.name}'"
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
install_package
|
39
|
+
@updated = true
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: Remove the package.
|
43
|
+
#
|
44
|
+
# Returns nothing.
|
45
|
+
def remove
|
46
|
+
if uptodate?(:remove)
|
47
|
+
Wright.log.debug "package already removed: '#{@resource.name}'"
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
remove_package
|
52
|
+
@updated = true
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def install_package
|
58
|
+
package = @resource.name
|
59
|
+
if Wright.dry_run?
|
60
|
+
Wright.log.info "(would) install package: '#{package}'"
|
61
|
+
else
|
62
|
+
Wright.log.info "install package: '#{package}'"
|
63
|
+
apt_get(:install, package, @resource.version)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def remove_package
|
68
|
+
package = @resource.name
|
69
|
+
if Wright.dry_run?
|
70
|
+
Wright.log.info "(would) remove package: '#{package}'"
|
71
|
+
else
|
72
|
+
Wright.log.info "remove package: '#{package}'"
|
73
|
+
apt_get(:remove, package)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def apt_get(action, package, version = nil)
|
78
|
+
package_version = version.nil? ? '' : "=#{version}"
|
79
|
+
apt_cmd = "apt-get #{action} -qy #{package}#{package_version}"
|
80
|
+
_cmd_stdout, cmd_stderr, cmd_status = Open3.capture3(env, apt_cmd)
|
81
|
+
return if cmd_status.success?
|
82
|
+
|
83
|
+
apt_error = cmd_stderr.chomp
|
84
|
+
fail %(cannot #{action} package '#{package}': "#{apt_error}")
|
85
|
+
end
|
86
|
+
|
87
|
+
def env
|
88
|
+
{ 'DEBIAN_FRONTEND' => 'noninteractive' }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'wright/provider'
|
2
|
+
|
3
|
+
module Wright
|
4
|
+
class Provider
|
5
|
+
# Public: Package provider. Used as a Provider base class for
|
6
|
+
# Resource::Package.
|
7
|
+
class Package < Wright::Provider
|
8
|
+
private
|
9
|
+
|
10
|
+
# Public: Check if the package is up-to-date for a given
|
11
|
+
# action.
|
12
|
+
#
|
13
|
+
# action - The action symbol. Currently supports :install and
|
14
|
+
# :remove.
|
15
|
+
#
|
16
|
+
# Returns true if the package is up-to-date and false otherwise.
|
17
|
+
# Raises ArgumentError if the action is invalid.
|
18
|
+
def uptodate?(action)
|
19
|
+
case action
|
20
|
+
when :install
|
21
|
+
package_installed?
|
22
|
+
when :remove
|
23
|
+
!package_installed?
|
24
|
+
else
|
25
|
+
fail ArgumentError, "invalid action '#{action}'"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def package_installed?
|
30
|
+
if @resource.version
|
31
|
+
installed_versions.include?(@resource.version)
|
32
|
+
else
|
33
|
+
!installed_versions.empty?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|