cortex-reaver 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -5,7 +5,7 @@ Cortex Reaver is a terrifying machine which stalks the corridors of Citadel
5
5
  Station, searching for humans to assimilate into Shodan's perfection.
6
6
 
7
7
  Cortex Reaver is also a blog engine for textual journals, photographs, and
8
- projects; written using Ramaze and Sequel. It supports tags, comments, and
8
+ pages, written using Ramaze and Sequel. It supports tags, comments, and
9
9
  simple attachments. Features include canonically named URLs
10
10
  (/journals/show/a-post-title) with conflict resolution, useful formatting
11
11
  modules for content (HTML sanitizing, attachment references, BlueCloth, etc),
@@ -17,29 +17,29 @@ Why Cortex Reaver
17
17
  - Adaptible. Runs on every web server and database Ramaze and Sequel support.
18
18
  - Visual. Large, beautiful photographs, with concise EXIF support.
19
19
  - Comprehensive. Comments, file attachments, and tags on everything.
20
- - Devastating. The main page of Aphyr.com scales to ~400 requests/second.
20
+ - Devastating. The main page of aphyr.com scales to ~400 requests/second.
21
21
 
22
22
  Getting Started
23
23
  ---------------
24
24
 
25
25
  mkdir cortex_reaver # Create an empty directory for Cortex Reaver to lurk in.
26
26
  cd cortex_reaver
27
- cortex_reaver --migrate # Initialize an SQLite database.
28
- cortex_reaver --start # Start the daemon.
27
+ cortex_reaver migrate # Initialize an SQLite database.
28
+ cortex_reaver start # Start the daemon.
29
29
 
30
30
  Then point your web browser at localhost:7000, hit control-x, and log in with
31
31
  username "shodan", password "citadelstation".
32
32
 
33
- You can check Cortex Reaver's status with --status, and when you're done, shut
34
- it down with --stop.
33
+ You can check Cortex Reaver's status with status, and when you're done, shut
34
+ it down with cortex_reaver stop.
35
35
 
36
36
  Configuration
37
37
  -------------
38
38
 
39
- You'll need a YAML configuration file to define Cortex Reaver's configuration.
39
+ You can use a YAML configuration file to define Cortex Reaver's configuration.
40
40
  See proto/cortex_reaver.yaml. If no config file is specified on the command
41
41
  line with --config, Cortex Reaver assumes you mean cortex_reaver.yaml in the
42
- working directory. Copy lib/proto/cortex_reaver.yaml to get started.
42
+ working directory.
43
43
 
44
44
  Databases
45
45
  ---------
@@ -55,26 +55,39 @@ create database cortex_reaver;
55
55
  grant all privileges on cortex_reaver.* to 'cortex_reaver'@'localhost'
56
56
  identified by 'some-password' with grant option;
57
57
 
58
- When you've set up a new database, run cortex_reaver --migrate to update it to
58
+ When you've set up a new database, run cortex_reaver migrate to update it to
59
59
  the latest version. If you need to wipe your database and start over, use
60
- cortex_reaver --blank to drop the schema and rebuild it.
60
+ cortex_reaver blank to drop the schema and rebuild it.
61
+
62
+ You can export your database to an SQLite file with cortex_reaver dump, and restore it with cortex_reaver load. This can help with migrating between database systems.
61
63
 
62
64
  Customization
63
65
  -------------
64
66
 
65
67
  You may find development mode useful: it reloads source files when they're
66
68
  changed, displays traces for errors instead of 404 and 500 responses, logs
