Class: Geordi::Util

Inherits:
Object
  • Object
show all
Defined in:
lib/geordi/util.rb

Class Method Summary collapse

Class Method Details

.binstub_or_fallback(executable) ⇒ Object



85
86
87
88
89
# File 'lib/geordi/util.rb', line 85

def binstub_or_fallback(executable)
  binstub_file = "bin/#{executable}"

  File.exist?(binstub_file) ? binstub_file : "bundle exec #{executable}"
end

.cmd_exists?(cmd) ⇒ Boolean

check if given cmd is executable. Absolute path or command in $PATH allowed.

Returns:

  • (Boolean)


152
153
154
155
# File 'lib/geordi/util.rb', line 152

def cmd_exists?(cmd)
  system("which #{cmd} > /dev/null")
  $?.exitstatus.zero?
end

.console_command(environment) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/geordi/util.rb', line 91

def console_command(environment)
  if gem_major_version('rails') == 2
    "script/console #{environment}"
  elsif gem_major_version('rails') == 3
    "#{binstub_or_fallback('rails')} console #{environment}"
  else
    use_multiline = if irb_version >= Gem::Version.new('1.2') && ruby_version < Gem::Version.new('3.0')
      Interaction.note 'Using --nomultiline switch for faster pasting'
      '--nomultiline'
    end

    irb_flags = [use_multiline, Settings.new.irb_flags].join(' ').strip
    irb_flags.prepend('-- ') unless irb_flags.empty?

    "#{binstub_or_fallback('rails')} console -e #{environment} #{irb_flags}"
  end
end

.cucumber_path?(path) ⇒ Boolean

Returns:

  • (Boolean)


213
214
215
# File 'lib/geordi/util.rb', line 213

def cucumber_path?(path)
  %r{(^|\/)features|\.feature($|:)}.match?(path)
end

.current_branchObject



117
118
119
120
121
122
123
# File 'lib/geordi/util.rb', line 117

def current_branch
  if testing?
    git_default_branch
  else
    `git rev-parse --abbrev-ref HEAD`.strip
  end
end

.decide_texteditorObject

try to guess user’s favorite cli text editor



141
142
143
144
145
146
147
148
149
# File 'lib/geordi/util.rb', line 141

def decide_texteditor
  %w[/usr/bin/editor vi].each do |texteditor|
    if cmd_exists?(texteditor) && texteditor.start_with?('$')
      return ENV[texteditor[1..-1]]
    elsif cmd_exists? texteditor
      return texteditor
    end
  end
end

.deploy_targetsObject



134
135
136
137
138
# File 'lib/geordi/util.rb', line 134

def deploy_targets
  Dir['config/deploy/*'].map do |f|
    File.basename f, '.rb' # Filename without .rb extension
  end
end

.file_containing?(file, regex) ⇒ Boolean

Returns:

  • (Boolean)


190
191
192
# File 'lib/geordi/util.rb', line 190

def file_containing?(file, regex)
  File.exist?(file) && File.read(file).scan(regex).any?
end

.gem_available?(gem) ⇒ Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/geordi/util.rb', line 170

def gem_available?(gem)
  !!gem_version(gem)
end

.gem_major_version(gem) ⇒ Object

Get the major version or for the given gem by parsing the Gemfile.lock. Returns nil if the gem is not used.



176
177
178
179
# File 'lib/geordi/util.rb', line 176

def gem_major_version(gem)
  gem_version = gem_version(gem)
  gem_version && gem_version.segments[0]
end

.gem_version(gem) ⇒ Object

Get the version for the given gem by parsing Gemfile.lock. Returns nil if the gem is not used.



183
184
185
186
187
188
# File 'lib/geordi/util.rb', line 183

def gem_version(gem)
  lock_file = Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile))
  spec = lock_file.specs.detect { |spec| spec.name == gem }

  spec && spec.version
end

.git_default_branchObject



221
222
223
224
225
226
227
228
229
230
# File 'lib/geordi/util.rb', line 221

def git_default_branch
  default_branch = if testing?
    ENV['GEORDI_TESTING_DEFAULT_BRANCH']
  else
    head_symref = `git ls-remote --symref origin HEAD`
    head_symref[%r{\Aref: refs/heads/(\S+)\sHEAD}, 1]
  end

  default_branch || 'master'
end

.installing_missing_gemsObject

Geordi commands sometimes require external gems. However, we don’t want all employed gems as runtime dependencies because that would unnecessarily slow down all commands. Thus, we have this handy method here.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/geordi/util.rb', line 13

def installing_missing_gems
  yield
