Module: Overcommit::Utils

Defined in:
lib/overcommit/utils.rb

Overview

Utility functions for general use.

Class Method Summary collapse

Class Method Details

.broken_symlink?(file) ⇒ true, false

Returns whether a file is a broken symlink.

Returns:

  • (true, false)


155
156
157
158
159
# File 'lib/overcommit/utils.rb', line 155

def broken_symlink?(file)
  # JRuby's implementation of File.exist? returns true for broken
  # symlinks, so we need use File.size?
  File.symlink?(file) && File.size?(file).nil?
end

.camel_case(str) ⇒ Object

Converts a string containing underscores/hyphens/spaces into CamelCase.



68
69
70
# File 'lib/overcommit/utils.rb', line 68

def camel_case(str)
  str.split(/_|-| /).map { |part| part.sub(/^\w/) { |c| c.upcase } }.join
end

.convert_glob_to_absolute(glob) ⇒ String

Convert a glob pattern to an absolute path glob pattern rooted from the repository root directory.

Parameters:

  • glob (String)

Returns:

  • (String)


166
167
168
# File 'lib/overcommit/utils.rb', line 166

def convert_glob_to_absolute(glob)
  File.join(repo_root, glob)
end

.execute(args) ⇒ Overcommit::Subprocess::Result

Execute a command in a subprocess, capturing exit status and output from both standard and error streams.

This is intended to provide a centralized place to perform any checks or filtering of the command before executing it.

Parameters:

  • args (Array<String>)

Returns:



112
113
114
115
116
117
118
119
# File 'lib/overcommit/utils.rb', line 112

def execute(args)
  if args.include?('|')
    raise Overcommit::Exceptions::InvalidCommandArgs,
          'Cannot pipe commands with the `execute` helper'
  end

  Subprocess.spawn(args)
end

.execute_in_background(args) ⇒ Thread

Execute a command in a subprocess, returning immediately.

This provides a convenient way to execute long-running processes for which we do not need to know the result.

Parameters:

  • args (Array<String>)

Returns:

  • (Thread)

    thread watching the resulting child process



128
129
130
131
132
133
134
135
136
# File 'lib/overcommit/utils.rb', line 128

def execute_in_background(args)
  if args.include?('|')
    raise Overcommit::Exceptions::InvalidCommandArgs,
          'Cannot pipe commands with the `execute_in_background` helper'
  end

  # Dissociate process from parent's input/output streams
  Process.detach(Process.spawn({}, *args, [:in, :out, :err] => '/dev/null'))
end

.git_dir(repo_dir = repo_root) ⇒ String

Returns an absolute path to the .git directory for a repo.

Parameters:

  • repo_dir (String) (defaults to: repo_root)

    root directory of git repo

Returns:

  • (String)


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/overcommit/utils.rb', line 38

def git_dir(repo_dir = repo_root)
  @git_dir ||=
    begin
      git_dir = File.expand_path('.git', repo_dir)

      # .git could also be a file that contains the location of the git directory
      unless File.directory?(git_dir)
        git_dir = File.read(git_dir)[/^gitdir: (.*)$/, 1]

        # Resolve relative paths
        unless git_dir.start_with?('/')
          git_dir = File.expand_path(git_dir, repo_dir)
        end
      end

      git_dir
    end
end

.in_path?(cmd) ⇒ true, false

Returns whether a command can be found given the current environment path.

Parameters:

  • cmd (String)

Returns:

  • (true, false)

    whether a command can be found given the current environment path.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/overcommit/utils.rb', line 89

def in_path?(cmd)
  # ENV['PATH'] doesn't include the repo root, but that is a valid
  # location for executables, so we want to add it to the list of places
  # we are checking for the executable.
  paths = [repo_root] + ENV['PATH'].split(File::PATH_SEPARATOR)
  exts  = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
  paths.each do |path|
    exts.each do |ext|
      exe = File.join(path, "#{cmd}#{ext}")
      return true if File.executable?(exe)
    end
  end
  false
end

.matches_path?(pattern, path) ⇒ Boolean

Return whether a pattern matches the given path.

Parameters:

  • pattern (String)
  • path (String)

Returns:

  • (Boolean)


174
175
176
177
178
179
# File 'lib/overcommit/utils.rb', line 174

def matches_path?(pattern, path)
  File.fnmatch?(pattern, path,
                File::FNM_PATHNAME | # Wildcard doesn't match separator
                File::FNM_DOTMATCH   # Wildcards match dotfiles
  )
end

.repo_rootString

Returns an absolute path to the root of the repository.

We do this ourselves rather than call ‘git rev-parse –show-toplevel` to solve an issue where the .git directory might not actually be valid in tests.

Returns:

  • (String)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/overcommit/utils.rb', line 19

def repo_root
  @repo_root ||=
    begin
      git_dir = Pathname.new(File.expand_path('.')).enum_for(:ascend).find do |path|
        File.exist?(File.join(path, '.git'))
      end

      unless git_dir
        raise Overcommit::Exceptions::InvalidGitRepo, 'no .git directory found'
      end

      git_dir.to_s
    end
end

.script_path(script) ⇒ Object



8
9
10
# File 'lib/overcommit/utils.rb', line 8

def script_path(script)
  File.join(OVERCOMMIT_HOME, 'libexec', script)
end

.snake_case(str) ⇒ Object

Shamelessly stolen from: stackoverflow.com/questions/1509915/converting-camel-case-to-underscore-case-in-ruby



59
60
61
62
63
64
65
# File 'lib/overcommit/utils.rb', line 59

def snake_case(str)
  str.gsub(/::/, '/').
      gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
      gsub(/([a-z\d])([A-Z])/, '\1_\2').
      tr('-', '_').
      downcase
end

.supported_hook_type_classesObject

Returns a list of supported hook classes (PreCommit, CommitMsg, etc.)



80
81
82
83
84
# File 'lib/overcommit/utils.rb', line 80

def supported_hook_type_classes
  supported_hook_types.map do |file|
    file.split('-').map(&:capitalize).join
  end
end

.supported_hook_typesObject

Returns a list of supported hook types (pre-commit, commit-msg, etc.)



73
74
75
76
77
# File 'lib/overcommit/utils.rb', line 73

def supported_hook_types
  Dir[File.join(OVERCOMMIT_HOME, 'lib', 'overcommit', 'hook', '*')].
    select { |file| File.directory?(file) }.
    map { |file| File.basename(file, '.rb').gsub('_', '-') }
end

.with_environment(env) ⇒ Object

Calls a block of code with a modified set of environment variables, restoring them once the code has executed.



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/overcommit/utils.rb', line 140

def with_environment(env)
  old_env = {}
  env.each do |var, value|
    old_env[var] = ENV[var.to_s]
    ENV[var.to_s] = value
  end

  yield
ensure
  old_env.each { |var, value| ENV[var.to_s] = value }
end