67
- more, and runs in the console instead of detaching by default. Just set :mode
68
- => :development in your configuration.
69
+ more, and runs in the console instead of detaching by default. Just set mode =>
70
+ :development in your configuration.
71
+
72
+ Cortex Reaver includes Erubis layouts and templates, static resources, CSS, and
73
+ javascript files in lib/cortex_reaver/layout, lib/cortex_reaver/view, and
74
+ lib/cortex_reaver/public. CR will override these resources with your local
75
+ directory: if you request /images/foo.png, it will check
76
+ <local_dir>/public/images/foo.png first, then
77
+ <cortex_reaver_dir>/public/images/foo.png. CSS and JS files are compiled into
78
+ single cached files from several smaller files. If you want, you can
79
+ selectively replace parts of the default theme by creating css files with the
80
+ same names in <local_dir>/public/css/. The same applies to views and layouts.
81
+ You can also create new resources; they will be merged for you.
82
+
83
+ You can control the paths and search patterns in the configuration: see
84
+ lib/cortex_reaver/config.rb.
69
85
 
70
86
  Requests for static objects (images, css, javascript, etc.) is pulled from
71
87
  public/, which can be specified in your configuration or defaults to
72
88
  `cwd`/public. If a request for a file can't be found there, it's retrieved from
73
89
  Cortex Reaver's own public directory in lib/public.
74
90
 
75
- You can also set up your own view templates: copy lib/view to some other
76
- directory, and specify :view_root in your configuration.
77
-
78
91
  Credits
79
92
  -------
80
93
 
data/bin/cortex_reaver CHANGED
@@ -1,14 +1,27 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
3
  require 'rubygems'
4
- require 'optparse'
4
+ require 'trollop'
5
5
  require 'ramaze'
6
6
  require __DIR__ + '/../lib/cortex_reaver'
7
+ require 'irb'
8
+
9
+ # IRB monkeypatch to let us load a custom context object
10
+ class IRB::Irb
11
+ alias initialize_orig initialize
12
+ def initialize(workspace = nil, *args)
13
+ default = IRB.conf[:DEFAULT_OBJECT]
14
+ workspace ||= IRB::WorkSpace.new default if default
15
+ initialize_orig(workspace, *args)
16
+ end
17
+ end
18
+
19
+ class CortexReaver::Runner
20
+ COMMANDS = ['blank', 'start', 'status', 'reload', 'restart', 'stop', 'console', 'dump', 'load']
7
21
 
8
- module CortexReaver
9
22
  # Asks a question and returns a true_false answer
10
- def self.confirm(question)
11
- return true if @values[:force]
23
+ def confirm(question)
24
+ return true if @global_opts[:force]
12
25
 
13
26
  puts question + " (yes/no)"
14
27
  print '> '
@@ -21,86 +34,95 @@ module CortexReaver
21
34
  end
22
35
  end
23
36
 
24
- # Parse options
25
- @values = {}
26
- parser = OptionParser.new do |o|
27
- o.on '-b', '--blank',
28
- 'Wipes the database and sets up a clean copy of the latest version.' do
29
- @action = :blank
30
- end
31
-
32
- o.on '-c', '--config file', 'Configuration file' do |file|
33
- self.config_file = file
34
- end
35
-
36
- o.on '-d', '--dump file', 'Dump database' do |file|
37
- @action = :dump
38
- @values[:dump_file] = file
39
- end
40
-
41
- o.on '-f', '--force', 'Just do it' do
42
- @values[:force] = true
43
- end
44
-
45
- o.on '-h', '--help', 'Show help' do
46
- @action = :help
47
- end
48
-
49
- o.on '-i', '--irb', 'Start an IRB session' do
50
- @action = :irb
51
- end
52
-
53
- o.on '-k', '--stop', 'Stop Cortex Reaver' do
54
- @action = :stop
55
- end
56
-
57
- o.on '-l', '--load file', 'Load database' do |file|
58
- @action = :load
59
- @values[:load_file] = file
60
- end
61
-
62
- o.on '-m', '--migrate [version]',
63
- 'Migrate the database to schema version, or to the latest version' do |version|
64
- @action = :migrate
65
- @values[:schema_version] = version ? version.to_i : nil
66
- end
67
-
68
- o.on '-r', '--restart', 'Restart Cortex Reaver' do
69
- @action = :restart
37
+ def initialize
38
+ # Parse options
39
+ @global_opts = Trollop::options do
40
+ banner "#{CortexReaver::APP_NAME} #{CortexReaver::APP_VERSION}"
41
+ version CortexReaver::APP_VERSION
42
+ banner <<EOF
43
+ Syntax: cortex_reaver [opts] command [command_opts]
44
+
45
+ blank Wipes the database and sets up a clean copy of the
46
+ latest version
47
+ console Starts an IRB session
48
+ dump <to_file> Dump database to file
49
+ load <from_file> Load a database dump
50
+ migrate [version] Migrate the database to the given schema version, or to
51
+ the latest schema
52
+ reload Reload CSS, JS, configuration, etc.
53
+ restart Restart Cortex Reaver
54
+ start Start Cortex Reaver
55
+ status Check the status of the local CortexReaver via HTTP.
56
+ stop Stop Cortex Reaver
57
+
58
+ Options:
59
+
60
+ EOF
61
+
62
+ opt :force, "Just do it", :default => false
63
+ opt :config, "Configuration file"
64
+ stop_on COMMANDS
70
65
  end