rescue LoadError => error
  error.message =~ /-- (\S+)\Z/
  Regexp.last_match(1) || raise # could not extract a gem name from the error message, re-raise the error

  gem_name = Regexp.last_match(1).strip.split('/').first
  install_command = 'gem install ' + gem_name

  # install missing gem
  Interaction.warn 'Probably missing gem: ' + gem_name
  Interaction.prompt('Install it now?', 'y', /y|yes/) || Interaction.fail('Missing Gems.')
  Util.run!(install_command, show_cmd: true)

  # retry
  Gem.clear_paths
  Interaction.note 'Retrying ...'
  require gem_name
  retry
end

.irb_versionObject



198
199
200
201
202
203
204
205
206
# File 'lib/geordi/util.rb', line 198

def irb_version
  version_string = if testing?
    ENV['GEORDI_TESTING_IRB_VERSION']
  else
    `irb --version`[/irb (\d+\.\d+\.\d+)/, 1]
  end

  Gem::Version.new(version_string)
end

.is_port_open?(port) ⇒ Boolean

Returns:

  • (Boolean)


157
158
159
160
161
162
163
# File 'lib/geordi/util.rb', line 157

def is_port_open?(port)
  socket = TCPSocket.new('127.0.0.1', port)
  socket.close
  true
rescue Errno::ECONNREFUSED
  false
end

.rspec_path?(path) ⇒ Boolean

Returns:

  • (Boolean)


217
218
219
# File 'lib/geordi/util.rb', line 217

def rspec_path?(path)
  %r{(^|\/)spec|_spec\.rb($|:)}.match?(path)
end

.ruby_versionObject



208
209
210
211
# File 'lib/geordi/util.rb', line 208

def ruby_version
  version_string = testing? ? ENV['GEORDI_TESTING_RUBY_VERSION'] : RUBY_VERSION
  Gem::Version.new(version_string)
end

.run!(command, show_cmd: false, confirm: false, fail_message: 'Something went wrong.', exec: false) ⇒ Object

Run a command with a clean environment. Print an error message and exit if the command fails.

show_cmd: Whether to print the command confirm: Whether to ask for confirmation before running it fail_message: The text to print on command failure exec: Whether to run the command with ‘exec` instead of `system`



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
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/geordi/util.rb', line 41

def run!(command, show_cmd: false, confirm: false, fail_message: 'Something went wrong.', exec: false)
  # Disable shell features for arrays https://stackoverflow.com/questions/13338147/ruby-system-method-arguments
  # Conversion: ['ls *', 'some arg'] => ['ls', '*', 'some arg']
  # If you need shell features, you need to pass in a String instead of an array.
  if command.is_a?(Array)
    real_command, *arguments = *command
    command = [real_command.split(' '), arguments].flatten
    show_command = command
  else
    show_command = [command]
  end

  if show_cmd
    # Join with spaces for better readability and copy-pasting
    Interaction.note_cmd show_command.join(' ')
  end

  if confirm
    Interaction.prompt('Run this now?', 'n', /y|yes/) or Interaction.fail('Cancelled.')
  end

  if testing?
    # Join with commas for precise argument distinction
    puts "Util.run!#{' (exec)' if exec} #{show_command.join(', ')}"
  else
    method = exec ? :exec : :system

    # Remove Geordi's Bundler environment when running commands.
    success = if !defined?(Bundler)
      Kernel.public_send(method, *command)
    elsif Gem::Version.new(Bundler::VERSION) >= Gem::Version.new('1.17.3')
      Bundler.with_original_env do
        Kernel.public_send(method, *command)
      end
    else
      method = exec ? :clean_exec : :clean_system
      Bundler.public_send(method, *command)
    end

    # This part will never be reached when `exec` is true
    success || Interaction.fail(fail_message)
  end
end

.server_commandObject



109
110
111
112
113
114
115
# File 'lib/geordi/util.rb', line 109

def server_command
  if gem_major_version('rails') == 2
    'script/server ""'
  else
    "#{binstub_or_fallback('rails')} server"
  end
end

.staged_changes?Boolean

Returns:

  • (Boolean)


125
126
127
128
129
130
131
132
# File 'lib/geordi/util.rb', line 125

def staged_changes?
  if testing?
    ENV['GEORDI_TESTING_STAGED_CHANGES'] == 'true'
  else
    statuses = `git status --porcelain`.split("\n")
    statuses.any? { |l| /^[A-Z]/i =~ l }
  end
end

.stripped_lines(input_string) ⇒ Object

splint lines e.g. read from a file into lines and clean those up



166
167
168
# File 'lib/geordi/util.rb', line 166

def stripped_lines(input_string)
  input_string.lines.map(&:chomp).map(&:strip)
end

.testing?Boolean

Returns:

  • (Boolean)


194
195
196
# File 'lib/geordi/util.rb', line 194

def testing?
  !!ENV['GEORDI_TESTING']
end