overcommit 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/overcommit +3 -4
- data/config/default.yml +139 -0
- data/lib/overcommit.rb +7 -5
- data/lib/overcommit/cli.rb +59 -64
- data/lib/overcommit/configuration.rb +108 -34
- data/lib/overcommit/configuration_loader.rb +47 -0
- data/lib/overcommit/constants.rb +7 -0
- data/lib/overcommit/exceptions.rb +16 -0
- data/lib/overcommit/hook/base.rb +91 -0
- data/lib/overcommit/hook/commit_msg/base.rb +11 -0
- data/lib/overcommit/hook/commit_msg/gerrit_change_id.rb +18 -0
- data/lib/overcommit/{plugins → hook}/commit_msg/hard_tabs.rb +5 -6
- data/lib/overcommit/hook/commit_msg/russian_novel.rb +14 -0
- data/lib/overcommit/hook/commit_msg/single_line_subject.rb +12 -0
- data/lib/overcommit/hook/commit_msg/text_width.rb +20 -0
- data/lib/overcommit/hook/commit_msg/trailing_period.rb +12 -0
- data/lib/overcommit/hook/post_checkout/base.rb +11 -0
- data/lib/overcommit/hook/post_checkout/bundle_check.rb +29 -0
- data/lib/overcommit/hook/post_checkout/index_tags.rb +24 -0
- data/lib/overcommit/hook/pre_commit/author_email.rb +17 -0
- data/lib/overcommit/hook/pre_commit/author_name.rb +17 -0
- data/lib/overcommit/hook/pre_commit/base.rb +10 -0
- data/lib/overcommit/hook/pre_commit/bundle_check.rb +30 -0
- data/lib/overcommit/hook/pre_commit/coffee_lint.rb +14 -0
- data/lib/overcommit/hook/pre_commit/css_lint.rb +16 -0
- data/lib/overcommit/hook/pre_commit/haml_lint.rb +26 -0
- data/lib/overcommit/hook/pre_commit/hard_tabs.rb +16 -0
- data/lib/overcommit/hook/pre_commit/image_optim.rb +41 -0
- data/lib/overcommit/hook/pre_commit/js_hint.rb +15 -0
- data/lib/overcommit/hook/pre_commit/jscs.rb +31 -0
- data/lib/overcommit/hook/pre_commit/python_flake8.rb +14 -0
- data/lib/overcommit/hook/pre_commit/rubocop.rb +26 -0
- data/lib/overcommit/hook/pre_commit/scss_lint.rb +26 -0
- data/lib/overcommit/hook/pre_commit/trailing_whitespace.rb +15 -0
- data/lib/overcommit/hook/pre_commit/yaml_syntax.rb +22 -0
- data/lib/overcommit/hook_context.rb +16 -0
- data/lib/overcommit/hook_context/base.rb +68 -0
- data/lib/overcommit/hook_context/commit_msg.rb +32 -0
- data/lib/overcommit/hook_context/post_checkout.rb +24 -0
- data/lib/overcommit/hook_context/pre_commit.rb +96 -0
- data/lib/overcommit/hook_runner.rb +150 -0
- data/lib/overcommit/installer.rb +61 -68
- data/lib/overcommit/logger.rb +16 -13
- data/lib/overcommit/utils.rb +63 -38
- data/lib/overcommit/version.rb +1 -1
- data/{bin/scripts → libexec}/gerrit-change-id +0 -0
- data/{bin/scripts → libexec}/index-tags +1 -3
- data/template-dir/hooks/commit-msg +83 -0
- data/template-dir/hooks/overcommit-hook +83 -0
- data/template-dir/hooks/post-checkout +83 -0
- data/template-dir/hooks/pre-commit +83 -0
- metadata +76 -57
- data/bin/hooks/commit-msg +0 -8
- data/bin/hooks/post-checkout +0 -9
- data/bin/hooks/post-merge +0 -23
- data/bin/hooks/pre-commit +0 -8
- data/bin/hooks/prepare-commit-msg +0 -159
- data/bin/run-hook +0 -8
- data/bin/scripts/check-gemfile +0 -9
- data/bin/scripts/csslint-rhino.js +0 -9080
- data/bin/scripts/jshint.js +0 -5921
- data/bin/scripts/jshint_runner.js +0 -42
- data/lib/overcommit/errors.rb +0 -3
- data/lib/overcommit/git_hook.rb +0 -89
- data/lib/overcommit/hook_specific_check.rb +0 -110
- data/lib/overcommit/hooks/commit_msg.rb +0 -7
- data/lib/overcommit/hooks/pre_commit.rb +0 -9
- data/lib/overcommit/plugins/commit_msg/change_id.rb +0 -15
- data/lib/overcommit/plugins/commit_msg/release_note.rb +0 -25
- data/lib/overcommit/plugins/commit_msg/russian_novel.rb +0 -16
- data/lib/overcommit/plugins/commit_msg/single_line_subject.rb +0 -13
- data/lib/overcommit/plugins/commit_msg/text_width.rb +0 -20
- data/lib/overcommit/plugins/commit_msg/trailing_period.rb +0 -13
- data/lib/overcommit/plugins/pre_commit/author_name.rb +0 -16
- data/lib/overcommit/plugins/pre_commit/causes_email.rb +0 -15
- data/lib/overcommit/plugins/pre_commit/coffee_lint.rb +0 -16
- data/lib/overcommit/plugins/pre_commit/css_linter.rb +0 -17
- data/lib/overcommit/plugins/pre_commit/haml_style.rb +0 -34
- data/lib/overcommit/plugins/pre_commit/haml_syntax.rb +0 -24
- data/lib/overcommit/plugins/pre_commit/image_optimization.rb +0 -50
- data/lib/overcommit/plugins/pre_commit/js_console_log.rb +0 -16
- data/lib/overcommit/plugins/pre_commit/js_syntax.rb +0 -30
- data/lib/overcommit/plugins/pre_commit/python_flake8.rb +0 -15
- data/lib/overcommit/plugins/pre_commit/ruby_style.rb +0 -67
- data/lib/overcommit/plugins/pre_commit/ruby_syntax.rb +0 -19
- data/lib/overcommit/plugins/pre_commit/scss_lint.rb +0 -66
- data/lib/overcommit/plugins/pre_commit/test_history.rb +0 -58
- data/lib/overcommit/plugins/pre_commit/whitespace.rb +0 -21
- data/lib/overcommit/plugins/pre_commit/yaml_syntax.rb +0 -22
- data/lib/overcommit/reporter.rb +0 -90
- data/lib/overcommit/staged_file.rb +0 -86
@@ -0,0 +1,150 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Overcommit
|
4
|
+
# Responsible for loading the hooks the repository has configured and running
|
5
|
+
# them, collecting and displaying the results.
|
6
|
+
class HookRunner
|
7
|
+
def initialize(config, logger, context)
|
8
|
+
@config = config
|
9
|
+
@log = logger
|
10
|
+
@context = context
|
11
|
+
@hooks = []
|
12
|
+
end
|
13
|
+
|
14
|
+
# Loads and runs the hooks registered for this {HookRunner}.
|
15
|
+
def run
|
16
|
+
load_hooks
|
17
|
+
@context.setup_environment
|
18
|
+
run_hooks
|
19
|
+
ensure
|
20
|
+
@context.cleanup_environment
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :log
|
26
|
+
|
27
|
+
def run_hooks
|
28
|
+
if @hooks.any? { |hook| hook.run? || hook.skip? }
|
29
|
+
log.bold "Running #{@context.hook_script_name} hooks"
|
30
|
+
|
31
|
+
statuses = @hooks.map { |hook| run_hook(hook) }.compact
|
32
|
+
|
33
|
+
log.log # Newline
|
34
|
+
|
35
|
+
run_failed = statuses.include?(:bad)
|
36
|
+
|
37
|
+
if run_failed
|
38
|
+
log.error "✗ One or more #{@context.hook_script_name} hooks failed"
|
39
|
+
else
|
40
|
+
log.success "✓ All #{@context.hook_script_name} hooks passed"
|
41
|
+
end
|
42
|
+
|
43
|
+
log.log # Newline
|
44
|
+
|
45
|
+
!run_failed
|
46
|
+
else
|
47
|
+
log.success "✓ No applicable #{@context.hook_script_name} hooks to run"
|
48
|
+
true # Run was successful
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def run_hook(hook)
|
53
|
+
return unless hook.enabled?
|
54
|
+
|
55
|
+
if hook.skip?
|
56
|
+
if hook.required?
|
57
|
+
log.warning "Cannot skip #{hook.name} since it is required"
|
58
|
+
else
|
59
|
+
log.warning "Skipping #{hook.name}"
|
60
|
+
return
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
return unless hook.run?
|
65
|
+
|
66
|
+
unless hook.quiet?
|
67
|
+
print_header(hook)
|
68
|
+
end
|
69
|
+
|
70
|
+
begin
|
71
|
+
status, output = hook.run
|
72
|
+
rescue => ex
|
73
|
+
status = :bad
|
74
|
+
output = "Hook raised unexpected error\n#{ex.message}"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Want to print the header in the event the result wasn't good so that the
|
78
|
+
# user knows what failed
|
79
|
+
if hook.quiet? && status != :good
|
80
|
+
print_header(hook)
|
81
|
+
end
|
82
|
+
|
83
|
+
case status
|
84
|
+
when :good
|
85
|
+
log.success 'OK' unless hook.quiet?
|
86
|
+
when :warn
|
87
|
+
log.warning 'WARNING'
|
88
|
+
print_report(output, :bold_warning)
|
89
|
+
when :bad
|
90
|
+
log.error 'FAILED'
|
91
|
+
print_report(output, :bold_error)
|
92
|
+
end
|
93
|
+
|
94
|
+
status
|
95
|
+
end
|
96
|
+
|
97
|
+
def print_header(hook)
|
98
|
+
log.partial hook.description
|
99
|
+
log.partial '.' * (70 - hook.description.length)
|
100
|
+
end
|
101
|
+
|
102
|
+
def print_report(output, format = :log)
|
103
|
+
log.send(format, output) unless output.empty?
|
104
|
+
end
|
105
|
+
|
106
|
+
# Loads hooks that will be run.
|
107
|
+
# This is done explicitly so that we only load hooks which will actually be
|
108
|
+
# used.
|
109
|
+
def load_hooks
|
110
|
+
require "overcommit/hook/#{@context.hook_type_name}/base"
|
111
|
+
|
112
|
+
load_builtin_hooks
|
113
|
+
load_hook_plugins # Load after so they can subclass/modify existing hooks
|
114
|
+
end
|
115
|
+
|
116
|
+
# Load hooks that ship with Overcommit, ignoring ones that are excluded from
|
117
|
+
# the repository's configuration.
|
118
|
+
def load_builtin_hooks
|
119
|
+
@config.enabled_builtin_hooks(@context.hook_class_name).each do |hook_name|
|
120
|
+
underscored_hook_name = Overcommit::Utils.snake_case(hook_name)
|
121
|
+
require "overcommit/hook/#{@context.hook_type_name}/#{underscored_hook_name}"
|
122
|
+
@hooks << create_hook(hook_name)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Load hooks that are stored in the repository's plugin directory.
|
127
|
+
def load_hook_plugins
|
128
|
+
directory = File.join(@config.plugin_directory, @context.hook_type_name)
|
129
|
+
|
130
|
+
Dir[File.join(directory, '*.rb')].sort.each do |plugin|
|
131
|
+
require plugin
|
132
|
+
|
133
|
+
hook_name = Overcommit::Utils.camel_case(File.basename(plugin, '.rb'))
|
134
|
+
@hooks << create_hook(hook_name)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Load and return a {Hook} from a CamelCase hook name and the given
|
139
|
+
# hook configuration.
|
140
|
+
def create_hook(hook_name)
|
141
|
+
Overcommit::Hook.const_get(@context.hook_class_name).
|
142
|
+
const_get(hook_name).
|
143
|
+
new(@config, @context)
|
144
|
+
rescue LoadError, NameError => error
|
145
|
+
raise Overcommit::Exceptions::HookLoadError,
|
146
|
+
"Unable to load hook '#{hook_name}': #{error}",
|
147
|
+
error.backtrace
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
data/lib/overcommit/installer.rb
CHANGED
@@ -1,113 +1,106 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'yaml'
|
3
2
|
|
4
3
|
module Overcommit
|
4
|
+
# Manages the installation of Overcommit hooks in a git repository.
|
5
5
|
class Installer
|
6
|
-
def initialize(
|
7
|
-
@
|
8
|
-
@target = target
|
6
|
+
def initialize(logger)
|
7
|
+
@log = logger
|
9
8
|
end
|
10
9
|
|
11
|
-
def run
|
10
|
+
def run(target, options)
|
11
|
+
@target = target
|
12
|
+
@options = options
|
12
13
|
validate_target
|
13
|
-
@options[:
|
14
|
+
@options[:action] == :uninstall ? uninstall : install
|
14
15
|
end
|
15
16
|
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :log
|
20
|
+
|
16
21
|
def install
|
17
22
|
log.log "Installing hooks into #{@target}"
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
|
24
|
+
ensure_hooks_directory
|
25
|
+
install_master_hook
|
26
|
+
install_hook_symlinks
|
27
|
+
|
28
|
+
log.success "Successfully installed hooks into #{@target}"
|
22
29
|
end
|
23
30
|
|
24
31
|
def uninstall
|
25
32
|
log.log "Removing hooks from #{@target}"
|
26
33
|
|
27
|
-
|
28
|
-
|
29
|
-
rm_configuration
|
30
|
-
end
|
34
|
+
uninstall_master_hook
|
35
|
+
uninstall_hook_symlinks
|
31
36
|
|
32
|
-
|
37
|
+
log.success "Successfully removed hooks from #{@target}"
|
38
|
+
end
|
33
39
|
|
34
|
-
def
|
35
|
-
|
40
|
+
def hooks_path
|
41
|
+
absolute_target = File.expand_path(@target)
|
42
|
+
File.join(absolute_target, '.git', 'hooks')
|
36
43
|
end
|
37
44
|
|
38
|
-
def
|
39
|
-
|
40
|
-
File.join(absolute_target, '.git/hooks')
|
45
|
+
def ensure_hooks_directory
|
46
|
+
FileUtils.mkdir_p(hooks_path)
|
41
47
|
end
|
42
48
|
|
43
49
|
def validate_target
|
44
|
-
absolute_target = File.expand_path
|
45
|
-
|
46
|
-
|
50
|
+
absolute_target = File.expand_path(@target)
|
51
|
+
|
52
|
+
unless File.directory?(absolute_target)
|
53
|
+
raise Overcommit::Exceptions::InvalidGitRepo, 'is not a directory'
|
47
54
|
end
|
48
55
|
|
49
56
|
unless File.directory?(File.join(absolute_target, '.git'))
|
50
|
-
raise
|
57
|
+
raise Overcommit::Exceptions::InvalidGitRepo, 'does not appear to be a git repository'
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
54
|
-
|
55
|
-
|
56
|
-
|
61
|
+
def install_master_hook
|
62
|
+
master_hook = File.join(OVERCOMMIT_HOME, 'template-dir', 'hooks', 'overcommit-hook')
|
63
|
+
install_location = File.join(hooks_path, 'overcommit-hook')
|
64
|
+
FileUtils.mkdir_p(hooks_path)
|
65
|
+
FileUtils.cp(master_hook, install_location)
|
57
66
|
end
|
58
67
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
FileUtils.cp hook, File.join(hook_path, File.basename(hook))
|
63
|
-
end
|
68
|
+
def uninstall_master_hook
|
69
|
+
install_location = File.join(hooks_path, 'overcommit-hook')
|
70
|
+
FileUtils.rm_rf(install_location)
|
64
71
|
end
|
65
72
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
73
|
+
def install_hook_symlinks
|
74
|
+
# Link each hook type (pre-commit, commit-msg, etc.) to the master hook.
|
75
|
+
# We change directories so that the relative symlink paths work regardless
|
76
|
+
# of where the repository is located.
|
77
|
+
Dir.chdir(hooks_path) do
|
78
|
+
Overcommit::Utils.supported_hook_types.each do |hook_type|
|
79
|
+
unless can_replace_file?(hook_type)
|
80
|
+
raise Overcommit::Exceptions::PreExistingHooks,
|
81
|
+
"Hook '#{File.expand_path(hook_type)}' already exists and was not installed by Overcommit"
|
82
|
+
end
|
83
|
+
FileUtils.ln_sf('overcommit-hook', hook_type)
|
84
|
+
end
|
69
85
|
end
|
70
86
|
end
|
71
87
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
88
|
+
def can_replace_file?(file)
|
89
|
+
@options[:force] ||
|
90
|
+
!File.exists?(file) ||
|
91
|
+
overcommit_symlink?(file)
|
75
92
|
end
|
76
93
|
|
77
|
-
def
|
78
|
-
Dir
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
def write_configuration
|
83
|
-
template = @options.fetch(:template, 'default')
|
84
|
-
base_config = Overcommit.config.templates[template]
|
85
|
-
if base_config.nil?
|
86
|
-
raise ArgumentError, "No such template '#{template}'"
|
87
|
-
end
|
88
|
-
|
89
|
-
base_config = base_config.dup
|
90
|
-
(base_config['excludes'] ||= {}).
|
91
|
-
merge!(@options[:excludes] || {}) do |_, a, b|
|
92
|
-
# Concat the arrays together
|
93
|
-
a + b
|
94
|
-
end
|
95
|
-
|
96
|
-
File.open(configuration_location, 'w') do |config|
|
97
|
-
YAML.dump(base_config, config)
|
94
|
+
def uninstall_hook_symlinks
|
95
|
+
Dir.chdir(hooks_path) do
|
96
|
+
Overcommit::Utils.supported_hook_types.each do |hook_type|
|
97
|
+
FileUtils.rm_rf(hook_type) if overcommit_symlink?(hook_type)
|
98
|
+
end
|
98
99
|
end
|
99
100
|
end
|
100
101
|
|
101
|
-
def
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
def configuration_location
|
106
|
-
File.join(hook_path, 'overcommit.yml')
|
107
|
-
end
|
108
|
-
|
109
|
-
def delete(file)
|
110
|
-
File.delete file rescue false
|
102
|
+
def overcommit_symlink?(file)
|
103
|
+
File.symlink?(file) && File.readlink(file) == 'overcommit-hook'
|
111
104
|
end
|
112
105
|
end
|
113
106
|
end
|
data/lib/overcommit/logger.rb
CHANGED
@@ -1,18 +1,21 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
|
3
|
-
# This class centralizes all communication to STDOUT
|
4
1
|
module Overcommit
|
2
|
+
# Encapsulates all communication to an output source.
|
5
3
|
class Logger
|
6
|
-
|
4
|
+
# Helper for creating a logger which outputs nothing.
|
5
|
+
def self.silent
|
6
|
+
new(File.open('/dev/null', 'w'))
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
+
def initialize(out)
|
10
|
+
@out = out
|
11
|
+
end
|
9
12
|
|
10
13
|
def partial(*args)
|
11
|
-
out.print
|
14
|
+
@out.print(*args)
|
12
15
|
end
|
13
16
|
|
14
17
|
def log(*args)
|
15
|
-
out.puts
|
18
|
+
@out.puts(*args)
|
16
19
|
end
|
17
20
|
|
18
21
|
def bold(str)
|
@@ -23,6 +26,10 @@ module Overcommit
|
|
23
26
|
color(31, str)
|
24
27
|
end
|
25
28
|
|
29
|
+
def bold_error(str)
|
30
|
+
color('1;31', str)
|
31
|
+
end
|
32
|
+
|
26
33
|
def success(str)
|
27
34
|
color(32, str)
|
28
35
|
end
|
@@ -31,18 +38,14 @@ module Overcommit
|
|
31
38
|
color(33, str)
|
32
39
|
end
|
33
40
|
|
34
|
-
def
|
41
|
+
def bold_warning(str)
|
35
42
|
color('1;33', str)
|
36
43
|
end
|
37
44
|
|
38
|
-
def out
|
39
|
-
self.output ||= $stdout
|
40
|
-
end
|
41
|
-
|
42
45
|
private
|
43
46
|
|
44
47
|
def color(code, str)
|
45
|
-
log(out.
|
48
|
+
log(@out.tty? ? "\033[#{code}m#{str}\033[0m" : str)
|
46
49
|
end
|
47
50
|
end
|
48
51
|
end
|
data/lib/overcommit/utils.rb
CHANGED
@@ -1,62 +1,87 @@
|
|
1
|
+
require 'wopen3'
|
2
|
+
|
1
3
|
module Overcommit
|
4
|
+
# Utility functions for general use.
|
2
5
|
module Utils
|
3
6
|
class << self
|
4
|
-
|
5
|
-
|
6
|
-
def register_hook(hook)
|
7
|
-
@@hooks << hook
|
8
|
-
end
|
9
|
-
|
10
|
-
def run_hooks(*args)
|
11
|
-
@@hooks.each { |hook| hook.new.run(*args) }
|
7
|
+
def script_path(script)
|
8
|
+
File.join(OVERCOMMIT_HOME, 'libexec', script)
|
12
9
|
end
|
13
10
|
|
14
|
-
|
15
|
-
|
11
|
+
# Returns an absolute path to the root of the repository.
|
12
|
+
def repo_root
|
13
|
+
@repo_root ||=
|
14
|
+
begin
|
15
|
+
result = `git rev-parse --show-toplevel`.chomp
|
16
|
+
result if $?.success?
|
17
|
+
end
|
16
18
|
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
# Shamelessly stolen from:
|
21
|
+
# stackoverflow.com/questions/1509915/converting-camel-case-to-underscore-case-in-ruby
|
22
|
+
def snake_case(str)
|
23
|
+
str.gsub(/::/, '/').
|
24
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
|
25
|
+
gsub(/([a-z\d])([A-Z])/, '\1_\2').
|
26
|
+
tr('-', '_').
|
27
|
+
downcase
|
23
28
|
end
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
# Converts a string containing underscores/hyphens/spaces into CamelCase.
|
31
|
+
def camel_case(str)
|
32
|
+
str.split(/_|-| /).map { |part| part.sub(/^\w/) { |c| c.upcase } }.join
|
27
33
|
end
|
28
34
|
|
29
|
-
|
30
|
-
|
35
|
+
# Returns a list of supported hook types (pre-commit, commit-msg, etc.)
|
36
|
+
def supported_hook_types
|
37
|
+
Dir[File.join(OVERCOMMIT_HOME, 'lib', 'overcommit', 'hook', '*')].
|
38
|
+
select { |file| File.directory?(file) }.
|
39
|
+
map { |file| File.basename(file, '.rb').gsub('_', '-') }
|
31
40
|
end
|
32
41
|
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
42
|
+
# Returns a list of supported hook classes (PreCommit, CommitMsg, etc.)
|
43
|
+
def supported_hook_type_classes
|
44
|
+
supported_hook_types.map do |file|
|
45
|
+
file.split('-').map { |part| part.capitalize }.join
|
46
|
+
end
|
38
47
|
end
|
39
48
|
|
40
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
49
|
+
# Returns whether a command can be found given the current environment path.
|
50
|
+
def in_path?(cmd)
|
51
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
52
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
53
|
+
exts.each do |ext|
|
54
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
55
|
+
return true if File.executable?(exe)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
false
|
48
59
|
end
|
49
60
|
|
50
|
-
#
|
51
|
-
#
|
52
|
-
|
53
|
-
|
61
|
+
# Wrap external subshell calls. This is necessary in order to allow
|
62
|
+
# Overcommit to call other Ruby executables without requiring that they be
|
63
|
+
# specified in Overcommit's Gemfile--a nasty consequence of using
|
64
|
+
# `bundle exec overcommit` while developing locally.
|
65
|
+
def command(command)
|
66
|
+
with_environment 'RUBYOPT' => nil do
|
67
|
+
Wopen3.system(command)
|
68
|
+
end
|
54
69
|
end
|
55
70
|
|
56
71
|
private
|
57
72
|
|
58
|
-
|
59
|
-
|
73
|
+
# Calls a block of code with a modified set of environment variables,
|
74
|
+
# restoring them once the code has executed.
|
75
|
+
def with_environment(env, &block)
|
76
|
+
old_env = {}
|
77
|
+
env.each do |var, value|
|
78
|
+
old_env[var] = ENV[var.to_s]
|
79
|
+
ENV[var.to_s] = value
|
80
|
+
end
|
81
|
+
|
82
|
+
yield
|
83
|
+
ensure
|
84
|
+
old_env.each { |var, value| ENV[var.to_s] = value }
|
60
85
|
end
|
61
86
|
end
|
62
87
|
end
|