71
66
 
72
- o.on '-s', '--start',
73
- 'Start the Cortex Reaver server' do
74
- @action = :start
67
+ if file = @global_opts[:config]
68
+ CortexReaver.config_file = file
75
69
  end
76
70
 
77
- o.on '-t', '--test',
78
- 'Run tests' do
79
- @action = :test
80
- end
81
-
82
- o.on '--status', 'Check Cortex Reaver status' do
83
- @action = :status
71
+ @command = ARGV.shift
72
+ @opts = case @command
73
+ when "blank"
74
+ blank
75
+ when 'console'
76
+ console
77
+ when "dump"
78
+ if file = ARGV.shift
79
+ dump file
80
+ else
81
+ abort "No dump file given"
82
+ end
83
+ when "load"
84
+ if file = ARGV.shift
85
+ self.load file
86
+ else
87
+ abort "No load file given"
88
+ end
89
+ when "migrate"
90
+ if version = ARGV.shift
91
+ migrate version.to_i
92
+ else
93
+ migrate
94
+ end
95
+ when 'restart'
96
+ restart
97
+ when 'reload'
98
+ reload
99
+ when 'start'
100
+ start
101
+ @opts = Trollop::options do
102
+ opt :daemon, :type => :boolean, :default => nil
103
+ end
104
+ when 'status'
105
+ status
106
+ when 'stop'
107
+ stop
108
+ when 'test'
109
+ else
110
+ Trollop::die "unknown subcommand #{@command.inspect}"
84
111
  end
85
112
  end
86
113
 
87
- parser.parse! ARGV
88
-
89
- # Main
90
- case @action
91
- when :dump
92
- # Dump the database to disk
114
+ # Dump the database to disk
115
+ def dump(file)
116
+ require 'sequel/extensions/migration'
93
117
 
94
118
  # Connect to current DB
95
- reload_config
96
- setup_db false
97
- require 'sequel/extensions/migration'
98
- current_version = Sequel::Migrator.get_current_migration_version(db)
119
+ CortexReaver.reload_config
120
+ CortexReaver.setup_db false
121
+ current_version = Sequel::Migrator.get_current_migration_version(CortexReaver.db)
99
122
 
100
- puts "Using database #{config[:database][:host]}/#{config[:database][:database]}."
123
+ puts "Using database #{CortexReaver.config[:database][:host]}/#{CortexReaver.config[:database][:database]}."
101
124
 
102
125
  # Prepare dump file
103
- file = @values[:dump_file]
104
126
  if File.file? file
105
127
  exit unless confirm("Overwrite #{File.expand_path(file)} with current Cortex Reaver database?")
106
128
  FileUtils.rm file
@@ -108,10 +130,10 @@ module CortexReaver
108
130
 
109
131
  # Connect to dump DB
