angry_mob 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.md +123 -0
- data/bin/mob +139 -0
- data/lib/angry_mob.rb +28 -0
- data/lib/angry_mob/act.rb +111 -0
- data/lib/angry_mob/act/scheduler.rb +143 -0
- data/lib/angry_mob/action.rb +11 -0
- data/lib/angry_mob/builder.rb +115 -0
- data/lib/angry_mob/extend.rb +10 -0
- data/lib/angry_mob/extend/array.rb +30 -0
- data/lib/angry_mob/extend/blank.rb +108 -0
- data/lib/angry_mob/extend/blankslate.rb +109 -0
- data/lib/angry_mob/extend/dictionary.rb +140 -0
- data/lib/angry_mob/extend/hash.rb +67 -0
- data/lib/angry_mob/extend/object.rb +21 -0
- data/lib/angry_mob/extend/pathname.rb +23 -0
- data/lib/angry_mob/extend/string.rb +8 -0
- data/lib/angry_mob/log.rb +28 -0
- data/lib/angry_mob/mob.rb +77 -0
- data/lib/angry_mob/mob_loader.rb +115 -0
- data/lib/angry_mob/node.rb +44 -0
- data/lib/angry_mob/notifier.rb +76 -0
- data/lib/angry_mob/target.rb +257 -0
- data/lib/angry_mob/target/arguments.rb +71 -0
- data/lib/angry_mob/target/call.rb +57 -0
- data/lib/angry_mob/target/default_resource_locator.rb +11 -0
- data/lib/angry_mob/target/defaults.rb +23 -0
- data/lib/angry_mob/target/mother.rb +66 -0
- data/lib/angry_mob/target/notify.rb +57 -0
- data/lib/angry_mob/target/tracking.rb +96 -0
- data/lib/angry_mob/ui.rb +247 -0
- data/lib/angry_mob/util.rb +11 -0
- data/lib/angry_mob/vendored.rb +8 -0
- data/lib/angry_mob/version.rb +3 -0
- data/vendor/angry_hash/Rakefile +17 -0
- data/vendor/angry_hash/VERSION +1 -0
- data/vendor/angry_hash/angry_hash.gemspec +47 -0
- data/vendor/angry_hash/examples/accessors_eg.rb +46 -0
- data/vendor/angry_hash/examples/creation_eg.rb +43 -0
- data/vendor/angry_hash/examples/dsl.eg.rb +18 -0
- data/vendor/angry_hash/examples/dup_eg.rb +86 -0
- data/vendor/angry_hash/examples/eg_helper.rb +24 -0
- data/vendor/angry_hash/examples/merge_eg.rb +135 -0
- data/vendor/angry_hash/lib/angry_hash.rb +215 -0
- data/vendor/angry_hash/lib/angry_hash/dsl.rb +44 -0
- data/vendor/angry_hash/lib/angry_hash/extension_tracking.rb +12 -0
- data/vendor/angry_hash/lib/angry_hash/merge_string.rb +58 -0
- data/vendor/json/COPYING +58 -0
- data/vendor/json/GPL +340 -0
- data/vendor/json/README +360 -0
- data/vendor/json/lib/json/common.rb +371 -0
- data/vendor/json/lib/json/pure.rb +77 -0
- data/vendor/json/lib/json/pure/generator.rb +443 -0
- data/vendor/json/lib/json/pure/parser.rb +303 -0
- data/vendor/json/lib/json/version.rb +8 -0
- data/vendor/thor/CHANGELOG.rdoc +89 -0
- data/vendor/thor/LICENSE +20 -0
- data/vendor/thor/README.rdoc +297 -0
- data/vendor/thor/Thorfile +69 -0
- data/vendor/thor/bin/rake2thor +86 -0
- data/vendor/thor/bin/thor +6 -0
- data/vendor/thor/lib/thor.rb +244 -0
- data/vendor/thor/lib/thor/actions.rb +275 -0
- data/vendor/thor/lib/thor/actions/create_file.rb +103 -0
- data/vendor/thor/lib/thor/actions/directory.rb +91 -0
- data/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
- data/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
- data/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
- data/vendor/thor/lib/thor/base.rb +540 -0
- data/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
- data/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
- data/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
- data/vendor/thor/lib/thor/error.rb +30 -0
- data/vendor/thor/lib/thor/group.rb +271 -0
- data/vendor/thor/lib/thor/invocation.rb +180 -0
- data/vendor/thor/lib/thor/parser.rb +4 -0
- data/vendor/thor/lib/thor/parser/argument.rb +67 -0
- data/vendor/thor/lib/thor/parser/arguments.rb +150 -0
- data/vendor/thor/lib/thor/parser/option.rb +128 -0
- data/vendor/thor/lib/thor/parser/options.rb +169 -0
- data/vendor/thor/lib/thor/rake_compat.rb +66 -0
- data/vendor/thor/lib/thor/runner.rb +314 -0
- data/vendor/thor/lib/thor/shell.rb +83 -0
- data/vendor/thor/lib/thor/shell/basic.rb +239 -0
- data/vendor/thor/lib/thor/shell/color.rb +108 -0
- data/vendor/thor/lib/thor/task.rb +102 -0
- data/vendor/thor/lib/thor/util.rb +224 -0
- data/vendor/thor/lib/thor/version.rb +3 -0
- data/vendor/thor/spec/actions/create_file_spec.rb +170 -0
- data/vendor/thor/spec/actions/directory_spec.rb +131 -0
- data/vendor/thor/spec/actions/empty_directory_spec.rb +91 -0
- data/vendor/thor/spec/actions/file_manipulation_spec.rb +271 -0
- data/vendor/thor/spec/actions/inject_into_file_spec.rb +135 -0
- data/vendor/thor/spec/actions_spec.rb +292 -0
- data/vendor/thor/spec/base_spec.rb +263 -0
- data/vendor/thor/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
- data/vendor/thor/spec/core_ext/ordered_hash_spec.rb +115 -0
- data/vendor/thor/spec/fixtures/application.rb +2 -0
- data/vendor/thor/spec/fixtures/bundle/execute.rb +6 -0
- data/vendor/thor/spec/fixtures/bundle/main.thor +1 -0
- data/vendor/thor/spec/fixtures/doc/%file_name%.rb.tt +1 -0
- data/vendor/thor/spec/fixtures/doc/README +3 -0
- data/vendor/thor/spec/fixtures/doc/config.rb +1 -0
- data/vendor/thor/spec/fixtures/group.thor +90 -0
- data/vendor/thor/spec/fixtures/invoke.thor +112 -0
- data/vendor/thor/spec/fixtures/script.thor +145 -0
- data/vendor/thor/spec/fixtures/task.thor +10 -0
- data/vendor/thor/spec/group_spec.rb +171 -0
- data/vendor/thor/spec/invocation_spec.rb +107 -0
- data/vendor/thor/spec/parser/argument_spec.rb +47 -0
- data/vendor/thor/spec/parser/arguments_spec.rb +64 -0
- data/vendor/thor/spec/parser/option_spec.rb +202 -0
- data/vendor/thor/spec/parser/options_spec.rb +292 -0
- data/vendor/thor/spec/rake_compat_spec.rb +68 -0
- data/vendor/thor/spec/runner_spec.rb +210 -0
- data/vendor/thor/spec/shell/basic_spec.rb +205 -0
- data/vendor/thor/spec/shell/color_spec.rb +41 -0
- data/vendor/thor/spec/shell_spec.rb +34 -0
- data/vendor/thor/spec/spec.opts +1 -0
- data/vendor/thor/spec/spec_helper.rb +54 -0
- data/vendor/thor/spec/task_spec.rb +69 -0
- data/vendor/thor/spec/thor_spec.rb +237 -0
- data/vendor/thor/spec/util_spec.rb +163 -0
- data/vendor/thor/thor.gemspec +120 -0
- metadata +199 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2010 PLUS2 Pty. Ltd.
|
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 PURPOa AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SaALL 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.
|
21
|
+
|
data/README.md
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
# This is AngryMob
|
2
|
+
AngryMob (AM) is the automated system configuration component of [YesMaster](http://yesmasterapp.com).
|
3
|
+
|
4
|
+
It combines:
|
5
|
+
|
6
|
+
* convenient configuration data (`the node`)
|
7
|
+
* idempotent code to ensure the configuration of the parts of a system (`targets`)
|
8
|
+
* and a method of controlling the flow of the setup (`acts`)
|
9
|
+
|
10
|
+
AngryMob values having:
|
11
|
+
|
12
|
+
* zero external dependencies.
|
13
|
+
* a small, simple core.
|
14
|
+
* Rubiness.
|
15
|
+
|
16
|
+
Having *zero external dependencies* means that AM can be used from the very moment a bare ruby interpreter is installed on a server.
|
17
|
+
|
18
|
+
A *small, simple core* means that debugging and testing the code is simplified. It also allows AM to be embedded directly into other projects.
|
19
|
+
|
20
|
+
Please note that **AngryMob is a reaction to Chef**. Despite this, I retain the utmost respect the Chef movement and the guys who've built it.
|
21
|
+
|
22
|
+
AM purposely omits or eschews the following features you might be familiar with from Chef:
|
23
|
+
|
24
|
+
* **The client and server and its dependencies.** AM operates similarly to "chef-solo" or is combined with other components for network based "chef-client"-like operation.
|
25
|
+
* **A built in, fixed cookbook layout and metadata.** You can define your own ResourceLocator, or use the basic supplied one.
|
26
|
+
* **A single copy nirvana implementation.** Again, define it yourself if you want it.
|
27
|
+
* **The puppet resource/provider separation.** I don't have a particular solution to supporting multiple operating systems, but its strongly YAGNI for now.
|
28
|
+
* **Exhaustive system discovery like Ohai.** I think Ohai is great, but running it before every AM run to find the hostname and IP is excessive.
|
29
|
+
* **Type-checking of data.** This is ruby, where ducks rule the roost.
|
30
|
+
|
31
|
+
### Status
|
32
|
+
AngryMob is young and fluid, but I'm using it a lot in the maintainence of VPSes at PLUS2.
|
33
|
+
|
34
|
+
In particular, AM lacks any unit-level specs or tests so far. The servers it maintains are valid functional testing in my eyes ;)
|
35
|
+
|
36
|
+
### Taxonomy
|
37
|
+
|
38
|
+
* The `node` is a glob of data representing the thing you're configuring.
|
39
|
+
* `targets` are things you want to configure.
|
40
|
+
* `acts` are groups of target invocations. They can also schedule the execution of other acts.
|
41
|
+
* `mobs` are groups of acts and targets.
|
42
|
+
|
43
|
+
#### The Node
|
44
|
+
The Node is a place to hang your data. In essence its a `Hash` (though more specifically its an [AngryHash](http://github.com/plus2/angry_hash), which is similar to `Hashie::Mash`)
|
45
|
+
|
46
|
+
#### Targets
|
47
|
+
Targets are parts of the server which you want to configure, for example:
|
48
|
+
|
49
|
+
* directories
|
50
|
+
* templates
|
51
|
+
* users
|
52
|
+
|
53
|
+
*Note* the targets interface is likely to change soon. Its overly complicated right now.
|
54
|
+
|
55
|
+
Targets perform a similar role to Chef/puppet resource/providers.
|
56
|
+
|
57
|
+
**TODO** talk about Target definition dsl and SingletonTargets
|
58
|
+
|
59
|
+
#### Acts
|
60
|
+
Acts are groups of targets. They're conceptually similar to a rake task. Subsequent acts can be scheduled.
|
61
|
+
|
62
|
+
#### Mobs
|
63
|
+
Mobs are groups of target definitions and acts. They can be mixed and matched.
|
64
|
+
|
65
|
+
##### common mob
|
66
|
+
|
67
|
+
http://github.com/plus2/common_mob
|
68
|
+
|
69
|
+
A small toolkit of handy targets:
|
70
|
+
|
71
|
+
* dir
|
72
|
+
* file
|
73
|
+
* template - ERB
|
74
|
+
* symlink
|
75
|
+
* tarball
|
76
|
+
* fetch
|
77
|
+
* git
|
78
|
+
* user
|
79
|
+
* apt - apt-get package
|
80
|
+
* gem - a rubygem
|
81
|
+
* block - a ruby block
|
82
|
+
* sh - a shell command
|
83
|
+
* service - a super-class for defining ubuntu service targets
|
84
|
+
|
85
|
+
## The mob command
|
86
|
+
|
87
|
+
"chef-solo"-like command for setting an AngryMob on your server.
|
88
|
+
|
89
|
+
**TODO** write!
|
90
|
+
|
91
|
+
## Meta
|
92
|
+
|
93
|
+
AngryMob was written by [Lachie Cox](http://github.com/lachie) for [PLUS2](http://plus2.com.au) and [YesMaster](http://yesmasterapp.com).
|
94
|
+
|
95
|
+
It lives at [http://github.com/plus2/angry_mob](http://github.com/plus2/angry_mob).
|
96
|
+
|
97
|
+
Please try it out and send us feedback via the github page.
|
98
|
+
|
99
|
+
## License
|
100
|
+
|
101
|
+
Copyright (c) 2010 PLUS2
|
102
|
+
|
103
|
+
Permission is hereby granted, free of charge, to any person
|
104
|
+
obtaining a copy of this software and associated documentation
|
105
|
+
files (the "Software"), to deal in the Software without
|
106
|
+
restriction, including without limitation the rights to use,
|
107
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
108
|
+
copies of the Software, and to permit persons to whom the
|
109
|
+
Software is furnished to do so, subject to the following
|
110
|
+
conditions:
|
111
|
+
|
112
|
+
The above copyright notice and this permission notice shall be
|
113
|
+
included in all copies or substantial portions of the Software.
|
114
|
+
|
115
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
116
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
117
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
118
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
119
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
120
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
121
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
122
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
123
|
+
|
data/bin/mob
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
@root = Pathname(__FILE__).dirname.parent.expand_path
|
6
|
+
|
7
|
+
%w{json thor angry_hash}.each do |lib|
|
8
|
+
root = @root+'vendor'+lib
|
9
|
+
$: << (root+'lib')
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'thor'
|
13
|
+
|
14
|
+
$:.unshift @root+'lib'
|
15
|
+
require 'angry_mob'
|
16
|
+
|
17
|
+
class MobCLI < Thor
|
18
|
+
|
19
|
+
default_task 'riot'
|
20
|
+
desc 'riot', 'riot the mob'
|
21
|
+
method_option :nodename , :type => :string, :required => true
|
22
|
+
method_option :json_file, :type => :string, :required => true
|
23
|
+
method_option :act , :type => :string, :required => true
|
24
|
+
|
25
|
+
method_option :hooks , :type => :string
|
26
|
+
|
27
|
+
method_option :debug , :type => :boolean, :default => false
|
28
|
+
method_option :dry_run , :type => :boolean, :default => false
|
29
|
+
method_option :allow_missing_act, :type => :boolean, :default => false
|
30
|
+
|
31
|
+
method_option :mobs, :type => :array, :default => []
|
32
|
+
|
33
|
+
attr_reader :config
|
34
|
+
def riot
|
35
|
+
begin
|
36
|
+
@config = AngryHash[ options ]
|
37
|
+
|
38
|
+
load_hooks(config.hooks)
|
39
|
+
|
40
|
+
@hooks.pre
|
41
|
+
|
42
|
+
ui = AngryMob::UI.new(:debug => config.debug?)
|
43
|
+
|
44
|
+
attributes = build_attributes
|
45
|
+
|
46
|
+
@hooks.attrs( attributes )
|
47
|
+
|
48
|
+
AngryMob::Mob.ui = ui # XXX not threadsafe, but what is?
|
49
|
+
mob_loader = AngryMob::MobLoader.new
|
50
|
+
|
51
|
+
config.mobs.each {|mob_path| mob_loader.add_mob(mob_path)}
|
52
|
+
|
53
|
+
mob = mob_loader.to_mob
|
54
|
+
mob.riot!( config.nodename, attributes )
|
55
|
+
|
56
|
+
rescue
|
57
|
+
$stdout.flush
|
58
|
+
$stderr.flush
|
59
|
+
|
60
|
+
puts "\nerror [#{$!.class}] #{$!}"
|
61
|
+
$!.backtrace.each {|b| puts " #{b}"}
|
62
|
+
exit(1)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
def build_attributes
|
68
|
+
attributes = load_attributes
|
69
|
+
|
70
|
+
attributes.acts = [ config.act ]
|
71
|
+
|
72
|
+
if config.allow_missing_act?
|
73
|
+
attributes.raise_on_missing_act = false
|
74
|
+
end
|
75
|
+
|
76
|
+
attributes.dry_run = config.dry_run?
|
77
|
+
|
78
|
+
attributes
|
79
|
+
end
|
80
|
+
|
81
|
+
def load_attributes
|
82
|
+
return AngryHash.new unless config.json_file?
|
83
|
+
|
84
|
+
if config.json_file.to_s[/^https?:/]
|
85
|
+
require 'net/http'
|
86
|
+
require 'uri'
|
87
|
+
json = Net::HTTP.get(URI.parse(config.json_file))
|
88
|
+
else
|
89
|
+
json = Pathname(config.json_file.tapp("loading attributes from")).expand_path.read
|
90
|
+
end
|
91
|
+
|
92
|
+
require 'json/pure'
|
93
|
+
attributes = JSON.parse( json )
|
94
|
+
|
95
|
+
AngryHash[attributes || {}]
|
96
|
+
end
|
97
|
+
|
98
|
+
def load_hooks(file)
|
99
|
+
@hooks = MobHooks.new( self, file )
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
class MobHooks
|
105
|
+
attr_reader :cli
|
106
|
+
def initialize(cli,file=nil)
|
107
|
+
@cli = cli
|
108
|
+
if file
|
109
|
+
@building = true
|
110
|
+
instance_eval( Pathname(file).read )
|
111
|
+
@building = false
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def pre(&block)
|
116
|
+
if building?
|
117
|
+
pre_blocks << block
|
118
|
+
else
|
119
|
+
pre_blocks.each {|b| b.call}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def attrs( *args, &block )
|
124
|
+
if building?
|
125
|
+
attr_blocks << block
|
126
|
+
else
|
127
|
+
attr_blocks.each {|b| b.call(*args)}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
protected
|
132
|
+
|
133
|
+
def building?; @building end
|
134
|
+
def pre_blocks ; @pre_blocks ||= [] end
|
135
|
+
def attr_blocks; @attr_blocks ||= [] end
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
MobCLI.start
|
data/lib/angry_mob.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
here = Pathname(__FILE__).dirname
|
3
|
+
|
4
|
+
require 'angry_hash'
|
5
|
+
|
6
|
+
# XXX duckpunches aren't good for not stepping on other codes' toes
|
7
|
+
require 'angry_mob/extend'
|
8
|
+
|
9
|
+
class AngryMob
|
10
|
+
autoload :Mob , 'angry_mob/mob'
|
11
|
+
autoload :Node , 'angry_mob/node'
|
12
|
+
|
13
|
+
autoload :Target , 'angry_mob/target'
|
14
|
+
autoload :SingletonTarget, 'angry_mob/singleton_target'
|
15
|
+
autoload :Action , 'angry_mob/action'
|
16
|
+
|
17
|
+
autoload :Notifier , 'angry_mob/notifier'
|
18
|
+
|
19
|
+
autoload :Act , 'angry_mob/act'
|
20
|
+
|
21
|
+
autoload :Log , 'angry_mob/log'
|
22
|
+
autoload :UI , 'angry_mob/ui'
|
23
|
+
autoload :Util , 'angry_mob/util'
|
24
|
+
|
25
|
+
autoload :Builder , 'angry_mob/builder'
|
26
|
+
autoload :MobLoader , 'angry_mob/mob_loader'
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
class AngryMob
|
2
|
+
# A `Builder::Act` groups target calls.
|
3
|
+
class Act
|
4
|
+
autoload :Scheduler, "angry_mob/act/scheduler"
|
5
|
+
|
6
|
+
attr_reader :mob, :name, :definition_file
|
7
|
+
|
8
|
+
def initialize(name,multi,&blk)
|
9
|
+
@name = name
|
10
|
+
@multi = multi
|
11
|
+
@blk = blk
|
12
|
+
end
|
13
|
+
|
14
|
+
def ui; mob.ui end
|
15
|
+
def log(message); mob.ui.log message end
|
16
|
+
|
17
|
+
def multi?; !!@multi end
|
18
|
+
|
19
|
+
# Binds the act to the mob and the file from which it came.
|
20
|
+
def bind(mob,file)
|
21
|
+
@mob = mob
|
22
|
+
@definition_file = file
|
23
|
+
|
24
|
+
mob.act_scheduler.add_act @name, self
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.synthesise(mob,name,&blk)
|
28
|
+
act = new(name,true,&blk)
|
29
|
+
act.bind(mob,"name")
|
30
|
+
act.run!
|
31
|
+
end
|
32
|
+
|
33
|
+
#### Compilation
|
34
|
+
|
35
|
+
# Executes the block via `instance_exec`
|
36
|
+
def run!(*arguments)
|
37
|
+
ui.push("act '#{name}'", :bubble => true) do
|
38
|
+
@running = true
|
39
|
+
|
40
|
+
instance_exec *arguments, &@blk
|
41
|
+
|
42
|
+
@running = false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# bundler + rubygems clusterfuck
|
47
|
+
def gem(*args,&blk)
|
48
|
+
__run_target(:gem,*args,&blk)
|
49
|
+
end
|
50
|
+
|
51
|
+
# TODO - de-mm
|
52
|
+
def method_missing(nickname,*args,&blk)
|
53
|
+
return super unless @running
|
54
|
+
__run_target(nickname,*args,&blk)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Schedules a target, adding call-location context along the way.
|
58
|
+
def __run_target(nickname,*args,&blk)
|
59
|
+
call = mob.target_mother.target_call(nickname,*args,&blk)
|
60
|
+
|
61
|
+
call.merge_defaults(defaults.defaults_for(nickname))
|
62
|
+
call.call(self)
|
63
|
+
|
64
|
+
call.target
|
65
|
+
end
|
66
|
+
|
67
|
+
def in_sub_act(*args,&blk)
|
68
|
+
sub_act = self.class.new("#{name}-sub-act",true,&blk)
|
69
|
+
sub_act.bind(@mob,@definition_file)
|
70
|
+
sub_act.run!(*args)
|
71
|
+
end
|
72
|
+
|
73
|
+
#### Definition helpers
|
74
|
+
|
75
|
+
def defaults
|
76
|
+
@defaults ||= Target::Defaults.new
|
77
|
+
end
|
78
|
+
|
79
|
+
def notify
|
80
|
+
Target::Notify.new(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
def notifications
|
84
|
+
mob.notifier
|
85
|
+
end
|
86
|
+
|
87
|
+
# directly schedule a call on the delayed list
|
88
|
+
def later
|
89
|
+
n = Target::Notify.new(self)
|
90
|
+
mob.notifier.schedule_notification n
|
91
|
+
n
|
92
|
+
end
|
93
|
+
|
94
|
+
def node
|
95
|
+
mob.node
|
96
|
+
end
|
97
|
+
|
98
|
+
def act_now act_name, *args
|
99
|
+
mob.act_scheduler.act_now(act_name,*args)
|
100
|
+
end
|
101
|
+
|
102
|
+
def schedule_act act_name
|
103
|
+
mob.act_scheduler.schedule_act(act_name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def schedule_acts_matching(regex,&block)
|
107
|
+
mob.act_scheduler.schedule_acts_matching(regex,&block)
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
class AngryMob
|
2
|
+
class Act
|
3
|
+
class Scheduler
|
4
|
+
attr_writer :node
|
5
|
+
attr_reader :acted, :mob
|
6
|
+
|
7
|
+
def initialize(mob)
|
8
|
+
@mob = mob
|
9
|
+
reset!
|
10
|
+
end
|
11
|
+
|
12
|
+
def ui; @mob.ui end
|
13
|
+
|
14
|
+
def reset!
|
15
|
+
@act_names = nil
|
16
|
+
@acted = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def act_names
|
20
|
+
@act_names ||= @node.acts || []
|
21
|
+
end
|
22
|
+
|
23
|
+
def acts
|
24
|
+
@acts ||= Dictionary.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_act(name,act)
|
28
|
+
acts[name.to_s] = act
|
29
|
+
end
|
30
|
+
|
31
|
+
def run!
|
32
|
+
ui.task "running acts #{act_names.inspect}"
|
33
|
+
each_act {|act| act_now(act)}
|
34
|
+
ui.good "finished running acts"
|
35
|
+
finalise_acts!
|
36
|
+
end
|
37
|
+
|
38
|
+
def each_act
|
39
|
+
while act_name = next_act
|
40
|
+
ui.debug "acting out #{act_name}"
|
41
|
+
|
42
|
+
act = acts[act_name]
|
43
|
+
|
44
|
+
unless act
|
45
|
+
act_missing!(act_name)
|
46
|
+
next
|
47
|
+
end
|
48
|
+
|
49
|
+
yield act
|
50
|
+
end
|
51
|
+
@iterating = false
|
52
|
+
end
|
53
|
+
|
54
|
+
def start_iterating!(with=act_names)
|
55
|
+
unless @iterating
|
56
|
+
@iterating_act_names = with.dup
|
57
|
+
@iterating = true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def next_act
|
62
|
+
start_iterating!
|
63
|
+
@iterating_act_names.shift
|
64
|
+
end
|
65
|
+
|
66
|
+
def schedule_act(*acts)
|
67
|
+
raise(CompilationError, "schedule_act called when not compiling") unless @iterating
|
68
|
+
ui.info "scheduling #{acts.inspect}"
|
69
|
+
@iterating_act_names += acts
|
70
|
+
end
|
71
|
+
|
72
|
+
def schedule_acts_matching(regex=nil,&block)
|
73
|
+
raise(CompilationError, "schedule_act called when not compiling") unless @iterating
|
74
|
+
|
75
|
+
act_keys = acts.keys
|
76
|
+
|
77
|
+
acts_to_schedule = if regex
|
78
|
+
act_keys.grep(regex)
|
79
|
+
else
|
80
|
+
act_keys.select(&block)
|
81
|
+
end
|
82
|
+
|
83
|
+
schedule_act(*acts_to_schedule)
|
84
|
+
end
|
85
|
+
|
86
|
+
def finalise_acts!
|
87
|
+
# notifications only act as necessary, so its safe to run them all.
|
88
|
+
ui.task "running notifications"
|
89
|
+
to_notify = acts.keys.select {|k| k[%r{^notifications_for/}]}
|
90
|
+
|
91
|
+
unless to_notify.empty?
|
92
|
+
ui.info "running notifiers #{to_notify.inspect}"
|
93
|
+
|
94
|
+
start_iterating!(to_notify)
|
95
|
+
each_act {|act| act_now(act)}
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
# finalisers should only run if the act of the same name has run first
|
100
|
+
ui.task "running finalisations"
|
101
|
+
|
102
|
+
to_finalise = acted.map {|name| "finalise/#{name}"} & acts.keys
|
103
|
+
unless to_finalise.empty?
|
104
|
+
ui.info "running acts finalisers #{to_finalise.inspect}"
|
105
|
+
|
106
|
+
start_iterating!(to_finalise)
|
107
|
+
each_act {|act| act_now(act)}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def raise_on_missing_act?
|
112
|
+
!( FalseClass === mob.node.raise_on_missing_act )
|
113
|
+
end
|
114
|
+
|
115
|
+
def act_missing!(name)
|
116
|
+
raise(AngryMob::MobError, "no act named '#{name}'") if raise_on_missing_act?
|
117
|
+
end
|
118
|
+
|
119
|
+
def act_now(act_name,*arguments)
|
120
|
+
if AngryMob::Act === act_name
|
121
|
+
act = act_name
|
122
|
+
act_name = act.name
|
123
|
+
else
|
124
|
+
act = acts[act_name]
|
125
|
+
end
|
126
|
+
|
127
|
+
unless act
|
128
|
+
act_missing!(act_name)
|
129
|
+
return
|
130
|
+
end
|
131
|
+
|
132
|
+
if !act.multi? && acted.include?(act_name)
|
133
|
+
ui.skipped! "(not re-running act #{act_name} - already run)"
|
134
|
+
return
|
135
|
+
end
|
136
|
+
|
137
|
+
acted << act_name
|
138
|
+
|
139
|
+
act.run!(*arguments)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|