-
Notifications
You must be signed in to change notification settings - Fork 2
/
file.rb
168 lines (141 loc) · 4.29 KB
/
file.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
require 'erubis'
module Config
module Patterns
class File < Config::Pattern
desc "The full path of the file"
key :path
desc "The user that owns the file"
attr :owner, nil
desc "The group that owns the file"
attr :group, nil
desc "The octal mode of the file, such as 0755"
attr :mode, nil
desc "Specify the literal file content"
attr :content, nil
desc "Specify that content comes from a template file"
attr :template_path, nil
desc "Specify the object to provide the template binding"
attr :template_context, nil
desc "The operation to perform. See append! and only_create!"
attr :operation, :write
def describe
["File", pn].compact.join(" ")
end
# Public: Appending is a questionable operation so call it with
# bang for confidence.
#
# Returns nothing.
def append!
self.operation = :append
end
# Public: Not modifying an existing file is a questionable
# operation so call it with bang for confidence.
#
# Returns nothing.
def only_create!
self.operation = :only_create
end
def validate
if content.nil?
if template_path.nil? || template_context.nil?
validation_errors << "You must set either `content` or (`template_path` and `template_context`)"
end
if template_path && !::File.exist?(template_path)
validation_errors << "template_path #{template_path} does not exist"
end
if template_context && !template_context.respond_to?(:get_binding)
validation_errors << "template_context must define #get_binding"
end
end
end
class ColorizingEruby < Erubis::Eruby
include Config::Core::Loggable
def add_expr_literal(src, code)
src << '_buf << (' << colorize(code) << ');'
end
protected
def colorize(code)
if log.color?
'"' + log.colorize("#{code.strip}:", :blue) + log.colorize("\#{#{code}}", :red) + '"'
else
%("[#{code.strip}:\#{#{code}}]")
end
end
end
def prepare
if create?
if content
@new_content = String(content)
log_content = @new_content
else
template = ::File.read(template_path)
log_template = ColorizingEruby.new(template)
log_content = log_template.result(template_context.get_binding)
new_template = Erubis::Eruby.new(template)
@new_content = new_template.result(template_context.get_binding)
end
log << log.colorize(">>>", :cyan)
log << log_content
log << log.colorize("<<<", :cyan)
end
end
def call
if owner || group
add Config::Patterns::Chown do |p|
p.path = path
p.owner = owner
p.group = group
end
end
if mode
add Config::Patterns::Chmod do |p|
p.path = path
p.mode = mode
end
end
end
def create
change_status = nil
if pn.exist?
change_status = case operation
when :append
"appended"
when :write
# TODO: checksum to compare? use File.identical?
if @new_content == pn.read
"identical"
else
"updated"
end
end
else
change_status = "created"
end
if change_status
case change_status
when "created", "updated"
pn.open("w") { |f| f.print @new_content }
changes << change_status
log << log.colorize(change_status.upcase, :brown)
when "appended"
pn.open("a") { |f| f.print @new_content }
changes << change_status
log << log.colorize(change_status.upcase, :brown)
when "identical"
log << log.colorize("IDENTICAL", :cyan)
end
end
end
def destroy
if pn.exist?
pn.delete
changes << "deleted"
end
end
protected
def pn
@pn ||= Pathname.new(path).cleanpath if path
end
end
end
end