deprecation_collector 0.2.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +13 -3
- data/README.md +10 -0
- data/Rakefile +20 -3
- data/deprecation_collector.gemspec +4 -2
- data/gemfiles/rails_6.gemfile +3 -0
- data/gemfiles/rails_6.gemfile.lock +90 -86
- data/gemfiles/rails_7.gemfile +3 -0
- data/gemfiles/rails_7.gemfile.lock +85 -75
- data/gemfiles/rails_none.gemfile +3 -0
- data/gemfiles/rails_none.gemfile.lock +20 -7
- data/lib/deprecation_collector/version.rb +1 -1
- data/lib/deprecation_collector/web/application.rb +94 -0
- data/lib/deprecation_collector/web/helpers.rb +76 -0
- data/lib/deprecation_collector/web/router.rb +206 -0
- data/lib/deprecation_collector/web/utils.rb +52 -0
- data/lib/deprecation_collector/web/views/import.html.template.rb +13 -0
- data/lib/deprecation_collector/web/views/index.html.template.rb +111 -0
- data/lib/deprecation_collector/web/views/layout.html.template.rb +91 -0
- data/lib/deprecation_collector/web/views/show.html.template.rb +13 -0
- data/lib/deprecation_collector/web.rb +40 -0
- data/lib/deprecation_collector.rb +13 -1
- metadata +29 -6
@@ -0,0 +1,206 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DeprecationCollector
|
4
|
+
class Web
|
5
|
+
module Router
|
6
|
+
HTTP_METHODS = %w[GET HEAD POST PUT PATCH DELETE].freeze
|
7
|
+
HTTP_METHODS.each do |http_method|
|
8
|
+
const_set http_method, http_method
|
9
|
+
class_eval <<~RUBY, __FILE__, __LINE__+1
|
10
|
+
def #{http_method.downcase}(path, &block)
|
11
|
+
route(#{http_method}, path, &block)
|
12
|
+
end
|
13
|
+
RUBY
|
14
|
+
end
|
15
|
+
|
16
|
+
def root(&block)
|
17
|
+
route(GET, '/', &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def route(method, path, &block)
|
21
|
+
((@routes ||= {})[method] ||= []) << Route.new(method, path, block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def helpers(mod = nil, &block)
|
25
|
+
return ActionContext.class_eval(&block) if block
|
26
|
+
ActionContext.send(:include, mod)
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
ROUTE_PARAMS = "rack.route_params"
|
31
|
+
PATH_INFO = "PATH_INFO"
|
32
|
+
|
33
|
+
def match(env)
|
34
|
+
request = ::Rack::Request.new(env)
|
35
|
+
request_method = request.request_method
|
36
|
+
request_method = request.params["_method"] if request.params["_method"]
|
37
|
+
|
38
|
+
path_info = ::Rack::Utils.unescape env[PATH_INFO]
|
39
|
+
path_info = "/" if path_info == "" # some buggy servers may pass empty root path
|
40
|
+
|
41
|
+
@routes[request_method.upcase]&.find do |route|
|
42
|
+
params = route.match(request_method, path_info)
|
43
|
+
next unless params
|
44
|
+
env[ROUTE_PARAMS] = params
|
45
|
+
break ActionContext.new(request, &route.block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def call(env, application=nil)
|
50
|
+
action = match(env)
|
51
|
+
unless action
|
52
|
+
return [
|
53
|
+
404,
|
54
|
+
{"content-type" => "text/plain", "x-cascade" => "pass"},
|
55
|
+
["Not Found #{env["REQUEST_METHOD"].inspect} #{env[PATH_INFO].inspect}"]
|
56
|
+
]
|
57
|
+
end
|
58
|
+
|
59
|
+
resp = catch(:halt) do
|
60
|
+
action.call(env, application)
|
61
|
+
ensure
|
62
|
+
end
|
63
|
+
|
64
|
+
return resp if resp.is_a?(Array) # raw rack responses (redirects etc.)
|
65
|
+
|
66
|
+
# rendered content goes here
|
67
|
+
headers = {
|
68
|
+
"content-type" => "text/html",
|
69
|
+
"cache-control" => "private, no-store",
|
70
|
+
# TODO:
|
71
|
+
# "content-language" => action.locale,
|
72
|
+
# "content-security-policy" => CSP_HEADER
|
73
|
+
}
|
74
|
+
# we'll let Rack calculate Content-Length for us.
|
75
|
+
[200, headers, [resp]]
|
76
|
+
end
|
77
|
+
|
78
|
+
class Route
|
79
|
+
attr_accessor :request_method, :pattern, :block
|
80
|
+
|
81
|
+
NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([^.:$\/]+)/
|
82
|
+
|
83
|
+
def initialize(request_method, pattern, block)
|
84
|
+
@request_method = request_method
|
85
|
+
@pattern = pattern
|
86
|
+
@block = block
|
87
|
+
end
|
88
|
+
|
89
|
+
def matcher
|
90
|
+
@matcher ||= compile_matcher
|
91
|
+
end
|
92
|
+
|
93
|
+
def compile_matcher
|
94
|
+
return pattern unless pattern.match?(NAMED_SEGMENTS_PATTERN)
|
95
|
+
regex_pattern = pattern.gsub(NAMED_SEGMENTS_PATTERN, '/\1(?<\2>[^$/]+)') # /some/:id => /some/(?<id>[^$/]+)
|
96
|
+
|
97
|
+
Regexp.new("\\A#{regex_pattern}\\Z")
|
98
|
+
end
|
99
|
+
|
100
|
+
def match(request_method, path)
|
101
|
+
case matcher
|
102
|
+
when String
|
103
|
+
{} if path == matcher
|
104
|
+
else
|
105
|
+
path_match = path.match(matcher)
|
106
|
+
path_match&.named_captures&.transform_keys(&:to_sym)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class ActionContext
|
112
|
+
attr_accessor :request
|
113
|
+
|
114
|
+
def initialize(request, &block)
|
115
|
+
@request = request
|
116
|
+
@block = block
|
117
|
+
end
|
118
|
+
|
119
|
+
def call(env, application)
|
120
|
+
@web = application.web
|
121
|
+
instance_exec(&@block)
|
122
|
+
end
|
123
|
+
|
124
|
+
def env
|
125
|
+
request.env
|
126
|
+
end
|
127
|
+
|
128
|
+
def route_params
|
129
|
+
env[Router::ROUTE_PARAMS]
|
130
|
+
end
|
131
|
+
|
132
|
+
def params
|
133
|
+
@params ||= Hash.new { |hash, key| hash[key.to_s] if Symbol === key }
|
134
|
+
.merge!(request.params)
|
135
|
+
.merge!(route_params.transform_keys(&:to_s))
|
136
|
+
end
|
137
|
+
|
138
|
+
def halt(res, content=nil)
|
139
|
+
throw :halt, [res, {"content-type" => "text/plain"}, [content || res.to_s]]
|
140
|
+
end
|
141
|
+
|
142
|
+
def redirect_to(location)
|
143
|
+
throw :halt, [302, {"location" => "#{request.base_url}#{location}"}, []]
|
144
|
+
end
|
145
|
+
|
146
|
+
def render(plain: nil, html: nil, json: nil, erb: nil, slim: nil, status: 200, locals: nil, layout: 'layout.html.slim')
|
147
|
+
raise ArgumentError, "provide exactly one render format" unless [plain, html, json, erb, slim].compact.size == 1
|
148
|
+
|
149
|
+
if json
|
150
|
+
json = JSON.generate(json) unless json.is_a?(String)
|
151
|
+
return [status, {"content-type" => "application/json"}, [json]]
|
152
|
+
end
|
153
|
+
return [status, {"content-type" => "text/plain"}, [plain.to_s]] if plain
|
154
|
+
|
155
|
+
_define_locals(locals) if locals
|
156
|
+
template = "#{erb}.erb" if erb
|
157
|
+
template = "#{slim}.slim" if slim
|
158
|
+
html = render_template(template) if template
|
159
|
+
html = render_template(layout) { html } if layout
|
160
|
+
|
161
|
+
color_scheme_headers = {
|
162
|
+
'Accept-CH' => 'Sec-CH-Prefers-Color-Scheme',
|
163
|
+
'Vary' => 'Sec-CH-Prefers-Color-Scheme',
|
164
|
+
'Critical-CH' => 'Sec-CH-Prefers-Color-Scheme'
|
165
|
+
}
|
166
|
+
|
167
|
+
return [status, {"content-type" => "text/html"}.merge(color_scheme_headers), [html.to_s]] if html
|
168
|
+
end
|
169
|
+
|
170
|
+
VIEW_PATH = "#{__dir__}/views"
|
171
|
+
|
172
|
+
def render_template(template, &block)
|
173
|
+
original_template_name = File.join(VIEW_PATH, template.to_s)
|
174
|
+
template = template.gsub(/\.slim\z/, '.template.rb')
|
175
|
+
template_method_name = "_template_#{template.gsub(/[^\w]/, '_')}"
|
176
|
+
template_filename = File.join(VIEW_PATH, template.to_s)
|
177
|
+
|
178
|
+
if ENV['DEPRECATION_COLLECTOR_RELOAD_WEB_TEMPLATES']
|
179
|
+
require 'slim'
|
180
|
+
puts "Recompiling #{original_template_name}"
|
181
|
+
ActionContext.class_eval { undef_method(template_method_name) } if respond_to?(template_method_name)
|
182
|
+
if original_template_name.end_with?('.slim')
|
183
|
+
File.write(template_filename, Slim::Template.new(original_template_name).precompiled_template)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
unless respond_to?(template_method_name)
|
188
|
+
src = File.read(template_filename)
|
189
|
+
src = ERB.new(src).src if template_filename.end_with?('.erb')
|
190
|
+
ActionContext.class_eval <<-RUBY, template_filename.gsub(/\.template\.rb\z/, '.slim'), 1
|
191
|
+
def #{template_method_name}; #{src}
|
192
|
+
end
|
193
|
+
RUBY
|
194
|
+
end
|
195
|
+
|
196
|
+
send(template_method_name, &block)
|
197
|
+
end
|
198
|
+
|
199
|
+
private
|
200
|
+
def _define_locals(locals)
|
201
|
+
locals&.each { |k, v| define_singleton_method(k) { v } unless singleton_methods.include?(k) }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
begin
|
3
|
+
require 'cgi/escape'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
module Temple
|
8
|
+
# @api public
|
9
|
+
module Utils
|
10
|
+
extend self
|
11
|
+
|
12
|
+
# Returns an escaped copy of `html`.
|
13
|
+
# Strings which are declared as html_safe are not escaped.
|
14
|
+
#
|
15
|
+
# @param html [String] The string to escape
|
16
|
+
# @return [String] The escaped string
|
17
|
+
def escape_html_safe(html)
|
18
|
+
s = html.to_s
|
19
|
+
s.html_safe? || html.html_safe? ? s : escape_html(s)
|
20
|
+
end
|
21
|
+
|
22
|
+
if defined?(CGI.escapeHTML)
|
23
|
+
# Returns an escaped copy of `html`.
|
24
|
+
#
|
25
|
+
# @param html [String] The string to escape
|
26
|
+
# @return [String] The escaped string
|
27
|
+
def escape_html(html)
|
28
|
+
CGI.escapeHTML(html.to_s)
|
29
|
+
end
|
30
|
+
else
|
31
|
+
# Used by escape_html
|
32
|
+
# @api private
|
33
|
+
ESCAPE_HTML = {
|
34
|
+
'&' => '&',
|
35
|
+
'"' => '"',
|
36
|
+
'\'' => ''',
|
37
|
+
'<' => '<',
|
38
|
+
'>' => '>'
|
39
|
+
}.freeze
|
40
|
+
|
41
|
+
ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys)
|
42
|
+
|
43
|
+
# Returns an escaped copy of `html`.
|
44
|
+
#
|
45
|
+
# @param html [String] The string to escape
|
46
|
+
# @return [String] The escaped string
|
47
|
+
def escape_html(html)
|
48
|
+
html.to_s.gsub(ESCAPE_HTML_PATTERN, ESCAPE_HTML)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
_buf = ''; _buf << ("<header><h1>Import dump</h1></header><main><form".freeze);
|
2
|
+
;
|
3
|
+
;
|
4
|
+
;
|
5
|
+
; _slim_codeattributes1 = import_deprecations_path; if _slim_codeattributes1; if _slim_codeattributes1 == true; _buf << (" action=\"\"".freeze); else; _buf << (" action=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes1))).to_s); _buf << ("\"".freeze); end; end; _buf << (" enctype=\"multipart/form-data\" method=\"post\"><div class=\"mb-3\"><label class=\"form-label\" for=\"file\">Choose a JSON file to upload:</label> <input class=\"form-comtrol\" id=\"file\" name=\"file\" type=\"file\" /></div><div class=\"mb-3\"><button class=\"btn btn-primary\" type=\"submit\">Upload</button> <a class=\"btn btn-secondary\"".freeze);
|
6
|
+
;
|
7
|
+
;
|
8
|
+
;
|
9
|
+
;
|
10
|
+
;
|
11
|
+
; _slim_codeattributes2 = dump_deprecations_path; if _slim_codeattributes2; if _slim_codeattributes2 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes2))).to_s); _buf << ("\"".freeze); end; end; _buf << (">Dump</a> <a class=\"btn btn-secondary\"".freeze);
|
12
|
+
; _slim_codeattributes3 = deprecations_path; if _slim_codeattributes3; if _slim_codeattributes3 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes3))).to_s); _buf << ("\"".freeze); end; end; _buf << (">Back</a> </div></form></main>".freeze);
|
13
|
+
; _buf
|
@@ -0,0 +1,111 @@
|
|
1
|
+
_buf = ''; _buf << ("<header class=\"mb-3\"><h1>Deprecations</h1><a class=\"btn btn-primary\" data-method=\"post\"".freeze);
|
2
|
+
;
|
3
|
+
;
|
4
|
+
; _slim_codeattributes1 = deprecation_path(:trigger); if _slim_codeattributes1; if _slim_codeattributes1 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes1))).to_s); _buf << ("\"".freeze); end; end; _buf << (" rel=\"nofollow\">Trigger a couple</a> <a class=\"btn btn-danger\" data-confirm=\"Sure?\" data-method=\"delete\"".freeze);
|
5
|
+
; _slim_codeattributes2 = deprecation_path(:all); if _slim_codeattributes2; if _slim_codeattributes2 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes2))).to_s); _buf << ("\"".freeze); end; end; _buf << (" rel=\"nofollow\"><i class=\"bi bi-trash\"></i>Delete all </a> ".freeze);
|
6
|
+
;
|
7
|
+
;
|
8
|
+
;
|
9
|
+
; if DeprecationCollector.instance.enabled_in_redis?;
|
10
|
+
;
|
11
|
+
;
|
12
|
+
;
|
13
|
+
; _buf << ("<a class=\"btn btn-danger\" data-confirm=\"Sure? Will need to restart workers after enabling\" data-method=\"delete\"".freeze); _slim_codeattributes3 = disable_deprecations_path; if _slim_codeattributes3; if _slim_codeattributes3 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes3))).to_s); _buf << ("\"".freeze); end; end; _buf << (" rel=\"nofollow\">Disable</a> ".freeze);
|
14
|
+
; else;
|
15
|
+
;
|
16
|
+
;
|
17
|
+
; _buf << ("<a class=\"btn btn-secondary\" data-method=\"post\"".freeze); _slim_codeattributes4 = enable_deprecations_path; if _slim_codeattributes4; if _slim_codeattributes4 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes4))).to_s); _buf << ("\"".freeze); end; end; _buf << (" rel=\"nofollow\">Turn on (after workers restart)</a> ".freeze);
|
18
|
+
;
|
19
|
+
; end; _buf << ("</header><main><table class=\"table table-striped\"><tr><th>Count</th><th>Message</th><th>Location</th><th>Ruby/Rails</th></tr>".freeze);
|
20
|
+
;
|
21
|
+
;
|
22
|
+
;
|
23
|
+
;
|
24
|
+
;
|
25
|
+
;
|
26
|
+
;
|
27
|
+
; total = 0;
|
28
|
+
; @deprecations.each do |deprecation|;
|
29
|
+
; total += 1;
|
30
|
+
; _buf << ("<tr".freeze); _slim_codeattributes5 = deprecation[:digest]; if _slim_codeattributes5; if _slim_codeattributes5 == true; _buf << (" data-digest=\"\"".freeze); else; _buf << (" data-digest=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes5))).to_s); _buf << ("\"".freeze); end; end; _buf << ("><td><a".freeze);
|
31
|
+
;
|
32
|
+
; _slim_codeattributes6 = deprecation_path(deprecation[:digest]); if _slim_codeattributes6; if _slim_codeattributes6 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes6))).to_s); _buf << ("\"".freeze); end; end; _buf << (">".freeze); _buf << ((::Temple::Utils.escape_html((deprecation[:count]))).to_s);
|
33
|
+
; _buf << ("</a><br />".freeze);
|
34
|
+
; deprecation_tags(deprecation).each_pair do |tag, cls|;
|
35
|
+
; _buf << ("<div".freeze); _temple_html_attributeremover1 = ''; _temple_html_attributemerger1 = []; _temple_html_attributemerger1[0] = "badge"; _temple_html_attributemerger1[1] = ''; _slim_codeattributes7 = cls; if Array === _slim_codeattributes7; _slim_codeattributes7 = _slim_codeattributes7.flatten; _slim_codeattributes7.map!(&:to_s); _slim_codeattributes7.reject!(&:empty?); _temple_html_attributemerger1[1] << ((::Temple::Utils.escape_html((_slim_codeattributes7.join(" ")))).to_s); else; _temple_html_attributemerger1[1] << ((::Temple::Utils.escape_html((_slim_codeattributes7))).to_s); end; _temple_html_attributemerger1[1]; _temple_html_attributeremover1 << ((_temple_html_attributemerger1.reject(&:empty?).join(" ")).to_s); _temple_html_attributeremover1; if !_temple_html_attributeremover1.empty?; _buf << (" class=\"".freeze); _buf << ((_temple_html_attributeremover1).to_s); _buf << ("\"".freeze); end; _buf << (">".freeze); _buf << ((::Temple::Utils.escape_html((tag))).to_s);
|
36
|
+
;
|
37
|
+
; _buf << ("</div> ".freeze); end; _buf << ("</td><td>".freeze);
|
38
|
+
;
|
39
|
+
; msg = deprecation[:message]
|
40
|
+
delete_prefixes = Gem.path + [defined?(Rails) && Rails.root.to_s].compact
|
41
|
+
delete_prefixes.each { |path| msg.gsub!(path, '') }
|
42
|
+
msg.delete_prefix! deprecation[:gem_traceline].gsub(/:in .+/, ':') if deprecation[:gem_traceline]
|
43
|
+
msg.delete_prefix! deprecation[:app_traceline].gsub(/:in .+/, ':') if deprecation[:app_traceline]
|
44
|
+
msg.strip!
|
45
|
+
msg.delete_prefix!("DEPRECATION WARNING: ")
|
46
|
+
msg.delete_prefix!("warning: ")
|
47
|
+
;
|
48
|
+
; if msg.lines.size > 2;
|
49
|
+
; _buf << ("<pre class=\"pre-scrollable p-1\" style=\"overflow: auto; max-width: 700px; max-height: 200px; font-size: 11px\"><code>".freeze);
|
50
|
+
; _buf << ((::Temple::Utils.escape_html((msg))).to_s);
|
51
|
+
; _buf << ("</code></pre>".freeze); else;
|
52
|
+
; _buf << ("<div class=\"small\">".freeze); _buf << ((::Temple::Utils.escape_html((msg))).to_s);
|
53
|
+
; _buf << ("</div>".freeze); end; if deprecation.dig(:notes, :comment);
|
54
|
+
; _buf << ((::Temple::Utils.escape_html((deprecation.dig(:notes, :comment)))).to_s);
|
55
|
+
;
|
56
|
+
; end; if deprecation.dig(:context, :action);
|
57
|
+
; _buf << ("<div class=\"small controller\">".freeze); _buf << ((::Temple::Utils.escape_html((deprecation.dig(:context, :action)))).to_s);
|
58
|
+
; _buf << ("</div>".freeze); elsif deprecation.dig(:context, :params, :controller);
|
59
|
+
; _buf << ("<div class=\"small controller\">".freeze); _buf << ((::Temple::Utils.escape_html((deprecation.dig(:context, :params).slice(:controller, :action).values.join('#')))).to_s);
|
60
|
+
;
|
61
|
+
; _buf << ("</div>".freeze); end; _buf << ("</td><td class=\"small\">".freeze);
|
62
|
+
; if deprecation[:gem_traceline];
|
63
|
+
; _buf << ("<div class=\"gem_location\">".freeze);
|
64
|
+
; location, function = deprecation[:gem_traceline].split(':in `', 2);
|
65
|
+
; full_gemname = location.delete_prefix('/gems/').gsub(%r{/.*}, '');
|
66
|
+
; location_in_gem = location.delete_prefix("/gems/#{full_gemname}/");
|
67
|
+
; _buf << ("<i>".freeze); _buf << ((::Temple::Utils.escape_html((full_gemname))).to_s);
|
68
|
+
; _buf << ("</i> <code class=\"code_location\"".freeze); _slim_codeattributes8 = location_in_gem; if _slim_codeattributes8; if _slim_codeattributes8 == true; _buf << (" data-copy-value=\"\"".freeze); else; _buf << (" data-copy-value=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes8))).to_s); _buf << ("\"".freeze); end; end; _buf << (">".freeze); _buf << ((::Temple::Utils.escape_html((location_in_gem.delete_prefix('lib/')))).to_s);
|
69
|
+
; _buf << ("</code> <i>".freeze); _buf << ((::Temple::Utils.escape_html((function.delete_suffix("'")))).to_s);
|
70
|
+
; _buf << ("</i></div>".freeze); end; if deprecation[:app_traceline];
|
71
|
+
; _buf << ("<div class=\"app_location\">".freeze);
|
72
|
+
; location, function = deprecation[:app_traceline].split(':in `', 2);
|
73
|
+
; _buf << ("<code class=\"code_location\">".freeze); _buf << ((::Temple::Utils.escape_html((location))).to_s);
|
74
|
+
; _buf << ("</code> <i>".freeze); _buf << ((::Temple::Utils.escape_html((function.delete_suffix("'")))).to_s);
|
75
|
+
; _buf << ("</i></div>".freeze); end; _buf << ("</td><td><div class=\"small ruby\">".freeze);
|
76
|
+
; _buf << ((::Temple::Utils.escape_html((deprecation[:ruby_version]))).to_s);
|
77
|
+
; _buf << ("</div><div class=\"small rails\">".freeze); _buf << ((::Temple::Utils.escape_html((deprecation[:rails_version]))).to_s);
|
78
|
+
;
|
79
|
+
; _buf << ("</div><a data-confirm=\"Delete?\" data-method=\"delete\"".freeze); _slim_codeattributes9 = deprecation_path(deprecation[:digest]); if _slim_codeattributes9; if _slim_codeattributes9 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes9))).to_s); _buf << ("\"".freeze); end; end; _buf << (" rel=\"nofollow\" title=\"Delete\"><i class=\"bi bi-trash\"></i></a></td></tr>".freeze);
|
80
|
+
;
|
81
|
+
; end; if total.zero?;
|
82
|
+
; _buf << ("<tr><td".freeze);
|
83
|
+
; _slim_codeattributes10 = 4; if _slim_codeattributes10; if _slim_codeattributes10 == true; _buf << (" colspan=\"\"".freeze); else; _buf << (" colspan=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes10))).to_s); _buf << ("\"".freeze); end; end; _buf << ("><p>Looks like there're no deprecations (or workers have not yet wrote to redis)</p><p>You can try <a data-method=\"post\"".freeze);
|
84
|
+
;
|
85
|
+
;
|
86
|
+
;
|
87
|
+
; _slim_codeattributes11 = deprecation_path(:trigger); if _slim_codeattributes11; if _slim_codeattributes11 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes11))).to_s); _buf << ("\"".freeze); end; end; _buf << (" rel=\"nofollow\">trigger a couple</a>".freeze);
|
88
|
+
; if import_enabled?;
|
89
|
+
; _buf << (", or <a".freeze);
|
90
|
+
; _slim_codeattributes12 = import_deprecations_path; if _slim_codeattributes12; if _slim_codeattributes12 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes12))).to_s); _buf << ("\"".freeze); end; end; _buf << (">import</a> ".freeze);
|
91
|
+
;
|
92
|
+
;
|
93
|
+
; end; _buf << ("</p></td></tr>".freeze); end; _buf << ("</table></main><footer>".freeze);
|
94
|
+
; if total > 3;
|
95
|
+
; _buf << ((::Temple::Utils.escape_html((total))).to_s);
|
96
|
+
; _buf << (" deprecations ".freeze);
|
97
|
+
; end; _buf << ("</footer><style>.code_location {\n cursor: pointer;\n}</style><script>document.querySelectorAll('.code_location').forEach(function(elem){\n elem.addEventListener('click', function () {\n let textToCopy = elem.getAttribute('data-copy-value');\n if(!textToCopy) textToCopy = elem.innerText;\n console.log(\"Copying\", textToCopy)\n navigator.clipboard.writeText(textToCopy);\n }, false);\n});</script>".freeze);
|
98
|
+
;
|
99
|
+
;
|
100
|
+
;
|
101
|
+
;
|
102
|
+
;
|
103
|
+
;
|
104
|
+
;
|
105
|
+
;
|
106
|
+
;
|
107
|
+
;
|
108
|
+
;
|
109
|
+
;
|
110
|
+
;
|
111
|
+
; _buf
|
@@ -0,0 +1,91 @@
|
|
1
|
+
_buf = ''; _buf << ("<!DOCTYPE html><html".freeze);
|
2
|
+
; _slim_codeattributes1 = current_color_theme; if _slim_codeattributes1; if _slim_codeattributes1 == true; _buf << (" data-bs-theme=\"\"".freeze); else; _buf << (" data-bs-theme=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes1))).to_s); _buf << ("\"".freeze); end; end; _buf << (" lang=\"en\"><head><meta charset=\"utf-8\" /><meta content=\"IE=edge;chrome=1\" http-equiv=\"X-UA-Compatible\" /><title>".freeze);
|
3
|
+
;
|
4
|
+
;
|
5
|
+
;
|
6
|
+
;
|
7
|
+
; _buf << ((::Temple::Utils.escape_html(("Deprecations"))).to_s);
|
8
|
+
; _buf << ("</title><meta content=\"Deprecation collector ui\" name=\"description\" /><meta content=\"width=device-width\" name=\"viewport\" /><link crossorigin=\"anonymous\" href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css\" integrity=\"sha256-Fu5/PVNGJlC70y4mPEjA6nWVdPz2IMaBrXGQCJEsRho= sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ\" rel=\"stylesheet\" /><link crossorigin=\"anonymous\" href=\"https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css\" integrity=\"sha256-4RctOgogjPAdwGbwq+rxfwAmSpZhWaafcZR9btzUk18= sha384-b6lVK+yci+bfDmaY1u0zE8YYJt0TZxLEAFyYSLHId4xoVvsrQu3INevFKo+Xir8e\" rel=\"stylesheet\" /></head><body><div class=\"container-fluid\">".freeze);
|
9
|
+
;
|
10
|
+
;
|
11
|
+
;
|
12
|
+
;
|
13
|
+
;
|
14
|
+
;
|
15
|
+
; _buf << ((yield).to_s);
|
16
|
+
;
|
17
|
+
; _buf << ("</div><script async=\"\" crossorigin=\"anonymous\" integrity=\"sha256-9Mbe9mGA7d+AJbnz0O6CoLGabCbe6JAYnGshvGIADiE=\" src=\"https://cdn.jsdelivr.net/npm/@rails/ujs@7.0.4-3/lib/assets/compiled/rails-ujs.js\"></script><script async=\"\" crossorigin=\"anonymous\" integrity=\"sha256-QucgBAKNM4KKPJHqTfH8e+JON1G/gmPPqtMmBb+wHpc= sha384-Y4oOpwW3duJdCWv5ly8SCFYWqFDsfob/3GkgExXKV4idmbt98QcxXYs9UoXAB7BZ\" src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.min.js\"></script><script>(() => {\n 'use strict'\n\n const storedTheme = localStorage.getItem('theme')\n\n const getPreferredTheme = () => {\n if (storedTheme) { return storedTheme }\n let fromServer = document.documentElement.getAttribute('data-bs-theme')\n if(fromServer) { return fromServer }\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n }\n\n const setTheme = function (theme) {\n if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {\n document.documentElement.setAttribute('data-bs-theme', 'dark')\n } else {\n document.documentElement.setAttribute('data-bs-theme', theme)\n }\n }\n\n setTheme(getPreferredTheme())\n\n const showActiveTheme = (theme, focus = false) => {\n const themeSwitcher = document.querySelector('#bd-theme')\n\n if (!themeSwitcher) {\n return\n }\n\n const themeSwitcherText = document.querySelector('#bd-theme-text')\n const activeThemeIcon = document.querySelector('.theme-icon-active use')\n const btnToActive = document.querySelector(`[data-bs-theme-value=\"${theme}\"]`)\n const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')\n\n document.querySelectorAll('[data-bs-theme-value]').forEach(element => {\n element.classList.remove('active')\n element.setAttribute('aria-pressed', 'false')\n })\n\n btnToActive.classList.add('active')\n btnToActive.setAttribute('aria-pressed', 'true')\n activeThemeIcon.setAttribute('href', svgOfActiveBtn)\n const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`\n themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)\n\n if (focus) {\n themeSwitcher.focus()\n }\n }\n\n window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {\n if (storedTheme !== 'light' || storedTheme !== 'dark') {\n setTheme(getPreferredTheme())\n }\n })\n\n window.addEventListener('DOMContentLoaded', () => {\n showActiveTheme(getPreferredTheme())\n\n document.querySelectorAll('[data-bs-theme-value]')\n .forEach(toggle => {\n toggle.addEventListener('click', () => {\n const theme = toggle.getAttribute('data-bs-theme-value')\n localStorage.setItem('theme', theme)\n setTheme(theme)\n showActiveTheme(theme, true)\n })\n })\n })\n})()</script></body></html>".freeze);
|
18
|
+
;
|
19
|
+
;
|
20
|
+
;
|
21
|
+
;
|
22
|
+
;
|
23
|
+
;
|
24
|
+
;
|
25
|
+
;
|
26
|
+
;
|
27
|
+
;
|
28
|
+
;
|
29
|
+
;
|
30
|
+
;
|
31
|
+
;
|
32
|
+
;
|
33
|
+
;
|
34
|
+
;
|
35
|
+
;
|
36
|
+
;
|
37
|
+
;
|
38
|
+
;
|
39
|
+
;
|
40
|
+
;
|
41
|
+
;
|
42
|
+
;
|
43
|
+
;
|
44
|
+
;
|
45
|
+
;
|
46
|
+
;
|
47
|
+
;
|
48
|
+
;
|
49
|
+
;
|
50
|
+
;
|
51
|
+
;
|
52
|
+
;
|
53
|
+
;
|
54
|
+
;
|
55
|
+
;
|
56
|
+
;
|
57
|
+
;
|
58
|
+
;
|
59
|
+
;
|
60
|
+
;
|
61
|
+
;
|
62
|
+
;
|
63
|
+
;
|
64
|
+
;
|
65
|
+
;
|
66
|
+
;
|
67
|
+
;
|
68
|
+
;
|
69
|
+
;
|
70
|
+
;
|
71
|
+
;
|
72
|
+
;
|
73
|
+
;
|
74
|
+
;
|
75
|
+
;
|
76
|
+
;
|
77
|
+
;
|
78
|
+
;
|
79
|
+
;
|
80
|
+
;
|
81
|
+
;
|
82
|
+
;
|
83
|
+
;
|
84
|
+
;
|
85
|
+
;
|
86
|
+
;
|
87
|
+
;
|
88
|
+
;
|
89
|
+
;
|
90
|
+
;
|
91
|
+
; _buf
|
@@ -0,0 +1,13 @@
|
|
1
|
+
_buf = ''; _buf << ("<header class=\"mb-3\"><h1>Deprecation</h1><a class=\"btn btn-secondary\"".freeze);
|
2
|
+
;
|
3
|
+
;
|
4
|
+
; _slim_codeattributes1 = deprecations_path; if _slim_codeattributes1; if _slim_codeattributes1 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes1))).to_s); _buf << ("\"".freeze); end; end; _buf << (">Back</a> <a class=\"btn btn-danger\" data-confirm=\"Delete?\" data-method=\"delete\"".freeze);
|
5
|
+
; _slim_codeattributes2 = deprecation_path(@deprecation[:digest]); if _slim_codeattributes2; if _slim_codeattributes2 == true; _buf << (" href=\"\"".freeze); else; _buf << (" href=\"".freeze); _buf << ((::Temple::Utils.escape_html((_slim_codeattributes2))).to_s); _buf << ("\"".freeze); end; end; _buf << (" rel=\"nofollow\" title=\"Delete\"><span class=\"glyphicon glyphicon-trash insalesicon-trash\"></span>Delete</a> </header><main><div class=\"card p-3\"><pre><code>".freeze);
|
6
|
+
;
|
7
|
+
;
|
8
|
+
;
|
9
|
+
;
|
10
|
+
;
|
11
|
+
;
|
12
|
+
; _buf << ((::Temple::Utils.escape_html((@deprecation.pretty_inspect))).to_s);
|
13
|
+
; _buf << ("</code></pre></div></main>".freeze); _buf
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
require "rack/content_length"
|
5
|
+
require "rack/builder"
|
6
|
+
|
7
|
+
require_relative 'web/application'
|
8
|
+
|
9
|
+
class DeprecationCollector
|
10
|
+
class Web
|
11
|
+
attr_accessor :import_enabled
|
12
|
+
|
13
|
+
def initialize(import_enabled: nil)
|
14
|
+
@import_enabled = import_enabled
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.call(env)
|
18
|
+
@app ||= new
|
19
|
+
@app.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
app.call(env)
|
24
|
+
end
|
25
|
+
|
26
|
+
def app
|
27
|
+
@app ||= build
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def build
|
32
|
+
web = self
|
33
|
+
::Rack::Builder.new do
|
34
|
+
# use Rack::Static etc goes here
|
35
|
+
|
36
|
+
run Web::Application.new(web)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -183,7 +183,19 @@ class DeprecationCollector
|
|
183
183
|
end
|
184
184
|
|
185
185
|
def dump
|
186
|
-
read_each.to_a.to_json
|
186
|
+
read_each.to_a.compact.to_json
|
187
|
+
end
|
188
|
+
|
189
|
+
def import_dump(json)
|
190
|
+
dump = JSON.parse(json)
|
191
|
+
# TODO: some checks
|
192
|
+
|
193
|
+
digests = dump.map { |dep| dep["digest"] }
|
194
|
+
raise 'need digests' unless digests.none?(&:nil?)
|
195
|
+
|
196
|
+
dump_hash = dump.map { |dep| [dep.delete('digest'), dep] }.to_h
|
197
|
+
|
198
|
+
@redis.mapped_hmset("deprecations:data", dump_hash.transform_values(&:to_json))
|
187
199
|
end
|
188
200
|
|
189
201
|
def read_each
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deprecation_collector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vasily Fedoseyev
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rack-test
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: Collects and aggregates warnings and deprecations. Optimized for production
|
42
56
|
environment.
|
43
57
|
email:
|
@@ -67,6 +81,15 @@ files:
|
|
67
81
|
- lib/deprecation_collector/collectors.rb
|
68
82
|
- lib/deprecation_collector/deprecation.rb
|
69
83
|
- lib/deprecation_collector/version.rb
|
84
|
+
- lib/deprecation_collector/web.rb
|
85
|
+
- lib/deprecation_collector/web/application.rb
|
86
|
+
- lib/deprecation_collector/web/helpers.rb
|
87
|
+
- lib/deprecation_collector/web/router.rb
|
88
|
+
- lib/deprecation_collector/web/utils.rb
|
89
|
+
- lib/deprecation_collector/web/views/import.html.template.rb
|
90
|
+
- lib/deprecation_collector/web/views/index.html.template.rb
|
91
|
+
- lib/deprecation_collector/web/views/layout.html.template.rb
|
92
|
+
- lib/deprecation_collector/web/views/show.html.template.rb
|
70
93
|
- sig/deprecation_collector.rbs
|
71
94
|
homepage: https://github.com/Vasfed/deprecation_collector
|
72
95
|
licenses:
|
@@ -75,7 +98,7 @@ metadata:
|
|
75
98
|
homepage_uri: https://github.com/Vasfed/deprecation_collector
|
76
99
|
source_code_uri: https://github.com/Vasfed/deprecation_collector
|
77
100
|
changelog_uri: https://github.com/Vasfed/deprecation_collector/blob/main/CHANGELOG.md
|
78
|
-
post_install_message:
|
101
|
+
post_install_message:
|
79
102
|
rdoc_options: []
|
80
103
|
require_paths:
|
81
104
|
- lib
|
@@ -90,8 +113,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
113
|
- !ruby/object:Gem::Version
|
91
114
|
version: '0'
|
92
115
|
requirements: []
|
93
|
-
rubygems_version: 3.
|
94
|
-
signing_key:
|
116
|
+
rubygems_version: 3.1.6
|
117
|
+
signing_key:
|
95
118
|
specification_version: 4
|
96
119
|
summary: Collector for ruby/rails deprecations and warnings, suitable for production
|
97
120
|
test_files: []
|