bmarzolf-picnic 0.8.0.20090420

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/CHANGELOG.txt +1 -0
  2. data/History.txt +78 -0
  3. data/LICENSE.txt +165 -0
  4. data/Manifest.txt +45 -0
  5. data/README.txt +31 -0
  6. data/Rakefile +64 -0
  7. data/lib/picnic/authentication.rb +254 -0
  8. data/lib/picnic/cli.rb +165 -0
  9. data/lib/picnic/conf.rb +135 -0
  10. data/lib/picnic/controllers.rb +4 -0
  11. data/lib/picnic/logger.rb +41 -0
  12. data/lib/picnic/server.rb +99 -0
  13. data/lib/picnic/service_control.rb +274 -0
  14. data/lib/picnic/version.rb +9 -0
  15. data/lib/picnic.rb +11 -0
  16. data/setup.rb +1585 -0
  17. data/test/picnic_test.rb +11 -0
  18. data/test/test_helper.rb +2 -0
  19. data/vendor/camping-2.0.20090420/CHANGELOG +118 -0
  20. data/vendor/camping-2.0.20090420/COPYING +18 -0
  21. data/vendor/camping-2.0.20090420/README +82 -0
  22. data/vendor/camping-2.0.20090420/Rakefile +180 -0
  23. data/vendor/camping-2.0.20090420/bin/camping +97 -0
  24. data/vendor/camping-2.0.20090420/doc/camping.1.gz +0 -0
  25. data/vendor/camping-2.0.20090420/examples/README +5 -0
  26. data/vendor/camping-2.0.20090420/examples/blog.rb +375 -0
  27. data/vendor/camping-2.0.20090420/examples/campsh.rb +629 -0
  28. data/vendor/camping-2.0.20090420/examples/tepee.rb +242 -0
  29. data/vendor/camping-2.0.20090420/extras/Camping.gif +0 -0
  30. data/vendor/camping-2.0.20090420/extras/permalink.gif +0 -0
  31. data/vendor/camping-2.0.20090420/lib/camping/ar/session.rb +132 -0
  32. data/vendor/camping-2.0.20090420/lib/camping/ar.rb +78 -0
  33. data/vendor/camping-2.0.20090420/lib/camping/mab.rb +26 -0
  34. data/vendor/camping-2.0.20090420/lib/camping/reloader.rb +184 -0
  35. data/vendor/camping-2.0.20090420/lib/camping/server.rb +159 -0
  36. data/vendor/camping-2.0.20090420/lib/camping/session.rb +75 -0
  37. data/vendor/camping-2.0.20090420/lib/camping-unabridged.rb +630 -0
  38. data/vendor/camping-2.0.20090420/lib/camping.rb +52 -0
  39. data/vendor/camping-2.0.20090420/setup.rb +1551 -0
  40. data/vendor/camping-2.0.20090420/test/apps/env_debug.rb +65 -0
  41. data/vendor/camping-2.0.20090420/test/apps/forms.rb +95 -0
  42. data/vendor/camping-2.0.20090420/test/apps/misc.rb +86 -0
  43. data/vendor/camping-2.0.20090420/test/apps/sessions.rb +38 -0
  44. data/vendor/camping-2.0.20090420/test/test_camping.rb +54 -0
  45. metadata +140 -0
