sitefuel 0.0.0a
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/README +86 -0
- data/RELEASE_NOTES +7 -0
- data/bin/sitefuel +162 -0
- data/lib/sitefuel/Configuration.rb +35 -0
- data/lib/sitefuel/SiteFuelLogger.rb +128 -0
- data/lib/sitefuel/SiteFuelRuntime.rb +293 -0
- data/lib/sitefuel/extensions/ArrayComparisons.rb +34 -0
- data/lib/sitefuel/extensions/DynamicClassMethods.rb +19 -0
- data/lib/sitefuel/extensions/FileComparison.rb +24 -0
- data/lib/sitefuel/extensions/Silently.rb +27 -0
- data/lib/sitefuel/extensions/StringFormatting.rb +75 -0
- data/lib/sitefuel/extensions/SymbolComparison.rb +13 -0
- data/lib/sitefuel/external/AbstractExternalProgram.rb +616 -0
- data/lib/sitefuel/external/ExternalProgramTestCase.rb +67 -0
- data/lib/sitefuel/external/GIT.rb +9 -0
- data/lib/sitefuel/external/JPEGTran.rb +68 -0
- data/lib/sitefuel/external/PNGCrush.rb +66 -0
- data/lib/sitefuel/processors/AbstractExternalProgramProcessor.rb +72 -0
- data/lib/sitefuel/processors/AbstractProcessor.rb +378 -0
- data/lib/sitefuel/processors/AbstractStringBasedProcessor.rb +88 -0
- data/lib/sitefuel/processors/CSSProcessor.rb +84 -0
- data/lib/sitefuel/processors/HAMLProcessor.rb +52 -0
- data/lib/sitefuel/processors/HTMLProcessor.rb +211 -0
- data/lib/sitefuel/processors/JavaScriptProcessor.rb +57 -0
- data/lib/sitefuel/processors/PHPProcessor.rb +32 -0
- data/lib/sitefuel/processors/PNGProcessor.rb +80 -0
- data/lib/sitefuel/processors/RHTMLProcessor.rb +25 -0
- data/lib/sitefuel/processors/SASSProcessor.rb +50 -0
- data/test/processor_listing.rb +28 -0
- data/test/test_AbstractExternalProgram.rb +186 -0
- data/test/test_AbstractProcessor.rb +237 -0
- data/test/test_AbstractStringBasedProcessor.rb +48 -0
- data/test/test_AllProcessors.rb +65 -0
- data/test/test_ArrayComparisons.rb +32 -0
- data/test/test_CSSProcessor.rb +120 -0
- data/test/test_FileComparisons.rb +42 -0
- data/test/test_HAMLProcessor.rb.rb +60 -0
- data/test/test_HTMLProcessor.rb +186 -0
- data/test/test_JPEGTran.rb +40 -0
- data/test/test_JavaScriptProcessor.rb +63 -0
- data/test/test_PHPProcessor.rb +51 -0
- data/test/test_PNGCrush.rb +58 -0
- data/test/test_PNGProcessor.rb +32 -0
- data/test/test_RHTMLProcessor.rb +62 -0
- data/test/test_SASSProcessor.rb +68 -0
- data/test/test_SiteFuelLogging.rb +79 -0
- data/test/test_SiteFuelRuntime.rb +96 -0
- data/test/test_StringFormatting.rb +51 -0
- data/test/test_SymbolComparison.rb +27 -0
- data/test/test_images/sample_jpg01.jpg +0 -0
- data/test/test_images/sample_png01.png +0 -0
- data/test/test_programs/versioning.rb +26 -0
- data/test/test_sites/simplehtml/deployment.yml +22 -0
- data/test/test_sites/simplehtml/index.html +66 -0
- data/test/test_sites/simplehtml/style.css +40 -0
- data/test/ts_all.rb +39 -0
- metadata +165 -0
data/README
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
|
2
|
+
|
3
|
+
|
4
|
+
SiteFuel
|
5
|
+
http://sitefuel.org
|
6
|
+
v0.1.0 (initial release)
|
7
|
+
|
8
|
+
|
9
|
+
~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
|
10
|
+
|
11
|
+
A program and API for minifying websites and web applications and
|
12
|
+
deploying them from version control.
|
13
|
+
|
14
|
+
* Get started: http://sitefuel.org/getstarted
|
15
|
+
* Lists: http://sitefuel.org/mailinglists
|
16
|
+
* Report a bug: http://sitefuel.org/bug
|
17
|
+
|
18
|
+
* Contribute! http://sitefuel.org/contribute
|
19
|
+
|
20
|
+
|
21
|
+
== Table of Contents
|
22
|
+
|
23
|
+
1. Introduction
|
24
|
+
. System Requirements
|
25
|
+
. Supported Formats
|
26
|
+
. Installation
|
27
|
+
. Getting Started
|
28
|
+
. Reporting a Bug
|
29
|
+
. A Note about the API
|
30
|
+
. Further Reading
|
31
|
+
|
32
|
+
|
33
|
+
== Introduction
|
34
|
+
SiteFuel is a Ruby program
|
35
|
+
|
36
|
+
Use SiteFuel to:
|
37
|
+
* deploy your website out of SVN or GIT
|
38
|
+
* minify your
|
39
|
+
|
40
|
+
|
41
|
+
== System Requirements
|
42
|
+
|
43
|
+
* Ruby 1.8.6 or greater.
|
44
|
+
* pngcrush (for PNG compression)
|
45
|
+
* jpegtran (for JPEG compression)
|
46
|
+
* git (for deploying sites from Git repositories)
|
47
|
+
* svn (for deploying sites from SVN repositories)
|
48
|
+
|
49
|
+
SiteFuel hasn't been tested on Windows machines.
|
50
|
+
|
51
|
+
|
52
|
+
== Installation
|
53
|
+
|
54
|
+
SiteFuel is deployed as a RubyGem through http://gemcutter.org. You
|
55
|
+
should be able to install it directly using RubyGems:
|
56
|
+
|
57
|
+
$ gem install -t sitefuel
|
58
|
+
|
59
|
+
You can also download a ZIP-file containing SiteFuel and all of the gems
|
60
|
+
it depends on from http://sitefuel.org/download/sitefuel-complete.zip
|
61
|
+
|
62
|
+
Note that for PNG and JPEG compression to be enabled you must install
|
63
|
+
the 'pngcrush' and 'jpegtran' programs.
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
== Getting Started
|
68
|
+
|
69
|
+
SiteFuel
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
== Reporting a Bug
|
75
|
+
|
76
|
+
|
77
|
+
== A Note About the API
|
78
|
+
|
79
|
+
The general API in SiteFuel should be considered unstable while SiteFuel
|
80
|
+
is <1.0. For practical reasons we can't increment the major version
|
81
|
+
number each time there is a non-backwards compatible API change....
|
82
|
+
|
83
|
+
|
84
|
+
== Further Reading
|
85
|
+
* http://sitefuel.org - main sitefuel website
|
86
|
+
* http://sitefuel.org/help - pointers to various resources
|
data/RELEASE_NOTES
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
== 0.1.0
|
2
|
+
* initial public release of the SiteFuel alpha
|
3
|
+
* support for trivial minification of HTML, RHTML, and PHP.
|
4
|
+
* uses CSSMin and JSMin to minify CSS and JavaScript; both in individual
|
5
|
+
files and embedded in HTML.
|
6
|
+
* uses pngcrush and jpegtran to minify PNG and JPEG images.
|
7
|
+
* support for the Git and SVN version control systems.
|
data/bin/sitefuel
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
#!/usr/bin/ruby -wrubygems
|
2
|
+
|
3
|
+
# == Synopsis
|
4
|
+
#
|
5
|
+
# A lightweight ruby framework for processing and deploying websites, either
|
6
|
+
# from
|
7
|
+
#
|
8
|
+
# == Usage
|
9
|
+
#
|
10
|
+
# sitefuel deploy|process SOURCE [OPTIONS]
|
11
|
+
#
|
12
|
+
# == Introduction
|
13
|
+
# sitefuel is a lightweight ruby framework for deploying websites directly from
|
14
|
+
# version control. sitefuel includes support for compressing HTML and CSS as
|
15
|
+
# well as optimizing PNG graphics. Support is planned for SASS; compressing
|
16
|
+
# JavaScript; automatically creating sprites; and supporting more image formats.
|
17
|
+
# (and more!)
|
18
|
+
#
|
19
|
+
# TODO: add more details
|
20
|
+
#
|
21
|
+
# * More information: http://sitefuel.org
|
22
|
+
# * Getting started: http://sitefuel.org/getstarted
|
23
|
+
# * Documentation: http://sitefuel.org/documentation
|
24
|
+
#
|
25
|
+
# == Commands
|
26
|
+
#
|
27
|
+
# deploy:: Deploy a site using sitefuel.
|
28
|
+
# process:: Modify an existing website inplace.
|
29
|
+
# stage:: Simulates a deployment without actually changing anything.
|
30
|
+
# help:: Show this message.
|
31
|
+
#
|
32
|
+
# == Examples
|
33
|
+
# Process an already deployed site:
|
34
|
+
# sitefuel process /var/www/
|
35
|
+
#
|
36
|
+
# Deploy a site from SVN:
|
37
|
+
# sitefuel deploy svn+ssh://sitefuel.org/svn/tags/21 /var/www/
|
38
|
+
#
|
39
|
+
# Specify a non-default deployment file:
|
40
|
+
# sitefuel process /var/www/ -c customdeployment.yml
|
41
|
+
#
|
42
|
+
#
|
43
|
+
# == Author
|
44
|
+
# Zanoccio, LLC.
|
45
|
+
#
|
46
|
+
# == Copyright
|
47
|
+
# Copyright (c) 2009 Zanoccio.
|
48
|
+
#
|
49
|
+
# == License
|
50
|
+
# This program is free software; you can redistribute it and/or
|
51
|
+
# modify it under the terms of the GNU General Public License
|
52
|
+
# as published by the Free Software Foundation; either version 2
|
53
|
+
# of the License, or (at your option) any later version.
|
54
|
+
#
|
55
|
+
# This program is distributed in the hope that it will be useful,
|
56
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
57
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
58
|
+
# GNU General Public License for more details.
|
59
|
+
#
|
60
|
+
# You should have received a copy of the GNU General Public License
|
61
|
+
# along with this program; if not, write to the Free Software
|
62
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
63
|
+
#
|
64
|
+
|
65
|
+
# add source/ to the load path
|
66
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
67
|
+
|
68
|
+
begin
|
69
|
+
require 'rubygems'
|
70
|
+
rescue LoadError
|
71
|
+
# attempt to continue running the program
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
require 'rdoc/usage'
|
76
|
+
require 'term/ansicolor'
|
77
|
+
|
78
|
+
require 'sitefuel/SiteFuelRuntime'
|
79
|
+
|
80
|
+
include Term::ANSIColor
|
81
|
+
|
82
|
+
def puts_and_exit(*args)
|
83
|
+
puts(*args)
|
84
|
+
exit
|
85
|
+
end
|
86
|
+
|
87
|
+
$HELP_HINT_LINE = "type \'#{$0} help\' for usage"
|
88
|
+
|
89
|
+
# parse command line arguments and configure a SiteFuelRuntime
|
90
|
+
def parse_command_line(runtime)
|
91
|
+
|
92
|
+
#### BUILD THE OPTIONS PARSER
|
93
|
+
opts = OptionParser.new
|
94
|
+
|
95
|
+
# the banner text comes from the header comment for this file
|
96
|
+
|
97
|
+
opts.on('-oARG', '-o=ARG', '-o PLACE', '--output=ARG', '--output PLACE', String,
|
98
|
+
'Where to put a deployed site') do |out|
|
99
|
+
runtime.deploy_to = out
|
100
|
+
end
|
101
|
+
opts.on('-v', '--version', 'Gives the version of sitefuel') do
|
102
|
+
puts 'SiteFuel ' + VERSION_TEXT
|
103
|
+
end
|
104
|
+
|
105
|
+
opts.on('--[no-]verbose', 'List actions as they are preformed') do
|
106
|
+
puts 'cause SiteFuel to be verbose listing actions as they are preformed'
|
107
|
+
end
|
108
|
+
|
109
|
+
opts.on('--only-list-recognized-files', 'Only list summaries for files which were changed') do
|
110
|
+
runtime.only_list_recognized_files = true
|
111
|
+
end
|
112
|
+
|
113
|
+
opts.on('-h', '--help', '-?', '--about', 'Gives help for a specific command.') do
|
114
|
+
RDoc::usage_no_exit('Synopsis', 'Usage', 'Introduction')
|
115
|
+
puts opts
|
116
|
+
RDoc::usage_no_exit('Examples', 'Author', 'Copyright', 'License')
|
117
|
+
exit
|
118
|
+
end
|
119
|
+
|
120
|
+
opts.separator ''
|
121
|
+
opts.separator 'Specific options for a command can be seen with: '
|
122
|
+
opts.separator ' COMMAND --help'
|
123
|
+
|
124
|
+
|
125
|
+
#### ATTEMPT TO PARSE THE COMMAND LINE
|
126
|
+
begin
|
127
|
+
commands = opts.parse(*ARGV)
|
128
|
+
rescue OptionParser::InvalidOption => iopt
|
129
|
+
puts iopt
|
130
|
+
puts_and_exit $HELP_HINT_LINE
|
131
|
+
rescue => exception
|
132
|
+
# TODO: add better handling for the various exceptions (unnecessary
|
133
|
+
# argument, missing argument, etc.)
|
134
|
+
puts_and_exit "couldn't parse command line: #{exception}", $HELP_HINT_LINE
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
# note that --help will have already been intercepted but 'help' still needs
|
139
|
+
# special treatment
|
140
|
+
puts_and_exit 'no command given', $HELP_HINT_LINE if commands.length < 1
|
141
|
+
puts_and_exit opts if commands[0].downcase == 'help'
|
142
|
+
|
143
|
+
case commands[0].downcase
|
144
|
+
when 'deploy'
|
145
|
+
runtime.deploy_from = commands[1]
|
146
|
+
runtime.deploy
|
147
|
+
|
148
|
+
when 'stage'
|
149
|
+
runtime.deploy_from = commands[1]
|
150
|
+
runtime.stage
|
151
|
+
|
152
|
+
else
|
153
|
+
puts_and_exit "unknown command: '#{commands[0]}'", $HELP_HINT_LINE
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def main
|
158
|
+
runtime = SiteFuel::SiteFuelRuntime.new
|
159
|
+
parse_command_line(runtime)
|
160
|
+
end
|
161
|
+
|
162
|
+
main()
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#
|
2
|
+
# File:: configuration.rb
|
3
|
+
# Author:: wkm
|
4
|
+
# Copyright:: 2009
|
5
|
+
# License:: GPL
|
6
|
+
#
|
7
|
+
# Load and process SiteFuel YAML configuration files
|
8
|
+
#
|
9
|
+
|
10
|
+
module SiteFuel
|
11
|
+
require 'yaml'
|
12
|
+
|
13
|
+
class Configuration
|
14
|
+
|
15
|
+
# exception which represents that a configuration could not be found
|
16
|
+
class NotFound < StandardError
|
17
|
+
end
|
18
|
+
|
19
|
+
# given a directory path will attempt to location a configuration file
|
20
|
+
# and load it, returning a SiteFuel::Configuration class
|
21
|
+
def self.load(path)
|
22
|
+
unless File.exist?(path)
|
23
|
+
throw NotFound, path
|
24
|
+
end
|
25
|
+
|
26
|
+
yamlconfig = YAML::load_file(configfile)
|
27
|
+
|
28
|
+
Configuration.new(yamlconfig)
|
29
|
+
end
|
30
|
+
|
31
|
+
# builds a sitefuel configuration from a parsed YAML file
|
32
|
+
def initialize(yamlconfig)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
#
|
2
|
+
# File:: SiteFuelLogger.rb
|
3
|
+
# Author:: wkm
|
4
|
+
# Copyright:: 2009
|
5
|
+
# License:: GPL
|
6
|
+
#
|
7
|
+
|
8
|
+
module SiteFuel
|
9
|
+
|
10
|
+
require 'logger'
|
11
|
+
require 'singleton'
|
12
|
+
require 'term/ansicolor'
|
13
|
+
|
14
|
+
include Term::ANSIColor
|
15
|
+
|
16
|
+
# Singleton abstraction around the Logger:: library, typically every processor
|
17
|
+
# will hook into using this logger while letting us control it's placement
|
18
|
+
# and display globally
|
19
|
+
class SiteFuelLogger < Logger
|
20
|
+
include Singleton
|
21
|
+
|
22
|
+
# the number of fatal messages logged so far (even if lower than #level)
|
23
|
+
attr_reader :fatal_count
|
24
|
+
|
25
|
+
# the number of error messages logged so far (even if lower than #level)
|
26
|
+
attr_reader :error_count
|
27
|
+
|
28
|
+
# the number of warning messages logged so far (even if lower than #level)
|
29
|
+
attr_reader :warn_count
|
30
|
+
|
31
|
+
# the number of info messages logged so far (even if lower than #level)
|
32
|
+
attr_reader :info_count
|
33
|
+
|
34
|
+
# the number of debug messages logged so far (even if lower than #level)
|
35
|
+
attr_reader :debug_count
|
36
|
+
|
37
|
+
# adjust the style of logging:
|
38
|
+
#
|
39
|
+
# default:: use the Logger logging style
|
40
|
+
# clean:: gives a clean logging output intended for human use
|
41
|
+
attr_accessor :log_style
|
42
|
+
|
43
|
+
def initialize(filename = STDOUT)
|
44
|
+
super(filename)
|
45
|
+
|
46
|
+
@fatal_count = 0
|
47
|
+
@error_count = 0
|
48
|
+
@warn_count = 0
|
49
|
+
@info_count = 0
|
50
|
+
@debug_count = 0
|
51
|
+
|
52
|
+
self.level = WARN
|
53
|
+
@log_style = :default
|
54
|
+
@progname = 'SiteFuel'
|
55
|
+
end
|
56
|
+
|
57
|
+
def fatal(*args)
|
58
|
+
@fatal_count += 1
|
59
|
+
super(*args)
|
60
|
+
end
|
61
|
+
|
62
|
+
def error(*args)
|
63
|
+
@error_count += 1
|
64
|
+
super(*args)
|
65
|
+
end
|
66
|
+
|
67
|
+
def warn(*args)
|
68
|
+
@warn_count += 1
|
69
|
+
super(*args)
|
70
|
+
end
|
71
|
+
|
72
|
+
def info(*args)
|
73
|
+
@info_count += 1
|
74
|
+
super(*args)
|
75
|
+
end
|
76
|
+
|
77
|
+
def debug(*args)
|
78
|
+
@debug_count += 1
|
79
|
+
super(*args)
|
80
|
+
end
|
81
|
+
|
82
|
+
# implement our own #add so we can have cleaner logs
|
83
|
+
def format_message(severity, date_time, program_name, msg)
|
84
|
+
case @log_style
|
85
|
+
when :default
|
86
|
+
super(severity, date_time, program_name, msg)
|
87
|
+
|
88
|
+
when :clean
|
89
|
+
string = "#{severity}: #{msg}\n"
|
90
|
+
case severity
|
91
|
+
when 'ERROR', 'FATAL'
|
92
|
+
string = bold(red(string))
|
93
|
+
|
94
|
+
when 'WARN'
|
95
|
+
string = yellow(string)
|
96
|
+
|
97
|
+
when 'DEBUG'
|
98
|
+
string = string
|
99
|
+
end
|
100
|
+
string
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# mixin for adding logging functionality to any class, typically included
|
106
|
+
# by every SiteFuel class
|
107
|
+
module Logging
|
108
|
+
# sets the logger for a class
|
109
|
+
def logger=(logger)
|
110
|
+
@logger = logger
|
111
|
+
end
|
112
|
+
|
113
|
+
# adds a fatal error to the log
|
114
|
+
def fatal(*args) @logger.fatal(*args); end
|
115
|
+
|
116
|
+
# adds an error to the log
|
117
|
+
def error(*args) @logger.error(*args); end
|
118
|
+
|
119
|
+
# adds a warning to the log
|
120
|
+
def warn(*args) @logger.warn(*args); end
|
121
|
+
|
122
|
+
# adds an info message to the log
|
123
|
+
def info(*args) @logger.info(*args); end
|
124
|
+
|
125
|
+
# adds a debugging message to the log
|
126
|
+
def debug(*args) @logger.debug(*args); end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,293 @@
|
|
1
|
+
#
|
2
|
+
# File:: SiteFuelRuntime.rb
|
3
|
+
# Author:: wkm
|
4
|
+
# Copyright:: 2009
|
5
|
+
# License:: GPL
|
6
|
+
#
|
7
|
+
# Defines the primary interface class used by sitefuel to do actual work.
|
8
|
+
# Keeping this as a class let's us abstract away the command line interface
|
9
|
+
# while automatically having a direct API for programatically accessing
|
10
|
+
# sitefuel.
|
11
|
+
#
|
12
|
+
|
13
|
+
|
14
|
+
module SiteFuel
|
15
|
+
|
16
|
+
require 'optparse'
|
17
|
+
require 'term/ansicolor'
|
18
|
+
|
19
|
+
include Term::ANSIColor
|
20
|
+
|
21
|
+
require 'sitefuel/SiteFuelLogger'
|
22
|
+
|
23
|
+
require 'sitefuel/extensions/StringFormatting'
|
24
|
+
require 'sitefuel/extensions/FileComparison'
|
25
|
+
|
26
|
+
# we need the AbstractProcessor symbol when we go child-class hunting
|
27
|
+
require 'sitefuel/processors/AbstractProcessor'
|
28
|
+
|
29
|
+
# version of SiteFuel
|
30
|
+
VERSION = [0, 0, 1].freeze
|
31
|
+
|
32
|
+
# a human readable version
|
33
|
+
VERSION_TEXT = VERSION.join('.').freeze
|
34
|
+
|
35
|
+
|
36
|
+
class SiteFuelRuntime
|
37
|
+
|
38
|
+
include SiteFuel::Logging
|
39
|
+
|
40
|
+
# what action is the runtime supposed to preform
|
41
|
+
attr_accessor :action
|
42
|
+
|
43
|
+
# what is the source *from* which we are deploying
|
44
|
+
attr_accessor :deploy_from
|
45
|
+
|
46
|
+
# what is the source *to* which we are deploying
|
47
|
+
attr_accessor :deploy_to
|
48
|
+
|
49
|
+
# configuration loaded from a deployment.yml file
|
50
|
+
attr_accessor :deploymentconfiguration
|
51
|
+
|
52
|
+
# only lists file which have a known processor
|
53
|
+
attr_accessor :only_list_recognized_files
|
54
|
+
|
55
|
+
def initialize
|
56
|
+
@processors = SiteFuelRuntime.find_processors
|
57
|
+
self.logger = SiteFuelLogger.instance
|
58
|
+
SiteFuelLogger.instance.log_style = :clean
|
59
|
+
|
60
|
+
@only_list_recognized_files = false
|
61
|
+
end
|
62
|
+
|
63
|
+
# gives true if the given file (typically a processor) has already been
|
64
|
+
# loaded (by looking into $"). Unfortunately #require is easily tricked,
|
65
|
+
# so this function uses some heuristics to prevent processors from being
|
66
|
+
# loaded twice (by basically comparing the "core" part of the filename)
|
67
|
+
def self.processor_loaded?(file)
|
68
|
+
$".map do |f|
|
69
|
+
if File.equivalent?(file, f)
|
70
|
+
return true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
return false
|
75
|
+
end
|
76
|
+
|
77
|
+
# finds all processors under processors/ and loads them. Any file matching
|
78
|
+
# *Processor.rb will be loaded
|
79
|
+
def self.load_processors
|
80
|
+
dir = File.dirname(__FILE__).split(File::SEPARATOR)
|
81
|
+
dir = File.join(*dir[0..-2]) + File::SEPARATOR
|
82
|
+
|
83
|
+
# build up the search pattern by taking this file's directory and shoving
|
84
|
+
# it onto the search pattern
|
85
|
+
patt = File.join(dir, 'sitefuel/processors/*Processor.rb')
|
86
|
+
|
87
|
+
# find all file matching that pattern
|
88
|
+
files = Dir[patt]
|
89
|
+
|
90
|
+
# rip off the path prefix eg. 'sitefuel/lib/b/foo.rb' becomes 'b/foo.rb'
|
91
|
+
files = files.map do |filename|
|
92
|
+
filename.gsub(Regexp.new("^"+Regexp.escape(dir)), '')
|
93
|
+
end
|
94
|
+
|
95
|
+
# get rid of anything we've already loaded
|
96
|
+
files = files.delete_if { |file| processor_loaded?(file) }
|
97
|
+
|
98
|
+
# load whatever files we're left with
|
99
|
+
files.each { |f| require f }
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# returns a list of processors found by looking for all children of
|
104
|
+
# SiteFuel::Processor::AbstractProcessor
|
105
|
+
#
|
106
|
+
# for a processor to be automatically included it has to:
|
107
|
+
# * be loaded (see #load_processors)
|
108
|
+
# * be a child class of AbstractProcessor
|
109
|
+
# * the class name must end with Processor
|
110
|
+
#
|
111
|
+
def self.find_processors
|
112
|
+
Processor::AbstractProcessor.find_processors
|
113
|
+
end
|
114
|
+
|
115
|
+
# lists the actions which are possible with this runtime.
|
116
|
+
def actions
|
117
|
+
[ :deploy, :stage ]
|
118
|
+
end
|
119
|
+
|
120
|
+
# gives the array of processors available to this runtime
|
121
|
+
attr_reader :processors
|
122
|
+
|
123
|
+
# adds a processor or an array of processors to the runtime
|
124
|
+
def add_processor(proc)
|
125
|
+
case proc
|
126
|
+
when Array
|
127
|
+
proc.each { |p|
|
128
|
+
@processors << p
|
129
|
+
}
|
130
|
+
else
|
131
|
+
@processors << proc
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# gives the processor to use for a given file
|
136
|
+
def choose_processor(filename)
|
137
|
+
matchingprocs = processors.clone.delete_if {|proc| not proc.processes_file?(filename) }
|
138
|
+
|
139
|
+
case
|
140
|
+
when matchingprocs.length > 1
|
141
|
+
chosen = matchingprocs.first
|
142
|
+
raise Processor::MultipleApplicableProcessors.new(filename, matchingprocs, chosen)
|
143
|
+
when matchingprocs.length == 1
|
144
|
+
return matchingprocs.first
|
145
|
+
else
|
146
|
+
return nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# like #choose_processor but prints a message if there are clashing
|
151
|
+
# processors and returns the first of the clashing processors.
|
152
|
+
# (effectively alerting the user, but continuing to work)
|
153
|
+
def choose_processor!(filename)
|
154
|
+
begin
|
155
|
+
choose_processor(filename)
|
156
|
+
rescue Processor::MultipleApplicableProcessors => exception
|
157
|
+
# log the exception
|
158
|
+
warn exception
|
159
|
+
exception.chosen_processor
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
# implements the stage command. Staging, by itself, will give statistics on
|
165
|
+
# the deployment; how many bytes were saved by minification; etc.
|
166
|
+
#
|
167
|
+
# However, #stage when part of #deploy will go and create the requisite files
|
168
|
+
# in a temporary directory
|
169
|
+
def stage
|
170
|
+
return nil if @deploy_from == nil
|
171
|
+
|
172
|
+
puts '== %s '.format('Staging').ljust(80, '=')
|
173
|
+
|
174
|
+
# find all files under deploy_from
|
175
|
+
files = find_all_files @deploy_from
|
176
|
+
|
177
|
+
total_original_size = 0
|
178
|
+
total_processed_size = 0
|
179
|
+
@resource_processors = {}
|
180
|
+
@processor_statistics = Hash.new([0, 0, 0])
|
181
|
+
files.each do |filename|
|
182
|
+
processor = choose_processor!(filename)
|
183
|
+
if processor == nil
|
184
|
+
@resource_processors[filename] = nil
|
185
|
+
else
|
186
|
+
@resource_processors[filename] = processor.process_file(filename)
|
187
|
+
end
|
188
|
+
|
189
|
+
processor = @resource_processors[filename]
|
190
|
+
if processor == nil
|
191
|
+
if only_list_recognized_files == false
|
192
|
+
puts '%s %s' %['--'.ljust(8), filename.cabbrev(65)]
|
193
|
+
end
|
194
|
+
else
|
195
|
+
total_original_size += processor.original_size
|
196
|
+
total_processed_size += processor.processed_size
|
197
|
+
|
198
|
+
stats = @processor_statistics[processor.class.processor_name].clone
|
199
|
+
stats[0] += 1
|
200
|
+
stats[1] += processor.original_size
|
201
|
+
stats[2] += processor.processed_size
|
202
|
+
@processor_statistics[processor.class.processor_name] = stats
|
203
|
+
|
204
|
+
puts '%s %s %4.3f' %
|
205
|
+
[
|
206
|
+
cyan(processor.class.processor_name.ljust(8)),
|
207
|
+
filename.cabbrev(65).ljust(65),
|
208
|
+
processor.processed_size.prec_f/processor.original_size.prec_f
|
209
|
+
]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
puts '='*80
|
214
|
+
puts 'Size delta: %+5d bytes; %4.3f' %
|
215
|
+
[
|
216
|
+
total_processed_size - total_original_size,
|
217
|
+
total_processed_size.prec_f/total_original_size.prec_f
|
218
|
+
]
|
219
|
+
|
220
|
+
staging_statistics
|
221
|
+
end
|
222
|
+
|
223
|
+
# outputs a little grid showing the number of files of each processor
|
224
|
+
# and the total savings
|
225
|
+
#
|
226
|
+
# todo: this should be computed in the staging step
|
227
|
+
def staging_statistics
|
228
|
+
puts ''
|
229
|
+
puts ' %s | %s | %s | %s' %
|
230
|
+
['processor', '# files', 'delta', 'ratio'].map{|v| bold(v)}
|
231
|
+
puts ' -----------+----------+-------------+-------'
|
232
|
+
|
233
|
+
@processor_statistics.keys.sort.each do |key|
|
234
|
+
puts ' %s|%9d |%+12d | %4.3f' %
|
235
|
+
[
|
236
|
+
key.ljust(10),
|
237
|
+
@processor_statistics[key][0],
|
238
|
+
@processor_statistics[key][2] - @processor_statistics[key][1],
|
239
|
+
@processor_statistics[key][2].prec_f / @processor_statistics[key][1].prec_f
|
240
|
+
]
|
241
|
+
end
|
242
|
+
puts ' -----------+----------+-------------+-------'
|
243
|
+
puts ''
|
244
|
+
end
|
245
|
+
|
246
|
+
# create a deployment
|
247
|
+
def deploy
|
248
|
+
# first we have to stage the files
|
249
|
+
stage
|
250
|
+
|
251
|
+
files = find_all_files @deploy_from
|
252
|
+
|
253
|
+
return if @deploy_to == nil
|
254
|
+
puts
|
255
|
+
puts bold('Deploying:')
|
256
|
+
|
257
|
+
unless File.exists?(@deploy_to)
|
258
|
+
Dir.mkdir(@deploy_to)
|
259
|
+
end
|
260
|
+
# write out content
|
261
|
+
files.each do |filename|
|
262
|
+
results = @resource_processors[filename]
|
263
|
+
if results == nil
|
264
|
+
putc 'I'
|
265
|
+
else
|
266
|
+
putc '.'
|
267
|
+
results.save(@deploy_to)
|
268
|
+
end
|
269
|
+
STDOUT.flush
|
270
|
+
end
|
271
|
+
puts
|
272
|
+
end
|
273
|
+
|
274
|
+
# gives an array listing of all files on a given path
|
275
|
+
#
|
276
|
+
# This is a very lightweight wrapper around Dir.
|
277
|
+
def find_all_files(path)
|
278
|
+
Dir[File.join(path, "**/*")]
|
279
|
+
end
|
280
|
+
|
281
|
+
# changes the verbosity of the runtime by adjusting the log level
|
282
|
+
def verbosity(level = 1)
|
283
|
+
case level
|
284
|
+
when 1
|
285
|
+
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
# load the various processors
|
292
|
+
SiteFuelRuntime.load_processors
|
293
|
+
end
|