/
static_file.rb
160 lines (136 loc) · 4.08 KB
/
static_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
module Jekyll
class StaticFile
extend Forwardable
attr_reader :relative_path, :extname, :name, :data
def_delegator :to_liquid, :to_json, :to_json
class << self
# The cache of last modification times [path] -> mtime.
def mtimes
@mtimes ||= {}
end
def reset_cache
@mtimes = nil
end
end
# Initialize a new StaticFile.
#
# site - The Site.
# base - The String path to the <source>.
# dir - The String path between <source> and the file.
# name - The String filename of the file.
# rubocop: disable ParameterLists
def initialize(site, base, dir, name, collection = nil)
@site = site
@base = base
@dir = dir
@name = name
@collection = collection
@relative_path = File.join(*[@dir, @name].compact)
@extname = File.extname(@name)
@data = @site.frontmatter_defaults.all(relative_path, type)
end
# rubocop: enable ParameterLists
# Returns source file path.
def path
File.join(*[@base, @dir, @name].compact)
end
# Obtain destination path.
#
# dest - The String path to the destination dir.
#
# Returns destination file path.
def destination(dest)
@site.in_dest_dir(*[dest, destination_rel_dir, @name].compact)
end
def destination_rel_dir
if @collection
File.dirname(url)
else
@dir
end
end
def modified_time
@modified_time ||= File.stat(path).mtime
end
# Returns last modification time for this file.
def mtime
modified_time.to_i
end
# Is source path modified?
#
# Returns true if modified since last write.
def modified?
self.class.mtimes[path] != mtime
end
# Whether to write the file to the filesystem
#
# Returns true unless the defaults for the destination path from
# _config.yml contain `published: false`.
def write?
defaults.fetch("published", true)
end
# Write the static file to the destination directory (if modified).
#
# dest - The String path to the destination dir.
#
# Returns false if the file was not modified since last time (no-op).
def write(dest)
dest_path = destination(dest)
return false if File.exist?(dest_path) && !modified?
self.class.mtimes[path] = mtime
FileUtils.mkdir_p(File.dirname(dest_path))
FileUtils.rm(dest_path) if File.exist?(dest_path)
copy_file(dest_path)
true
end
def to_liquid
@to_liquid ||= Drops::StaticFileDrop.new(self)
end
def basename
File.basename(name, extname)
end
def placeholders
{
:collection => @collection.label,
:path => relative_path[
@collection.relative_directory.size..relative_path.size],
:output_ext => "",
:name => "",
:title => "",
}
end
# Applies a similar URL-building technique as Jekyll::Document that takes
# the collection's URL template into account. The default URL template can
# be overriden in the collection's configuration in _config.yml.
def url
@url ||= if @collection.nil?
relative_path
else
::Jekyll::URL.new({
:template => @collection.url_template,
:placeholders => placeholders,
})
end.to_s.gsub(%r!/$!, "")
end
# Returns the type of the collection if present, nil otherwise.
def type
@type ||= @collection.nil? ? nil : @collection.label.to_sym
end
# Returns the front matter defaults defined for the file's URL and/or type
# as defined in _config.yml.
def defaults
@defaults ||= @site.frontmatter_defaults.all url, type
end
private
def copy_file(dest_path)
if @site.safe || Jekyll.env == "production"
FileUtils.cp(path, dest_path)
else
FileUtils.copy_entry(path, dest_path)
end
unless File.symlink?(dest_path)
File.utime(self.class.mtimes[path], self.class.mtimes[path], dest_path)
end
end
end
end