scout 1.1.8 → 2.0.4
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/{CHANGELOG → History.txt} +28 -0
- data/{LICENSE → License.txt} +2 -1
- data/Manifest.txt +33 -0
- data/PostInstall.txt +7 -0
- data/README.txt +76 -0
- data/Rakefile +4 -134
- data/bin/scout +1 -200
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +15 -0
- data/lib/scout/command/clone.rb +21 -0
- data/lib/scout/command/install.rb +62 -0
- data/lib/scout/command/run.rb +14 -0
- data/lib/scout/command/test.rb +38 -0
- data/lib/scout/command.rb +225 -0
- data/lib/scout/plugin.rb +97 -1
- data/lib/scout/server.rb +24 -2
- data/lib/scout/version.rb +9 -0
- data/lib/scout.rb +2 -4
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +82 -0
- data/setup.rb +799 -574
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/test_helper.rb +2 -0
- data/test/test_scout.rb +11 -0
- data/website/index.html +138 -0
- data/website/index.txt +81 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.html.erb +48 -0
- metadata +61 -34
- data/AUTHORS +0 -4
- data/COPYING +0 -340
- data/INSTALL +0 -18
- data/README +0 -34
- data/TODO +0 -6
- data/test/scout_test.rb +0 -91
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
require "pp"
|
4
|
+
|
5
|
+
module Scout
|
6
|
+
class Command
|
7
|
+
class Test < Command
|
8
|
+
def run
|
9
|
+
plugin, options = @args
|
10
|
+
|
11
|
+
# read the plugin_code from the file specified
|
12
|
+
plugin_code = File.read(plugin)
|
13
|
+
plugin_options = if options.to_s[0, 1] == "{"
|
14
|
+
eval(options) # options from command-line
|
15
|
+
elsif options
|
16
|
+
#
|
17
|
+
# read the plugin_options from the YAML file specified,
|
18
|
+
# parse each option and use the default value specified
|
19
|
+
# in the options as the value to be passed to the test plugin
|
20
|
+
#
|
21
|
+
Hash[ *File.open(options) { |f| YAML.load(f) }["options"].
|
22
|
+
map { |name, details| [name, details["default"]] }.flatten ]
|
23
|
+
else
|
24
|
+
Hash.new
|
25
|
+
end
|
26
|
+
|
27
|
+
Scout::Server.new(nil, nil, history, log) do |scout|
|
28
|
+
pp scout.process_plugin( :interval => 0,
|
29
|
+
:plugin_id => 1,
|
30
|
+
:name => "Local Plugin",
|
31
|
+
:code => plugin_code,
|
32
|
+
:options => plugin_options,
|
33
|
+
:path => plugin )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "logger"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
module Scout
|
8
|
+
class Command
|
9
|
+
def self.user
|
10
|
+
@user ||= ENV["USER"] || ENV["USERNAME"] || "root"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.program_name
|
14
|
+
@program_name ||= File.basename($PROGRAM_NAME)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.program_path
|
18
|
+
@program_path ||= File.expand_path($PROGRAM_NAME)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.usage
|
22
|
+
@usage
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.parse_options(argv)
|
26
|
+
options = { }
|
27
|
+
|
28
|
+
ARGV.options do |opts|
|
29
|
+
opts.banner = "Usage:"
|
30
|
+
|
31
|
+
opts.separator " Normal checkin with server:"
|
32
|
+
opts.separator " #{program_name} [OPTIONS] CLIENT_KEY"
|
33
|
+
opts.separator " ... OR ..."
|
34
|
+
opts.separator " #{program_name} [OPTIONS] run CLIENT_KEY"
|
35
|
+
opts.separator " Install:"
|
36
|
+
opts.separator " #{program_name}"
|
37
|
+
opts.separator " ... OR ..."
|
38
|
+
opts.separator " #{program_name} [OPTIONS] install"
|
39
|
+
opts.separator " Local plugin testing:"
|
40
|
+
opts.separator " #{program_name} [OPTIONS] test " +
|
41
|
+
"PATH_TO_PLUGIN [PLUGIN_OPTIONS]"
|
42
|
+
opts.separator " Clone a client setup:"
|
43
|
+
opts.separator " #{program_name} [OPTIONS] clone " +
|
44
|
+
"CLIENT_KEY NEW_CLIENT_NAME"
|
45
|
+
opts.separator ""
|
46
|
+
opts.separator "CLIENT_KEY is the indentification key assigned to"
|
47
|
+
opts.separator "this client by the server."
|
48
|
+
opts.separator ""
|
49
|
+
opts.separator "PATH_TO_PLUGIN is the file system path to a Ruby file"
|
50
|
+
opts.separator "that contains a Scout plugin."
|
51
|
+
opts.separator ""
|
52
|
+
opts.separator "PLUGIN_OPTIONS can be the code for a Ruby Hash or the"
|
53
|
+
opts.separator "path to a YAML options file containing defaults. These"
|
54
|
+
opts.separator "options will be used for the plugin run."
|
55
|
+
opts.separator ""
|
56
|
+
opts.separator "NEW_CLIENT_NAME is name you wish to use for the new"
|
57
|
+
opts.separator "client the server creates."
|
58
|
+
opts.separator ""
|
59
|
+
opts.separator "Note: This client is meant to be installed and"
|
60
|
+
opts.separator "invoked through cron or any other scheduler."
|
61
|
+
opts.separator ""
|
62
|
+
opts.separator "Specific Options:"
|
63
|
+
|
64
|
+
opts.on( "-s", "--server SERVER", String,
|
65
|
+
"The URL for the server to report to." ) do |url|
|
66
|
+
options[:server] = url
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.separator ""
|
70
|
+
|
71
|
+
opts.on( "-d", "--data DATA", String,
|
72
|
+
"The data file used to track history." ) do |file|
|
73
|
+
options[:history] = file
|
74
|
+
end
|
75
|
+
opts.on( "-l", "--level LEVEL",
|
76
|
+
Logger::SEV_LABEL.map { |l| l.downcase },
|
77
|
+
"The level of logging to report." ) do |level|
|
78
|
+
options[:level] = level
|
79
|
+
end
|
80
|
+
|
81
|
+
opts.separator "Common Options:"
|
82
|
+
|
83
|
+
opts.on( "-h", "--help",
|
84
|
+
"Show this message." ) do
|
85
|
+
puts opts
|
86
|
+
exit
|
87
|
+
end
|
88
|
+
opts.on( "-v", "--[no-]verbose",
|
89
|
+
"Turn on logging to STDOUT" ) do |bool|
|
90
|
+
options[:verbose] = bool
|
91
|
+
end
|
92
|
+
|
93
|
+
opts.on( "-V", "--version",
|
94
|
+
"Display the current version") do |version|
|
95
|
+
puts Scout::VERSION::STRING
|
96
|
+
exit
|
97
|
+
end
|
98
|
+
|
99
|
+
begin
|
100
|
+
opts.parse!
|
101
|
+
@usage = opts.to_s
|
102
|
+
rescue
|
103
|
+
puts opts
|
104
|
+
exit
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
options
|
109
|
+
end
|
110
|
+
private_class_method :parse_options
|
111
|
+
|
112
|
+
def self.dispatch(argv)
|
113
|
+
options = parse_options(argv)
|
114
|
+
command = if name_or_key = argv.shift
|
115
|
+
if cls = Scout::Command.const_get(name_or_key.capitalize) \
|
116
|
+
rescue nil
|
117
|
+
cls.new(options, argv)
|
118
|
+
else
|
119
|
+
Run.new(options, [name_or_key] + argv)
|
120
|
+
end
|
121
|
+
else
|
122
|
+
Install.new(options, argv)
|
123
|
+
end
|
124
|
+
command.create_pid_file_or_exit.run
|
125
|
+
end
|
126
|
+
|
127
|
+
def initialize(options, args)
|
128
|
+
@server = options[:server] || "https://scoutapp.com/"
|
129
|
+
@history = options[:history] ||
|
130
|
+
File.join( File.join( (File.expand_path("~") rescue "/"),
|
131
|
+
".scout" ),
|
132
|
+
"client_history.yaml" )
|
133
|
+
@verbose = options[:verbose] || false
|
134
|
+
@level = options[:level] || "info"
|
135
|
+
|
136
|
+
@args = args
|
137
|
+
end
|
138
|
+
|
139
|
+
attr_reader :server, :history
|
140
|
+
|
141
|
+
def config_dir
|
142
|
+
return @config_dir if defined? @config_dir
|
143
|
+
@config_dir = File.dirname(history)
|
144
|
+
FileUtils.mkdir_p(@config_dir) # ensure dir exists
|
145
|
+
@config_dir
|
146
|
+
end
|
147
|
+
|
148
|
+
def verbose?
|
149
|
+
@verbose
|
150
|
+
end
|
151
|
+
|
152
|
+
def log
|
153
|
+
return @log if defined? @log
|
154
|
+
@log = if verbose?
|
155
|
+
log = Logger.new($stdout)
|
156
|
+
log.datetime_format = "%Y-%m-%d %H:%M:%S "
|
157
|
+
log.level = level
|
158
|
+
log
|
159
|
+
else
|
160
|
+
nil
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def level
|
165
|
+
Logger.const_get(@level.upcase) rescue Logger::INFO
|
166
|
+
end
|
167
|
+
|
168
|
+
def user
|
169
|
+
@user ||= Command.user
|
170
|
+
end
|
171
|
+
|
172
|
+
def program_name
|
173
|
+
@program_name ||= Command.program_name
|
174
|
+
end
|
175
|
+
|
176
|
+
def program_path
|
177
|
+
@program_path ||= Command.program_path
|
178
|
+
end
|
179
|
+
|
180
|
+
def usage
|
181
|
+
@usage ||= Command.usage
|
182
|
+
end
|
183
|
+
|
184
|
+
def create_pid_file_or_exit
|
185
|
+
pid_file = File.join(config_dir, "scout_client_pid.txt")
|
186
|
+
begin
|
187
|
+
File.open(pid_file, File::CREAT|File::EXCL|File::WRONLY) do |pid|
|
188
|
+
pid.puts $$
|
189
|
+
end
|
190
|
+
at_exit do
|
191
|
+
begin
|
192
|
+
File.unlink(pid_file)
|
193
|
+
rescue
|
194
|
+
log.error "Unable to unlink pid file: #{$!.message}" if log
|
195
|
+
end
|
196
|
+
end
|
197
|
+
rescue
|
198
|
+
pid = File.read(pid_file).strip.to_i rescue "unknown"
|
199
|
+
running = true
|
200
|
+
begin
|
201
|
+
Process.kill(0, pid)
|
202
|
+
rescue Errno::ESRCH
|
203
|
+
running = false
|
204
|
+
rescue
|
205
|
+
# do nothing, we didn't have permission to check the running process
|
206
|
+
end
|
207
|
+
if running
|
208
|
+
log.warn "Process #{pid} was already running" if log
|
209
|
+
exit
|
210
|
+
else
|
211
|
+
log.info "Stale PID file found. Clearing it and reloading..." if log
|
212
|
+
File.unlink(pid_file) rescue nil
|
213
|
+
retry
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
self
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# dynamically load all available commands
|
223
|
+
Dir.glob(File.join(File.dirname(__FILE__), *%w[command *.rb])) do |command|
|
224
|
+
require command
|
225
|
+
end
|
data/lib/scout/plugin.rb
CHANGED
@@ -15,11 +15,107 @@ module Scout
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# Creates a new Scout Plugin to run.
|
18
|
-
#
|
19
18
|
def initialize(last_run, memory, options)
|
20
19
|
@last_run = last_run
|
21
20
|
@memory = memory
|
22
21
|
@options = options
|
23
22
|
end
|
23
|
+
|
24
|
+
def option(name)
|
25
|
+
@options[name] ||
|
26
|
+
@options[name.is_a?(String) ? name.to_sym : String(name)]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Builds the data to send to the server.
|
30
|
+
#
|
31
|
+
# We programatically define several helper methods for creating this data.
|
32
|
+
#
|
33
|
+
# Usage:
|
34
|
+
#
|
35
|
+
# reports << {:data => "here"}
|
36
|
+
# report(:data => "here")
|
37
|
+
# add_report(:data => "here")
|
38
|
+
#
|
39
|
+
# alerts << {:subject => "subject", :body => "body"}
|
40
|
+
# alert("subject", "body")
|
41
|
+
# alert(:subject => "subject", :body => "body")
|
42
|
+
# add_alert("subject", "body")
|
43
|
+
# add_alert(:subject => "subject", :body => "body")
|
44
|
+
#
|
45
|
+
# errors << {:subject => "subject", :body => "body"}
|
46
|
+
# error("subject", "body")
|
47
|
+
# error(:subject => "subject", :body => "body")
|
48
|
+
# add_error("subject", "body")
|
49
|
+
# add_error(:subject => "subject", :body => "body")
|
50
|
+
#
|
51
|
+
def data_for_server
|
52
|
+
@data_for_server ||= { :reports => [ ],
|
53
|
+
:alerts => [ ],
|
54
|
+
:errors => [ ],
|
55
|
+
:memory => { } }
|
56
|
+
end
|
57
|
+
|
58
|
+
%w[report alert error].each do |kind|
|
59
|
+
class_eval <<-END
|
60
|
+
def #{kind}s
|
61
|
+
data_for_server[:#{kind}s]
|
62
|
+
end
|
63
|
+
|
64
|
+
if "#{kind}" == "report"
|
65
|
+
def report(new_entry)
|
66
|
+
reports << new_entry
|
67
|
+
end
|
68
|
+
else
|
69
|
+
def #{kind}(*fields)
|
70
|
+
#{kind}s << ( fields.first.is_a?(Hash) ?
|
71
|
+
fields.first :
|
72
|
+
{:subject => fields.first, :body => fields.last} )
|
73
|
+
end
|
74
|
+
end
|
75
|
+
alias_method :add_#{kind}, :#{kind}
|
76
|
+
END
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Usage:
|
81
|
+
#
|
82
|
+
# memory(:no_track)
|
83
|
+
# memory.delete(:no_track)
|
84
|
+
# memory.clear
|
85
|
+
#
|
86
|
+
def memory(name = nil)
|
87
|
+
if name.nil?
|
88
|
+
data_for_server[:memory]
|
89
|
+
else
|
90
|
+
@memory[name] ||
|
91
|
+
@memory[name.is_a?(String) ? name.to_sym : String(name)]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Usage:
|
97
|
+
#
|
98
|
+
# remember(:name, value)
|
99
|
+
# remember(:name1, value1, :name2, value2)
|
100
|
+
# remember(:name => value)
|
101
|
+
# remember(:name1 => value1, :name2 => value2)
|
102
|
+
# remember(:name1, value1, :name2 => value2)
|
103
|
+
#
|
104
|
+
def remember(*args)
|
105
|
+
hashes, other = args.partition { |value| value.is_a? Hash }
|
106
|
+
hashes.each { |hash| memory.merge!(hash) }
|
107
|
+
(0...other.size).step(2) { |i| memory.merge!(other[i] => other[i + 1]) }
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Old plugins will work because they override this method. New plugins can
|
112
|
+
# now leave this method in place, add a build_report() method instead, and
|
113
|
+
# use the new helper methods to build up content inside which will
|
114
|
+
# automatically be returned as the end result of the run.
|
115
|
+
#
|
116
|
+
def run
|
117
|
+
build_report
|
118
|
+
data_for_server
|
119
|
+
end
|
24
120
|
end
|
25
121
|
end
|
data/lib/scout/server.rb
CHANGED
@@ -14,7 +14,8 @@ module Scout
|
|
14
14
|
URLS = { :plan => "/clients/CLIENT_KEY/plugins.scout?version=CLIENT_VERSION",
|
15
15
|
:report => "/clients/CLIENT_KEY/plugins/PLUGIN_ID/reports.scout?version=CLIENT_VERSION",
|
16
16
|
:error => "/clients/CLIENT_KEY/plugins/PLUGIN_ID/errors.scout?version=CLIENT_VERSION",
|
17
|
-
:alert => "/clients/CLIENT_KEY/plugins/PLUGIN_ID/alerts.scout?version=CLIENT_VERSION"
|
17
|
+
:alert => "/clients/CLIENT_KEY/plugins/PLUGIN_ID/alerts.scout?version=CLIENT_VERSION",
|
18
|
+
:clone => "/clients/CLIENT_KEY/clone_from?version=CLIENT_VERSION" }
|
18
19
|
|
19
20
|
#
|
20
21
|
# A plugin cannot take more than PLUGIN_TIMEOUT seconds to execute,
|
@@ -96,6 +97,7 @@ module Scout
|
|
96
97
|
eval(plugin[:code], TOPLEVEL_BINDING, plugin[:path] || plugin[:name])
|
97
98
|
info "Plugin compiled."
|
98
99
|
rescue Exception
|
100
|
+
raise if $!.is_a? SystemExit
|
99
101
|
error "Plugin would not compile: #{$!.message}"
|
100
102
|
return
|
101
103
|
end
|
@@ -113,6 +115,7 @@ module Scout
|
|
113
115
|
error "Plugin took too long to run."
|
114
116
|
return
|
115
117
|
rescue Exception
|
118
|
+
raise if $!.is_a? SystemExit
|
116
119
|
error "Plugin failed to run: #{$!.backtrace}"
|
117
120
|
end
|
118
121
|
info "Plugin completed its run."
|
@@ -151,6 +154,7 @@ module Scout
|
|
151
154
|
Plugin.last_defined = nil
|
152
155
|
info "Plugin Removed."
|
153
156
|
rescue
|
157
|
+
raise if $!.is_a? SystemExit
|
154
158
|
error "Unable to remove plugin."
|
155
159
|
end
|
156
160
|
end
|
@@ -223,11 +227,28 @@ module Scout
|
|
223
227
|
info "Error sent."
|
224
228
|
end
|
225
229
|
|
230
|
+
def clone_client(new_name, success_output)
|
231
|
+
url = urlify(:clone)
|
232
|
+
debug "Sending clone request to #{url}..."
|
233
|
+
post( url,
|
234
|
+
"Unable to send clone request to server.",
|
235
|
+
"client[name]" => new_name ) do |response|
|
236
|
+
case server_reply = response.body
|
237
|
+
when /\AError:/i
|
238
|
+
fatal "Clone error."
|
239
|
+
abort server_reply
|
240
|
+
else
|
241
|
+
info "Client cloned."
|
242
|
+
puts success_output.gsub(/\bCLIENT_KEY\b/, server_reply.strip)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
226
247
|
private
|
227
248
|
|
228
249
|
def urlify(url_name, options = Hash.new)
|
229
250
|
return unless @server
|
230
|
-
options.merge!(:client_version => Scout::VERSION)
|
251
|
+
options.merge!(:client_version => Scout::VERSION::STRING)
|
231
252
|
URI.join( @server,
|
232
253
|
URLS[url_name].
|
233
254
|
gsub(/\bCLIENT_KEY\b/, @client_key).
|
@@ -278,6 +299,7 @@ module Scout
|
|
278
299
|
fatal "Request timed out."
|
279
300
|
exit
|
280
301
|
rescue Exception
|
302
|
+
raise if $!.is_a? SystemExit
|
281
303
|
fatal "An HTTP error occurred: #{$!.message}"
|
282
304
|
exit
|
283
305
|
end
|
data/lib/scout.rb
CHANGED
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/scout.rb'}"
|
9
|
+
puts "Loading scout gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/script/txt2html
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
GEM_NAME = 'scout' # what ppl will type to install your gem
|
4
|
+
RUBYFORGE_PROJECT = 'scout'
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
begin
|
8
|
+
require 'newgem'
|
9
|
+
require 'rubyforge'
|
10
|
+
rescue LoadError
|
11
|
+
puts "\n\nGenerating the website requires the newgem RubyGem"
|
12
|
+
puts "Install: gem install newgem\n\n"
|
13
|
+
exit(1)
|
14
|
+
end
|
15
|
+
require 'redcloth'
|
16
|
+
require 'syntax/convertors/html'
|
17
|
+
require 'erb'
|
18
|
+
require File.dirname(__FILE__) + "/../lib/#{GEM_NAME}/version.rb"
|
19
|
+
|
20
|
+
version = Scout::VERSION::STRING
|
21
|
+
download = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
22
|
+
|
23
|
+
def rubyforge_project_id
|
24
|
+
RubyForge.new.autoconfig["group_ids"][RUBYFORGE_PROJECT]
|
25
|
+
end
|
26
|
+
|
27
|
+
class Fixnum
|
28
|
+
def ordinal
|
29
|
+
# teens
|
30
|
+
return 'th' if (10..19).include?(self % 100)
|
31
|
+
# others
|
32
|
+
case self % 10
|
33
|
+
when 1: return 'st'
|
34
|
+
when 2: return 'nd'
|
35
|
+
when 3: return 'rd'
|
36
|
+
else return 'th'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Time
|
42
|
+
def pretty
|
43
|
+
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def convert_syntax(syntax, source)
|
48
|
+
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
|
49
|
+
end
|
50
|
+
|
51
|
+
if ARGV.length >= 1
|
52
|
+
src, template = ARGV
|
53
|
+
template ||= File.join(File.dirname(__FILE__), '/../website/template.html.erb')
|
54
|
+
else
|
55
|
+
puts("Usage: #{File.split($0).last} source.txt [template.html.erb] > output.html")
|
56
|
+
exit!
|
57
|
+
end
|
58
|
+
|
59
|
+
template = ERB.new(File.open(template).read)
|
60
|
+
|
61
|
+
title = nil
|
62
|
+
body = nil
|
63
|
+
File.open(src) do |fsrc|
|
64
|
+
title_text = fsrc.readline
|
65
|
+
body_text_template = fsrc.read
|
66
|
+
body_text = ERB.new(body_text_template).result(binding)
|
67
|
+
syntax_items = []
|
68
|
+
body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
|
69
|
+
ident = syntax_items.length
|
70
|
+
element, syntax, source = $1, $2, $3
|
71
|
+
syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
|
72
|
+
"syntax-temp-#{ident}"
|
73
|
+
}
|
74
|
+
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
|
75
|
+
body = RedCloth.new(body_text).to_html
|
76
|
+
body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
|
77
|
+
end
|
78
|
+
stat = File.stat(src)
|
79
|
+
created = stat.ctime
|
80
|
+
modified = stat.mtime
|
81
|
+
|
82
|
+
$stdout << template.result(binding)
|