emory 0.1.0
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/.gitignore +26 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +193 -0
- data/Rakefile +16 -0
- data/bin/emory +32 -0
- data/emory.gemspec +26 -0
- data/examples/simple-stdout/.emory +15 -0
- data/examples/simple-stdout/.gitignore +1 -0
- data/examples/simple-stdout/src/.gitkeep +0 -0
- data/lib/emory/configuration_file.rb +29 -0
- data/lib/emory/dsl/dsl.rb +54 -0
- data/lib/emory/dsl/handler_builder.rb +78 -0
- data/lib/emory/dsl/teleport_config_builder.rb +62 -0
- data/lib/emory/handlers/abstract_handler.rb +35 -0
- data/lib/emory/handlers/stdout_handler.rb +33 -0
- data/lib/emory/runner.rb +75 -0
- data/lib/emory/teleport_config.rb +7 -0
- data/lib/emory/version.rb +3 -0
- data/lib/emory.rb +1 -0
- data/spec/emory/configuration_file_spec.rb +43 -0
- data/spec/emory/dsl/dsl_spec.rb +91 -0
- data/spec/emory/dsl/handler_builder_spec.rb +163 -0
- data/spec/emory/dsl/teleport_config_builder_spec.rb +116 -0
- data/spec/emory/handlers/abstract_handler_spec.rb +35 -0
- data/spec/emory/handlers/stdout_handler_spec.rb +29 -0
- data/spec/emory/runner_spec.rb +75 -0
- data/spec/spec_helper.rb +10 -0
- data/test/emory/test_configuration_file.rb +10 -0
- metadata +171 -0
data/.gitignore
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
.idea/
|
19
|
+
.project
|
20
|
+
emory.log
|
21
|
+
|
22
|
+
## MAC OS
|
23
|
+
.DS_Store
|
24
|
+
.Trashes
|
25
|
+
.com.apple.timemachine.supported
|
26
|
+
.fseventsd
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Tacit Knowledge
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
Emory
|
2
|
+
=====
|
3
|
+
|
4
|
+
The Emory gem listens to file modifications and runs an action against it (for example, upload to a remote location).
|
5
|
+
|
6
|
+
Contents
|
7
|
+
--------
|
8
|
+
|
9
|
+
* [Installation](#installation)
|
10
|
+
* [Usage](#usage)
|
11
|
+
* [Emory configuration DSL](#emory-dsl)
|
12
|
+
* [handler](#emory-dsl-handler)
|
13
|
+
* [teleport](#emory-dsl-teleport)
|
14
|
+
* [Contributing](#contributing)
|
15
|
+
* [Authors](#authors)
|
16
|
+
|
17
|
+
<a name="installation" />
|
18
|
+
Installation
|
19
|
+
------------
|
20
|
+
|
21
|
+
Add this line to your application's `Gemfile`:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'emory'
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
```bash
|
30
|
+
$ bundle
|
31
|
+
```
|
32
|
+
|
33
|
+
Or install it yourself as:
|
34
|
+
|
35
|
+
```bash
|
36
|
+
$ gem install emory
|
37
|
+
```
|
38
|
+
|
39
|
+
<a name="usage" />
|
40
|
+
Usage
|
41
|
+
-----
|
42
|
+
|
43
|
+
Emory is run from the command line. Please open your terminal and go to your project's work directory.
|
44
|
+
|
45
|
+
There you would need to create Emory config file `.emory` which in fact is nothing more than regular
|
46
|
+
Ruby code wrapped in gem's configuration DSL.
|
47
|
+
|
48
|
+
Example configuration:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
require 'emory/handlers/stdout_handler'
|
52
|
+
|
53
|
+
handler do
|
54
|
+
name :listener
|
55
|
+
implementation Emory::Handlers::StdoutHandler
|
56
|
+
events :all
|
57
|
+
end
|
58
|
+
|
59
|
+
teleport do
|
60
|
+
path '~/_emory-test/'
|
61
|
+
handler :listener
|
62
|
+
ignore %r{ignored/}
|
63
|
+
filter /\.txt$/
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
The gem supplies an executable file which scans for the configuration file in current directory
|
68
|
+
(and up the path if not found), configures itself and launches the process. If you need to terminate
|
69
|
+
execution then proceed like your operating system allows you to (Ctrl-C, for example).
|
70
|
+
|
71
|
+
```bash
|
72
|
+
$ emory
|
73
|
+
[2012-05-31 12:08:23] INFO Emory::ConfigurationFile: Found config file: /Users/xxx/.emory
|
74
|
+
[2012-05-31 12:08:23] INFO Emory::Runner: Watching directory: /Users/xxx/_emory-test
|
75
|
+
```
|
76
|
+
|
77
|
+
Emory outputs some information into the console where it was launched from. However if you would
|
78
|
+
like to consult more detailed information on what it's doing then feel free to supply `-d` or
|
79
|
+
`--debug` when launching it like in this example:
|
80
|
+
|
81
|
+
```bash
|
82
|
+
$ emory --debug
|
83
|
+
[2012-05-31 12:08:29] DEBUG Emory::Runner: Looking for the configuration file
|
84
|
+
[2012-05-31 12:08:29] DEBUG Emory::ConfigurationFile: Examining directory: /Users/xxx/Projects
|
85
|
+
[2012-05-31 12:08:29] DEBUG Emory::ConfigurationFile: Examining directory: /Users/xxx
|
86
|
+
[2012-05-31 12:08:29] INFO Emory::ConfigurationFile: Found config file: /Users/xxx/.emory
|
87
|
+
[2012-05-31 12:08:29] DEBUG Emory::Runner: Reading configuration file contents
|
88
|
+
[2012-05-31 12:08:29] DEBUG Emory::Runner: Evaluating configuration file contents:
|
89
|
+
<<< the rest of the output is ommitted >>>
|
90
|
+
```
|
91
|
+
|
92
|
+
<a name="emory-dsl" />
|
93
|
+
Emory configuration DSL
|
94
|
+
-----------------------
|
95
|
+
|
96
|
+
The Emory configuration DSL is evaluated as plain Ruby, so you can use normal Ruby code in your
|
97
|
+
`.emory` file. Emory itself provides the following DSL methods that can be used for configuration:
|
98
|
+
|
99
|
+
<a name="emory-dsl-handler" />
|
100
|
+
### handler
|
101
|
+
|
102
|
+
A handler in Emory is an entity which knows how to react on file system modification events.
|
103
|
+
By default only two are provided:
|
104
|
+
|
105
|
+
- `Emory::Handlers::AbstractHandler` - defines common interface for other handlers to implement
|
106
|
+
- `Emory::Handlers::StdoutHandler` - spits out some information on what/how changed to the standard output
|
107
|
+
|
108
|
+
A handler can be configured with 3 mandatory and 1 optional parameter:
|
109
|
+
|
110
|
+
- mandatory
|
111
|
+
- name - defines a name for the handler so that it could be used in other parts of the configuration
|
112
|
+
- implementation - name of the specific class that conforms to `Emory::Handlers::AbstractHandler`'s interface
|
113
|
+
- events - a comma separated list of events the handler should react to (**:added**,
|
114
|
+
**:modified**, **:removed**) while ignoring the ones not mentioned. There's also an **:all**
|
115
|
+
shortcut to indicate all events without explicitly writing them.
|
116
|
+
- optional
|
117
|
+
- options - a hash of optional data that will be passed on during handler's construction. Please
|
118
|
+
note that the handler's class needs to know how to treat these otherwise it's a no-op. For
|
119
|
+
example, `Emory::Handlers::StdoutHandler` does not know how to deal with the options so it would
|
120
|
+
just ignore them.
|
121
|
+
|
122
|
+
Some examples of defining handlers
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
require 'emory/handlers/stdout_handler'
|
126
|
+
require 'some_company/integration/system_x_handler'
|
127
|
+
|
128
|
+
handler do
|
129
|
+
name :stdout_handler
|
130
|
+
implementation Emory::Handlers::StdoutHandler
|
131
|
+
events :added, :removed
|
132
|
+
end
|
133
|
+
|
134
|
+
handler do
|
135
|
+
name :integration_handler
|
136
|
+
implementation SomeCompany::Integration::SystemXHandler
|
137
|
+
events :modified
|
138
|
+
options host: 'host1.othercompany.com', port: 12345, username: 'bozo', password: 'p@ssw0rd'
|
139
|
+
# or the arrows syntax in Ruby 1.8
|
140
|
+
# options :host => 'host1.othercompany.com', :port => 12345, :username => 'bozo', :password => 'p@ssw0rd'
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
<a name="emory-dsl-teleport" />
|
145
|
+
### teleport
|
146
|
+
|
147
|
+
A teleport in Emory is an entity that knows that it needs to monitor some path (including sub-directories)
|
148
|
+
and notify the linked handler if something interesting happens. A teleport can be configured with
|
149
|
+
2 mandatory and 2 optional parameters:
|
150
|
+
|
151
|
+
- mandatory
|
152
|
+
- path - the path to monitor (including its sub-directories). Can be either absolute or relative
|
153
|
+
to the location of the configuration file (`.emory`).
|
154
|
+
- handler - the handler to invoke/notify when the filesystem events occur in the path supplied above
|
155
|
+
- optional
|
156
|
+
- ignore - the regex patterns that need to be ignored by the teleport
|
157
|
+
- filter - the regex patterns that filter out unwanted monitoring events
|
158
|
+
|
159
|
+
An example teleport definition:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
# Will monitor file system events starting under <config_location>/ftp/incoming/x/ directory,
|
163
|
+
# but will ignore paths containing reconciled/ and pending/ directories, and additionaly will
|
164
|
+
# apply only to .txt files. Once events are identified will notify the handler named :integration_handler.
|
165
|
+
teleport do
|
166
|
+
path 'ftp/incoming/x'
|
167
|
+
handler :integration_handler
|
168
|
+
ignore %r{reconciled/ pending/}
|
169
|
+
filter /\.txt$/
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
<a name="contributing" />
|
174
|
+
Contributing
|
175
|
+
------------
|
176
|
+
|
177
|
+
1. Fork it
|
178
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
179
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
180
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
181
|
+
5. Create new Pull Request
|
182
|
+
|
183
|
+
<a name="authors" />
|
184
|
+
Authors
|
185
|
+
-------
|
186
|
+
|
187
|
+
* [Vladislav Gangan](https://github.com/vgangan)
|
188
|
+
|
189
|
+
Contributors
|
190
|
+
------------
|
191
|
+
|
192
|
+
* [Scott Askew](https://github.com/scottfromsf)
|
193
|
+
* [Ion Lenta](https://github.com/noi)
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
Rake::TestTask.new do |t|
|
5
|
+
t.libs << 'test'
|
6
|
+
t.test_files = FileList['test/**/test*.rb']
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
RSpec::Core::RakeTask.new('spec')
|
11
|
+
|
12
|
+
require 'bundler'
|
13
|
+
Bundler::GemHelper.install_tasks
|
14
|
+
|
15
|
+
desc "Run rspec tests"
|
16
|
+
task :default => :spec
|
data/bin/emory
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'logging'
|
5
|
+
require 'emory/runner'
|
6
|
+
require 'emory/version'
|
7
|
+
|
8
|
+
options = {}
|
9
|
+
OptionParser.new do |opts|
|
10
|
+
options[:log_level] = :info
|
11
|
+
opts.on('-d', '--debug', "Display debug output") do
|
12
|
+
options[:log_level] = :debug
|
13
|
+
end
|
14
|
+
opts.on('-v', '--version', 'Display version information') do
|
15
|
+
puts "Emory version #{Emory::VERSION}"
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
19
|
+
puts opts
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
end.parse!
|
23
|
+
|
24
|
+
logging_lines_colors = {debug: :green, info: :light_green, warn: :yellow, error: :red, fatal: [:white, :on_red]}
|
25
|
+
Logging.color_scheme('bright', lines: logging_lines_colors)
|
26
|
+
|
27
|
+
logging_layouts_pattern = Logging.layouts.pattern(color_scheme: 'bright', pattern: '[%d] %-5l %c: %m\n')
|
28
|
+
Logging.appenders.stdout('stdout', layout: logging_layouts_pattern, level: options[:log_level])
|
29
|
+
|
30
|
+
Logging.logger.root.add_appenders('stdout')
|
31
|
+
|
32
|
+
Emory::Runner.start
|
data/emory.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'emory/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'emory'
|
7
|
+
s.version = Emory::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Scott Askew', 'Vladislav Gangan', 'Ion Lenta']
|
10
|
+
s.email = ['scott@tacitknowledge.com', 'vgangan@tacitknowledge.com', 'ilenta@tacitknowledge.com']
|
11
|
+
s.homepage = 'https://github.com/tacitknowledge/emory'
|
12
|
+
s.summary = 'Invokes a configured action when something interesting happens to a monitored file'
|
13
|
+
s.description = 'The Emory gem listens to file modifications and runs an action against it (for example, upload to a remote location)'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split($\)
|
16
|
+
s.executables = %w(emory)
|
17
|
+
s.test_files = Dir.glob("{spec,test}/**/*.rb")
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_development_dependency 'rspec', '~> 2.10'
|
21
|
+
s.add_development_dependency 'simplecov', '~> 0.6.2'
|
22
|
+
s.add_development_dependency 'rake'
|
23
|
+
|
24
|
+
s.add_runtime_dependency 'logging'
|
25
|
+
s.add_runtime_dependency 'listen'
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'emory/handlers/stdout_handler'
|
2
|
+
|
3
|
+
# Define a handler emits any file add/modify/delete in ./src to STDOUT.
|
4
|
+
handler do
|
5
|
+
name :stdout
|
6
|
+
implementation Emory::Handlers::StdoutHandler
|
7
|
+
events :all
|
8
|
+
end
|
9
|
+
|
10
|
+
# Map ./src to the handler defined above. Note that the 'path' is relative
|
11
|
+
# to the location .emory (i.e. this file)
|
12
|
+
teleport do
|
13
|
+
path 'src'
|
14
|
+
handler :stdout
|
15
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
src/*
|
File without changes
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Emory
|
4
|
+
|
5
|
+
class EmoryConfigurationFileNotFoundException < Exception; end
|
6
|
+
|
7
|
+
class ConfigurationFile
|
8
|
+
|
9
|
+
LOGGER = Logging.logger[self]
|
10
|
+
CONFIG_FILE_NAME = ".emory"
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def locate
|
15
|
+
Pathname.new(Dir.pwd).ascend do |dir|
|
16
|
+
LOGGER.debug "Examining directory: #{dir}"
|
17
|
+
config_file = File.join(dir, CONFIG_FILE_NAME)
|
18
|
+
next unless File.exists?(config_file)
|
19
|
+
LOGGER.info "Found config file: #{config_file}"
|
20
|
+
return config_file
|
21
|
+
end
|
22
|
+
|
23
|
+
raise EmoryConfigurationFileNotFoundException, 'Configuration file (.emory) was not found'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'emory/teleport_config'
|
2
|
+
require 'emory/dsl/handler_builder'
|
3
|
+
require 'emory/dsl/teleport_config_builder'
|
4
|
+
|
5
|
+
module Emory
|
6
|
+
module DSL
|
7
|
+
|
8
|
+
class EmoryMisconfigurationException < Exception; end
|
9
|
+
class DuplicateHandlerNameException < Exception; end
|
10
|
+
|
11
|
+
class Dsl
|
12
|
+
|
13
|
+
LOGGER = Logging.logger[self]
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def instance_eval_emoryfile(contents, config_path)
|
17
|
+
config = new
|
18
|
+
config.instance_eval(contents, config_path, 1)
|
19
|
+
config.handlers.freeze
|
20
|
+
config.teleports.freeze
|
21
|
+
config
|
22
|
+
rescue
|
23
|
+
LOGGER.error("Incorrect contents of .emory file, original error is:\n#{ $! }")
|
24
|
+
raise EmoryMisconfigurationException, 'Incorrect contents of .emory file'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def teleport(&block)
|
29
|
+
teleport_builder = TeleportConfigBuilder.new(handlers, &block)
|
30
|
+
teleport = teleport_builder.build
|
31
|
+
teleports << teleport
|
32
|
+
LOGGER.debug("Processed and added #{teleport} to the list: #{teleports}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def handler(&block)
|
36
|
+
handler_builder = HandlerBuilder.new(&block)
|
37
|
+
handler = handler_builder.build
|
38
|
+
raise DuplicateHandlerNameException, "The handler name ':#{handler.name}' is defined more than once" if handlers.include?(handler.name)
|
39
|
+
handlers[handler.name] = handler
|
40
|
+
LOGGER.debug("Processed and added ':#{handler.name}' to the list: #{handlers}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def handlers
|
44
|
+
@handlers ||= {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def teleports
|
48
|
+
@teleports ||= []
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Emory
|
2
|
+
module DSL
|
3
|
+
|
4
|
+
class HandlerConfigurationBlockMustBeSuppliedException < Exception; end
|
5
|
+
class HandlerNameMustBeSuppliedException < Exception; end
|
6
|
+
class HandlerImplementationMustBeSuppliedException < Exception; end
|
7
|
+
class HandlerActionAllMustBeSingletonException < Exception; end
|
8
|
+
class HandlerActionMustBeSuppliedException < Exception; end
|
9
|
+
class HandlerActionUnsupportedException < Exception; end
|
10
|
+
|
11
|
+
class HandlerBuilder
|
12
|
+
|
13
|
+
LOGGER = Logging.logger[self]
|
14
|
+
HANDLER_ACTION_ALL = :all
|
15
|
+
ALLOWED_HANDLER_ACTIONS = [HANDLER_ACTION_ALL, :added, :modified, :removed]
|
16
|
+
|
17
|
+
def initialize(&block)
|
18
|
+
LOGGER.debug('Initializing a new handler builder')
|
19
|
+
raise HandlerConfigurationBlockMustBeSuppliedException, "The configuration block with handler settings must be supplied" unless block_given?
|
20
|
+
@block = block
|
21
|
+
@options = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def build
|
25
|
+
LOGGER.debug('Evaluating handler configuration')
|
26
|
+
instance_eval &@block
|
27
|
+
|
28
|
+
raise HandlerNameMustBeSuppliedException, "The handler name must be supplied in its configuration" if @name.nil?
|
29
|
+
raise HandlerImplementationMustBeSuppliedException, "The handler implementation must be supplied in its configuration" if @implementation.nil?
|
30
|
+
|
31
|
+
LOGGER.debug('Creating a new handler instance')
|
32
|
+
handler = @implementation.new(@name, @options)
|
33
|
+
|
34
|
+
raise HandlerActionMustBeSuppliedException, "At least one handler action needs to be supplied" if @events.nil?
|
35
|
+
if @events.first != HANDLER_ACTION_ALL
|
36
|
+
handler.instance_eval { undef :added } unless @events.include?(:added)
|
37
|
+
handler.instance_eval { undef :modified } unless @events.include?(:modified)
|
38
|
+
handler.instance_eval { undef :removed } unless @events.include?(:removed)
|
39
|
+
end
|
40
|
+
|
41
|
+
handler
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def name(name)
|
47
|
+
LOGGER.debug('Setting handler\'s name')
|
48
|
+
@name = name
|
49
|
+
end
|
50
|
+
|
51
|
+
def implementation(impl)
|
52
|
+
LOGGER.debug('Setting handler\'s implementation')
|
53
|
+
@implementation = impl
|
54
|
+
end
|
55
|
+
|
56
|
+
def options(opts)
|
57
|
+
LOGGER.debug('Setting handler\'s options')
|
58
|
+
@options = opts
|
59
|
+
end
|
60
|
+
|
61
|
+
def events(*actions)
|
62
|
+
LOGGER.debug('Setting handler\'s events')
|
63
|
+
uniq_actions = actions.uniq
|
64
|
+
|
65
|
+
raise HandlerActionMustBeSuppliedException, "At least one handler action needs to be supplied" if actions.empty?
|
66
|
+
raise HandlerActionAllMustBeSingletonException, "The handler action ':#{HANDLER_ACTION_ALL}' cannot be mixed with other types" if uniq_actions.include?(HANDLER_ACTION_ALL) and uniq_actions.size > 1
|
67
|
+
uniq_actions.each do |action|
|
68
|
+
raise HandlerActionUnsupportedException,
|
69
|
+
"The action ':#{action}' is unsupported. Supported actions are #{ALLOWED_HANDLER_ACTIONS}." unless ALLOWED_HANDLER_ACTIONS.include?(action)
|
70
|
+
end
|
71
|
+
|
72
|
+
@events = uniq_actions
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'emory/teleport_config'
|
2
|
+
|
3
|
+
module Emory
|
4
|
+
module DSL
|
5
|
+
|
6
|
+
class TeleportConfigurationBlockMustBeSuppliedException < Exception; end
|
7
|
+
class UndefinedTeleportHandlerException < Exception; end
|
8
|
+
class HandlerReferenceMustBeSuppliedException < Exception; end
|
9
|
+
class WatchedPathMustBeSuppliedException < Exception; end
|
10
|
+
|
11
|
+
class TeleportConfigBuilder
|
12
|
+
|
13
|
+
LOGGER = Logging.logger[self]
|
14
|
+
|
15
|
+
def initialize(handlers, &block)
|
16
|
+
LOGGER.debug('Initializing a new teleport builder')
|
17
|
+
raise TeleportConfigurationBlockMustBeSuppliedException, "The configuration block with teleport settings must be supplied" unless block_given?
|
18
|
+
|
19
|
+
@block = block
|
20
|
+
@available_handlers = handlers
|
21
|
+
|
22
|
+
LOGGER.debug('Creating a new teleport config instance')
|
23
|
+
@teleport_config = TeleportConfig.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def build
|
27
|
+
LOGGER.debug('Evaluating teleport configuration')
|
28
|
+
instance_eval &@block
|
29
|
+
|
30
|
+
raise HandlerReferenceMustBeSuppliedException, "A reference to an existing handler must be supplied in teleport configuration" if @teleport_config.handler.nil?
|
31
|
+
raise WatchedPathMustBeSuppliedException, "A watched path must be supplied in teleport configuration" if @teleport_config.watched_path.nil?
|
32
|
+
|
33
|
+
@teleport_config
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def path(path)
|
39
|
+
LOGGER.debug('Setting teleport\'s watched path')
|
40
|
+
@teleport_config.watched_path = path
|
41
|
+
end
|
42
|
+
|
43
|
+
def handler(handler_name)
|
44
|
+
LOGGER.debug('Setting teleport\'s handler')
|
45
|
+
raise UndefinedTeleportHandlerException, "The handler ':#{handler_name}' wired to teleport could not be found" unless @available_handlers.include?(handler_name)
|
46
|
+
@teleport_config.handler = @available_handlers[handler_name]
|
47
|
+
end
|
48
|
+
|
49
|
+
def ignore(ignore)
|
50
|
+
LOGGER.debug('Setting teleport\'s ignore expression')
|
51
|
+
@teleport_config.ignore = ignore
|
52
|
+
end
|
53
|
+
|
54
|
+
def filter(filter)
|
55
|
+
LOGGER.debug('Setting teleport\'s filter expression')
|
56
|
+
@teleport_config.filter = filter
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Emory
|
2
|
+
module Handlers
|
3
|
+
|
4
|
+
class AbstractHandler
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(name, options = {})
|
9
|
+
self.name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def added(file_path = nil)
|
13
|
+
raise_not_implemented_error(self.class, __method__)
|
14
|
+
end
|
15
|
+
|
16
|
+
def modified(file_path = nil)
|
17
|
+
raise_not_implemented_error(self.class, __method__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def removed(file_path = nil)
|
21
|
+
raise_not_implemented_error(self.class, __method__)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_writer :name
|
27
|
+
|
28
|
+
def raise_not_implemented_error(class_name, method_name)
|
29
|
+
raise NotImplementedError, "This method is not implemented: #{class_name}##{method_name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'emory/handlers/abstract_handler'
|
2
|
+
|
3
|
+
module Emory
|
4
|
+
module Handlers
|
5
|
+
|
6
|
+
class StdoutHandler < AbstractHandler
|
7
|
+
|
8
|
+
def initialize(name, options = {})
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def added(file_path)
|
13
|
+
report_file_path_action(file_path, __method__)
|
14
|
+
end
|
15
|
+
|
16
|
+
def modified(file_path)
|
17
|
+
report_file_path_action(file_path, __method__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def removed(file_path)
|
21
|
+
report_file_path_action(file_path, __method__)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def report_file_path_action(file_path, action)
|
27
|
+
puts ":#{name} ~> The file '#{file_path}' was '#{action}'"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|