wright 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|