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.
@@ -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
+ '&' => '&amp;',
35
+ '"' => '&quot;',
36
+ '\'' => '&#39;',
37
+ '<' => '&lt;',
38
+ '>' => '&gt;'
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.2.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-01-17 00:00:00.000000000 Z
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.4.1
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: []