110
132
  dump = Sequel.connect "sqlite:////#{File.expand_path(file)}"
111
- Sequel::Migrator.apply dump, File.join(LIB_DIR, 'migrations'), current_version
133
+ Sequel::Migrator.apply dump, File.join(CortexReaver::LIB_DIR, 'migrations'), current_version
112
134
 
113
135
  # Copy tables
114
- db.tables.each do |table|
136
+ CortexReaver.db.tables.each do |table|
115
137
  puts "Table #{table} (#{db[table].count} rows)..."
116
138
  dump_table = dump[table]
117
139
  db[table].each do |row|
@@ -120,61 +142,62 @@ module CortexReaver
120
142
  end
121
143
 
122
144
  puts "Dumped database to #{file}."
145
+ end
123
146
 
124
- when :load
125
- # Load an SQLite database from disk.
126
-
147
+ # Load an SQLite database from disk.
148
+ def load(file)
149
+ require 'sequel/extensions/migration'
150
+
127
151
  # Connect to dump DB
128
- file = @values[:load_file]
129
152
  dump = Sequel.connect "sqlite:////#{File.expand_path(file)}"
130
- require 'sequel/extensions/migration'
131
153
  current_version = Sequel::Migrator.get_current_migration_version(dump)
132
154
 
133
155
  # Connect to current DB
134
- reload_config
135
- setup_db false
136
- puts "Using database #{config[:database][:host]}/#{config[:database][:database]}."
156
+ CortexReaver.reload_config
157
+ CortexReaver.setup_db false
158
+ puts "Using database #{CortexReaver.config[:database][:host]}/#{CortexReaver.config[:database][:database]}."
137
159
 
138
160
  unless confirm("Overwrite current database with #{File.expand_path(file)}?")
139
161
  exit
140
162
  end
141
163
 
142
164
  # Drop current migrations and move to the dump's version
143
- system($0, '-f', '-m', '0')
144
- Sequel::Migrator.apply db, File.join(LIB_DIR, 'migrations'), current_version
165
+ system($0, '-f', 'migrate', '0')
166
+ Sequel::Migrator.apply CortexReaver.db, File.join(CortexReaver::LIB_DIR, 'migrations'), current_version
145
167
 
146
168
  # Copy tables
147
169
  dump.tables.each do |table|
148
170
  puts "Table #{table} (#{dump[table].count} rows)..."
149
- db_table = db[table]
171
+ db_table = CortexReaver.db[table]
150
172
  dump[table].each do |row|
151
173
  db_table << row
152
174
  end
153
175
  end
154
176
 
155
177
  puts "Database #{file} loaded."
178
+ end
156
179
 
157
- when :status
158
- # Make a quick HTTP request to see how we're doing.
180
+ # Make a quick HTTP request to see how we're doing.
181
+ def status
159
182
  require 'open-uri'
160
- reload_config
161
- response = open("http://#{config[:host] || 'localhost'}:#{config[:port]}/")
183
+ CortexReaver.reload_config
184
+ response = open("http://#{CortexReaver.config[:host] || 'localhost'}:#{CortexReaver.config[:port]}/")
162
185
  puts response.status.join(' ');
186
+ end
163
187
 
164
- when :migrate
165
- version = @values[:schema_version]
166
-
188
+ def migrate(version = nil)
189
+ require 'sequel/extensions/migration'
190
+
167
191
  # Get ready
168
- reload_config
169
- setup_db false
170
- self.load
171
- init
192
+ CortexReaver.reload_config
193
+ CortexReaver.setup_db false
194
+ CortexReaver.load
195
+ CortexReaver.init
172
196
 
173
- puts "Using database #{config[:database][:host]}/#{config[:database][:database]}."
197
+ puts "Using database #{CortexReaver.config[:database][:host]}/#{CortexReaver.config[:database][:database]}."
174
198
 
