spectate 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +6 -0
- data/LICENSE +20 -0
- data/README.rdoc +7 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/api.mdown +58 -0
- data/bin/spectate +5 -0
- data/features/command.feature +16 -0
- data/features/step_definitions/command_steps.rb +7 -0
- data/features/step_definitions/spectate_steps.rb +7 -0
- data/features/support/env.rb +24 -0
- data/generators/config.ru +19 -0
- data/lib/spectate.rb +22 -0
- data/lib/spectate/client.rb +35 -0
- data/lib/spectate/command.rb +99 -0
- data/lib/spectate/config.rb +71 -0
- data/lib/spectate/encode.rb +23 -0
- data/lib/spectate/ping.rb +8 -0
- data/lib/spectate/server.rb +21 -0
- data/lib/spectate/status.rb +43 -0
- data/spec/client_spec.rb +150 -0
- data/spec/command_spec.rb +86 -0
- data/spec/config_spec.rb +247 -0
- data/spec/encode_spec.rb +32 -0
- data/spec/files/config.yml +7 -0
- data/spec/helpers/config_helpers.rb +27 -0
- data/spec/helpers/server_helpers.rb +20 -0
- data/spec/ping_spec.rb +20 -0
- data/spec/server_spec.rb +22 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/spectate_spec.rb +5 -0
- data/spec/spectators/root_spec.rb +10 -0
- data/spec/spectators/spectator_spec.rb +19 -0
- data/spec/status_spec.rb +41 -0
- data/spec/tree_spec.rb +29 -0
- data/spectate.gemspec +68 -0
- metadata +132 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Stephen Eley
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "spectate"
|
8
|
+
gem.summary = %Q{General event framework for testing and monitoring}
|
9
|
+
gem.email = "sfeley@gmail.com"
|
10
|
+
gem.homepage = "http://github.com/SFEley/spectate"
|
11
|
+
gem.authors = ["Stephen Eley"]
|
12
|
+
gem.rubyforge_project = "spectate"
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
|
15
|
+
# ADDED BY SFE
|
16
|
+
gem.requirements << "Tokyo Cabinet (easily installed from apt, MacPorts, etc.)"
|
17
|
+
gem.add_development_dependency "rspec", ">= 1.2.6"
|
18
|
+
gem.add_development_dependency "mocha", ">= 0.9.5"
|
19
|
+
gem.add_runtime_dependency "rufus-tokyo", ">=0.1.12"
|
20
|
+
end
|
21
|
+
|
22
|
+
Jeweler::RubyforgeTasks.new
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'spec/rake/spectask'
|
28
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
31
|
+
end
|
32
|
+
|
33
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
34
|
+
spec.libs << 'lib' << 'spec'
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
begin
|
40
|
+
require 'cucumber/rake/task'
|
41
|
+
Cucumber::Rake::Task.new(:features)
|
42
|
+
rescue LoadError
|
43
|
+
task :features do
|
44
|
+
abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
task :default => :spec
|
49
|
+
|
50
|
+
require 'rake/rdoctask'
|
51
|
+
Rake::RDocTask.new do |rdoc|
|
52
|
+
if File.exist?('VERSION.yml')
|
53
|
+
config = YAML.load(File.read('VERSION.yml'))
|
54
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
55
|
+
else
|
56
|
+
version = ""
|
57
|
+
end
|
58
|
+
|
59
|
+
rdoc.rdoc_dir = 'rdoc'
|
60
|
+
rdoc.title = "spectate #{version}"
|
61
|
+
rdoc.rdoc_files.include('README*')
|
62
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
63
|
+
end
|
64
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/api.mdown
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
The Spectate Model
|
2
|
+
==================
|
3
|
+
|
4
|
+
The Spectate server follows a consistent tree-based model for storing the status of...well, whatever. File changes. Unit test results. Git commits. We don't care. It's optimized for rapid and systematic notification of changes. There are three interesting types of applications in the Spectate system:
|
5
|
+
|
6
|
+
1. The **Spectate server** provides REST-based access to the data store and notifies spectators when data changes. The reference implementation is written in Sinatra, with a Tokyo Cabinet B+ tree for a data store. Individual nodes or arbitrarily deep collections can be retrieved quickly and with the same mechanics.
|
7
|
+
2. **Agents** run on the client side and make updates to the server when something interesting happens.
|
8
|
+
3. **Spectators** are Web hooks which register themselves to the server on one or more nodes, and are notified of changes to those nodes or any of their children.
|
9
|
+
|
10
|
+
There's also a command line client to add and remove services, but it's not as interesting.
|
11
|
+
|
12
|
+
The rest of this document deals with the Spectate server, its data hierarchy and event model, and the API for communicating with it. The architecture of agents and spectators left for service implementers.
|
13
|
+
|
14
|
+
Anatomy of a Node
|
15
|
+
-----------------
|
16
|
+
The Spectate data store is a key-value store in which the keys compose a tree structure consisting of _nodes_ and _properties._ These types differ only slightly in their key declaration and are consistent with URI standards, allowing for a flat and simple implementation.
|
17
|
+
|
18
|
+
* **Nodes** represent objects of any sort -- directories and files, tasks, unit tests, anything that can be graphed hierarchically. The _node key_ is the node's full URI for server retrieval: e.g., `http://localhost:20574/projects/spectate/doc/api.mdown`. Any node can have any number of child nodes and properties. _System nodes_ are ordinary nodes with a base name beginning with an underscore '\_'; this convention denotes data for Spectate's internal use, and is not ordinarily shown in query results.
|
19
|
+
* **Properties** are attributes of nodes, and are denoted by a URI fragment identifier (aka a hash sign, aka '#'). The _property key_ is the property's full URI for server retrieval: e.g., `http://localhost:20574/projects/spectate/doc/api.mdown#last_modified`. Properties may not contain children, but may have multiple values, i.e. an array.
|
20
|
+
|
21
|
+
|
22
|
+
### (Stopped rewriting here.)
|
23
|
+
You can also define any other properties or behavior you wish in subclasses. You can make an property _persistent_ by using the **spectates** declaration:
|
24
|
+
|
25
|
+
class NiftySpectator < Spectate::Spectator
|
26
|
+
spectates :niftiness,
|
27
|
+
:coolness
|
28
|
+
spectates :hipness, :quiet => true
|
29
|
+
end
|
30
|
+
|
31
|
+
Internally, persistent properties are just standalone key/value pairs; the key is the concatenation of the spectator's path, the URI _fragment_ identifier (i.e. the hash symbol, '#') and the property's name. (E.g. `/niftyThings/NiftyExample1#coolness`.) The _quiet_ option prevents hooks from running when the property is updated.
|
32
|
+
|
33
|
+
Ordinarily, every property update is saved immediately, and each hook is notified upon each update. If you're assigning several properties at once or performing operations on a chain of spectators, you should use the **update** method:
|
34
|
+
|
35
|
+
spectator.update do |s|
|
36
|
+
s.niftiness = :very
|
37
|
+
s.coolness = -40
|
38
|
+
s.hipness = "tragic"
|
39
|
+
end
|
40
|
+
|
41
|
+
**update** offers simple transaction behavior: it defers saving and hook announcement _for all spectators_ until the block is completed. This is useful for changes that trickle down to a spectator's children. If an exception is raised out of the block, all changes are canceled and nothing is saved or announced.
|
42
|
+
|
43
|
+
If you want to defer saving and announcement _globally_, there is also a class method version (**Spectate::Spectator.update**) which supplies no parameters, but otherwise offers the same behavior as calling the instance method on the tree's root node.
|
44
|
+
|
45
|
+
Sociology of Spectators
|
46
|
+
-----------------------
|
47
|
+
[describe the tree]
|
48
|
+
|
49
|
+
The following read-only attributes are available for convenience:
|
50
|
+
|
51
|
+
* **path** is the URI path used to uniquely locate this spectator in REST requests. It also indicates the spectator's position in the storage tree, and is (not coincidentally) the key value used for hash storage. The path is the concatenation of the parent's path and a URI-safe version of the spectator's name. All of the following relationship attributes are based on transformations of the path.
|
52
|
+
* **parent** is the parent spectator.
|
53
|
+
* **children** is an array of all spectators immediately descended from this one.
|
54
|
+
* **descendants** is an array of the spectator's children, all of _their_ children, and so on, in breadth-first order.
|
55
|
+
* **siblings** is an array of all of the parent's children, excluding the current spectator.
|
56
|
+
|
57
|
+
|
58
|
+
|
data/bin/spectate
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Feature: Command line utility
|
2
|
+
In order to easily control everything about Spectate
|
3
|
+
As a user
|
4
|
+
I want to call "spectate" from the command line
|
5
|
+
|
6
|
+
Scenario: Usage help
|
7
|
+
When I execute "spectate --help"
|
8
|
+
Then I should see "Usage:"
|
9
|
+
|
10
|
+
Scenario: Basic startup
|
11
|
+
Given no Spectate is running
|
12
|
+
When I execute "spectate"
|
13
|
+
Then I should see "Starting Spectate"
|
14
|
+
And Spectate should be running
|
15
|
+
|
16
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
BASEDIR = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(BASEDIR + '/lib')
|
4
|
+
|
5
|
+
# Make sure the binary is in our path
|
6
|
+
ENV['PATH'] = BASEDIR + '/bin:' + ENV['PATH']
|
7
|
+
|
8
|
+
require 'spectate'
|
9
|
+
|
10
|
+
require 'spec/expectations'
|
11
|
+
|
12
|
+
require File.join(BASEDIR, 'spec', 'helpers', 'config_helpers')
|
13
|
+
World(Spectate::Spec::ConfigHelpers)
|
14
|
+
|
15
|
+
# Set up a config file that makes sense for us
|
16
|
+
Before do
|
17
|
+
create_config
|
18
|
+
end
|
19
|
+
|
20
|
+
After do
|
21
|
+
remove_config
|
22
|
+
end
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Spectate lives wherever this config.ru file lives.
|
2
|
+
module Spectate
|
3
|
+
ROOT_DIR = File.expand_path(File.dirname(__FILE__))
|
4
|
+
end
|
5
|
+
|
6
|
+
# If you're developing or customizing Spectate, you can create a 'src'
|
7
|
+
# directory and it'll load Spectate from here instead of the gem. If you want to
|
8
|
+
# use your own projects directory instead, make a symlink. (If you don't know
|
9
|
+
# how to do THAT, you probably shouldn't be developing or customizing Spectate.)
|
10
|
+
if File.exists?(File.join(Spectate::ROOT_DIR, 'src'))
|
11
|
+
SOURCE_DIR = File.join(Spectate::ROOT_DIR, 'src')
|
12
|
+
require File.join(SOURCE_DIR, 'lib', 'spectate')
|
13
|
+
else
|
14
|
+
require 'rubygems'
|
15
|
+
require 'spectate'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Make the magic happen
|
19
|
+
run Spectate::Server
|
data/lib/spectate.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Jump to the front of the line
|
2
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
3
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'spectate/config'
|
7
|
+
require 'spectate/exceptions'
|
8
|
+
|
9
|
+
module Spectate
|
10
|
+
autoload :Client, 'spectate/client'
|
11
|
+
autoload :Encode, 'spectate/encode'
|
12
|
+
autoload :Ping, 'spectate/ping'
|
13
|
+
autoload :Server, 'spectate/server'
|
14
|
+
autoload :Spectator, 'spectate/spectator'
|
15
|
+
autoload :Status, 'spectate/status'
|
16
|
+
autoload :Tree, 'spectate/tree'
|
17
|
+
# Set vital defaults
|
18
|
+
VERSION = File.read(File.join(File.dirname(__FILE__), '..', 'VERSION')).chomp
|
19
|
+
ROOT_DIR = File.expand_path(File.join('~','.spectate')) unless const_defined?(:ROOT_DIR)
|
20
|
+
# Config['basedir'] = ENV['SPECTATE_DIR'] || File.expand_path(File.join('~','.spectate'))
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spectate'
|
2
|
+
require 'restclient'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Spectate
|
6
|
+
class Client
|
7
|
+
attr_accessor :protocol, :host, :port, :accept
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
Spectate::Config.load_configuration unless Spectate::Config.loaded?
|
11
|
+
@protocol = options[:protocol] || Spectate::Config['protocol'] || 'http'
|
12
|
+
@host = options[:host] || Spectate::Config['host'] || 'localhost'
|
13
|
+
@port = options[:port] || Spectate::Config['port'] || 0
|
14
|
+
@accept = options[:accept] || Spectate::Config['accept'] || 'application/json'
|
15
|
+
|
16
|
+
@driver = RestClient::Resource.new(root, :accept => accept)
|
17
|
+
end
|
18
|
+
|
19
|
+
def root
|
20
|
+
protocol.tr(':/','') +
|
21
|
+
'://' +
|
22
|
+
host +
|
23
|
+
((port.to_i > 0) ? ":#{port}" : '')
|
24
|
+
end
|
25
|
+
|
26
|
+
def get
|
27
|
+
response = @driver.get
|
28
|
+
s = Spectate::Status.new(root,'/',JSON.parse(response)) if accept == 'application/json'
|
29
|
+
rescue RestClient::ResourceNotFound
|
30
|
+
nil
|
31
|
+
rescue Errno::ECONNREFUSED
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'spectate'
|
3
|
+
|
4
|
+
module Spectate
|
5
|
+
SERVER_TYPES = %w[passenger thin mongrel webrick]
|
6
|
+
|
7
|
+
PASSENGER_DEFAULTS = {
|
8
|
+
'rackup' => false,
|
9
|
+
'server' => 'passenger',
|
10
|
+
'host' => 'spectate.local'
|
11
|
+
}
|
12
|
+
|
13
|
+
RACKUP_DEFAULTS = {
|
14
|
+
'rackup' => true,
|
15
|
+
'host' => 'localhost',
|
16
|
+
'port' => 20574
|
17
|
+
}
|
18
|
+
|
19
|
+
# Drives the 'spectate' command line utility.
|
20
|
+
class Command
|
21
|
+
extend Spectate::Ping
|
22
|
+
|
23
|
+
# The primary event called by the command line
|
24
|
+
def self.run
|
25
|
+
skip_server = false
|
26
|
+
only_setup = false
|
27
|
+
stop_server = false
|
28
|
+
unless ARGV.empty?
|
29
|
+
options = OptionParser.new
|
30
|
+
options.on("-d", "--directory", "=DIR", String, "Set base directory for support files (default is ~/.spectate)") do |val|
|
31
|
+
Spectate::Config['basedir'] = val
|
32
|
+
puts "Directory set to #{Spectate::Config['basedir']}"
|
33
|
+
end
|
34
|
+
options.on("--setup", "=TYPE", SERVER_TYPES, "Create the base directory and initialize config.yml with the given server type (#{SERVER_TYPES.join(', ')})") do |type|
|
35
|
+
only_setup = true
|
36
|
+
Spectate::Config['server'] = type
|
37
|
+
case type
|
38
|
+
when 'passenger':
|
39
|
+
Spectate::Config.default(PASSENGER_DEFAULTS)
|
40
|
+
else
|
41
|
+
Spectate::Config.default(RACKUP_DEFAULTS)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
options.on("--host", "-h", "=NAME", String, "Set hostname or IP address for server access") do |host|
|
45
|
+
Spectate::Config['host'] = host
|
46
|
+
end
|
47
|
+
options.on("--port", "-p", "=PORT", Integer, "Set port number for server access") do |port|
|
48
|
+
Spectate::Config['port'] = port
|
49
|
+
end
|
50
|
+
options.on("--help", "-?", "--usage", "Displays this help screen") {|o| puts options.to_s; skip_server = true}
|
51
|
+
options.on("--stop", "Stops the Spectate server if running") {stop_server = true}
|
52
|
+
unparsed = options.parse(ARGV)
|
53
|
+
end
|
54
|
+
|
55
|
+
if only_setup
|
56
|
+
Spectate::Config.generate_configuration
|
57
|
+
else
|
58
|
+
Spectate::Config.load_configuration
|
59
|
+
if stop_server
|
60
|
+
self.kill_server
|
61
|
+
else
|
62
|
+
self.ensure_server unless skip_server
|
63
|
+
end
|
64
|
+
end
|
65
|
+
true
|
66
|
+
rescue OptionParser::ParseError
|
67
|
+
puts "Oops... #{$!}"
|
68
|
+
puts options
|
69
|
+
false
|
70
|
+
rescue StandardError
|
71
|
+
puts $!
|
72
|
+
puts options
|
73
|
+
false
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
def self.ensure_server
|
78
|
+
if ping
|
79
|
+
puts "Spectate is already running!"
|
80
|
+
else
|
81
|
+
puts "Starting Spectate on #{Spectate::Config['host']}:#{Spectate::Config['port']}..."
|
82
|
+
Dir.chdir Spectate::Config.basedir do |dir|
|
83
|
+
system "rackup -D -o #{Spectate::Config['host']} -p #{Spectate::Config['port']} -P spectate.pid config.ru"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.kill_server()
|
89
|
+
pidfile = File.join(Spectate::Config.basedir, 'spectate.pid')
|
90
|
+
pid = File.read(pidfile).to_i if File.exists?(pidfile)
|
91
|
+
if pid and `ps x #{pid}` =~ /rackup.*-p #{Spectate::Config['port']}/
|
92
|
+
Process.kill("KILL",pid) and puts "Spectate stopped."
|
93
|
+
File.delete(pidfile)
|
94
|
+
else
|
95
|
+
puts "Spectate wasn't running! (Or you're using Passenger, or your PID file is incorrect,\n or it's on a different server. In any case, you're on your own.)"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Spectate
|
5
|
+
module Config
|
6
|
+
@config = Hash.new
|
7
|
+
@loaded = false
|
8
|
+
|
9
|
+
def self.to_hash
|
10
|
+
@config
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.[](key)
|
14
|
+
@config[key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.[]=(key, val)
|
18
|
+
@config[key] = val
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.delete(key)
|
22
|
+
@config.delete(key)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.clear!
|
26
|
+
@config = Hash.new
|
27
|
+
@loaded = false
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.default(hash)
|
31
|
+
@config = hash.merge(@config)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.basedir
|
35
|
+
@basedir
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.loaded?
|
39
|
+
@loaded
|
40
|
+
end
|
41
|
+
|
42
|
+
# Loads persistent values from the config.yml file in the base directory.
|
43
|
+
# Assumes that the basedir configuration variable has already been set before calling.
|
44
|
+
def self.load_configuration(confdir = nil)
|
45
|
+
@basedir = confdir || self['basedir'] || ENV['SPECTATE_DIR'] || ROOT_DIR
|
46
|
+
raise "Could not find a base directory!\nRun spectate --setup to initialize things or tell us your base directory\nwith the -d option." unless basedir
|
47
|
+
raise "Directory #{basedir} not found!\nRun spectate --setup to initialize things." unless File.directory?(basedir)
|
48
|
+
conffile = File.join(basedir, "config.yml")
|
49
|
+
raise "File #{conffile} not found!\nRun spectate --setup to initialize things." unless File.exists?(conffile)
|
50
|
+
@loaded = @config.merge!(YAML.load_file(conffile))
|
51
|
+
end
|
52
|
+
|
53
|
+
# Confirms that the config.yml file doesn't already exist, then creates one from passed parameters
|
54
|
+
def self.generate_configuration
|
55
|
+
configfile = File.join(self['basedir'], "config.yml")
|
56
|
+
raise "You already have a config.yml file! We don't want to mess with a good thing.\n" +
|
57
|
+
"If you really want to start over, delete #{configfile} and run spectate --setup again." if File.exists?(configfile)
|
58
|
+
unless File.directory?(self['basedir'])
|
59
|
+
puts "Creating directory #{self['basedir']}"
|
60
|
+
FileUtils.makedirs self['basedir']
|
61
|
+
end
|
62
|
+
puts "Creating config.yml file"
|
63
|
+
File.open(configfile, 'w') {|config| YAML.dump(self.to_hash, config)}
|
64
|
+
puts "Creating rackup file"
|
65
|
+
FileUtils.copy File.join(File.dirname(__FILE__), '..', '..', 'generators', 'config.ru'), self['basedir']
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|