sigterm_extensions 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +6 -0
- data/LICENSE.md +0 -0
- data/README.md +0 -0
- data/bin/ctxirb +156 -0
- data/lib/git.rb +166 -0
- data/lib/git/LICENSE +21 -0
- data/lib/git/author.rb +14 -0
- data/lib/git/base.rb +551 -0
- data/lib/git/base/factory.rb +75 -0
- data/lib/git/branch.rb +126 -0
- data/lib/git/branches.rb +71 -0
- data/lib/git/config.rb +22 -0
- data/lib/git/diff.rb +159 -0
- data/lib/git/index.rb +5 -0
- data/lib/git/lib.rb +1041 -0
- data/lib/git/log.rb +128 -0
- data/lib/git/object.rb +312 -0
- data/lib/git/path.rb +31 -0
- data/lib/git/remote.rb +36 -0
- data/lib/git/repository.rb +6 -0
- data/lib/git/stash.rb +27 -0
- data/lib/git/stashes.rb +55 -0
- data/lib/git/status.rb +199 -0
- data/lib/git/version.rb +5 -0
- data/lib/git/working_directory.rb +4 -0
- data/lib/sigterm_extensions.rb +75 -0
- data/lib/sigterm_extensions/all.rb +12 -0
- data/lib/sigterm_extensions/backtrace_cleaner.rb +129 -0
- data/lib/sigterm_extensions/callbacks.rb +847 -0
- data/lib/sigterm_extensions/concern.rb +169 -0
- data/lib/sigterm_extensions/configurable.rb +38 -0
- data/lib/sigterm_extensions/core_ext.rb +4 -0
- data/lib/sigterm_extensions/core_ext/array.rb +3 -0
- data/lib/sigterm_extensions/core_ext/array/extract.rb +19 -0
- data/lib/sigterm_extensions/core_ext/array/extract_options.rb +29 -0
- data/lib/sigterm_extensions/core_ext/class.rb +3 -0
- data/lib/sigterm_extensions/core_ext/class/attribute.rb +139 -0
- data/lib/sigterm_extensions/core_ext/class/attribute_accessors.rb +4 -0
- data/lib/sigterm_extensions/core_ext/class/subclasses.rb +52 -0
- data/lib/sigterm_extensions/core_ext/custom.rb +12 -0
- data/lib/sigterm_extensions/core_ext/digest.rb +3 -0
- data/lib/sigterm_extensions/core_ext/digest/uuid.rb +51 -0
- data/lib/sigterm_extensions/core_ext/enumerable.rb +232 -0
- data/lib/sigterm_extensions/core_ext/file.rb +3 -0
- data/lib/sigterm_extensions/core_ext/file/atomic.rb +68 -0
- data/lib/sigterm_extensions/core_ext/hash.rb +3 -0
- data/lib/sigterm_extensions/core_ext/hash/deep_merge.rb +41 -0
- data/lib/sigterm_extensions/core_ext/hash/deep_transform_values.rb +44 -0
- data/lib/sigterm_extensions/core_ext/hash/except.rb +22 -0
- data/lib/sigterm_extensions/core_ext/hash/keys.rb +141 -0
- data/lib/sigterm_extensions/core_ext/hash/reverse_merge.rb +23 -0
- data/lib/sigterm_extensions/core_ext/hash/slice.rb +24 -0
- data/lib/sigterm_extensions/core_ext/kernel.rb +3 -0
- data/lib/sigterm_extensions/core_ext/kernel/concern.rb +12 -0
- data/lib/sigterm_extensions/core_ext/kernel/reporting.rb +43 -0
- data/lib/sigterm_extensions/core_ext/kernel/singleton_class.rb +6 -0
- data/lib/sigterm_extensions/core_ext/load_error.rb +7 -0
- data/lib/sigterm_extensions/core_ext/module.rb +3 -0
- data/lib/sigterm_extensions/core_ext/module/aliasing.rb +29 -0
- data/lib/sigterm_extensions/core_ext/module/anonymous.rb +28 -0
- data/lib/sigterm_extensions/core_ext/module/attr_internal.rb +36 -0
- data/lib/sigterm_extensions/core_ext/module/attribute_accessors.rb +208 -0
- data/lib/sigterm_extensions/core_ext/module/attribute_accessors_per_thread.rb +146 -0
- data/lib/sigterm_extensions/core_ext/module/concerning.rb +132 -0
- data/lib/sigterm_extensions/core_ext/module/delegation.rb +319 -0
- data/lib/sigterm_extensions/core_ext/module/redefine_method.rb +38 -0
- data/lib/sigterm_extensions/core_ext/module/remove_method.rb +15 -0
- data/lib/sigterm_extensions/core_ext/name_error.rb +36 -0
- data/lib/sigterm_extensions/core_ext/object.rb +3 -0
- data/lib/sigterm_extensions/core_ext/object/blank.rb +153 -0
- data/lib/sigterm_extensions/core_ext/object/colors.rb +39 -0
- data/lib/sigterm_extensions/core_ext/object/duplicable.rb +47 -0
- data/lib/sigterm_extensions/core_ext/object/inclusion.rb +27 -0
- data/lib/sigterm_extensions/core_ext/object/instance_variables.rb +28 -0
- data/lib/sigterm_extensions/core_ext/object/methods.rb +61 -0
- data/lib/sigterm_extensions/core_ext/object/with_options.rb +80 -0
- data/lib/sigterm_extensions/core_ext/range.rb +3 -0
- data/lib/sigterm_extensions/core_ext/range/compare_range.rb +74 -0
- data/lib/sigterm_extensions/core_ext/range/conversions.rb +39 -0
- data/lib/sigterm_extensions/core_ext/range/overlaps.rb +8 -0
- data/lib/sigterm_extensions/core_ext/securerandom.rb +43 -0
- data/lib/sigterm_extensions/core_ext/string.rb +3 -0
- data/lib/sigterm_extensions/core_ext/string/access.rb +93 -0
- data/lib/sigterm_extensions/core_ext/string/filters.rb +143 -0
- data/lib/sigterm_extensions/core_ext/string/starts_ends_with.rb +4 -0
- data/lib/sigterm_extensions/core_ext/string/strip.rb +25 -0
- data/lib/sigterm_extensions/core_ext/tryable.rb +132 -0
- data/lib/sigterm_extensions/descendants_tracker.rb +108 -0
- data/lib/sigterm_extensions/gem_methods.rb +47 -0
- data/lib/sigterm_extensions/hash_binding.rb +16 -0
- data/lib/sigterm_extensions/inflector.rb +339 -0
- data/lib/sigterm_extensions/inflector/acronyms.rb +42 -0
- data/lib/sigterm_extensions/inflector/inflections.rb +249 -0
- data/lib/sigterm_extensions/inflector/inflections/defaults.rb +117 -0
- data/lib/sigterm_extensions/inflector/rules.rb +37 -0
- data/lib/sigterm_extensions/inflector/version.rb +8 -0
- data/lib/sigterm_extensions/interactive_editor.rb +120 -0
- data/lib/sigterm_extensions/lazy.rb +34 -0
- data/lib/sigterm_extensions/lazy_load_hooks.rb +79 -0
- data/lib/sigterm_extensions/option_merger.rb +32 -0
- data/lib/sigterm_extensions/ordered_hash.rb +48 -0
- data/lib/sigterm_extensions/ordered_options.rb +83 -0
- data/lib/sigterm_extensions/paths.rb +235 -0
- data/lib/sigterm_extensions/per_thread_registry.rb +58 -0
- data/lib/sigterm_extensions/proxy_object.rb +14 -0
- data/lib/sigterm_extensions/staging/boot.rb +31 -0
- data/lib/sigterm_extensions/staging/boot/bundler_patch.rb +24 -0
- data/lib/sigterm_extensions/staging/boot/command.rb +26 -0
- data/lib/sigterm_extensions/staging/boot/gemfile_next_auto_sync.rb +79 -0
- data/lib/sigterm_extensions/version.rb +4 -0
- data/lib/sigterm_extensions/wrappable.rb +16 -0
- data/sigterm_extensions.gemspec +42 -0
- data/templates/dotpryrc.rb.erb +124 -0
- metadata +315 -0
data/lib/git/remote.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Git
|
2
|
+
class Remote < Path
|
3
|
+
|
4
|
+
attr_accessor :name, :url, :fetch_opts
|
5
|
+
|
6
|
+
def initialize(base, name)
|
7
|
+
@base = base
|
8
|
+
config = @base.lib.config_remote(name)
|
9
|
+
@name = name
|
10
|
+
@url = config['url']
|
11
|
+
@fetch_opts = config['fetch']
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch(opts={})
|
15
|
+
@base.fetch(@name, opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
# merge this remote locally
|
19
|
+
def merge(branch = 'master')
|
20
|
+
@base.merge("#{@name}/#{branch}")
|
21
|
+
end
|
22
|
+
|
23
|
+
def branch(branch = 'master')
|
24
|
+
Git::Branch.new(@base, "#{@name}/#{branch}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def remove
|
28
|
+
@base.lib.remote_remove(@name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
@name
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/lib/git/stash.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Git
|
2
|
+
class Stash
|
3
|
+
|
4
|
+
def initialize(base, message, existing=false)
|
5
|
+
@base = base
|
6
|
+
@message = message
|
7
|
+
save unless existing
|
8
|
+
end
|
9
|
+
|
10
|
+
def save
|
11
|
+
@saved = @base.lib.stash_save(@message)
|
12
|
+
end
|
13
|
+
|
14
|
+
def saved?
|
15
|
+
@saved
|
16
|
+
end
|
17
|
+
|
18
|
+
def message
|
19
|
+
@message
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
message
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/git/stashes.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Git
|
2
|
+
|
3
|
+
# object that holds all the available stashes
|
4
|
+
class Stashes
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(base)
|
8
|
+
@stashes = []
|
9
|
+
|
10
|
+
@base = base
|
11
|
+
|
12
|
+
@base.lib.stashes_all.each do |id, message|
|
13
|
+
@stashes.unshift(Git::Stash.new(@base, message, true))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Returns an multi-dimensional Array of elements that have been stash saved.
|
19
|
+
# Array is based on position and name. See Example
|
20
|
+
#
|
21
|
+
# @example Returns Array of items that have been stashed
|
22
|
+
# .all - [0, "testing-stash-all"]]
|
23
|
+
# @return [Array]
|
24
|
+
def all
|
25
|
+
@base.lib.stashes_all
|
26
|
+
end
|
27
|
+
|
28
|
+
def save(message)
|
29
|
+
s = Git::Stash.new(@base, message)
|
30
|
+
@stashes.unshift(s) if s.saved?
|
31
|
+
end
|
32
|
+
|
33
|
+
def apply(index=nil)
|
34
|
+
@base.lib.stash_apply(index)
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear
|
38
|
+
@base.lib.stash_clear
|
39
|
+
@stashes = []
|
40
|
+
end
|
41
|
+
|
42
|
+
def size
|
43
|
+
@stashes.size
|
44
|
+
end
|
45
|
+
|
46
|
+
def each(&block)
|
47
|
+
@stashes.each(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def [](index)
|
51
|
+
@stashes[index.to_i]
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/git/status.rb
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
module Git
|
2
|
+
#
|
3
|
+
# A class for git status
|
4
|
+
#
|
5
|
+
class Status
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(base)
|
9
|
+
@base = base
|
10
|
+
construct_status
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Returns an Enumerable containing files that have changed from the
|
15
|
+
# git base directory
|
16
|
+
#
|
17
|
+
# @return [Enumerable]
|
18
|
+
def changed
|
19
|
+
@files.select { |_k, f| f.type == 'M' }
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Determines whether the given file has been changed.
|
24
|
+
# File path starts at git base directory
|
25
|
+
#
|
26
|
+
# @param file [String] The name of the file.
|
27
|
+
# @example Check if lib/git.rb has changed.
|
28
|
+
# changed?('lib/git.rb')
|
29
|
+
# @return [Boolean]
|
30
|
+
def changed?(file)
|
31
|
+
changed.member?(file)
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Returns an Enumerable containing files that have been added.
|
36
|
+
# File path starts at git base directory
|
37
|
+
#
|
38
|
+
# @return [Enumerable]
|
39
|
+
def added
|
40
|
+
@files.select { |_k, f| f.type == 'A' }
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Determines whether the given file has been added to the repository
|
45
|
+
# File path starts at git base directory
|
46
|
+
#
|
47
|
+
# @param file [String] The name of the file.
|
48
|
+
# @example Check if lib/git.rb is added.
|
49
|
+
# added?('lib/git.rb')
|
50
|
+
# @return [Boolean]
|
51
|
+
def added?(file)
|
52
|
+
added.member?(file)
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Returns an Enumerable containing files that have been deleted.
|
57
|
+
# File path starts at git base directory
|
58
|
+
#
|
59
|
+
# @return [Enumerable]
|
60
|
+
def deleted
|
61
|
+
@files.select { |_k, f| f.type == 'D' }
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Determines whether the given file has been deleted from the repository
|
66
|
+
# File path starts at git base directory
|
67
|
+
#
|
68
|
+
# @param file [String] The name of the file.
|
69
|
+
# @example Check if lib/git.rb is deleted.
|
70
|
+
# deleted?('lib/git.rb')
|
71
|
+
# @return [Boolean]
|
72
|
+
def deleted?(file)
|
73
|
+
deleted.member?(file)
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Returns an Enumerable containing files that are not tracked in git.
|
78
|
+
# File path starts at git base directory
|
79
|
+
#
|
80
|
+
# @return [Enumerable]
|
81
|
+
def untracked
|
82
|
+
@files.select { |_k, f| f.untracked }
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Determines whether the given file has is tracked by git.
|
87
|
+
# File path starts at git base directory
|
88
|
+
#
|
89
|
+
# @param file [String] The name of the file.
|
90
|
+
# @example Check if lib/git.rb is an untracked file.
|
91
|
+
# untracked?('lib/git.rb')
|
92
|
+
# @return [Boolean]
|
93
|
+
def untracked?(file)
|
94
|
+
untracked.member?(file)
|
95
|
+
end
|
96
|
+
|
97
|
+
def pretty
|
98
|
+
out = ''
|
99
|
+
each do |file|
|
100
|
+
out << pretty_file(file)
|
101
|
+
end
|
102
|
+
out << "\n"
|
103
|
+
out
|
104
|
+
end
|
105
|
+
|
106
|
+
def pretty_file(file)
|
107
|
+
<<-FILE.strip_heredoc
|
108
|
+
#{file.path}
|
109
|
+
\tsha(r) #{file.sha_repo} #{file.mode_repo}
|
110
|
+
\tsha(i) #{file.sha_index} #{file.mode_index}
|
111
|
+
\ttype #{file.type}
|
112
|
+
\tstage #{file.stage}
|
113
|
+
\tuntrac #{file.untracked}
|
114
|
+
FILE
|
115
|
+
end
|
116
|
+
|
117
|
+
# enumerable method
|
118
|
+
|
119
|
+
def [](file)
|
120
|
+
@files[file]
|
121
|
+
end
|
122
|
+
|
123
|
+
def each(&block)
|
124
|
+
@files.values.each(&block)
|
125
|
+
end
|
126
|
+
|
127
|
+
# subclass that does heavy lifting
|
128
|
+
class StatusFile
|
129
|
+
attr_accessor :path, :type, :stage, :untracked
|
130
|
+
attr_accessor :mode_index, :mode_repo
|
131
|
+
attr_accessor :sha_index, :sha_repo
|
132
|
+
|
133
|
+
def initialize(base, hash)
|
134
|
+
@base = base
|
135
|
+
@path = hash[:path]
|
136
|
+
@type = hash[:type]
|
137
|
+
@stage = hash[:stage]
|
138
|
+
@mode_index = hash[:mode_index]
|
139
|
+
@mode_repo = hash[:mode_repo]
|
140
|
+
@sha_index = hash[:sha_index]
|
141
|
+
@sha_repo = hash[:sha_repo]
|
142
|
+
@untracked = hash[:untracked]
|
143
|
+
end
|
144
|
+
|
145
|
+
def blob(type = :index)
|
146
|
+
if type == :repo
|
147
|
+
@base.object(@sha_repo)
|
148
|
+
else
|
149
|
+
begin
|
150
|
+
@base.object(@sha_index)
|
151
|
+
rescue
|
152
|
+
@base.object(@sha_repo)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def construct_status
|
161
|
+
@files = @base.lib.ls_files
|
162
|
+
|
163
|
+
fetch_untracked
|
164
|
+
fetch_modified
|
165
|
+
fetch_added
|
166
|
+
|
167
|
+
@files.each do |k, file_hash|
|
168
|
+
@files[k] = StatusFile.new(@base, file_hash)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def fetch_untracked
|
173
|
+
ignore = @base.lib.ignored_files
|
174
|
+
|
175
|
+
Dir.chdir(@base.dir.path) do
|
176
|
+
Dir.glob('**/*', File::FNM_DOTMATCH) do |file|
|
177
|
+
next if @files[file] || File.directory?(file) ||
|
178
|
+
ignore.include?(file) || file =~ %r{^.git\/.+}
|
179
|
+
|
180
|
+
@files[file] = { path: file, untracked: true }
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def fetch_modified
|
186
|
+
# find modified in tree
|
187
|
+
@base.lib.diff_files.each do |path, data|
|
188
|
+
@files[path] ? @files[path].merge!(data) : @files[path] = data
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def fetch_added
|
193
|
+
# find added but not committed - new files
|
194
|
+
@base.lib.diff_index('HEAD').each do |path, data|
|
195
|
+
@files[path] ? @files[path].merge!(data) : @files[path] = data
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
data/lib/git/version.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'yaml'
|
3
|
+
require 'ostruct'
|
4
|
+
require 'rake'
|
5
|
+
require 'awesome_print'
|
6
|
+
require 'pry'
|
7
|
+
require 'logger'
|
8
|
+
|
9
|
+
Rake.application.options.trace = true
|
10
|
+
ENV['EDITOR'] = 'vim' if ENV['EDITOR'].nil?
|
11
|
+
ENV['SHELL'] = '/bin/bash' if ENV['SHELL'].nil?
|
12
|
+
|
13
|
+
module SigtermExtensions
|
14
|
+
def self.root_path(*args)
|
15
|
+
File.join File.expand_path('../', __dir__), *args
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.ext_path(*args)
|
19
|
+
File.join SigtermExtensions.root_path, 'lib/sigterm_extensions', args
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.revision
|
23
|
+
`git log --pretty=format:%h --abbrev=11 -n 1`
|
24
|
+
end
|
25
|
+
|
26
|
+
alias :orig_require :require
|
27
|
+
def self.require s
|
28
|
+
print "Requires #{s}\n" if orig_require(s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.get_classes_from mod
|
32
|
+
mod.constants.select { |k| mod.const_get(k).instance_of? Class }
|
33
|
+
end
|
34
|
+
|
35
|
+
autoload :BacktraceCleaner, SigtermExtensions.ext_path('backtrace_cleaner')
|
36
|
+
autoload :Callbacks, SigtermExtensions.ext_path('callbacks')
|
37
|
+
autoload :Concern, SigtermExtensions.ext_path('concern')
|
38
|
+
autoload :Configurable, SigtermExtensions.ext_path('configurable')
|
39
|
+
autoload :DescendantsTracker, SigtermExtensions.ext_path('descendants_tracker')
|
40
|
+
autoload :GemMethods, SigtermExtensions.ext_path('gem_methods')
|
41
|
+
autoload :Git, SigtermExtensions.root_path('lib/git')
|
42
|
+
autoload :HashBinding, SigtermExtensions.ext_path('hash_binding')
|
43
|
+
autoload :Inflector, SigtermExtensions.ext_path('inflector')
|
44
|
+
autoload :Lazy, SigtermExtensions.ext_path('lazy')
|
45
|
+
autoload :Paths, SigtermExtensions.ext_path('paths')
|
46
|
+
autoload :ProxyObject, SigtermExtensions.ext_path('proxy_object')
|
47
|
+
autoload :Wrappable, SigtermExtensions.ext_path('wrappable')
|
48
|
+
|
49
|
+
def self.all_requirements
|
50
|
+
$LOADED_FEATURES.
|
51
|
+
select { |feature| feature.include? 'gems' }.
|
52
|
+
map { |feature| File.dirname(feature) }.
|
53
|
+
map { |feature| feature.split('/').last }.
|
54
|
+
uniq.sort
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.all_required_unfiltered
|
58
|
+
$LOADED_FEATURES
|
59
|
+
end
|
60
|
+
|
61
|
+
class RuntimeClassBase
|
62
|
+
attr_accessor :settings
|
63
|
+
end
|
64
|
+
|
65
|
+
class RuntimeClass
|
66
|
+
def self.new(base=RuntimeClassBase, options={}, &block)
|
67
|
+
base = Class.new(base)
|
68
|
+
base.class_eval(&block) if block_given?
|
69
|
+
base
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
require_relative 'sigterm_extensions/all'
|
75
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'core_ext'
|
2
|
+
require_relative 'version'
|
3
|
+
require_relative 'lazy_load_hooks'
|
4
|
+
|
5
|
+
lib_dir = File.expand_path('..', __dir__)
|
6
|
+
$:.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
7
|
+
|
8
|
+
staging_dir = File.expand_path('staging', __dir__)
|
9
|
+
Dir["#{staging_dir}/*.rb"].each do |ext|
|
10
|
+
require ext
|
11
|
+
end
|
12
|
+
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module SigtermExtensions
|
2
|
+
# Backtraces often include many lines that are not relevant for the context
|
3
|
+
# under review. This makes it hard to find the signal amongst the backtrace
|
4
|
+
# noise, and adds debugging time. With a BacktraceCleaner, filters and
|
5
|
+
# silencers are used to remove the noisy lines, so that only the most relevant
|
6
|
+
# lines remain.
|
7
|
+
#
|
8
|
+
# Filters are used to modify lines of data, while silencers are used to remove
|
9
|
+
# lines entirely. The typical filter use case is to remove lengthy path
|
10
|
+
# information from the start of each line, and view file paths relevant to the
|
11
|
+
# app directory instead of the file system root. The typical silencer use case
|
12
|
+
# is to exclude the output of a noisy library from the backtrace, so that you
|
13
|
+
# can focus on the rest.
|
14
|
+
#
|
15
|
+
# bc = SigtermExtensions::BacktraceCleaner.new
|
16
|
+
# bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
|
17
|
+
# bc.add_silencer { |line| /puma|rubygems/.match?(line) } # skip any lines from puma or rubygems
|
18
|
+
# bc.clean(exception.backtrace) # perform the cleanup
|
19
|
+
#
|
20
|
+
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
|
21
|
+
# and show as much data as possible, you can always call
|
22
|
+
# <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the
|
23
|
+
# backtrace to a pristine state. If you need to reconfigure an existing
|
24
|
+
# BacktraceCleaner so that it does not filter or modify the paths of any lines
|
25
|
+
# of the backtrace, you can call <tt>BacktraceCleaner#remove_filters!</tt>
|
26
|
+
# These two methods will give you a completely untouched backtrace.
|
27
|
+
#
|
28
|
+
# Inspired by the Quiet Backtrace gem by thoughtbot.
|
29
|
+
class BacktraceCleaner
|
30
|
+
def initialize
|
31
|
+
@filters, @silencers = [], []
|
32
|
+
add_gem_filter
|
33
|
+
add_gem_silencer
|
34
|
+
add_stdlib_silencer
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the backtrace after all filters and silencers have been run
|
38
|
+
# against it. Filters run first, then silencers.
|
39
|
+
def clean(backtrace, kind = :silent)
|
40
|
+
filtered = filter_backtrace(backtrace)
|
41
|
+
|
42
|
+
case kind
|
43
|
+
when :silent
|
44
|
+
silence(filtered)
|
45
|
+
when :noise
|
46
|
+
noise(filtered)
|
47
|
+
else
|
48
|
+
filtered
|
49
|
+
end
|
50
|
+
end
|
51
|
+
alias :filter :clean
|
52
|
+
|
53
|
+
# Adds a filter from the block provided. Each line in the backtrace will be
|
54
|
+
# mapped against this filter.
|
55
|
+
#
|
56
|
+
# # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
|
57
|
+
# backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
|
58
|
+
def add_filter(&block)
|
59
|
+
@filters << block
|
60
|
+
end
|
61
|
+
|
62
|
+
# Adds a silencer from the block provided. If the silencer returns +true+
|
63
|
+
# for a given line, it will be excluded from the clean backtrace.
|
64
|
+
#
|
65
|
+
# # Will reject all lines that include the word "puma", like "/gems/puma/server.rb" or "/app/my_puma_server/rb"
|
66
|
+
# backtrace_cleaner.add_silencer { |line| /puma/.match?(line) }
|
67
|
+
def add_silencer(&block)
|
68
|
+
@silencers << block
|
69
|
+
end
|
70
|
+
|
71
|
+
# Removes all silencers, but leaves in the filters. Useful if your
|
72
|
+
# context of debugging suddenly expands as you suspect a bug in one of
|
73
|
+
# the libraries you use.
|
74
|
+
def remove_silencers!
|
75
|
+
@silencers = []
|
76
|
+
end
|
77
|
+
|
78
|
+
# Removes all filters, but leaves in the silencers. Useful if you suddenly
|
79
|
+
# need to see entire filepaths in the backtrace that you had already
|
80
|
+
# filtered out.
|
81
|
+
def remove_filters!
|
82
|
+
@filters = []
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
|
87
|
+
|
88
|
+
def add_gem_filter
|
89
|
+
gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
|
90
|
+
return if gems_paths.empty?
|
91
|
+
|
92
|
+
gems_regexp = %r{(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
|
93
|
+
gems_result = '\3 (\4) \5'
|
94
|
+
add_filter { |line| line.sub(gems_regexp, gems_result) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_gem_silencer
|
98
|
+
add_silencer { |line| FORMATTED_GEMS_PATTERN.match?(line) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_stdlib_silencer
|
102
|
+
add_silencer { |line| line.start_with?(RbConfig::CONFIG["rubylibdir"]) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def filter_backtrace(backtrace)
|
106
|
+
@filters.each do |f|
|
107
|
+
backtrace = backtrace.map { |line| f.call(line) }
|
108
|
+
end
|
109
|
+
|
110
|
+
backtrace
|
111
|
+
end
|
112
|
+
|
113
|
+
def silence(backtrace)
|
114
|
+
@silencers.each do |s|
|
115
|
+
backtrace = backtrace.reject { |line| s.call(line) }
|
116
|
+
end
|
117
|
+
|
118
|
+
backtrace
|
119
|
+
end
|
120
|
+
|
121
|
+
def noise(backtrace)
|
122
|
+
backtrace.select do |line|
|
123
|
+
@silencers.any? do |s|
|
124
|
+
s.call(line)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|