175
- require 'sequel/extensions/migration'
176
- current_version = Sequel::Migrator.get_current_migration_version(db)
177
- latest_version = Sequel::Migrator.latest_migration_version(File.join(LIB_DIR, 'migrations'))
199
+ current_version = Sequel::Migrator.get_current_migration_version(CortexReaver.db)
200
+ latest_version = Sequel::Migrator.latest_migration_version(File.join(CortexReaver::LIB_DIR, 'migrations'))
178
201
 
179
202
  if version == current_version and current_version == latest_version
180
203
  puts "The database is already at the latest version (#{latest_version})."
@@ -194,61 +217,56 @@ module CortexReaver
194
217
 
195
218
  if confirm message
196
219
  puts "Migrating database from version #{current_version} to version #{version}..."
197
- Sequel::Migrator.apply(db, File.join(LIB_DIR, 'migrations'), version)
220
+ Sequel::Migrator.apply(CortexReaver.db, File.join(CortexReaver::LIB_DIR, 'migrations'), version)
198
221
  puts "Done."
199
222
  else
200
223
  exit
201
224
  end
225
+ end
202
226
 
203
- when :blank
227
+ def blank
204
228
  if confirm "Are you sure you wish to wipe the database?"
205
229
  # Strangely, calling Migrator.apply to go down and then up doesn't seem
206
230
  # to work. :-/
207
- system($0, '-f', '-m', '0')
208
- system($0, '-f', '-m')
231
+ system($0, '-f', 'migrate', '0')
232
+ system($0, '-f', 'migrate')
209
233
  end
234
+ end
210
235
 
211
- when :help
212
- puts "Cortex Reaver #{APP_VERSION}: A dangerous Ruby blog engine, with a photographic memory."
213
- puts parser.help
214
-
215
- when :irb
236
+ def console
237
+ require 'irb'
238
+ require 'irb/completion'
239
+
216
240
  # Start an IRB session
217
- reload_config
218
- setup
241
+ CortexReaver.reload_config
242
+ CortexReaver.setup
219
243
 
220
244
  # Don't let IRB try to interpret our command line
221
245
  ARGV.clear
222
246
 
223
- require 'irb'
224
- require 'irb/completion'
225
-
226
- # IRB monkeypatch to let us load a custom context object
227
- class IRB::Irb
228
- alias initialize_orig initialize
229
- def initialize(workspace = nil, *args)
230
- default = IRB.conf[:DEFAULT_OBJECT]
231
- workspace ||= IRB::WorkSpace.new default if default
232
- initialize_orig(workspace, *args)
233
- end
234
- end
235
-
236
247
  IRB.conf[:DEFAULT_OBJECT] = CortexReaver
237
248
  IRB.start
249
+ end
238
250
 
239
- when :restart
240
- restart
251
+ def reload
252
+ CortexReaver.reload
253
+ end
241
254
 
242
- when :start
243
- start
255
+ def restart
256
+ CortexReaver.restart
257
+ end
244
258
 
245
- when :stop
246
- stop
259
+ def start
260
+ CortexReaver.start
261
+ end
247
262
 
248
- when :test
249
- require File.join(LIB_DIR, '..', '..', 'spec', 'spec')
263
+ def stop
264
+ CortexReaver.stop
265
+ end
250
266
 
251
- else
252
- abort("Unknown action: #{@action}")
267
+ def test
268
+ require File.join(CortexReaver::LIB_DIR, '..', '..', 'spec', 'spec')
253
269
  end
254
270
  end
271
+
272
+ CortexReaver::Runner.new
data/lib/cortex_reaver.rb CHANGED
@@ -33,6 +33,11 @@ module CortexReaver
33
33
  require File.join(LIB_DIR, 'version')
34
34
  require File.join(LIB_DIR, 'config')
35
35
 
36
+ # Reload on sighup
37
+ trap 'HUP' do
38
+ reload_app
39
+ end
40
+
36
41
  # Reads files from stock_dir and custom_dir matching pattern, and appends
37
42
  # their contents. Returns a string.
