hookit 0.7.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +3 -0
- data/Rakefile +10 -0
- data/bin/hookit +41 -0
- data/hookit.gemspec +30 -0
- data/lib/hookit/converginator.rb +141 -0
- data/lib/hookit/db.rb +37 -0
- data/lib/hookit/error.rb +8 -0
- data/lib/hookit/exit.rb +23 -0
- data/lib/hookit/helper/cron.rb +42 -0
- data/lib/hookit/helper/nfs.rb +113 -0
- data/lib/hookit/helper/shell.rb +35 -0
- data/lib/hookit/helper/xml.rb +25 -0
- data/lib/hookit/helper.rb +9 -0
- data/lib/hookit/hook.rb +102 -0
- data/lib/hookit/logger.rb +58 -0
- data/lib/hookit/logvac.rb +34 -0
- data/lib/hookit/platform/base.rb +11 -0
- data/lib/hookit/platform/smartos.rb +19 -0
- data/lib/hookit/platform/ubuntu.rb +19 -0
- data/lib/hookit/platform.rb +9 -0
- data/lib/hookit/platforms.rb +2 -0
- data/lib/hookit/registry.rb +53 -0
- data/lib/hookit/resource/base.rb +105 -0
- data/lib/hookit/resource/cron.rb +26 -0
- data/lib/hookit/resource/directory.rb +67 -0
- data/lib/hookit/resource/execute.rb +148 -0
- data/lib/hookit/resource/file.rb +71 -0
- data/lib/hookit/resource/hook_file.rb +80 -0
- data/lib/hookit/resource/link.rb +61 -0
- data/lib/hookit/resource/logrotate.rb +38 -0
- data/lib/hookit/resource/mount.rb +77 -0
- data/lib/hookit/resource/package.rb +74 -0
- data/lib/hookit/resource/rsync.rb +67 -0
- data/lib/hookit/resource/scp.rb +87 -0
- data/lib/hookit/resource/service.rb +89 -0
- data/lib/hookit/resource/socket.rb +67 -0
- data/lib/hookit/resource/template.rb +87 -0
- data/lib/hookit/resource/warning.rb +87 -0
- data/lib/hookit/resource/zfs.rb +99 -0
- data/lib/hookit/resource.rb +21 -0
- data/lib/hookit/resources.rb +15 -0
- data/lib/hookit/version.rb +3 -0
- data/lib/hookit.rb +27 -0
- metadata +205 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
module Hookit
|
2
|
+
class Logger
|
3
|
+
|
4
|
+
attr_reader :log_file, :log_level
|
5
|
+
|
6
|
+
def initialize(file, level)
|
7
|
+
@log_file = file || '/var/log/hookit/hookit.log'
|
8
|
+
@log_level = level || :error
|
9
|
+
end
|
10
|
+
|
11
|
+
def log(level, message)
|
12
|
+
|
13
|
+
if not message
|
14
|
+
message = level
|
15
|
+
level = :error
|
16
|
+
end
|
17
|
+
|
18
|
+
if level_to_int(level) <= level_to_int(log_level)
|
19
|
+
send(level, message)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def error(message)
|
25
|
+
log! "[error]: #{message}\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
def warn(message)
|
29
|
+
log! "[warn]: #{message}\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
def info(message)
|
33
|
+
log! "[info]: #{message}\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def debug(message)
|
37
|
+
log! "[debug]: #{message}\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def log!(message)
|
43
|
+
File.open log_file, 'a' do |f|
|
44
|
+
f.write message
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def level_to_int(level)
|
49
|
+
case level
|
50
|
+
when :error then 1
|
51
|
+
when :warn then 2
|
52
|
+
when :info then 3
|
53
|
+
when :debug then 4
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module Hookit
|
4
|
+
class Logvac
|
5
|
+
|
6
|
+
def initialize(opts)
|
7
|
+
@app = opts[:app]
|
8
|
+
@deploy = opts[:deploy]
|
9
|
+
@token = opts[:token]
|
10
|
+
end
|
11
|
+
|
12
|
+
def post(message)
|
13
|
+
connection.post("/deploy/#{@app}") do |req|
|
14
|
+
req.headers[:x_auth_token] = @token
|
15
|
+
req.headers[:x_deploy_id] = @deploy
|
16
|
+
req.body = message
|
17
|
+
end
|
18
|
+
end
|
19
|
+
alias :print :post
|
20
|
+
|
21
|
+
def puts(message='')
|
22
|
+
post("#{message}\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def connection
|
28
|
+
@connection ||= Faraday.new(url: 'http://logvac.admin.pagodabox.io:6361') do |faraday|
|
29
|
+
faraday.adapter :excon
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Hookit
|
2
|
+
module Platform
|
3
|
+
class Ubuntu < Base
|
4
|
+
|
5
|
+
def detect?
|
6
|
+
! `[ -x /usr/bin/lsb_release ] && /usr/bin/lsb_release -i 2>/dev/null | grep Ubuntu`.empty?
|
7
|
+
end
|
8
|
+
|
9
|
+
def name
|
10
|
+
'ubuntu'
|
11
|
+
end
|
12
|
+
|
13
|
+
def os
|
14
|
+
'linux'
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Hookit
|
2
|
+
# Register components in a single location that can be queried.
|
3
|
+
#
|
4
|
+
# This allows certain components (such as guest systems, configuration
|
5
|
+
# pieces, etc.) to be registered and queried.
|
6
|
+
class Registry
|
7
|
+
def initialize
|
8
|
+
@actions = {}
|
9
|
+
@results_cache = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
# Register a callable by key.
|
13
|
+
#
|
14
|
+
# The callable should be given in a block which will be lazily evaluated
|
15
|
+
# when the action is needed.
|
16
|
+
#
|
17
|
+
# If an action by the given name already exists then it will be
|
18
|
+
# overwritten.
|
19
|
+
def register(key, value=nil, &block)
|
20
|
+
@results_cache.delete key
|
21
|
+
block = lambda { value } unless value.nil?
|
22
|
+
@actions[key] = block
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get an action by the given key.
|
26
|
+
#
|
27
|
+
# This will evaluate the block given to `register` and return the resulting
|
28
|
+
# action stack.
|
29
|
+
def get(key)
|
30
|
+
return nil unless @actions.has_key?(key)
|
31
|
+
return @results_cache[key] if @results_cache.has_key?(key)
|
32
|
+
@results_cache[key] = @actions[key].call
|
33
|
+
end
|
34
|
+
alias :[] :get
|
35
|
+
|
36
|
+
# Iterate over the keyspace.
|
37
|
+
def each(&block)
|
38
|
+
@actions.each do |key, _|
|
39
|
+
yield key, get(key)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Converts this registry to a hash
|
44
|
+
def to_hash
|
45
|
+
result = {}
|
46
|
+
self.each do |key, value|
|
47
|
+
result[key] = value
|
48
|
+
end
|
49
|
+
|
50
|
+
result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Hookit
|
2
|
+
module Resource
|
3
|
+
class Base
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def field(key)
|
8
|
+
define_method key do |*args, &block|
|
9
|
+
if data = block || args[0]
|
10
|
+
instance_variable_set("@#{key}", data)
|
11
|
+
else
|
12
|
+
instance_variable_get("@#{key}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def actions(*actions)
|
18
|
+
if actions.any?
|
19
|
+
@actions = *actions
|
20
|
+
else
|
21
|
+
@actions
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_action(action=nil)
|
26
|
+
if action
|
27
|
+
@default_action = action
|
28
|
+
else
|
29
|
+
@default_action || :run
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_accessor :dict
|
36
|
+
|
37
|
+
field :name
|
38
|
+
|
39
|
+
def initialize(name)
|
40
|
+
name(name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def run(action); end
|
44
|
+
|
45
|
+
def can_run?
|
46
|
+
only_if_res = true
|
47
|
+
not_if_res = false
|
48
|
+
|
49
|
+
if only_if and only_if.respond_to? :call
|
50
|
+
only_if_res = only_if.call
|
51
|
+
end
|
52
|
+
|
53
|
+
if not_if and not_if.respond_to? :call
|
54
|
+
not_if_res = not_if.call
|
55
|
+
end
|
56
|
+
|
57
|
+
only_if_res and not not_if_res
|
58
|
+
end
|
59
|
+
|
60
|
+
def action(*actions)
|
61
|
+
if actions.any?
|
62
|
+
actions.each do |action|
|
63
|
+
if not self.class.actions.include? action
|
64
|
+
raise Hookit::Error::UnknownAction, "unknown action '#{action}'"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
@actions = *actions
|
68
|
+
else
|
69
|
+
@actions || [default_action]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def default_action
|
74
|
+
self.class.default_action
|
75
|
+
end
|
76
|
+
|
77
|
+
def not_if(&block)
|
78
|
+
if block_given?
|
79
|
+
@not_if = block
|
80
|
+
else
|
81
|
+
@not_if
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def only_if(&block)
|
86
|
+
if block_given?
|
87
|
+
@only_if = block
|
88
|
+
else
|
89
|
+
@only_if
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
protected
|
94
|
+
|
95
|
+
def run_command!(cmd, expect_code=0)
|
96
|
+
`#{cmd}`
|
97
|
+
code = $?.exitstatus
|
98
|
+
if code != expect_code
|
99
|
+
raise Hookit::Error::UnexpectedExit, "#{cmd} failed with exit code '#{code}'"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Hookit
|
2
|
+
module Resource
|
3
|
+
class Cron < Execute
|
4
|
+
|
5
|
+
def initialize(name)
|
6
|
+
super
|
7
|
+
timeout 60
|
8
|
+
cwd '/data'
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def run!
|
14
|
+
begin
|
15
|
+
Timeout::timeout(timeout) do
|
16
|
+
f = IO.popen("#{cmd} || exit 0", :err=>[:child, :out])
|
17
|
+
puts f.readline while true
|
18
|
+
end
|
19
|
+
rescue Timeout::Error
|
20
|
+
$stderr.puts 'Timed out running cron! Consider using a worker.'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Hookit
|
2
|
+
module Resource
|
3
|
+
class Directory < Base
|
4
|
+
|
5
|
+
field :path
|
6
|
+
field :recursive
|
7
|
+
field :mode
|
8
|
+
field :owner
|
9
|
+
field :group
|
10
|
+
|
11
|
+
actions :create, :delete
|
12
|
+
default_action :create
|
13
|
+
|
14
|
+
def initialize(name)
|
15
|
+
path name unless path
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def run(action)
|
20
|
+
case action
|
21
|
+
when :create
|
22
|
+
create!
|
23
|
+
chown!
|
24
|
+
chmod!
|
25
|
+
when :delete
|
26
|
+
delete!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def create!
|
33
|
+
return if ::File.exists? path
|
34
|
+
cmd = "mkdir #{"-p " if recursive}#{path}"
|
35
|
+
`#{cmd}`
|
36
|
+
code = $?.exitstatus
|
37
|
+
if code != 0
|
38
|
+
raise Hookit::Error::UnexpectedExit, "#{cmd} failed with exit code '#{code}'"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete!
|
43
|
+
return if not ::File.exists? path
|
44
|
+
cmd = "rm -rf #{path}"
|
45
|
+
`#{cmd}`
|
46
|
+
code = $?.exitstatus
|
47
|
+
if code != 0
|
48
|
+
raise Hookit::Error::UnexpectedExit, "#{cmd} failed with exit code '#{code}'"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def chown!
|
53
|
+
return unless owner or group
|
54
|
+
if ::File.exists? path
|
55
|
+
`chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}`
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def chmod!
|
60
|
+
if ::File.exists? path and mode
|
61
|
+
::File.chmod(mode, path)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
3
|
+
module Hookit
|
4
|
+
module Resource
|
5
|
+
class Execute < Base
|
6
|
+
|
7
|
+
field :command
|
8
|
+
field :cwd
|
9
|
+
field :environment
|
10
|
+
field :user
|
11
|
+
field :path
|
12
|
+
field :returns
|
13
|
+
field :timeout
|
14
|
+
field :stream
|
15
|
+
field :on_data
|
16
|
+
field :validator
|
17
|
+
field :ignore_exit
|
18
|
+
|
19
|
+
actions :run
|
20
|
+
default_action :run
|
21
|
+
|
22
|
+
def initialize(name)
|
23
|
+
command name unless command
|
24
|
+
timeout 3600
|
25
|
+
returns 0
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def run(action)
|
30
|
+
case action
|
31
|
+
when :run
|
32
|
+
if stream
|
33
|
+
stream!
|
34
|
+
else
|
35
|
+
run!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def validate!(res)
|
43
|
+
if validator.is_a? Proc
|
44
|
+
if validator.call(res)
|
45
|
+
res
|
46
|
+
else
|
47
|
+
raise "ERROR: execute resource \"#{name}\" failed validation!"
|
48
|
+
end
|
49
|
+
else
|
50
|
+
res
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def run!
|
55
|
+
Timeout::timeout(timeout) do
|
56
|
+
res = `#{cmd}`
|
57
|
+
code = $?.exitstatus
|
58
|
+
unexpected_exit(code) unless code == returns
|
59
|
+
validate! res
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def stream!
|
64
|
+
result = ""
|
65
|
+
|
66
|
+
STDOUT.sync = STDERR.sync = true # don't buffer stdout/stderr
|
67
|
+
|
68
|
+
::IO.popen(cmd, :err=>[:child, :out]) do |out|
|
69
|
+
eof = false
|
70
|
+
until eof do
|
71
|
+
begin
|
72
|
+
chunk = out.readpartial(4096)
|
73
|
+
if on_data and on_data.respond_to? :call
|
74
|
+
on_data.call(chunk)
|
75
|
+
end
|
76
|
+
rescue EOFError
|
77
|
+
eof = true
|
78
|
+
end
|
79
|
+
result << chunk.to_s
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
code = $?.exitstatus
|
84
|
+
unexpected_exit(code) unless code == returns
|
85
|
+
|
86
|
+
validate! result
|
87
|
+
end
|
88
|
+
|
89
|
+
def cmd
|
90
|
+
com = command
|
91
|
+
|
92
|
+
if environment
|
93
|
+
com = "#{env}#{com}"
|
94
|
+
end
|
95
|
+
|
96
|
+
if path
|
97
|
+
com = "export PATH=\"#{path}\"; #{com}"
|
98
|
+
end
|
99
|
+
|
100
|
+
if cwd
|
101
|
+
com = "cd #{cwd}; #{com}"
|
102
|
+
end
|
103
|
+
|
104
|
+
if user
|
105
|
+
com = su(user, com)
|
106
|
+
end
|
107
|
+
|
108
|
+
com
|
109
|
+
end
|
110
|
+
|
111
|
+
# strategy:
|
112
|
+
# 1- escape the escapes
|
113
|
+
# 2- escape quotes
|
114
|
+
# 3- escape dollar signs
|
115
|
+
def escape(cmd)
|
116
|
+
cmd.gsub!(/\\/, "\\\\\\")
|
117
|
+
cmd.gsub!(/"/, "\\\"")
|
118
|
+
cmd.gsub!(/\$/, "\\$")
|
119
|
+
cmd
|
120
|
+
end
|
121
|
+
|
122
|
+
def su(user, cmd)
|
123
|
+
"su - #{user} -c \"#{escape(cmd)}\""
|
124
|
+
end
|
125
|
+
|
126
|
+
def env
|
127
|
+
vars = environment || {}
|
128
|
+
env = ''
|
129
|
+
vars.each do |key, val|
|
130
|
+
env += " " if not env == ''
|
131
|
+
env += env_string(key, val)
|
132
|
+
end
|
133
|
+
(env == '')? env : "#{env}"
|
134
|
+
end
|
135
|
+
|
136
|
+
def env_string(key, val)
|
137
|
+
key = key.to_s if not key.is_a? String
|
138
|
+
val = val.to_s if not val.is_a? String
|
139
|
+
%Q{export #{key.upcase}="#{escape(val)}";}
|
140
|
+
end
|
141
|
+
|
142
|
+
def unexpected_exit(res)
|
143
|
+
raise Hookit::Error::UnexpectedExit, "'#{name}' exited with #{res}, expected #{returns}" unless ignore_exit
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Hookit
|
2
|
+
module Resource
|
3
|
+
class File < Base
|
4
|
+
|
5
|
+
field :path
|
6
|
+
field :content
|
7
|
+
field :mode
|
8
|
+
field :owner
|
9
|
+
field :group
|
10
|
+
|
11
|
+
actions :create, :create_if_missing, :delete, :touch
|
12
|
+
default_action :create
|
13
|
+
|
14
|
+
def initialize(name)
|
15
|
+
path name unless path
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def run(action)
|
20
|
+
case action
|
21
|
+
when :create
|
22
|
+
create!
|
23
|
+
chown!
|
24
|
+
chmod!
|
25
|
+
when :create_if_missing
|
26
|
+
create_if_missing!
|
27
|
+
chown!
|
28
|
+
chmod!
|
29
|
+
when :delete
|
30
|
+
delete!
|
31
|
+
when :touch
|
32
|
+
touch!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def create!
|
39
|
+
::File.write path, (content || "")
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_if_missing!
|
43
|
+
if not ::File.exists? path
|
44
|
+
create!
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete!
|
49
|
+
::File.delete path
|
50
|
+
end
|
51
|
+
|
52
|
+
def chown!
|
53
|
+
return unless owner or group
|
54
|
+
if ::File.exists? path
|
55
|
+
`chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}`
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def chmod!
|
60
|
+
if ::File.exists? path and mode
|
61
|
+
::File.chmod(mode, path)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def touch!
|
66
|
+
`touch -c #{path}`
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Hookit
|
2
|
+
module Resource
|
3
|
+
class HookFile < Base
|
4
|
+
|
5
|
+
field :path
|
6
|
+
field :source
|
7
|
+
field :mode
|
8
|
+
field :owner
|
9
|
+
field :group
|
10
|
+
|
11
|
+
actions :create, :create_if_missing, :delete, :touch
|
12
|
+
default_action :create
|
13
|
+
|
14
|
+
def initialize(name)
|
15
|
+
path name unless path
|
16
|
+
source ::File.basename(name)
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def run(action)
|
21
|
+
case action
|
22
|
+
when :create
|
23
|
+
create!
|
24
|
+
chown!
|
25
|
+
chmod!
|
26
|
+
when :create_if_missing
|
27
|
+
create_if_missing!
|
28
|
+
chown!
|
29
|
+
chmod!
|
30
|
+
when :delete
|
31
|
+
delete!
|
32
|
+
when :touch
|
33
|
+
touch!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def create!
|
40
|
+
::File.write path, render
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_if_missing!
|
44
|
+
if not ::File.exists? path
|
45
|
+
create!
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete!
|
50
|
+
::File.delete path
|
51
|
+
end
|
52
|
+
|
53
|
+
def chown!
|
54
|
+
return unless owner or group
|
55
|
+
`chown #{(group.nil?) ? owner : "#{owner}:#{group}"} #{path}`
|
56
|
+
end
|
57
|
+
|
58
|
+
def chmod!
|
59
|
+
::File.chmod(mode, path) if mode
|
60
|
+
end
|
61
|
+
|
62
|
+
def touch!
|
63
|
+
`touch -c #{path}`
|
64
|
+
end
|
65
|
+
|
66
|
+
def render
|
67
|
+
::File.read("#{file_dir}/#{source}")
|
68
|
+
end
|
69
|
+
|
70
|
+
def file_dir
|
71
|
+
"#{module_root}/files"
|
72
|
+
end
|
73
|
+
|
74
|
+
def module_root
|
75
|
+
dict[:module_root]
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|