distil 0.10.4 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/assets/distil.js +359 -0
- data/bin/distil +33 -10
- data/distil.gemspec +35 -24
- data/lib/distil/configurable/file-set.rb +86 -0
- data/lib/distil/configurable/interpolated.rb +36 -0
- data/lib/distil/configurable/output-path.rb +25 -0
- data/lib/distil/configurable/project-path.rb +25 -0
- data/lib/distil/configurable.rb +164 -0
- data/lib/distil/error-reporter.rb +63 -0
- data/lib/distil/product/concatenated.rb +85 -0
- data/lib/distil/product/css-product.rb +37 -0
- data/lib/distil/product/debug.rb +34 -0
- data/lib/distil/product/javascript-base-product.rb +35 -0
- data/lib/distil/product/javascript-doc-product.rb +61 -0
- data/lib/distil/product/javascript-product.rb +131 -0
- data/lib/distil/product/minified.rb +32 -0
- data/lib/distil/product.rb +97 -0
- data/lib/distil/project/distil-project.rb +99 -0
- data/lib/distil/project/external-project.rb +53 -0
- data/lib/distil/project.rb +78 -0
- data/lib/distil/source-file/css-file.rb +14 -0
- data/lib/distil/source-file/html-file.rb +14 -0
- data/lib/distil/source-file/javascript-file.rb +17 -0
- data/lib/distil/source-file/json-file.rb +16 -0
- data/lib/distil/source-file.rb +172 -0
- data/lib/distil/target.rb +235 -0
- data/lib/distil/task/css-dependency-task.rb +64 -0
- data/lib/distil/task/jsl-dependency-task.rb +49 -0
- data/lib/distil/task/nib-task.rb +72 -0
- data/lib/distil/task/validate-js-task.rb +75 -0
- data/lib/distil/task.rb +50 -0
- data/lib/distil.rb +72 -0
- data/lib/jsl.conf +4 -0
- data/vendor/jsl-0.3.0/src/Makefile.ref +16 -6
- data/vendor/jsl-0.3.0/src/config.mk +32 -2
- data/vendor/jsl-0.3.0/src/fdlibm/Makefile.ref +1 -2
- data/vendor/jsl-0.3.0/src/jsl.c +124 -13
- data/vendor/jsl-0.3.0/src/rules.mk +2 -1
- metadata +49 -28
- data/lib/bootstrap-template.js +0 -58
- data/lib/configurable.rb +0 -161
- data/lib/file-set.rb +0 -49
- data/lib/file-types/css-file.rb +0 -12
- data/lib/file-types/html-file.rb +0 -11
- data/lib/file-types/javascript-file.rb +0 -24
- data/lib/file-types/json-file.rb +0 -17
- data/lib/filter.rb +0 -41
- data/lib/filters/css-filter.rb +0 -58
- data/lib/filters/file-reference-filter.rb +0 -30
- data/lib/filters/jsl-dependency-filter.rb +0 -44
- data/lib/project.rb +0 -174
- data/lib/source-file.rb +0 -197
- data/lib/target.rb +0 -102
- data/lib/task.rb +0 -212
- data/lib/tasks/copy-task.rb +0 -17
- data/lib/tasks/css-task.rb +0 -12
- data/lib/tasks/javascript-task.rb +0 -206
- data/lib/tasks/multiple-output-task.rb +0 -140
- data/lib/tasks/output-task.rb +0 -76
- data/lib/tasks/single-output-task.rb +0 -104
- data/lib/tasks/test-task.rb +0 -280
@@ -0,0 +1,97 @@
|
|
1
|
+
module Distil
|
2
|
+
|
3
|
+
class Product < Configurable
|
4
|
+
option :concatenated_name, OutputPath, "$(name)-uncompressed.$(extension)", :aliases=>['concatenated']
|
5
|
+
option :debug_name, OutputPath, "$(name)-debug.$(extension)", :aliases=>['debug']
|
6
|
+
option :minified_name, OutputPath, "$(name).$(extension)", :aliases=>['minified']
|
7
|
+
option :compressed_name, OutputPath, "$(name).$(extension).gz", :aliases=>['compressed']
|
8
|
+
|
9
|
+
option :force, false
|
10
|
+
|
11
|
+
attr_accessor :assets, :target, :join_string
|
12
|
+
class_attr :extension
|
13
|
+
|
14
|
+
def initialize(settings, target)
|
15
|
+
@target= target
|
16
|
+
@files= []
|
17
|
+
@assets= Set.new
|
18
|
+
super(settings, target)
|
19
|
+
end
|
20
|
+
|
21
|
+
def can_embed_file?(file)
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def handles_file?(file)
|
26
|
+
[extension].include?(file.extension)
|
27
|
+
end
|
28
|
+
|
29
|
+
def files
|
30
|
+
@files
|
31
|
+
end
|
32
|
+
|
33
|
+
def files=(fileset)
|
34
|
+
fileset.each { |f|
|
35
|
+
next if !handles_file?(f)
|
36
|
+
@files << f
|
37
|
+
@assets.merge(f.assets)
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def up_to_date
|
42
|
+
return @up_to_date if !@up_to_date.nil?
|
43
|
+
return false if force
|
44
|
+
|
45
|
+
return @up_to_date=false if !File.exists?(filename)
|
46
|
+
|
47
|
+
output_modified= File.stat(filename).mtime
|
48
|
+
max_asset_modified= File.stat(target.project.project_file).mtime
|
49
|
+
|
50
|
+
assets.each { |f|
|
51
|
+
max_asset_modified= f.last_modified if f.last_modified > max_asset_modified
|
52
|
+
}
|
53
|
+
|
54
|
+
return @up_to_date=false if (output_modified < max_asset_modified)
|
55
|
+
|
56
|
+
external_files.each { |f|
|
57
|
+
next if !File.exist?(f)
|
58
|
+
last_modified= File.stat(f).mtime
|
59
|
+
max_asset_modified= last_modified if last_modified > max_asset_modified
|
60
|
+
}
|
61
|
+
|
62
|
+
return @up_to_date=false if (output_modified < max_asset_modified)
|
63
|
+
|
64
|
+
@up_to_date= true
|
65
|
+
end
|
66
|
+
|
67
|
+
def filename
|
68
|
+
raise NotImplementedError.new("This product does not implement the filename method.")
|
69
|
+
end
|
70
|
+
|
71
|
+
def write_output
|
72
|
+
raise NotImplementedError.new("No write_output method has been defined for this product.")
|
73
|
+
end
|
74
|
+
|
75
|
+
def relative_path(file)
|
76
|
+
file=SourceFile.from_path(file) if file.is_a?(String)
|
77
|
+
|
78
|
+
file_path= file.full_path
|
79
|
+
output_folder= target.project.output_folder
|
80
|
+
source_folder= target.project.source_folder
|
81
|
+
|
82
|
+
path=file.relative_to_folder(source_folder) if 0==file_path.index(source_folder)
|
83
|
+
path=file.relative_to_folder(output_folder) if 0==file_path.index(output_folder)
|
84
|
+
path
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
require 'distil/product/concatenated'
|
92
|
+
require 'distil/product/debug'
|
93
|
+
require 'distil/product/minified'
|
94
|
+
require 'distil/product/css-product'
|
95
|
+
require 'distil/product/javascript-base-product'
|
96
|
+
require 'distil/product/javascript-product'
|
97
|
+
require 'distil/product/javascript-doc-product'
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Distil
|
2
|
+
|
3
|
+
class DistilProject < Project
|
4
|
+
|
5
|
+
attr_reader :project_file
|
6
|
+
|
7
|
+
option :ignore_warnings, false
|
8
|
+
|
9
|
+
option :external_projects, [], :aliases=>['external']
|
10
|
+
option :distileries, Array, :aliases=>['distilleries', 'distilery', 'distillery']
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(project_file, settings={}, parent=nil)
|
14
|
+
@project_file= File.expand_path(project_file)
|
15
|
+
@projects_by_name={}
|
16
|
+
|
17
|
+
project_info= YAML.load_file(@project_file)
|
18
|
+
project_info.merge!(settings)
|
19
|
+
project_info["path"]= File.dirname(@project_file)
|
20
|
+
|
21
|
+
begin
|
22
|
+
super(project_info, parent)
|
23
|
+
rescue ValidationError
|
24
|
+
$stderr.print "#{APP_NAME}: #{project_file}: #{$!}\n"
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
load_external_projects
|
29
|
+
end
|
30
|
+
|
31
|
+
def targets
|
32
|
+
@targets if @targets
|
33
|
+
|
34
|
+
@targets= []
|
35
|
+
target_list= @extras['targets']
|
36
|
+
|
37
|
+
if !target_list
|
38
|
+
@targets << Target.new(@extras.clone, self)
|
39
|
+
return @targets
|
40
|
+
end
|
41
|
+
|
42
|
+
@targets= target_list.map { |target|
|
43
|
+
Target.new(target, self)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_external_projects
|
48
|
+
return if !external_projects
|
49
|
+
|
50
|
+
self.external_projects= external_projects.map { |config|
|
51
|
+
project= Project.from_config(config, self)
|
52
|
+
next if !project
|
53
|
+
@projects_by_name[project.name]= project
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def external_project_with_name(name)
|
58
|
+
@projects_by_name[name]
|
59
|
+
end
|
60
|
+
|
61
|
+
def build
|
62
|
+
FileUtils.mkdir_p(output_folder)
|
63
|
+
load_distileries
|
64
|
+
build_external_projects
|
65
|
+
build_targets
|
66
|
+
end
|
67
|
+
|
68
|
+
def load_distileries
|
69
|
+
return if distileries.nil?
|
70
|
+
|
71
|
+
distileries.each { |d|
|
72
|
+
if (File.exists?(d))
|
73
|
+
require d
|
74
|
+
next
|
75
|
+
end
|
76
|
+
path= Gem.required_location(d, 'distilery.rb')
|
77
|
+
if (path.nil?)
|
78
|
+
puts "Missing distilery: #{d}"
|
79
|
+
end
|
80
|
+
next if path.nil?
|
81
|
+
require path
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_external_projects
|
86
|
+
external_projects.each { |project|
|
87
|
+
project.build
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def build_targets
|
92
|
+
targets.each { |target|
|
93
|
+
target.build
|
94
|
+
}
|
95
|
+
report
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Distil
|
2
|
+
|
3
|
+
class ExternalProject < Project
|
4
|
+
|
5
|
+
option :name, String
|
6
|
+
option :repository
|
7
|
+
option :build_command, String, :aliases=>['build']
|
8
|
+
option :linkage, WEAK_LINKAGE, :valid_values=> [WEAK_LINKAGE, STRONG_LINKAGE, LAZY_LINKAGE]
|
9
|
+
|
10
|
+
option :import_name, OutputPath, "$(name)-debug.$(extension)", :aliases=>['import']
|
11
|
+
option :concatenated_name, OutputPath, "$(name)-uncompressed.$(extension)", :aliases=>['concatenated']
|
12
|
+
option :debug_name, OutputPath, "$(name)-debug.$(extension)", :aliases=>['debug']
|
13
|
+
option :minified_name, OutputPath, "$(name).$(extension)", :aliases=>['minified']
|
14
|
+
option :compressed_name, OutputPath, "$(name).$(extension).gz", :aliases=>['compressed']
|
15
|
+
|
16
|
+
def initialize(config, parent=nil)
|
17
|
+
if !config.has_key?("source_folder")
|
18
|
+
config["source_folder"]= "build/$(mode)"
|
19
|
+
end
|
20
|
+
super(config, parent)
|
21
|
+
|
22
|
+
@options.output_folder= File.join(parent.output_folder, name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def product_name(product_type, extension)
|
26
|
+
info= Struct.new(:extension).new(extension)
|
27
|
+
name= self.send("#{product_type.to_s}_name")
|
28
|
+
Interpolated.value_of(name, info)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build
|
32
|
+
wd= Dir.getwd
|
33
|
+
Dir.chdir(path)
|
34
|
+
system build_command
|
35
|
+
Dir.chdir(wd)
|
36
|
+
|
37
|
+
# external projects aren't included in the output when weak linked,
|
38
|
+
# they are just expected to be there, somehow. Like magic.
|
39
|
+
return if WEAK_LINKAGE==linkage
|
40
|
+
|
41
|
+
FileUtils.rm_r(output_folder) if File.directory?(output_folder)
|
42
|
+
FileUtils.unlink(output_folder) if File.symlink?(output_folder)
|
43
|
+
|
44
|
+
if DEBUG_MODE==mode
|
45
|
+
FileUtils.symlink(File.expand_path(source_folder), output_folder)
|
46
|
+
else
|
47
|
+
FileUtils.cp_r(File.expand_path(source_folder), output_folder)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Distil
|
2
|
+
|
3
|
+
class Project < Configurable
|
4
|
+
|
5
|
+
include ErrorReporter
|
6
|
+
|
7
|
+
option :output_folder, ProjectPath, "build/$(mode)", :aliases=>['output']
|
8
|
+
option :source_folder, ProjectPath, ""
|
9
|
+
|
10
|
+
option :path, String
|
11
|
+
option :mode, DEBUG_MODE, :valid_values=>[DEBUG_MODE, RELEASE_MODE]
|
12
|
+
option :force
|
13
|
+
|
14
|
+
def build
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_config(config, parent=nil)
|
18
|
+
|
19
|
+
if config.is_a?(String)
|
20
|
+
string= config
|
21
|
+
config= { "name" => File.basename(config, ".*") }
|
22
|
+
full_path= File.expand_path(string)
|
23
|
+
if File.exist?(full_path) && File.file?(full_path)
|
24
|
+
config["path"]= File.dirname(full_path)
|
25
|
+
else
|
26
|
+
config["path"]= full_path
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
config["mode"]||= parent.mode if parent
|
31
|
+
|
32
|
+
path= config["path"]
|
33
|
+
if !path
|
34
|
+
ErrorReporter.error "No path for project: #{config["name"]}"
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
|
38
|
+
if !File.directory?(path)
|
39
|
+
ErrorReporter.error "Path is not valid for project: #{config["name"]}"
|
40
|
+
return nil
|
41
|
+
end
|
42
|
+
|
43
|
+
basename= File.basename(path)
|
44
|
+
|
45
|
+
case
|
46
|
+
when exist?(path, "#{basename}.jsproj")
|
47
|
+
project_file= File.join(path, "#{basename}.jsproj")
|
48
|
+
project_info= YAML.load_file(project_file)
|
49
|
+
project_info.merge!(config)
|
50
|
+
project_info["path"]= path
|
51
|
+
project= ExternalProject.new(project_info, parent)
|
52
|
+
if parent
|
53
|
+
project.build_command ||= "distil --mode=#{parent.mode} --force=#{parent.force}"
|
54
|
+
else
|
55
|
+
project.build_command ||= "distil"
|
56
|
+
end
|
57
|
+
when exist?(path, "Makefile") || exist?(path, "makefile")
|
58
|
+
project= ExternalProject.new(config, parent)
|
59
|
+
project.build_command ||= "make"
|
60
|
+
when exist?(path, "Rakefile") || exist?(path, "rakefile")
|
61
|
+
project= ExternalProject.new(config, parent)
|
62
|
+
project.build_command ||= "rake"
|
63
|
+
when exist?(path, "Jakefile") || exist?(path, "jakefile")
|
64
|
+
project= ExternalProject.new(config, parent)
|
65
|
+
project.build_command ||= "jake"
|
66
|
+
else
|
67
|
+
ErrorReporter.error "Could not determine type for project: #{config["name"]}"
|
68
|
+
end
|
69
|
+
return project
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
require 'distil/project/external-project'
|
78
|
+
require 'distil/project/distil-project'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Distil
|
2
|
+
|
3
|
+
class JavascriptFile < SourceFile
|
4
|
+
extension 'js'
|
5
|
+
content_type 'js'
|
6
|
+
|
7
|
+
def can_embed_as_content(file)
|
8
|
+
[".css", ".html", ".json"].include?(file.extension)
|
9
|
+
end
|
10
|
+
|
11
|
+
def escape_embeded_content(content)
|
12
|
+
content.gsub("\\", "\\\\").gsub("\n", "\\n").gsub("\"", "\\\"").gsub("'", "\\\\'")
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
$compressor = File.expand_path("#{VENDOR_DIR}/yuicompressor-2.4.2.jar")
|
4
|
+
|
5
|
+
module Distil
|
6
|
+
|
7
|
+
class SourceFile
|
8
|
+
attr_accessor :parent_folder, :full_path
|
9
|
+
class_attr :extension
|
10
|
+
class_attr :content_type
|
11
|
+
|
12
|
+
include ErrorReporter
|
13
|
+
|
14
|
+
def initialize(filepath)
|
15
|
+
@full_path= File.expand_path(filepath)
|
16
|
+
|
17
|
+
@parent_folder= File.dirname(@full_path)
|
18
|
+
@dependencies= []
|
19
|
+
@assets= []
|
20
|
+
|
21
|
+
@@file_cache[@full_path]= self
|
22
|
+
end
|
23
|
+
|
24
|
+
def can_embed_as_content(file)
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def warning(message, line=nil)
|
29
|
+
super(message, self, line)
|
30
|
+
end
|
31
|
+
|
32
|
+
def error(message, line=nil)
|
33
|
+
super(message, self, line)
|
34
|
+
end
|
35
|
+
|
36
|
+
@@file_types= []
|
37
|
+
def self.inherited(subclass)
|
38
|
+
@@file_types << subclass
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.file_types
|
42
|
+
@@file_types
|
43
|
+
end
|
44
|
+
|
45
|
+
@@file_cache= Hash.new
|
46
|
+
def self.from_path(filepath)
|
47
|
+
full_path= File.expand_path(filepath)
|
48
|
+
file= @@file_cache[full_path]
|
49
|
+
return file if file
|
50
|
+
|
51
|
+
extension= File.extname(filepath)[1..-1]
|
52
|
+
|
53
|
+
@@file_types.each { |handler|
|
54
|
+
next if (handler.extension != extension)
|
55
|
+
|
56
|
+
return handler.new(filepath)
|
57
|
+
}
|
58
|
+
|
59
|
+
return SourceFile.new(filepath)
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
@full_path
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_str
|
67
|
+
@full_path
|
68
|
+
end
|
69
|
+
|
70
|
+
def basename(suffix=extension)
|
71
|
+
File.basename(@full_path, suffix)
|
72
|
+
end
|
73
|
+
|
74
|
+
def file_path
|
75
|
+
@file_path
|
76
|
+
end
|
77
|
+
|
78
|
+
def file_path=(path)
|
79
|
+
@file_path=path
|
80
|
+
end
|
81
|
+
|
82
|
+
def load_content
|
83
|
+
File.read(@full_path)
|
84
|
+
end
|
85
|
+
|
86
|
+
def escape_embeded_content(content)
|
87
|
+
content
|
88
|
+
end
|
89
|
+
|
90
|
+
def content
|
91
|
+
@content ||= load_content
|
92
|
+
end
|
93
|
+
|
94
|
+
def last_modified
|
95
|
+
@last_modified ||= File.stat(@full_path).mtime
|
96
|
+
end
|
97
|
+
|
98
|
+
def minified_content(source)
|
99
|
+
# Run the Y!UI Compressor
|
100
|
+
return source if !content_type
|
101
|
+
buffer= ""
|
102
|
+
|
103
|
+
IO.popen("java -jar #{$compressor} --type #{content_type}", "r+") { |pipe|
|
104
|
+
pipe.puts(source)
|
105
|
+
pipe.close_write
|
106
|
+
buffer= pipe.read
|
107
|
+
}
|
108
|
+
|
109
|
+
buffer
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.path_relative_to_folder(path, folder)
|
113
|
+
outputFolder= File.expand_path(folder).to_s
|
114
|
+
|
115
|
+
# Remove leading slash and split into parts
|
116
|
+
file_parts= path.slice(1..-1).split('/');
|
117
|
+
output_parts= outputFolder.slice(1..-1).split('/');
|
118
|
+
|
119
|
+
common_prefix_length= 0
|
120
|
+
|
121
|
+
file_parts.each_index { |i|
|
122
|
+
common_prefix_length= i
|
123
|
+
break if file_parts[i]!=output_parts[i]
|
124
|
+
}
|
125
|
+
|
126
|
+
return '../'*(output_parts.length-common_prefix_length) + file_parts[common_prefix_length..-1].join('/')
|
127
|
+
end
|
128
|
+
|
129
|
+
def relative_to_folder(output_folder)
|
130
|
+
self.class.path_relative_to_folder(@full_path, output_folder)
|
131
|
+
end
|
132
|
+
|
133
|
+
def relative_to_file(source_file)
|
134
|
+
folder= File.dirname(File.expand_path(source_file))
|
135
|
+
self.relative_to_folder(folder)
|
136
|
+
end
|
137
|
+
|
138
|
+
def dependencies
|
139
|
+
content
|
140
|
+
@dependencies
|
141
|
+
end
|
142
|
+
|
143
|
+
def add_dependency(file)
|
144
|
+
return if @dependencies.include?(file)
|
145
|
+
@dependencies << file
|
146
|
+
end
|
147
|
+
|
148
|
+
def assets
|
149
|
+
content
|
150
|
+
@assets
|
151
|
+
end
|
152
|
+
|
153
|
+
def add_asset(file)
|
154
|
+
@assets << file
|
155
|
+
end
|
156
|
+
|
157
|
+
def copy_to(folder, prefix)
|
158
|
+
file_path= self.file_path || relative_to_folder(prefix||"")
|
159
|
+
final_target_folder= File.join(folder, File.dirname(file_path))
|
160
|
+
FileUtils.mkdir_p final_target_folder
|
161
|
+
FileUtils.cp self.full_path, final_target_folder
|
162
|
+
File.join(final_target_folder, File.basename(file_path))
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
# load all the other file types
|
170
|
+
Dir.glob("#{LIB_DIR}/distil/source-file/*-file.rb") { |file|
|
171
|
+
require file
|
172
|
+
}
|