38
43
  def self.collect_files(stock_dir, custom_dir, pattern = /^[^\.].+/, opts = {})
@@ -306,6 +311,48 @@ module CortexReaver
306
311
  end
307
312
  end
308
313
 
314
+ # Tells the running CortexReaver to reload.
315
+ def self.reload
316
+ reload_config
317
+
318
+ unless config.pidfile
319
+ abort "No pidfile to reload."
320
+ end
321
+
322
+ unless File.file? config.pidfile
323
+ abort "Cortex Reaver not running? (check #{config.pidfile})"
324
+ end
325
+
326
+ # Get PID
327
+ pid = File.read(config.pidfile, 20).strip
328
+ unless (pid = pid.to_i) != 0
329
+ abort "Invalid process ID in pidfile (#{pid})."
330
+ end
331
+
332
+ puts "Reloading Cortex Reaver #{pid}..."
333
+
334
+ begin
335
+ # Try to shut down Ramaze nicely.
336
+ Process.kill('HUP', pid)
337
+ puts "Done."
338
+ rescue Errno::ESRCH
339
+ # The process doesn't exist.
340
+ puts "No Cortex Reaver with pid #{pid}."
341
+ rescue => e
342
+ # That failed, too.
343
+ puts "Unable to reload Cortex Reaver: #{e}."
344
+ end
345
+ end
346
+
347
+ # Reloads the app without restarting.
348
+ def self.reload_app
349
+ self.reload_config
350
+ self.load
351
+ self.init
352
+ self.compile_css
353
+ self.compile_js
354
+ end
355
+
309
356
  # Reloads the site configuration
310
357
  def self.reload_config
311
358
  begin
@@ -483,6 +530,11 @@ module CortexReaver
483
530
  run
484
531
  end
485
532
  else
533
+ # Write pidfile
534
+ File.open(config.pidfile, 'w') do |file|
535
+ file << Process.pid
536
+ end
537
+
486
538
  # Run in foreground.
487
539
  run
488
540
  end
@@ -28,7 +28,7 @@ module CortexReaver
28
28
  :pages
29
29
 
30
30
  cache_action(:method => :index, :ttl => 120) do
31
- user.id.to_i.to_s + flash.inspect + request.path_info
31
+ user.id.to_i.to_s + flash.inspect
32
32
  end
33
33
  cache_action(:method => :sitemap, :ttl => 300) do
34
34
  request.path_info
@@ -3,11 +3,11 @@ module Ramaze
3
3
  # Provides some error pages
4
4
  module Error
5
5
  def error_404
6
- respond 'Page not found', 404
6
+ respond! 'Page not found', 404, "Content-Type" => "text/plain"
7
7
  end
8
8
 
9
9
  def error_403
10
- respond 'Forbidden', 403
10
+ respond! 'Forbidden', 403, "Content-Type" => "text/plain"
11
11
  end
12
12
  end
13
13
  end
@@ -1,6 +1,6 @@
1
1
  module CortexReaver
2
2
  APP_NAME = 'Cortex Reaver'
3
- APP_VERSION = '0.2.8'
3
+ APP_VERSION = '0.2.9'
4
4
  APP_AUTHOR = 'Kyle Kingsbury'
5
5
  APP_EMAIL = 'aphyr@aphyr.com'
6
6
  APP_URL = 'http://aphyr.com'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cortex-reaver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Kingsbury
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-24 00:00:00 -08:00
12
+ date: 2010-02-09 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -142,6 +142,16 @@ dependencies:
142
142
  - !ruby/object:Gem::Version
143
143
  version: 1.1.9
144
144
  version:
145
+ - !ruby/object:Gem::Dependency
146
+ name: trollop
147
+ type: :runtime
148
+ version_requirement:
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ~>
152
+ - !ruby/object:Gem::Version
153
+ version: "1.15"
154
+ version:
145
155
  description:
146
156
  email: aphyr@aphyr.com
147
157
  executables: