Class: FormatStaged::Job
- Inherits:
-
Object
show all
- Includes:
- IOMixin
- Defined in:
- lib/format-staged/job.rb
Overview
Runs staged changes through a formatting tool
Instance Attribute Summary collapse
Instance Method Summary
collapse
Methods included from IOMixin
#fail!, #get_output, #get_status, #info, #pipe_command, #read_output, #verbose_info, #warning
Constructor Details
#initialize(formatter:, patterns:, **options) ⇒ Job
Returns a new instance of Job.
18
19
20
21
22
23
24
25
26
27
28
|
# File 'lib/format-staged/job.rb', line 18
def initialize(formatter:, patterns:, **options)
validate_patterns patterns
@formatter = formatter
@patterns = patterns
@update = options.fetch(:update, true)
@write = options.fetch(:write, true)
@verbose = options.fetch(:verbose, true)
String.disable_colorization = !options.fetch(:color_output, $stdout.isatty)
end
|
Instance Attribute Details
Returns the value of attribute formatter.
16
17
18
|
# File 'lib/format-staged/job.rb', line 16
def formatter
@formatter
end
|
#patterns ⇒ Object
Returns the value of attribute patterns.
16
17
18
|
# File 'lib/format-staged/job.rb', line 16
def patterns
@patterns
end
|
#update ⇒ Object
Returns the value of attribute update.
16
17
18
|
# File 'lib/format-staged/job.rb', line 16
def update
@update
end
|
#verbose ⇒ Object
Returns the value of attribute verbose.
16
17
18
|
# File 'lib/format-staged/job.rb', line 16
def verbose
@verbose
end
|
#write ⇒ Object
Returns the value of attribute write.
16
17
18
|
# File 'lib/format-staged/job.rb', line 16
def write
@write
end
|
Instance Method Details
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
|
# File 'lib/format-staged/job.rb', line 62
def format_file(file)
new_hash = format_object file
return true unless write
if new_hash == file.dst_hash
info "Unchanged #{file.src_path}"
return true
end
if object_is_empty new_hash
info "Skipping #{file.src_path}, formatted file is empty"
return false
end
replace_file_in_index file, new_hash
update_working_copy file, new_hash
if new_hash == file.src_hash
info "File #{file.src_path} equal to comitted"
return true
end
true
end
|
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
# File 'lib/format-staged/job.rb', line 98
def format_object(file)
info "Formatting #{file.src_path}"
format_command = formatter.sub('{}', file.src_path.shellescape)
pid1, r = pipe_command 'git', 'cat-file', '-p', file.dst_hash
pid2, r = pipe_command format_command, source: r
write_args = write ? ['-w'] : []
pid3, r = pipe_command 'git', 'hash-object', *write_args, '--stdin', source: r
result = read_output(r, lines: false).chomp
Process.wait pid1
raise "Cannot read #{file.dst_hash} from object database" unless $CHILD_STATUS.success?
Process.wait pid2
raise "Error formatting #{file.src_path}" unless $CHILD_STATUS.success?
Process.wait pid3
raise 'Error writing formatted file back to object database' unless $CHILD_STATUS.success? && !result.empty?
result
end
|
#matching_files(root) ⇒ Object
53
54
55
56
57
58
59
60
|
# File 'lib/format-staged/job.rb', line 53
def matching_files(root)
verbose_info 'Listing staged files'
get_output('git', 'diff-index', '--cached', '--diff-filter=AM', '--no-renames', 'HEAD')
.map { |line| Entry.new(line, root: root) }
.reject(&:symlink?)
.filter { |entry| entry.matches?(@patterns) }
end
|
#object_is_empty(hash) ⇒ Object
123
124
125
126
|
# File 'lib/format-staged/job.rb', line 123
def object_is_empty(hash)
size = get_output('git', 'cat-file', '-s', hash).first.to_i
size.zero?
end
|
#patch_working_file(file, new_hash) ⇒ Object
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
# File 'lib/format-staged/job.rb', line 128
def patch_working_file(file, new_hash)
info 'Updating working copy'
patch = get_output 'git', 'diff', file.dst_hash, new_hash, lines: false, silent: true
patch.gsub! "a/#{file.dst_hash}", "a/#{file.src_path}"
patch.gsub! "b/#{new_hash}", "b/#{file.src_path}"
input, patch_out = IO.pipe
pid, r = pipe_command 'git', 'apply', '-', source: input
patch_out.write patch
patch_out.close
read_output r
Process.wait pid
raise 'Error applying patch' unless $CHILD_STATUS.success?
end
|
#replace_file_in_index(file, new_hash) ⇒ Object
147
148
149
|
# File 'lib/format-staged/job.rb', line 147
def replace_file_in_index(file, new_hash)
get_output 'git', 'update-index', '--cacheinfo', "#{file.dst_mode},#{new_hash},#{file.src_path}"
end
|
#repo_root ⇒ Object
45
46
47
48
49
50
51
|
# File 'lib/format-staged/job.rb', line 45
def repo_root
verbose_info 'Finding repository root'
root = get_output('git', 'rev-parse', '--show-toplevel', lines: false).chomp
verbose_info "Repo at #{root}"
root
end
|
#run ⇒ Object
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
# File 'lib/format-staged/job.rb', line 30
def run
files = matching_files(repo_root)
if files.empty?
info 'No staged file matching pattern. Done'
return true
end
formatted = files.filter { |file| format_file file }
return false unless formatted.size == files.size
quiet = @verbose ? [] : ['--quiet']
return !write || get_status('git', 'diff-index', '--cached', '--exit-code', *quiet, 'HEAD') != 0
end
|
#update_working_copy(file, new_hash) ⇒ Object
88
89
90
91
92
93
94
95
96
|
# File 'lib/format-staged/job.rb', line 88
def update_working_copy(file, new_hash)
return unless update
begin
patch_working_file file, new_hash
rescue StandardError => e
warning "failed updating #{file.src_path} in working copy: #{e}"
end
end
|
#validate_patterns(patterns) ⇒ Object
151
152
153
154
155
|
# File 'lib/format-staged/job.rb', line 151
def validate_patterns(patterns)
patterns.each do |pattern|
fail! "Negative pattern '#{pattern}' is not yet supported" if pattern.start_with? '!'
end
end
|