data/lib/picnic/cli.rb ADDED
@@ -0,0 +1,165 @@
1
+ require 'optparse'
2
+
3
+ require 'picnic'
4
+ require 'picnic/conf'
5
+ require 'picnic/server'
6
+
7
+ module Picnic
8
+ # Provides a command-line interface for your app.
9
+ # This is useful for creating a 'bin' file for launching your application.
10
+ #
11
+ # Usage example (put this in a file called 'foo'):
12
+ #
13
+ # #!/usr/bin/env ruby
14
+ #
15
+ # require 'rubygems'
16
+ # require 'picnic'
17
+ #
18
+ # require 'picnic/cli'
19
+ #
20
+ # cli = Picnic::Cli.new(
21
+ # 'foo',
22
+ # :app_file => "/path/to/foo.br"
23
+ # )
24
+ #
25
+ # cli.handle_cli_input
26
+ #
27
+ # Also see the ServiceControl class for info on how to use your cli script
28
+ # as a service.
29
+ class Cli
30
+ attr_accessor :app, :options
31
+
32
+ # Creates a new command-line interface handler.
33
+ #
34
+ # +app+:: The name of the application. This should match the name of the
35
+ # binary, which by default is expected to be in the same directory
36
+ # as the service control script.
37
+ # +options+:: A hash overriding default options. The options are:
38
+ # +app_file+:: The path to your application's main Ruby file.
39
+ # By default this is expected to be <tt>../lib/<app>.rb</tt>
40
+ # +pid_file+:: Where the app's PID file (containing the app's
41
+ # process ID) should be placed. By default this is
42
+ # <tt>/etc/<app>/<app>.pid</tt>
43
+ def initialize(app, options = {})
44
+ @app = app
45
+
46
+ @options = options || {}
47
+ @options[:app_file] ||= File.expand_path(File.dirname(File.expand_path(__FILE__))+"/../lib/#{app}.rb")
48
+ @options[:app_name] ||= app
49
+ @options[:app_module] ||= app.capitalize
50
+ @options[:pid_file] ||= "/etc/#{app}/#{app}.pid"
51
+ @options[:conf_file] ||= nil
52
+ end
53
+
54
+ # Parses command line options given to the script.
55
+ def handle_cli_input
56
+ # if File.exists? options[:app_file]
57
+ # try to use given app base path
58
+ $APP_ROOT = File.dirname(options[:app_file]).gsub(/\/(lib|bin)\/?$/, '')
59
+ # else
60
+ # require 'rubygems'
61
+ #
62
+ # # fall back to using gem installation
63
+ # matches = Gem::source_index.find_name(app)
64
+ # raise LoadError, "#{app} gem doesn't appear to be installed!" if matches.empty?
65
+ #
66
+ # gem_spec = matches.last
67
+ # $APP_ROOT = gem_spec.full_gem_path
68
+ #
69
+ # gem(app)
70
+ # end
71
+
72
+ unless File.file?(options[:app_file])
73
+ raise ArgumentError, "options[:app_file] points to #{options[:app_file].inspect} but this does not appear to be a valid Camping application!}"
74
+ end
75
+
76
+
77
+ puts "Loading #{app.inspect} code from #{$APP_ROOT.inspect}..."
78
+
79
+ $: << $APP_ROOT+"/lib"
80
+
81
+ $PID_FILE = @options[:pid_file]
82
+ $CONFIG_FILE = @options[:conf_file]
83
+ $VERBOSE = @options[:verbose]
84
+
85
+ opts = OptionParser.new do |opts|
86
+ #opts.banner = ""
87
+ #opts.define_head ""
88
+ #opts.separator ""
89
+ opts.on("-d", "--daemonize", "Run daemonized in the background") do
90
+ $DAEMONIZE = true
91
+ end
92
+ opts.on("-c", "--config FILE", "Use this config file (default is /etc/<app>/config.yml)") do |c|
93
+ puts "Using config file #{c.inspect}"
94
+ $CONFIG_FILE = c
95
+ end
96
+ opts.on("-P", "--pid_file FILE", "Path to pid file (used only when running daemonized; default is /etc/<app>/<app>.pid)") do |p|
97
+ if $DAEMONIZE && !File.exists?(p)
98
+ puts "Using pid file #{p.inspect}"
99
+ $PID_FILE = p
100
+ elsif File.exists?(p)
101
+ puts "The pid file already exists. Is #{app} running?\n" +
102
+ "You will have to first manually remove the pid file at '#{p}' to start the server as a daemon."
103
+ exit 1
104
+ else
105
+ puts "Not running as daemon. Ignoring pid option"
106
+ end
107
+ end
108
+
109
+ # optoinal block with additonal opts.on() calls specific to your application
110
+ if @options[:extra_cli_options]
111
+ @options[:extra_cli_options].call(opts)
112
+ end
113
+
114
+ # No argument, shows at tail. This will print an options summary.
115
+ # Try it and see!
116
+ opts.on_tail("-h", "--help", "Show this message") do
117
+ puts opts
118
+ exit
119
+ end
120
+
121
+ opts.on_tail("-v", "--version", "Show the application's version number") do
122
+ require "#{$APP_ROOT}/lib/#{app}/version.rb"
123
+ app_mod = Object.const_get(@options[:app_module])
124
+ puts "#{app}-#{app_mod::VERSION::STRING}"
125
+ exit
126
+ end
127
+ end
128
+
129
+ begin
130
+ opts.parse! ARGV
131
+ rescue OptionParser::ParseError => ex
132
+ STDERR.puts "!! #{ex.message}"
133
+ puts "** use `#{File.basename($0)} --help` for more details..."
134
+ exit 1
135
+ end
136
+
137
+
138
+ $CONF = Picnic::Conf.new
139
+ $CONF.load_from_file(app, $APP_ROOT, $CONF_FILE)
140
+
141
+ if $DAEMONIZE
142
+ # TODO: use Process.daemon when RUBY_VERSION >= 1.9
143
+
144
+ exit if fork
145
+ Process.setsid
146
+ exit if fork
147
+
148
+ Dir.chdir $APP_ROOT
149
+ File.umask 0000
150
+
151
+ STDIN.reopen $CONF.log[:file], "a"
152
+ STDOUT.reopen $CONF.log[:file], "a"
153
+ STDERR.reopen $CONF.log[:file], "a"
154
+
155
+ File.open($PID_FILE, 'w'){ |f| f.write("#{Process.pid}") }
156
+ at_exit { File.delete($PID_FILE) if File.exist?($PID_FILE) }
157
+ end
158
+
159
+ server = Picnic::Server::Base.new($CONF, [options[:app_file]])
160
+ server.start
161
+ end
162
+ end
163
+ end
164
+
165
+
@@ -0,0 +1,135 @@
1
+ require 'active_support'
2
+
3
+ module Picnic
4
+ # Provides an interface for accessing your Picnic app's configuration file.
5
+ #
6
+ # Usage example:
7
+ #
8
+ # # Load the configuration from /etc/foo/config.yml
9
+ # Conf.load('foo')
10
+ #
11
+ # # The contents of config.yml is now available as follows:
12
+ # puts Conf[:server]
13
+ # puts Conf[:authentication][:username]
14
+ # # ... etc.
15
+ class Conf
16
+ def initialize(from_hash = {})
17
+ @conf = HashWithIndifferentAccess.new(from_hash)
18
+
19
+ @conf[:log] ||= HashWithIndifferentAccess.new
20
+ @conf[:log].merge!(:file => STDOUT, :level => 'DEBUG')
21
+
22
+ @conf[:uri_path] ||= "/"
23
+ end
24
+
25
+ # Read a configuration option.
26
+ #
27
+ # For example:
28
+ # puts Conf[:server]
29
+ def [](key)
30
+ @conf[key]
31
+ end
32
+
33
+ # Another way of reading a configuration option.
34
+ #
35
+ # The following statements are equivalent:
36
+ # puts Conf[:server]
37
+ # puts Conf.server
38
+ def method_missing(method, *args)
39
+ self[method]
40
+ end
41
+
42
+ # Needs to be defined when we have a custom method_missing().
43
+ def respond_to?(method)
44
+ (@conf.stringify_keys.keys).include?(method.to_s) || super
45
+ end
46
+
47
+ # Returns the path to your application's example config file.
48
+ #
49
+ # The example config file should be in the root directory of
50
+ # your application's distribution package and should be called
51
+ # <tt>config.example.yml</tt>. This file is used as a template
52
+ # for your app's configuration, to be customized by the end
53
+ # user.
54
+ def example_config_file_path(app_root)
55
+ "#{app_root}/config.example.yml"
56
+ end
57
+
58
+ # Copies the example config file into the appropriate
59
+ # configuration directory.
60
+ #
61
+ # +app_name+:: The name of your application. For example: <tt>foo</tt>
62
+ # +app_root+:: The path to your application's root directory. For example: <tt>/srv/www/camping/foo/</tt>
63
+ # +dest_conf_file:: The path where the example conf file should be copied to.
64
+ # For example: <tt>/etc/foo/config.yml</tt>
65
+ def copy_example_config_file(app_name, app_root, dest_conf_file)
66
+ require 'fileutils'
67
+
68
+ example_conf_file = example_config_file_path(app_root)
69
+
70
+ puts "\n#{app_name.to_s.upcase} SERVER HAS NOT YET BEEN CONFIGURED!!!\n"
71
+ puts "\nAttempting to copy sample configuration from '#{example_conf_file}' to '#{dest_conf_file}'...\n"
72
+
73
+ unless File.exists? example_conf_file
74
+ puts "\nThe example conf file does not exist! The author of #{app_name} may have forgotten to include it. You'll have to create the config file manually.\n"
75
+ exit 2
76
+ end
77
+
78
+ begin
79
+ dest_conf_file_dir = File.dirname(dest_conf_file)
80
+ FileUtils.mkpath(dest_conf_file_dir) unless File.exists? dest_conf_file_dir
81
+ FileUtils.cp(example_conf_file, dest_conf_file)
82
+ rescue Errno::EACCES
83
+ puts "\nIt appears that you do not have permissions to create the '#{dest_conf_file}' file. Try running this command using sudo (as root).\n"
84
+ exit 2
85
+ rescue => e
86
+ puts "\nFor some reason the '#{dest_conf_file}' file could not be created (#{e})."
87
+ puts "You'll have to copy the file manually. Use '#{example_conf_file}' as a template.\n"
88
+ exit 2
89
+ end
90
+
91
+ puts "\nA sample configuration has been created for you in '#{dest_conf_file}'. Please edit this file to" +
92
+ " suit your needs and then run #{app_name} again.\n"
93
+ exit 1
94
+ end
95
+
96
+ # Loads the configuration from the YAML file for the given app.
97
+ #
98
+ # <tt>app_name</tt> should be the name of your app; for example: <tt>foo</tt>
99
+ # <tt>app_root</tt> should be the path to your application's root directory; for example:: <tt>/srv/www/camping/foo/</tt>
100
+ # [<tt>config_file</tt>] can be the path to an alternate location for the config file to load
101
+ #
102
+ # By default, the configuration will be loaded from <tt>/etc/<app_name>/config.yml</tt>.
103
+ def load_from_file(app_name, app_root, config_file = nil)
104
+ conf_file = config_file || "/etc/#{app_name.to_s.downcase}/config.yml"
105
+
106
+ puts "Loading configuration for #{app_name.inspect} from #{conf_file.inspect}..."
107
+
108
+ begin
109
+ conf_file = etc_conf = conf_file
110
+ unless File.exists? conf_file
111
+ # can use local config.yml file in case we're running non-gem installation
112
+ conf_file = "#{app_root}/config.yml"
113
+ end
114
+
115
+ unless File.exists? conf_file
116
+ copy_example_config_file(app_name, app_root, etc_conf)
117
+ end
118
+
119
+ loaded_conf = HashWithIndifferentAccess.new(YAML.load_file(conf_file))
120
+
121
+ @conf.merge!(loaded_conf)
122
+
123
+ rescue => e
124
+ raise "Your #{app_name} configuration may be invalid."+
125
+ " Please double-check check your config.yml file."+
126
+ " Make sure that you are using spaces instead of tabs for your indentation!!" +
127
+ "\n\nTHE UNDERLYING ERROR WAS:\n#{e.inspect}"
128
+ end
129
+ end
130
+
131
+ def merge_defaults(defaults)
132
+ @conf = HashWithIndifferentAccess.new(HashWithIndifferentAccess.new(defaults).merge(@conf))
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,4 @@
1
+ module Picnic
2
+ module Controllers
3
+ end
4
+ end
@@ -0,0 +1,41 @@
1
+ require 'logger'
2
+
3
+ module Picnic
4
+ module Logger
5
+
6
+ # Makes available a Logger instance under the global $LOG variable.
7
+ def init_global_logger!
8
+ logdev = ($CONF && $CONF.log[:file]) || STDOUT
9
+ $LOG = Picnic::Logger::Base.new(logdev)
10
+ $LOG.level = Picnic::Logger::Base.const_get(($CONF && $CONF.log[:level]) || 'DEBUG')
11
+
12
+ puts "Initialized global logger to #{logdev.inspect}."
13
+ end
14
+ module_function :init_global_logger!
15
+
16
+ class Base < ::Logger
17
+ def initialize(logdev, shift_age = 0, shift_size = 1048576)
18
+ begin
19
+ super
20
+ rescue Exception
21
+ puts "WARNING: Couldn't create Logger with output '#{logdev}'. Logger output will be redirected to STDOUT."
22
+ super(STDOUT, shift_age, shift_size)
23
+ end
24
+ end
25
+
26
+ def format_message(severity, datetime, progrname, msg)
27
+ (@formatter || @default_formatter).call(severity, datetime, progname, msg)
28
+ end
29
+ end
30
+
31
+ # Custom log formatter used by the Picnic Logger.
32
+ class Formatter < ::Logger::Formatter
33
+ Format = "[%s#%d] %5s -- %s: %s\n"
34
+
35
+ def call(severity, time, progname, msg)
36
+ Format % [format_datetime(time), $$, severity, progname,
37
+ msg2str(msg)]
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,99 @@
1
+ require 'camping/server'
2
+
3
+ module Picnic::Server
4
+ class Base < Camping::Server::Base
5
+ def start
6
+ handler, conf = case @conf.server
7
+ when "console"
8
+ ARGV.clear
9
+ IRB.start
10
+ exit
11
+ when "mongrel"
12
+ prep_mongrel
13
+ when "webrick"
14
+ prep_webrick
15
+ end
16
+
17
+ rapp = apps.first
18
+
19
+ if @conf.uri_path
20
+ rapp = Rack::URLMap.new(@conf.uri_path => rapp)
21
+ end
22
+
23
+ rapp = Rack::Static.new(rapp, @conf[:static]) if @conf[:static]
24
+ rapp = Rack::ContentLength.new(rapp)
25
+ rapp = FixContentLength.new(rapp)
26
+ rapp = Rack::Lint.new(rapp)
27
+ rapp = Camping::Server::XSendfile.new(rapp)
28
+ rapp = Rack::ShowExceptions.new(rapp)
29
+
30
+ handler.run(rapp, conf)
31
+ end
32
+
33
+
34
+ private
35
+
36
+ def prep_webrick
37
+ handler = Rack::Handler::WEBrick
38
+ options = {
39
+ :BindAddress => @conf.bind_address || "0.0.0.0",
40
+ :Port => @conf.port
41
+ }
42
+
43
+ cert_path = @conf.ssl_cert
44
+ key_path = @conf.ssl_key || @conf.ssl_cert
45
+ # look for the key in the ssl_cert if no ssl_key is specified
46
+
47
+ unless cert_path.nil? && key_path.nil?
48
+ raise "The specified certificate file #{cert_path.inspect} does not exist or is not readable. " +
49
+ " Your 'ssl_cert' configuration setting must be a path to a valid " +
50
+ " ssl certificate." unless
51
+ File.exists? cert_path
52
+
53
+ raise "The specified key file #{key_path.inspect} does not exist or is not readable. " +
54
+ " Your 'ssl_key' configuration setting must be a path to a valid " +
55
+ " ssl private key." unless
56
+ File.exists? key_path
57
+
58
+ require 'openssl'
59
+ require 'webrick/https'
60
+
61
+ cert = OpenSSL::X509::Certificate.new(File.read(cert_path))
62
+ key = OpenSSL::PKey::RSA.new(File.read(key_path))
63
+
64
+ options[:SSLEnable] = true
65
+ options[:SSLVerifyClient] = ::OpenSSL::SSL::VERIFY_NONE
66
+ options[:SSLCertificate] = cert
67
+ options[:SSLPrivateKey] = key
68
+ end
69
+
70
+ return handler, options
71
+ end
72
+
73
+
74
+ def prep_mongrel
75
+ handler = Rack::Handler::Mongrel
76
+ options = {
77
+ :Host => @conf.bind_address || "0.0.0.0",
78
+ :Port => @conf.port
79
+ }
80
+
81
+ return handler, options
82
+ end
83
+
84
+ end
85
+
86
+ class FixContentLength
87
+ def initialize(app)
88
+ @app = app
89
+ end
90
+
91
+ def call(env)
92
+ status, headers, body = @app.call(env)
93
+ if headers.has_key?('Content-Length') && headers['Content-Length'].to_i == 0
94
+ headers['Content-Length'] = body.body.length.to_s
95
+ end
96
+ [status, headers, body]
97
+ end
98
+ end
99
+ end