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



80
81
82
83
84
# File 'lib/geordi/util.rb', line 80

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

  File.exists?(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)


139
140
141
142
# File 'lib/geordi/util.rb', line 139

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

.console_command(environment) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/geordi/util.rb', line 86

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
    "#{binstub_or_fallback('rails')} console -e #{environment}"
  end
end

.current_branchObject



104
105
106
107
108
109
110
# File 'lib/geordi/util.rb', line 104

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

.decide_texteditorObject

try to guess user’s favorite cli text editor



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

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



121
122
123
124
125
# File 'lib/geordi/util.rb', line 121

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)


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

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

.gem_available?(gem) ⇒ Boolean

Returns:

  • (Boolean)


157
158
159
# File 'lib/geordi/util.rb', line 157

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.



163
164
165
166
# File 'lib/geordi/util.rb', line 163

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.



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

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

.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

.is_port_open?(port) ⇒ Boolean

Returns:

  • (Boolean)


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

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

.run!(command, show_cmd: false, confirm: false, fail_message: 'Something went wrong.') ⇒ 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



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
71
72
73
74
75
76
77
78
# File 'lib/geordi/util.rb', line 40

def run!(command, show_cmd: false, confirm: false, fail_message: 'Something went wrong.')
  # 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! #{show_command.join(', ')}"
  else
    # Remove Geordi's Bundler environment when running commands.
    success = if !defined?(Bundler)
      system(*command)
    elsif Gem::Version.new(Bundler::VERSION) >= Gem::Version.new('1.17.3')
      Bundler.with_original_env do
        system(*command)
      end
    else
      Bundler.clean_system(*command)
    end

    success || Interaction.fail(fail_message)
  end
end

.server_commandObject



96
97
98
99
100
101
102
# File 'lib/geordi/util.rb', line 96

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

.staged_changes?Boolean

Returns:

  • (Boolean)


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

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



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

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

.testing?Boolean

Returns:

  • (Boolean)


181
182
183
# File 'lib/geordi/util.rb', line 181

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