hawkins 2.0.2 → 2.0.3
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.
- checksums.yaml +4 -4
- data/.travis.yml +9 -0
- data/README.md +15 -0
- data/js/livereload.js +752 -624
- data/lib/hawkins/liveserve.rb +41 -9
- data/lib/hawkins/post.rb +1 -0
- data/lib/hawkins/servlet.rb +12 -19
- data/lib/hawkins/version.rb +1 -1
- data/lib/hawkins/websockets.rb +19 -27
- data/test/test_liveserve.rb +3 -4
- data/test/test_post.rb +3 -1
- metadata +3 -2
data/lib/hawkins/liveserve.rb
CHANGED
@@ -6,8 +6,7 @@ module Hawkins
|
|
6
6
|
class << self
|
7
7
|
COMMAND_OPTIONS = {
|
8
8
|
"swf" => ["--swf", "Use Flash for WebSockets support"],
|
9
|
-
|
10
|
-
"ignore" => ["--ignore [REGEX]", "Files not to reload"],
|
9
|
+
"ignore" => ["--ignore GLOB1[,GLOB2[,...]]", "Files not to reload"],
|
11
10
|
"min_delay" => ["--min-delay [SECONDS]", "Minimum reload delay"],
|
12
11
|
"max_delay" => ["--max-delay [SECONDS]", "Maximum reload delay"],
|
13
12
|
"reload_port" => ["--reload-port [PORT]", Integer, "Port for LiveReload to listen on"],
|
@@ -30,9 +29,7 @@ module Hawkins
|
|
30
29
|
end
|
31
30
|
|
32
31
|
cmd.action do |_, opts|
|
33
|
-
# TODO need to figure out how to set defaults correctly
|
34
32
|
opts["reload_port"] ||= LIVERELOAD_PORT
|
35
|
-
|
36
33
|
opts["serving"] = true
|
37
34
|
opts["watch"] = true unless opts.key?("watch")
|
38
35
|
start(opts)
|
@@ -41,19 +38,22 @@ module Hawkins
|
|
41
38
|
end
|
42
39
|
|
43
40
|
def start(opts)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
@reload_reactor = LiveReloadReactor.new(opts)
|
48
|
-
@reload_reactor.start
|
41
|
+
config = opts["config"]
|
42
|
+
@reload_reactor = nil
|
43
|
+
register_reload_hooks(opts)
|
49
44
|
Jekyll::Commands::Build.process(opts)
|
45
|
+
opts["config"] = config
|
50
46
|
LiveServe.process(opts)
|
51
47
|
end
|
52
48
|
|
53
49
|
def process(opts)
|
50
|
+
opts = configuration_from_options(opts)
|
54
51
|
destination = opts["destination"]
|
55
52
|
setup(destination)
|
56
53
|
|
54
|
+
@running = Queue.new
|
55
|
+
@reload_reactor.start(opts)
|
56
|
+
|
57
57
|
@server = WEBrick::HTTPServer.new(webrick_opts(opts)).tap { |o| o.unmount("") }
|
58
58
|
|
59
59
|
@server.mount("#{opts['baseurl']}/__livereload",
|
@@ -73,6 +73,38 @@ module Hawkins
|
|
73
73
|
@server.shutdown if running?
|
74
74
|
end
|
75
75
|
|
76
|
+
private
|
77
|
+
def register_reload_hooks(opts)
|
78
|
+
require_relative "websockets"
|
79
|
+
@reload_reactor = LiveReloadReactor.new
|
80
|
+
|
81
|
+
Jekyll::Hooks.register(:site, :post_render) do |site|
|
82
|
+
regenerator = Jekyll::Regenerator.new(site)
|
83
|
+
@changed_pages = site.pages.select do |p|
|
84
|
+
regenerator.regenerate?(p)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# A note on ignoring files: LiveReload errs on the side of reloading when it
|
89
|
+
# comes to the message it gets. If, for example, a page is ignored but a CSS
|
90
|
+
# file linked in the page isn't, the page will still be reloaded if the CSS
|
91
|
+
# file is contained in the message sent to LiveReload. Additionally, the
|
92
|
+
# path matching is very loose so that a message to reload "/" will always
|
93
|
+
# lead the page to reload since every page starts with "/".
|
94
|
+
Jekyll::Hooks.register(:site, :post_write) do
|
95
|
+
unless @changed_pages.nil? || !@reload_reactor.running?
|
96
|
+
ignore, @changed_pages = @changed_pages.partition do |p|
|
97
|
+
Array(opts["ignore"]).any? do |filter|
|
98
|
+
File.fnmatch(filter, Jekyll.sanitized_path(p.relative_path))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
Jekyll.logger.debug "LiveReload:", "Ignoring #{ignore.map(&:relative_path)}"
|
102
|
+
@reload_reactor.reload(@changed_pages)
|
103
|
+
end
|
104
|
+
@changed_pages = nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
76
108
|
# Do a base pre-setup of WEBRick so that everything is in place
|
77
109
|
# when we get ready to party, checking for an setting up an error page
|
78
110
|
# and making sure our destination exists.
|
data/lib/hawkins/post.rb
CHANGED
data/lib/hawkins/servlet.rb
CHANGED
@@ -18,7 +18,7 @@ module Hawkins
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def skip_processing?
|
21
|
-
!html? || chunked? || inline? ||
|
21
|
+
!html? || chunked? || inline? || bad_browser?
|
22
22
|
end
|
23
23
|
|
24
24
|
def chunked?
|
@@ -29,11 +29,6 @@ module Hawkins
|
|
29
29
|
@res['Content-Disposition'] =~ %r{^inline}
|
30
30
|
end
|
31
31
|
|
32
|
-
def ignored?
|
33
|
-
path = @req.query_string.nil? ? @req.path_info : "#{@req.path_info}?#{@req.query_string}"
|
34
|
-
@options["ignore"] && @options["ignore"].any? { |filter| path[filter] }
|
35
|
-
end
|
36
|
-
|
37
32
|
def bad_browser?
|
38
33
|
BAD_USER_AGENTS.any? { |pattern| @req['User-Agent'] =~ pattern }
|
39
34
|
end
|
@@ -63,12 +58,17 @@ module Hawkins
|
|
63
58
|
end
|
64
59
|
|
65
60
|
def process!
|
61
|
+
# @body will usually be a File object but Strings occur in rare cases
|
62
|
+
# that occur for reasons unknown to me.
|
66
63
|
@new_body = []
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
64
|
+
if @body.respond_to?(:each)
|
65
|
+
begin
|
66
|
+
@body.each { |line| @new_body << line.to_s }
|
67
|
+
ensure
|
68
|
+
@body.close
|
69
|
+
end
|
70
|
+
else
|
71
|
+
@new_body = @body.lines
|
72
72
|
end
|
73
73
|
|
74
74
|
@content_length = 0
|
@@ -102,19 +102,12 @@ module Hawkins
|
|
102
102
|
<script type="text/javascript" src="<%= @options["baseurl"] %>/__livereload/web_socket.js"></script>
|
103
103
|
<% end %>
|
104
104
|
<script type="text/javascript">
|
105
|
-
|
106
|
-
HAWKINS_LIVERELOAD_PROTOCOL = <%= livereload_protocol %>;
|
105
|
+
document.write('<script src="<%= livereload_source %>"></' + 'script>');
|
107
106
|
</script>
|
108
|
-
<script type="text/javascript" src="<%= livereload_source %>"></script>
|
109
107
|
TEMPLATE
|
110
108
|
ERB.new(Jekyll::Utils.strip_heredoc(template))
|
111
109
|
end
|
112
110
|
|
113
|
-
def livereload_protocol
|
114
|
-
use_ssl = @options["ssl_cert"] && @options["ssl_key"]
|
115
|
-
use_ssl ? '"wss://"' : '"ws://"'
|
116
|
-
end
|
117
|
-
|
118
111
|
def livereload_source
|
119
112
|
use_ssl = @options["ssl_cert"] && @options["ssl_key"]
|
120
113
|
protocol = use_ssl ? "https" : "http"
|
data/lib/hawkins/version.rb
CHANGED
data/lib/hawkins/websockets.rb
CHANGED
@@ -7,19 +7,27 @@ module Hawkins
|
|
7
7
|
# despite the fact that the protocol itself uses WebSockets. This custom connection
|
8
8
|
# class addresses the dual protocols that the server needs to understand.
|
9
9
|
class HttpAwareConnection < EventMachine::WebSocket::Connection
|
10
|
-
attr_reader :
|
10
|
+
attr_reader :reload_body, :reload_size
|
11
11
|
|
12
12
|
def initialize(opts)
|
13
|
+
em_opts = {}
|
13
14
|
@ssl_enabled = opts['ssl_cert'] && opts['ssl_key']
|
14
15
|
if @ssl_enabled
|
15
|
-
|
16
|
+
em_opts[:tls_options] = {
|
16
17
|
:private_key_file => Jekyll.sanitized_path(opts['source'], opts['ssl_key']),
|
17
18
|
:cert_chain_file => Jekyll.sanitized_path(opts['source'], opts['ssl_cert']),
|
18
19
|
}
|
19
|
-
|
20
|
+
em_opts[:secure] = true
|
20
21
|
end
|
21
|
-
|
22
|
-
|
22
|
+
|
23
|
+
# Too noisy even for debug level logging.
|
24
|
+
# em_opts[:debug] = true
|
25
|
+
|
26
|
+
super(em_opts)
|
27
|
+
|
28
|
+
reload_file = File.join(LIVERELOAD_DIR, "livereload.js")
|
29
|
+
@reload_body = File.read(reload_file)
|
30
|
+
@reload_size = File.size(reload_file)
|
23
31
|
end
|
24
32
|
|
25
33
|
def dispatch(data)
|
@@ -33,14 +41,13 @@ module Hawkins
|
|
33
41
|
headers = [
|
34
42
|
'HTTP/1.1 200 OK',
|
35
43
|
'Content-Type: application/javascript',
|
36
|
-
"Content-Length: #{
|
44
|
+
"Content-Length: #{reload_size}",
|
37
45
|
'',
|
38
46
|
'',
|
39
47
|
].join("\r\n")
|
40
48
|
send_data(headers)
|
41
|
-
|
42
|
-
|
43
|
-
end
|
49
|
+
send_data(reload_body)
|
50
|
+
close_connection_after_writing
|
44
51
|
else
|
45
52
|
body = "This port only serves livereload.js over HTTP.\n"
|
46
53
|
headers = [
|
@@ -61,23 +68,22 @@ module Hawkins
|
|
61
68
|
attr_reader :thread
|
62
69
|
attr_reader :opts
|
63
70
|
|
64
|
-
def initialize
|
65
|
-
@opts = opts
|
71
|
+
def initialize
|
66
72
|
@thread = nil
|
67
73
|
@websockets = []
|
68
74
|
@connections_count = 0
|
69
75
|
end
|
70
76
|
|
71
77
|
def stop
|
78
|
+
EM.stop if EM.reactor_running?
|
72
79
|
Jekyll.logger.debug("LiveReload Server:", "halted")
|
73
|
-
@thread.kill unless @thread.nil?
|
74
80
|
end
|
75
81
|
|
76
82
|
def running?
|
77
83
|
!@thread.nil? && @thread.alive?
|
78
84
|
end
|
79
85
|
|
80
|
-
def start
|
86
|
+
def start(opts)
|
81
87
|
@thread = Thread.new do
|
82
88
|
# Use epoll if the kernel supports it
|
83
89
|
EM.epoll
|
@@ -99,22 +105,8 @@ module Hawkins
|
|
99
105
|
end
|
100
106
|
end
|
101
107
|
end
|
102
|
-
|
103
|
-
Jekyll::Hooks.register(:site, :post_render) do |site|
|
104
|
-
regenerator = Jekyll::Regenerator.new(site)
|
105
|
-
@changed_pages = site.pages.select do |p|
|
106
|
-
regenerator.regenerate?(p)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
Jekyll::Hooks.register(:site, :post_write) do
|
111
|
-
reload(@changed_pages) unless @changed_pages.nil?
|
112
|
-
@changed_pages = nil
|
113
|
-
end
|
114
108
|
end
|
115
109
|
|
116
|
-
private
|
117
|
-
|
118
110
|
# For a description of the protocol see http://feedback.livereload.com/knowledgebase/articles/86174-livereload-protocol
|
119
111
|
def reload(pages)
|
120
112
|
pages.each do |p|
|
data/test/test_liveserve.rb
CHANGED
@@ -117,7 +117,8 @@ module Hawkins
|
|
117
117
|
client.ssl_config.add_trust_ca(cert)
|
118
118
|
content = client.get_content(
|
119
119
|
"https://#{opts['host']}:#{opts['port']}/#{opts['baseurl']}/hello.html")
|
120
|
-
expect(content).to include(
|
120
|
+
expect(content).to include(
|
121
|
+
"src=\"https://#{opts['host']}:#{opts['reload_port']}/livereload.js")
|
121
122
|
end
|
122
123
|
|
123
124
|
it "serves nothing else over HTTP on the default LiveReload port" do
|
@@ -131,9 +132,7 @@ module Hawkins
|
|
131
132
|
opts = serve(standard_opts)
|
132
133
|
content = client.get_content(
|
133
134
|
"http://#{opts['host']}:#{opts['port']}/#{opts['baseurl']}/hello.html")
|
134
|
-
expect(content).to include("
|
135
|
-
expect(content).to include('HAWKINS_LIVERELOAD_PROTOCOL = "ws://";')
|
136
|
-
expect(content).to include("livereload.js?snipver=1")
|
135
|
+
expect(content).to include("livereload.js?snipver=1&port=#{opts['livereload_port']}")
|
137
136
|
expect(content).to include("I am a simple web page")
|
138
137
|
end
|
139
138
|
|
data/test/test_post.rb
CHANGED
@@ -37,6 +37,7 @@ module Hawkins
|
|
37
37
|
title = "1999"
|
38
38
|
expected_body = <<-BODY.gsub(/^\s*/, '')
|
39
39
|
---
|
40
|
+
layout: post
|
40
41
|
title: #{title}
|
41
42
|
---
|
42
43
|
BODY
|
@@ -60,6 +61,7 @@ module Hawkins
|
|
60
61
|
title = "Raspberry Beret"
|
61
62
|
expected_body = <<-BODY.gsub(/^\s*/, '')
|
62
63
|
---
|
64
|
+
layout: post
|
63
65
|
title: #{title}
|
64
66
|
---
|
65
67
|
BODY
|
@@ -152,7 +154,7 @@ module Hawkins
|
|
152
154
|
|
153
155
|
%w(xemacs emacs).each do |editor|
|
154
156
|
allow(Commands::Post).to receive(:exec)
|
155
|
-
.with(editor, '+
|
157
|
+
.with(editor, '+4', /#{expected_file}/)
|
156
158
|
.and_return(nil)
|
157
159
|
stub_const("ENV", ENV.to_h.tap { |h| h['VISUAL'] = editor })
|
158
160
|
expect do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hawkins
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Wood
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jekyll
|
@@ -202,6 +202,7 @@ files:
|
|
202
202
|
- ".document"
|
203
203
|
- ".gitignore"
|
204
204
|
- ".rubocop.yml"
|
205
|
+
- ".travis.yml"
|
205
206
|
- Gemfile
|
206
207
|
- LICENSE.txt
|
207
208
|
- README.md
|