Module: Overcommit::Utils

Defined in:
lib/overcommit/utils.rb

Overview

Utility functions for general use.

Defined Under Namespace

Classes: Version

Class Method Summary collapse

Class Method Details

.broken_symlink?(file) ⇒ true, false

Returns whether a file is a broken symlink.

Returns:

  • (true, false)


178
179
180
181
182
# File 'lib/overcommit/utils.rb', line 178

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.



86
87
88
# File 'lib/overcommit/utils.rb', line 86

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)


189
190
191
# File 'lib/overcommit/utils.rb', line 189

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:



136
137
138
139
140
141
142
143
# File 'lib/overcommit/utils.rb', line 136

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) ⇒ ChildProcess

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:

  • (ChildProcess)

    detached process spawned in the background



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

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

  Subprocess.spawn_detached(args)
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)


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/overcommit/utils.rb', line 56

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.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/overcommit/utils.rb', line 108

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)


197
198
199
200
201
202
# File 'lib/overcommit/utils.rb', line 197

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

.parent_commandObject

Return the parent command that triggered this hook run



124
125
126
# File 'lib/overcommit/utils.rb', line 124

def parent_command
  `ps -ocommand= -p #{Process.ppid}`.chomp
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)


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

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



26
27
28
# File 'lib/overcommit/utils.rb', line 26

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



77
78
79
80
81
82
83
# File 'lib/overcommit/utils.rb', line 77

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.)



99
100
101
102
103
# File 'lib/overcommit/utils.rb', line 99

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.)



91
92
93
94
95
96
# File 'lib/overcommit/utils.rb', line 91

def supported_hook_types
  Dir[File.join(HOOK_DIRECTORY, '*')].
    select { |file| File.directory?(file) }.
    reject { |file| File.basename(file) == 'shared' }.
    map { |file| File.basename(file).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.



163
164
165
166
167
168
169
170
171
172
173
# File 'lib/overcommit/utils.rb', line 163

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