rack_revision_info 0.3.5

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.
@@ -0,0 +1,77 @@
1
+ module Rack
2
+ class RevisionInfo
3
+ INJECT_ACTIONS = [:after, :before, :append, :prepend, :swap, :inner_html]
4
+
5
+ def initialize(app, opts={})
6
+ @app = app
7
+ path = opts[:path] or raise ArgumentError, "You must specify directory of your local repository!"
8
+ revision, date = get_revision_info(path, opts)
9
+ @revision_info = "#{get_revision_label(opts)} #{revision || 'unknown'}"
10
+ @revision_info << " (#{date.strftime(get_date_format(opts))})" if date
11
+ @action = (opts.keys & INJECT_ACTIONS).first
12
+ if @action
13
+ require ::File.join(::File.dirname(__FILE__), 'rack_revision_info', 'nokogiri_backend')
14
+ @selector = opts[@action]
15
+ @action = :inner_html= if @action == :inner_html
16
+ end
17
+ end
18
+
19
+ def call(env)
20
+ status, headers, body = @app.call(env)
21
+ if headers['Content-Type'].to_s.include?('text/html') && !Rack::Request.new(env).xhr?
22
+ body = body.inject("") { |acc, line| acc + line }
23
+ begin
24
+ if @action
25
+ doc = Nokogiri.parse(body)
26
+ elements = doc.css(@selector)
27
+ if elements.size > 0
28
+ elements.each { |e| e.send(@action, @revision_info) }
29
+ body = doc.to_s
30
+ end
31
+ end
32
+ rescue => e
33
+ puts e
34
+ puts e.backtrace
35
+ end
36
+ body << %(\n<!-- #{@revision_info} -->\n)
37
+ headers["Content-Length"] = body.size.to_s
38
+ body = [body]
39
+ end
40
+ [status, headers, body]
41
+ end
42
+
43
+ protected
44
+
45
+ def get_revision_label(opts={})
46
+ opts[:revision_label] || 'Revision'
47
+ end
48
+
49
+ def get_date_format(opts={})
50
+ opts[:date_format] || "%Y-%m-%d %H:%M:%S %Z"
51
+ end
52
+
53
+ def get_revision_info(path, opts={})
54
+ case detect_type(path)
55
+ when :git
56
+ revision_regex_extra = opts[:short_git_revisions] ? '{8}' : '+'
57
+ info = `cd #{path}; LC_ALL=C git log -1 --pretty=medium`
58
+ revision = info[/commit\s([a-z0-9]#{revision_regex_extra})/, 1]
59
+ date = (d = info[/Date:\s+(.+)$/, 1]) && (DateTime.parse(d) rescue nil)
60
+ when :svn
61
+ info = `cd #{path}; LC_ALL=C svn info`
62
+ revision = info[/Revision:\s(\d+)$/, 1]
63
+ date = (d = info[/Last Changed Date:\s([^\(]+)/, 1]) && (DateTime.parse(d.strip) rescue nil)
64
+ else
65
+ revision, date = nil, nil
66
+ end
67
+ [revision, date]
68
+ end
69
+
70
+ def detect_type(path)
71
+ return :git if ::File.directory?(::File.join(path, ".git"))
72
+ return :svn if ::File.directory?(::File.join(path, ".svn"))
73
+ :unknown
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,14 @@
1
+ require 'nokogiri'
2
+
3
+ # extending Nokogiri with 'append' and 'prepend' methods
4
+
5
+ class Nokogiri::XML::Element
6
+ def append(data)
7
+ self.inner_html = inner_html + data
8
+ end
9
+
10
+ def prepend(data)
11
+ self.inner_html = data + inner_html
12
+ end
13
+ end
14
+
@@ -0,0 +1,111 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'rack/builder'
4
+ require 'rack/mock'
5
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'rack_revision_info.rb')
6
+
7
+ class Rack::RevisionInfo
8
+ DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S %Z"
9
+ def get_revision_info(path, opts={})
10
+ [(opts[:short_git_revisions] ? SHORT_GIT_REV : REV), DATE]
11
+ end
12
+ def get_revision_label(opts={})
13
+ opts[:revision_label] or REV_LABEL
14
+ end
15
+ def get_date_format(opts={})
16
+ opts[:date_format] or DATETIME_FORMAT
17
+ end
18
+ end
19
+
20
+ describe "Rack::RevisionInfo" do
21
+ REV = "a4jf64jf4hff"
22
+ SHORT_GIT_REV = "a4jf64jf"
23
+ REV_LABEL = "Revision"
24
+ DATE = DateTime.now
25
+
26
+ it "should append revision info in html comment" do
27
+ app = Rack::Builder.new do
28
+ use Rack::RevisionInfo, :path => "/some/path/to/repo"
29
+ run lambda { |env| [200, { 'Content-Type' => 'text/html' }, ["<html><head></head><body>Hello, World!</body></html>"]] }
30
+ end
31
+ response = Rack::MockRequest.new(app).get('/')
32
+ response.body.should match(/#{Regexp.escape("<!-- Revision #{REV} (#{DATE.strftime(Rack::RevisionInfo::DATETIME_FORMAT)}) -->")}/m)
33
+ end
34
+
35
+ it "should append customised revision info in html comment" do
36
+ custom_date_format = "%d-%m-%Y %H:%M:%S"
37
+ app = Rack::Builder.new do
38
+ use Rack::RevisionInfo, :path => "/some/path/to/repo", :revision_label => "Rev", :date_format => custom_date_format
39
+ run lambda { |env| [200, { 'Content-Type' => 'text/html' }, ["<html><head></head><body>Hello, World!</body></html>"]] }
40
+ end
41
+ response = Rack::MockRequest.new(app).get('/')
42
+ response.body.should match(/#{Regexp.escape("<!-- Rev #{REV} (#{DATE.strftime(custom_date_format)}) -->")}/)
43
+ end
44
+
45
+ it "should append customised git specific revision info in html comment" do
46
+ custom_date_format = "%d-%m-%Y %H:%M:%S"
47
+ app = Rack::Builder.new do
48
+ use Rack::RevisionInfo, :path => "/some/path/to/repo", :revision_label => "Rev", :date_format => custom_date_format, :short_git_revisions => true
49
+ run lambda { |env| [200, { 'Content-Type' => 'text/html' }, ["<html><head></head><body>Hello, World!</body></html>"]] }
50
+ end
51
+ response = Rack::MockRequest.new(app).get('/')
52
+ response.body.should match(/#{Regexp.escape("<!-- Rev #{SHORT_GIT_REV} (#{DATE.strftime(custom_date_format)}) -->")}/)
53
+ end
54
+
55
+ it "shouldn't append revision info for non-html content-types" do
56
+ app = Rack::Builder.new do
57
+ use Rack::RevisionInfo, :path => "/some/path/to/repo"
58
+ run lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ["Hello, World!"]] }
59
+ end
60
+ response = Rack::MockRequest.new(app).get('/')
61
+ response.body.should_not match(/#{Regexp.escape('<!-- Revision ')}/m)
62
+ end
63
+
64
+ it "shouldn't append revision info for xhr requests" do
65
+ app = Rack::Builder.new do
66
+ use Rack::RevisionInfo, :path => "/some/path/to/repo"
67
+ run lambda { |env| [200, { 'Content-Type' => 'text/html' }, ["<html><head></head><body>Hello, World!</body></html>"]] }
68
+ end
69
+ response = Rack::MockRequest.new(app).get('/', "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest")
70
+ response.body.should_not match(/#{Regexp.escape('<!-- Revision ')}/m)
71
+ end
72
+
73
+ it "should raise exeption when no path given" do
74
+ app = Rack::Builder.new do
75
+ use Rack::RevisionInfo
76
+ run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
77
+ end
78
+ lambda do
79
+ response = Rack::MockRequest.new(app).get('/')
80
+ end.should raise_error(ArgumentError)
81
+ end
82
+
83
+ it "should inject revision info into DOM" do
84
+ Rack::RevisionInfo::INJECT_ACTIONS.each do |action|
85
+ app = Rack::Builder.new do
86
+ use Rack::RevisionInfo, :path => "/some/path/to/repo", action => "#footer"
87
+ run lambda { |env| [200, { 'Content-Type' => 'text/html' }, [%q{<html><head></head><body>Hello, World!<div id="footer">Foota</div></body></html>}]] }
88
+ end
89
+ response = Rack::MockRequest.new(app).get('/')
90
+ response.body.should match(/#{Regexp.escape("Revision #{REV} (#{DATE.strftime(Rack::RevisionInfo::DATETIME_FORMAT)})")}.*#{Regexp.escape("</body>")}/m)
91
+ end
92
+ end
93
+
94
+ it "shouldn't inject revision info into DOM if unknown action" do
95
+ app = Rack::Builder.new do
96
+ use Rack::RevisionInfo, :path => "/some/path/to/repo", :what_what => "#footer"
97
+ run lambda { |env| [200, { 'Content-Type' => 'text/html' }, [%q{<html><head></head><body>Hello, World!<div id="footer">Foota</div></body></html>}]] }
98
+ end
99
+ response = Rack::MockRequest.new(app).get('/')
100
+ response.body.should_not match(/#{Regexp.escape("Revision #{REV} (#{DATE.strftime(Rack::RevisionInfo::DATETIME_FORMAT)})")}.*#{Regexp.escape("</body>")}/m)
101
+ end
102
+
103
+ it "shouldn't escape backslashes" do # hpricot was doing this :|
104
+ app = Rack::Builder.new do
105
+ use Rack::RevisionInfo, :path => "/some/path/to/repo", :inner_html => "#footer"
106
+ run lambda { |env| [200, { 'Content-Type' => 'text/html' }, [%q{<html><head></head><body><input type="text" name="foo" value="\" /><div id="footer">Foota</div></body></html>}]] }
107
+ end
108
+ response = Rack::MockRequest.new(app).get('/')
109
+ response.body.should_not match(/value="\\\\"/m)
110
+ end
111
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack_revision_info
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.5
5
+ platform: ruby
6
+ authors:
7
+ - Marcin Kulik
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-18 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: marcin.kulik@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/rack_revision_info.rb
26
+ - lib/rack_revision_info/nokogiri_backend.rb
27
+ - spec/spec_rack_revision_info.rb
28
+ has_rdoc: true
29
+ homepage: http://sickill.net
30
+ licenses: []
31
+
32
+ post_install_message:
33
+ rdoc_options: []
34
+
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: "0"
42
+ version:
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.3.3
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: Rack middleware showing current git (or svn) revision number of application
56
+ test_files: []
57
+