Class: Picnic::Cli

Inherits:
Object
  • Object
show all
Defined in:
lib/picnic/cli.rb

Overview

Provides a command-line interface for your app. This is useful for creating a ‘bin’ file for launching your application.

Usage example (put this in a file called ‘foo’):

#!/usr/bin/env ruby

require 'rubygems'
require 'picnic'

require 'picnic/cli'

cli = Picnic::Cli.new(
  'foo',
  :app_file => "/path/to/foo.br"
)

cli.handle_cli_input

Also see the ServiceControl class for info on how to use your cli script as a service.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, options = {}) ⇒ Cli

Creates a new command-line interface handler.

app

The name of the application. This should match the name of the binary, which by default is expected to be in the same directory as the service control script.

options

A hash overriding default options. The options are:

app_file

The path to your application’s main Ruby file. By default this is expected to be ../lib/<app>.rb

pid_file

Where the app’s PID file (containing the app’s process ID) should be placed. By default this is /etc/<app>/<app>.pid



43
44
45
46
47
48
49
50
51
52
# File 'lib/picnic/cli.rb', line 43

def initialize(app, options = {})
  @app = app
  
  @options = options || {}
  @options[:app_file]   ||= File.expand_path(File.dirname(File.expand_path(__FILE__))+"/../lib/#{app}.rb")
  @options[:app_name]   ||= app
  @options[:app_module] ||= app.capitalize
  @options[:pid_file]   ||= "/etc/#{app}/#{app}.pid"
  @options[:conf_file]  ||= nil
end

Instance Attribute Details

#appObject

Returns the value of attribute app.



30
31
32
# File 'lib/picnic/cli.rb', line 30

def app
  @app
end

#optionsObject

Returns the value of attribute options.



30
31
32
# File 'lib/picnic/cli.rb', line 30

def options
  @options
end

Instance Method Details

#handle_cli_inputObject

Parses command line options given to the script.



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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/picnic/cli.rb', line 55

def handle_cli_input
#      if File.exists? options[:app_file]
    # try to use given app base path
    $APP_ROOT = File.dirname(options[:app_file]).gsub(/\/(lib|bin)\/?$/, '')
#      else
#        require 'rubygems'
#        
#        # fall back to using gem installation
#        matches = Gem::source_index.find_name(app)
#        raise LoadError, "#{app} gem doesn't appear to be installed!" if matches.empty?
#        
#        gem_spec = matches.last
#        $APP_ROOT = gem_spec.full_gem_path
#        
#        gem(app)
#      end
  
  unless File.file?(options[:app_file])
    raise ArgumentError, "options[:app_file] points to #{options[:app_file].inspect} but this does not appear to be a valid Camping application!}"
  end
  
  
  puts "Loading #{app.inspect} code from #{$APP_ROOT.inspect}..."
  
  $: <<  $APP_ROOT+"/lib"
  
  $PID_FILE     = @options[:pid_file]
  $CONFIG_FILE  = @options[:conf_file]
  $VERBOSE      = @options[:verbose]
  
  opts = OptionParser.new do |opts|
    #opts.banner = ""
    #opts.define_head ""
    #opts.separator ""
    opts.on("-d", "--daemonize", "Run daemonized in the background") do
      $DAEMONIZE = true
    end
    opts.on("-c", "--config FILE", "Use this config file (default is /etc/<app>/config.yml)") do |c| 
      puts "Using config file #{c.inspect}"
      $CONFIG_FILE = c
    end
    opts.on("-P", "--pid_file FILE", "Path to pid file (used only when running daemonized; default is /etc/<app>/<app>.pid)") do |p| 
      if $DAEMONIZE && !File.exists?(p)
        puts "Using pid file #{p.inspect}"
        $PID_FILE = p
      elsif File.exists?(p)
        puts "The pid file already exists.  Is #{app} running?\n" +
          "You will have to first manually remove the pid file at '#{p}' to start the server as a daemon."
        exit 1
      else
        puts "Not running as daemon.  Ignoring pid option"
      end
    end
    
    # optoinal block with additonal opts.on() calls specific to your application
    if @options[:extra_cli_options]
      @options[:extra_cli_options].call(opts)
    end   
  
    # No argument, shows at tail.  This will print an options summary.
    # Try it and see!
    opts.on_tail("-h", "--help", "Show this message") do
      puts opts
      exit
    end
    
    opts.on_tail("-v", "--version", "Show the application's version number") do
      require "#{$APP_ROOT}/lib/#{app}/version.rb"
      app_mod = Object.const_get(@options[:app_module])
      puts "#{app}-#{app_mod::VERSION::STRING}"
      exit
    end
  end
  
  begin
    opts.parse! ARGV
  rescue OptionParser::ParseError => ex
    STDERR.puts "!! #{ex.message}"
    puts "** use `#{File.basename($0)} --help` for more details..."
    exit 1
  end
  
  
  $CONF = Picnic::Conf.new
  $CONF.load_from_file(app, $APP_ROOT, $CONF_FILE)
  
  if $DAEMONIZE
    # TODO: use Process.daemon when RUBY_VERSION >= 1.9
    
    exit if fork
    Process.setsid
    exit if fork
    
    Dir.chdir $APP_ROOT
    File.umask 0000
    
    STDIN.reopen  $CONF.log[:file], "a"
    STDOUT.reopen $CONF.log[:file], "a"
    STDERR.reopen $CONF.log[:file], "a"
    
    File.open($PID_FILE, 'w'){ |f| f.write("#{Process.pid}") }
    at_exit { File.delete($PID_FILE) if File.exist?($PID_FILE) }
  end
  
  $CONF.database = :unused if $CONF.database.blank?
  
  server = Picnic::Server::Base.new($CONF, [options[:app_file]])
  server.start
end