cortex-reaver 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: