distil 0.13.6 → 0.14.0.b
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/assets/distil.js +9 -7
- data/bin/distil +36 -60
- data/distil.gemspec +17 -32
- data/distil.tmproj +46 -15
- data/lib/distil/browser.rb +30 -26
- data/lib/distil/configurable.rb +64 -153
- data/lib/distil/error-reporter.rb +22 -20
- data/lib/distil/file-vendor.rb +29 -0
- data/lib/distil/hash-additions.rb +45 -0
- data/lib/distil/javascript-code.rb +12 -0
- data/lib/distil/{task/validate-js-task.rb → javascript-file-validator.rb} +19 -23
- data/lib/distil/library.rb +243 -0
- data/lib/distil/product/cache-manifest-product.rb +21 -0
- data/lib/distil/product/css-product.rb +41 -23
- data/lib/distil/product/html-product.rb +20 -0
- data/lib/distil/product/javascript-product.rb +122 -111
- data/lib/distil/product.rb +90 -76
- data/lib/distil/project.rb +370 -104
- data/lib/distil/recursive-http-fetcher.rb +72 -0
- data/lib/distil/server.rb +43 -0
- data/lib/distil/source-file/css-file.rb +56 -3
- data/lib/distil/source-file/html-file.rb +5 -6
- data/lib/distil/source-file/javascript-file.rb +96 -8
- data/lib/distil/source-file/json-file.rb +2 -4
- data/lib/distil/source-file/yui-minifiable-file.rb +19 -0
- data/lib/distil/source-file.rb +50 -92
- data/lib/distil/subclass-tracker.rb +13 -0
- data/lib/distil.rb +21 -37
- metadata +40 -39
- data/assets/mime.types +0 -1240
- data/lib/distil/configurable/file-set.rb +0 -85
- data/lib/distil/configurable/interpolated.rb +0 -36
- data/lib/distil/configurable/output-path.rb +0 -25
- data/lib/distil/configurable/project-path.rb +0 -25
- data/lib/distil/product/concatenated.rb +0 -83
- data/lib/distil/product/debug.rb +0 -32
- data/lib/distil/product/javascript-base-product.rb +0 -35
- data/lib/distil/product/javascript-doc-product.rb +0 -61
- data/lib/distil/product/minified.rb +0 -41
- data/lib/distil/product/page-product.rb +0 -27
- data/lib/distil/product/pdoc-product.rb +0 -42
- data/lib/distil/project/distil-project.rb +0 -157
- data/lib/distil/project/external-project.rb +0 -58
- data/lib/distil/project/remote-project.rb +0 -43
- data/lib/distil/target.rb +0 -251
- data/lib/distil/task/css-dependency-task.rb +0 -64
- data/lib/distil/task/jsl-dependency-task.rb +0 -50
- data/lib/distil/task/nib-task.rb +0 -72
- data/lib/distil/task.rb +0 -50
- data/lib/jsdoc.conf +0 -18
- data/lib/test/HtmlTestReporter.js +0 -127
- data/lib/test/Test.js +0 -248
- data/lib/test/TestReporter.js +0 -79
- data/lib/test/TestRunner.js +0 -132
- data/lib/test/browser.rb +0 -97
- data/lib/test/scriptwrapper.html +0 -10
- data/lib/test/unittest.html +0 -127
data/lib/distil/project.rb
CHANGED
@@ -1,144 +1,410 @@
|
|
1
1
|
module Distil
|
2
2
|
|
3
|
-
|
3
|
+
BUILD_FILE= 'Buildfile'
|
4
|
+
DEFAULT_OUTPUT_FOLDER= 'build'
|
5
|
+
DEFAULT_LANGUAGE= 'en'
|
4
6
|
|
7
|
+
APPLICATION_TYPE= 'application'
|
8
|
+
FRAMEWORK_TYPE= 'framework'
|
9
|
+
|
10
|
+
class Project < Configurable
|
5
11
|
include ErrorReporter
|
12
|
+
include FileVendor
|
13
|
+
include JavascriptFileValidator
|
14
|
+
|
15
|
+
attr_reader :name, :path, :folder, :source_folder, :output_folder, :include_paths
|
16
|
+
attr_reader :assets, :asset_aliases
|
17
|
+
attr_reader :libraries_by_name, :libraries
|
18
|
+
attr_reader :languages, :project_type
|
19
|
+
attr_reader :source_files
|
20
|
+
attr_reader :global_export
|
21
|
+
attr_reader :additional_globals
|
22
|
+
attr_reader :subprojects
|
23
|
+
attr_reader :dependency_aliases
|
24
|
+
|
25
|
+
alias_config_key :project_type, :type
|
26
|
+
|
27
|
+
def self.find(dir=nil)
|
28
|
+
cwd= Dir.pwd
|
29
|
+
dir ||= Dir.pwd
|
30
|
+
while dir.length > 1
|
31
|
+
return from_file(File.join(dir, BUILD_FILE)) if File.exists?(File.join(dir, BUILD_FILE))
|
32
|
+
|
33
|
+
projects= Dir.glob(File.join(dir, "*.jsproj"))
|
34
|
+
return from_file(projects.first) if 1==projects.size
|
35
|
+
|
36
|
+
unless 0==projects.size
|
37
|
+
puts "More than one candidate for Project:"
|
38
|
+
projects.each { |e|
|
39
|
+
puts " #{path_relative_to_folder(e, cwd)}"
|
40
|
+
}
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
|
44
|
+
dir= File.dirname(dir)
|
45
|
+
end
|
46
|
+
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.from_file(file)
|
51
|
+
yaml= YAML::load_file(file)
|
52
|
+
if File.exists?("#{file}.local")
|
53
|
+
local_yaml= YAML::load_file("#{file}.local")
|
54
|
+
yaml.deep_merge!(local_yaml)
|
55
|
+
end
|
56
|
+
new(file, yaml)
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize(path, config={}, parent=nil)
|
60
|
+
@path= path
|
61
|
+
@folder= File.dirname(@path)
|
62
|
+
@source_folder= @folder
|
63
|
+
@output_folder= DEFAULT_OUTPUT_FOLDER
|
64
|
+
@include_paths= [@folder]
|
65
|
+
@include_files= []
|
66
|
+
@asset_aliases= {}
|
67
|
+
@dependency_aliases= {}
|
68
|
+
@assets= Set.new
|
69
|
+
@source_files= Set.new
|
70
|
+
@subprojects= []
|
71
|
+
@libraries= parent ? parent.libraries : []
|
72
|
+
@libraries_by_name= parent ? parent.libraries_by_name : {}
|
73
|
+
@languages= []
|
74
|
+
@additional_globals= []
|
75
|
+
@name= File.basename(@folder, ".*")
|
76
|
+
|
77
|
+
ignore_warnings= false
|
78
|
+
|
79
|
+
child_config= config.dup
|
80
|
+
child_config.delete("targets")
|
81
|
+
child_config.delete("require")
|
82
|
+
|
83
|
+
Dir.chdir(@folder) do
|
84
|
+
configure_with config do |c|
|
85
|
+
|
86
|
+
c.with :name do |name|
|
87
|
+
@name= name
|
88
|
+
end
|
89
|
+
|
90
|
+
c.with :output_folder do |output_folder|
|
91
|
+
@output_folder= output_folder
|
92
|
+
end
|
93
|
+
FileUtils.mkdir_p output_folder
|
94
|
+
|
95
|
+
c.with :source_folder do |source_folder|
|
96
|
+
@source_folder= source_folder
|
97
|
+
end
|
98
|
+
|
99
|
+
c.with :export do |export|
|
100
|
+
export=@name.as_identifier if true==export
|
101
|
+
@global_export= export
|
102
|
+
end
|
103
|
+
|
104
|
+
c.with_each :globals do |global|
|
105
|
+
@additional_globals << global
|
106
|
+
end
|
107
|
+
|
108
|
+
c.with_each :languages do |language|
|
109
|
+
@languages << language
|
110
|
+
end
|
111
|
+
|
112
|
+
c.with_each :require do |asset|
|
113
|
+
asset= Library.new(asset, self)
|
114
|
+
@libraries << asset
|
115
|
+
@libraries_by_name[asset.name]= asset
|
116
|
+
end
|
117
|
+
|
118
|
+
c.with_each :source do |file|
|
119
|
+
include_file(file)
|
120
|
+
end
|
121
|
+
|
122
|
+
c.with_each :targets do |target|
|
123
|
+
target_config= child_config.dup
|
124
|
+
target_config.deep_merge!(target)
|
125
|
+
@subprojects << Project.new(path, target_config, self)
|
126
|
+
end
|
127
|
+
|
128
|
+
end # configure_with
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
def validate_files
|
134
|
+
validate_javascript_files
|
135
|
+
end
|
6
136
|
|
7
|
-
|
8
|
-
|
137
|
+
def compute_source_files
|
138
|
+
return if @source_files_computed
|
139
|
+
@source_files_computed= true
|
140
|
+
|
141
|
+
inspected= Set.new
|
142
|
+
ordered_files= []
|
9
143
|
|
10
|
-
|
11
|
-
|
12
|
-
|
144
|
+
add_file= lambda { |f|
|
145
|
+
return unless include_files.include?(f)
|
146
|
+
return if inspected.include?(f)
|
147
|
+
inspected << f
|
148
|
+
|
149
|
+
if f.respond_to? :dependencies
|
150
|
+
f.dependencies.each { |d|
|
151
|
+
add_file.call d
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
ordered_files << f
|
156
|
+
}
|
157
|
+
|
158
|
+
include_files.each { |f| add_file.call(f) }
|
159
|
+
ordered_files.each { |f|
|
160
|
+
next if f.is_a?(SourceFile) && f.is_asset
|
161
|
+
|
162
|
+
used= false
|
163
|
+
products.each { |p|
|
164
|
+
used= true if p.include_file(f)
|
165
|
+
}
|
166
|
+
|
167
|
+
next if !used
|
168
|
+
|
169
|
+
if !f.is_a?(Library)
|
170
|
+
@source_files << f
|
171
|
+
@assets.merge(f.assets) if f.assets
|
172
|
+
end
|
173
|
+
}
|
174
|
+
end
|
13
175
|
|
14
|
-
def up_to_date
|
15
|
-
|
176
|
+
def up_to_date?
|
177
|
+
products.each { |product|
|
178
|
+
return false if !product.up_to_date?
|
179
|
+
}
|
180
|
+
return true
|
16
181
|
end
|
17
182
|
|
18
183
|
def build
|
19
|
-
|
184
|
+
subprojects.each { |subproject|
|
185
|
+
subproject.build
|
186
|
+
}
|
20
187
|
|
188
|
+
compute_source_files
|
189
|
+
return if up_to_date?
|
190
|
+
|
191
|
+
validate_files
|
192
|
+
build_assets
|
193
|
+
|
194
|
+
products.each { |product|
|
195
|
+
product.build
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
21
199
|
def clean
|
200
|
+
compute_source_files
|
201
|
+
products.each { |product|
|
202
|
+
product.clean
|
203
|
+
}
|
22
204
|
end
|
23
205
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
206
|
+
def inspect
|
207
|
+
"<#{self.class}:0x#{object_id.to_s(16)} name=#{name}>"
|
208
|
+
end
|
209
|
+
|
210
|
+
def output_path
|
211
|
+
@output_path ||= File.join(folder, output_folder)
|
212
|
+
end
|
213
|
+
|
214
|
+
def relative_path_for(thing)
|
215
|
+
Project.path_relative_to_folder(thing.is_a?(String) ? thing : thing.full_path, path)
|
216
|
+
end
|
217
|
+
|
218
|
+
def relative_output_path_for(thing)
|
219
|
+
return nil if !thing
|
220
|
+
# puts "relative_output_path_for: #{thing} #{output_path}"
|
221
|
+
Project.path_relative_to_folder(thing.is_a?(String) ? thing : thing.output_path, output_path)
|
222
|
+
end
|
223
|
+
|
224
|
+
def notice_text
|
28
225
|
begin
|
29
|
-
|
226
|
+
@notice_text ||= File.read(File.join(@folder, @notice)).strip
|
30
227
|
rescue
|
31
|
-
|
32
|
-
end
|
33
|
-
if $?.nil? || !$?.success?
|
34
|
-
raise ValidationError.new("The git version control tool is required to pull this repository: #{uri}")
|
228
|
+
@notice_text ||= ""
|
35
229
|
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def products
|
233
|
+
return @products unless @products.nil?
|
36
234
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
235
|
+
@products= []
|
236
|
+
langs= languages.empty? ? [nil] : languages
|
237
|
+
|
238
|
+
Product.subclasses.each { |klass|
|
239
|
+
langs.each { |lang|
|
240
|
+
klass.variants.each { |v|
|
241
|
+
@products << klass.new(self, lang, v)
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
@products
|
46
247
|
end
|
47
248
|
|
48
|
-
def
|
249
|
+
def symlink_assets
|
250
|
+
Dir.chdir(output_path) do
|
251
|
+
folders= []
|
49
252
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
config["path"]= uri.to_s
|
63
|
-
|
64
|
-
full_path= File.expand_path(config["path"])
|
65
|
-
|
66
|
-
if File.exist?(full_path) && File.file?(full_path)
|
67
|
-
config["path"]= File.dirname(full_path)
|
68
|
-
else
|
69
|
-
config["path"]= full_path
|
253
|
+
files= assets+source_files
|
254
|
+
files.each { |a|
|
255
|
+
next if (a.full_path).starts_with?(output_path)
|
256
|
+
|
257
|
+
path= relative_output_path_for(a)
|
258
|
+
|
259
|
+
parts= File.dirname(path).split(File::SEPARATOR)
|
260
|
+
if ('.'==parts[0])
|
261
|
+
product_path= File.join(output_folder, path)
|
262
|
+
FileUtils.rm product_path if File.exists? product_path
|
263
|
+
File.symlink path, product_path
|
264
|
+
next
|
70
265
|
end
|
71
|
-
end
|
72
|
-
end
|
73
266
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
else
|
81
|
-
raise ValidationError.new("External project has neither name, path nor repository")
|
82
|
-
end
|
83
|
-
end
|
267
|
+
folders << parts[0] if !folders.include?(parts[0])
|
268
|
+
}
|
269
|
+
|
270
|
+
folders.each { |f|
|
271
|
+
target= f
|
272
|
+
source= relative_output_path_for(File.join(source_folder, f))
|
84
273
|
|
85
|
-
|
86
|
-
|
274
|
+
FileUtils.rm target if File.symlink?(target)
|
275
|
+
next if File.directory?(target)
|
276
|
+
File.symlink source, target
|
277
|
+
}
|
87
278
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
279
|
+
end
|
280
|
+
|
281
|
+
def copy_assets
|
282
|
+
assets.each { |a|
|
283
|
+
a.copy_to(output_folder, source_folder)
|
284
|
+
}
|
285
|
+
end
|
286
|
+
|
287
|
+
def build_assets
|
288
|
+
symlink_assets
|
289
|
+
# if (RELEASE_MODE==mode)
|
290
|
+
# copy_assets
|
291
|
+
# else
|
292
|
+
# symlink_assets
|
293
|
+
# end
|
294
|
+
end
|
295
|
+
|
296
|
+
def add_alias_for_asset(alias_name, asset)
|
297
|
+
if asset_aliases.include?(alias_name)
|
298
|
+
error "Attempt to register asset with the same alias as another asset: #{alias_name}"
|
299
|
+
return
|
93
300
|
end
|
301
|
+
asset_aliases[asset]= alias_name
|
302
|
+
end
|
303
|
+
|
304
|
+
def include_files
|
305
|
+
@include_files
|
306
|
+
end
|
307
|
+
|
308
|
+
def include_file(file)
|
309
|
+
return if file.nil?
|
94
310
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
ErrorReporter.error "No path for project: #{config["name"]}"
|
100
|
-
return nil
|
311
|
+
asset= @libraries_by_name[file]
|
312
|
+
if (asset)
|
313
|
+
@include_files << asset unless @include_files.include?(asset)
|
314
|
+
return
|
101
315
|
end
|
102
316
|
|
103
|
-
|
104
|
-
|
105
|
-
|
317
|
+
matches= glob(file)
|
318
|
+
matches= glob(File.join(source_folder, file)) if matches.empty?
|
319
|
+
|
320
|
+
if (matches.empty?)
|
321
|
+
error("No matching files found for: #{file}")
|
322
|
+
return
|
106
323
|
end
|
107
324
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
when exist?(path, "#{basename}.jsproj")
|
112
|
-
project_file= File.join(path, "#{basename}.jsproj")
|
113
|
-
project_info= YAML.load_file(project_file)
|
114
|
-
project_info.merge!(config)
|
115
|
-
project_info["path"]= path
|
116
|
-
project= ExternalProject.new(project_info, parent)
|
117
|
-
if parent
|
118
|
-
project.build_command ||= "distil --mode=#{parent.mode} --force=#{parent.force}"
|
325
|
+
matches.each { |m|
|
326
|
+
if File.directory?(m)
|
327
|
+
include_file(File.join(m, "**/*"))
|
119
328
|
else
|
120
|
-
|
329
|
+
f= file_from_path(m)
|
330
|
+
unless @include_files.include?(f)
|
331
|
+
@include_files << f
|
332
|
+
# determine language
|
333
|
+
f.language= languages.find { |l| File.fnmatch?("**/#{l}/**", f.full_path) }
|
334
|
+
end
|
121
335
|
end
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
336
|
+
}
|
337
|
+
end
|
338
|
+
|
339
|
+
def glob(path)
|
340
|
+
return path if File.exists?(path)
|
341
|
+
|
342
|
+
files= []
|
343
|
+
|
344
|
+
parts= path.split(File::SEPARATOR)
|
345
|
+
asset_name= parts[0]
|
346
|
+
file_path= File.join(parts.slice(1..-1))
|
347
|
+
|
348
|
+
if (@libraries_by_name.include?(asset_name))
|
349
|
+
asset= @libraries_by_name[asset_name]
|
350
|
+
return Dir.glob(File.join(asset.output_path, file_path))
|
133
351
|
end
|
134
|
-
return project
|
135
352
|
|
353
|
+
files.concat(Dir.glob(path));
|
354
|
+
|
355
|
+
include_paths.each { |i|
|
356
|
+
files.concat(Dir.glob(File.join(i, path)))
|
357
|
+
}
|
358
|
+
return files
|
359
|
+
end
|
360
|
+
|
361
|
+
def add_alias_for_file(alias_name, file)
|
362
|
+
@dependency_aliases[alias_name]= file
|
363
|
+
end
|
364
|
+
|
365
|
+
def find_file(path, content_type=nil, mode=nil)
|
366
|
+
return path if File.exists?(path)
|
367
|
+
|
368
|
+
include_paths.each { |i|
|
369
|
+
f= File.join(i, path)
|
370
|
+
return f if File.exists?(f)
|
371
|
+
}
|
372
|
+
|
373
|
+
# Check remote assets
|
374
|
+
parts= path.split(File::SEPARATOR)
|
375
|
+
asset_name= parts[0]
|
376
|
+
file_path= File.join(parts.slice(1..-1))
|
377
|
+
|
378
|
+
return nil unless @libraries_by_name.include?(asset_name)
|
379
|
+
asset= @libraries_by_name[asset_name]
|
380
|
+
|
381
|
+
return asset.file_for(content_type, nil, mode) if 1==parts.length
|
382
|
+
|
383
|
+
f= File.join(asset.output_path, file_path)
|
384
|
+
return f if File.exists?(f)
|
385
|
+
|
386
|
+
nil
|
387
|
+
end
|
388
|
+
|
389
|
+
def self.path_relative_to_folder(path, folder)
|
390
|
+
path= File.expand_path(path)
|
391
|
+
outputFolder= File.expand_path(folder).to_s
|
392
|
+
|
393
|
+
# Remove leading slash and split into parts
|
394
|
+
file_parts= path.slice(1..-1).split('/');
|
395
|
+
output_parts= outputFolder.slice(1..-1).split('/');
|
396
|
+
|
397
|
+
common_prefix_length= 0
|
398
|
+
|
399
|
+
file_parts.each_index { |i|
|
400
|
+
common_prefix_length= i
|
401
|
+
break if file_parts[i]!=output_parts[i]
|
402
|
+
}
|
403
|
+
|
404
|
+
return '../'*(output_parts.length-common_prefix_length) + file_parts[common_prefix_length..-1].join('/')
|
136
405
|
end
|
137
406
|
|
138
407
|
end
|
139
408
|
|
409
|
+
|
140
410
|
end
|
141
|
-
|
142
|
-
require 'distil/project/remote-project'
|
143
|
-
require 'distil/project/external-project'
|
144
|
-
require 'distil/project/distil-project'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Distil
|
2
|
+
|
3
|
+
class RecursiveHTTPFetcher
|
4
|
+
attr_accessor :quiet
|
5
|
+
|
6
|
+
def initialize(urls_to_fetch, level = 1, cwd = ".")
|
7
|
+
@level = level
|
8
|
+
@cwd = cwd
|
9
|
+
@urls_to_fetch = RUBY_VERSION >= '1.9' ? urls_to_fetch.to_s.lines : urls_to_fetch.to_s.to_a
|
10
|
+
@quiet = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def ls
|
14
|
+
@urls_to_fetch.collect do |url|
|
15
|
+
if url =~ /^svn(\+ssh)?:\/\/.*/ || url =~ /\/svn\//
|
16
|
+
`svn ls #{url}`.split("\n").map {|entry| "/#{entry}"} rescue nil
|
17
|
+
else
|
18
|
+
open(url) do |stream|
|
19
|
+
links("", stream.read)
|
20
|
+
end rescue nil
|
21
|
+
end
|
22
|
+
end.flatten
|
23
|
+
end
|
24
|
+
|
25
|
+
def push_d(dir)
|
26
|
+
@cwd = File.join(@cwd, dir)
|
27
|
+
FileUtils.mkdir_p(@cwd)
|
28
|
+
end
|
29
|
+
|
30
|
+
def pop_d
|
31
|
+
@cwd = File.dirname(@cwd)
|
32
|
+
end
|
33
|
+
|
34
|
+
def links(base_url, contents)
|
35
|
+
links = []
|
36
|
+
contents.scan(/href\s*=\s*\"*[^\">]*/i) do |link|
|
37
|
+
link = link.sub(/href="/i, "")
|
38
|
+
next if link =~ /svnindex.xsl$/
|
39
|
+
next if link =~ /^(\w*:|)\/\// || link =~ /^\./
|
40
|
+
links << File.join(base_url, link)
|
41
|
+
end
|
42
|
+
links
|
43
|
+
end
|
44
|
+
|
45
|
+
def download(link)
|
46
|
+
puts "+ #{File.join(@cwd, File.basename(link))}" unless @quiet
|
47
|
+
open(link) do |stream|
|
48
|
+
File.open(File.join(@cwd, File.basename(link)), "wb") do |file|
|
49
|
+
file.write(stream.read)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def fetch(links = @urls_to_fetch)
|
55
|
+
links.each do |l|
|
56
|
+
(l =~ /\/$/ || links == @urls_to_fetch) ? fetch_dir(l) : download(l)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def fetch_dir(url)
|
61
|
+
@level += 1
|
62
|
+
push_d(File.basename(url)) if @level > 0
|
63
|
+
open(url) do |stream|
|
64
|
+
contents = stream.read
|
65
|
+
fetch(links(url, contents))
|
66
|
+
end
|
67
|
+
pop_d if @level > 0
|
68
|
+
@level -= 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Distil
|
2
|
+
|
3
|
+
def self.start_server(project, options)
|
4
|
+
require 'webrick'
|
5
|
+
require 'directory_watcher'
|
6
|
+
|
7
|
+
port= options['server_port'] || 8888;
|
8
|
+
path= options['url']
|
9
|
+
config= {
|
10
|
+
:Port => port
|
11
|
+
}
|
12
|
+
|
13
|
+
server= WEBrick::HTTPServer.new(config)
|
14
|
+
server.mount(path || '/', WEBrick::HTTPServlet::FileHandler, project.output_folder)
|
15
|
+
|
16
|
+
['INT', 'TERM'].each { |signal|
|
17
|
+
trap(signal){ server.shutdown }
|
18
|
+
}
|
19
|
+
|
20
|
+
puts "watching #{project.folder}"
|
21
|
+
dw = DirectoryWatcher.new(project.folder, {
|
22
|
+
:glob=>"**/*",
|
23
|
+
:pre_load => true,
|
24
|
+
:interval => 1
|
25
|
+
})
|
26
|
+
dw.add_observer { |*args|
|
27
|
+
args.each { |event|
|
28
|
+
puts event
|
29
|
+
if :modified==event.type
|
30
|
+
puts event.path
|
31
|
+
end
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
dw.start
|
36
|
+
gets
|
37
|
+
# b= Browser.new
|
38
|
+
# b.open("http://localhost:#{port}/#{path}")
|
39
|
+
# server.start
|
40
|
+
dw.stop
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -1,14 +1,67 @@
|
|
1
1
|
module Distil
|
2
2
|
|
3
|
+
CSS_IMPORT_REGEX = /@import\s+url\("?(.*\.css)"?\)/
|
4
|
+
CSS_IMAGE_URL_REGEX= /url\("?(.*\.(jpg|png|gif))"?\)/
|
5
|
+
|
3
6
|
class CssFile < SourceFile
|
4
|
-
|
7
|
+
include YuiMinifiableFile
|
8
|
+
|
5
9
|
extension "css"
|
6
10
|
content_type "css"
|
7
11
|
|
8
|
-
def
|
9
|
-
|
12
|
+
def content
|
13
|
+
return @content unless @content.nil?
|
14
|
+
@content= File.read(full_path)
|
15
|
+
# Replace all ' (single quotes) with " (double quotes)
|
16
|
+
@content.gsub!(/\'/,'"')
|
17
|
+
# Force a newline after a rule terminating ; (semi-colon)
|
18
|
+
@content.gsub!(/;(\n|\r)*/, ";\n")
|
19
|
+
@content
|
10
20
|
end
|
11
21
|
|
22
|
+
def rewrite_content_relative_to_path(path)
|
23
|
+
content.gsub(CSS_IMAGE_URL_REGEX) { |match|
|
24
|
+
image_file= File.join(dirname, $1)
|
25
|
+
|
26
|
+
if (!File.exists?(image_file))
|
27
|
+
match
|
28
|
+
else
|
29
|
+
asset= project.file_from_path(image_file)
|
30
|
+
"url(\"#{asset.relative_path}\")"
|
31
|
+
end
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def dependencies
|
36
|
+
@dependencies unless @dependencies.nil?
|
37
|
+
|
38
|
+
line_num=0
|
39
|
+
content.each_line { |line|
|
40
|
+
line_num+=1
|
41
|
+
|
42
|
+
line.scan(CSS_IMPORT_REGEX) { |match|
|
43
|
+
css_file= File.join(dirname, $1)
|
44
|
+
|
45
|
+
if (!File.exists?(css_file))
|
46
|
+
error "Imported CSS file not found: #{$1}", line_num
|
47
|
+
else
|
48
|
+
add_dependency(project.file_from_path(css_file))
|
49
|
+
end
|
50
|
+
}
|
51
|
+
|
52
|
+
line.scan(CSS_IMAGE_URL_REGEX) { |match|
|
53
|
+
image_file= File.join(dirname, $1)
|
54
|
+
|
55
|
+
if (!File.exists?(image_file))
|
56
|
+
warning "Resource not found: #{$1}", line_num
|
57
|
+
else
|
58
|
+
asset= project.file_from_path(image_file)
|
59
|
+
add_asset(asset)
|
60
|
+
end
|
61
|
+
}
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
12
65
|
end
|
13
66
|
|
14
67
|
end
|