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
|
# File 'lib/retouch/batch.rb', line 26
def self.run(inputs, to:, jobs: 1, force: false, dry_run: false)
paths = expand(inputs)
raise Error, "no input files matched" if paths.empty?
raise Error, "input file does not exist: #{paths.find { |path| !File.file?(path) }}" unless paths.all? { |path| File.file?(path) }
outputs = paths.each_with_index.map { |path, index| output_path(to, path, index) }
resolved_outputs = outputs.map { |path| destination_key(path) }
raise Error, "output template produces duplicate paths" unless resolved_outputs.uniq.length == outputs.length
jobs = Integer(jobs)
raise ArgumentError, "jobs must be positive" unless jobs.positive?
if !force && (existing = outputs.find { |path| File.exist?(path) })
raise Error, "refusing to overwrite #{existing}; use --force"
end
return outputs if dry_run
worker_count = Process.respond_to?(:fork) ? jobs : 1
children = []
failed = false
paths.zip(outputs).each do |input, output|
FileUtils.mkdir_p(File.dirname(output)) unless File.dirname(output) == "."
if worker_count > 1
children << Process.fork do
yield input, output
exit! 0
rescue StandardError => e
warn("retouch: #{e.message}")
exit! 1
end
if children.length >= worker_count
_pid, status = Process.wait2(children.shift)
failed ||= !status.success?
end
else
yield input, output
end
end
children.each do |pid|
_child, status = Process.wait2(pid)
failed ||= !status.success?
end
raise Error, "one or more batch jobs failed" if failed
outputs
end
|