cuboid 0.0.0 → 0.0.1alpha
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +0 -0
- data/Gemfile +20 -5
- data/LICENSE.md +22 -0
- data/README.md +158 -19
- data/Rakefile +56 -3
- data/config/paths.yml +15 -0
- data/cuboid.gemspec +61 -23
- data/lib/cuboid.rb +96 -4
- data/lib/cuboid/application.rb +326 -0
- data/lib/cuboid/application/parts/data.rb +18 -0
- data/lib/cuboid/application/parts/report.rb +29 -0
- data/lib/cuboid/application/parts/state.rb +274 -0
- data/lib/cuboid/application/runtime.rb +25 -0
- data/lib/cuboid/banner.rb +13 -0
- data/lib/cuboid/data.rb +86 -0
- data/lib/cuboid/data/application.rb +52 -0
- data/lib/cuboid/error.rb +9 -0
- data/lib/cuboid/option_group.rb +129 -0
- data/lib/cuboid/option_groups.rb +8 -0
- data/lib/cuboid/option_groups/datastore.rb +23 -0
- data/lib/cuboid/option_groups/dispatcher.rb +38 -0
- data/lib/cuboid/option_groups/output.rb +14 -0
- data/lib/cuboid/option_groups/paths.rb +184 -0
- data/lib/cuboid/option_groups/report.rb +39 -0
- data/lib/cuboid/option_groups/rpc.rb +105 -0
- data/lib/cuboid/option_groups/scheduler.rb +27 -0
- data/lib/cuboid/option_groups/snapshot.rb +13 -0
- data/lib/cuboid/option_groups/system.rb +10 -0
- data/lib/cuboid/options.rb +254 -0
- data/lib/cuboid/processes.rb +13 -0
- data/lib/cuboid/processes/dispatchers.rb +140 -0
- data/lib/cuboid/processes/executables/base.rb +54 -0
- data/lib/cuboid/processes/executables/dispatcher.rb +5 -0
- data/lib/cuboid/processes/executables/instance.rb +12 -0
- data/lib/cuboid/processes/executables/rest_service.rb +13 -0
- data/lib/cuboid/processes/executables/scheduler.rb +5 -0
- data/lib/cuboid/processes/helpers.rb +4 -0
- data/lib/cuboid/processes/helpers/dispatchers.rb +23 -0
- data/lib/cuboid/processes/helpers/instances.rb +39 -0
- data/lib/cuboid/processes/helpers/processes.rb +23 -0
- data/lib/cuboid/processes/helpers/schedulers.rb +23 -0
- data/lib/cuboid/processes/instances.rb +203 -0
- data/lib/cuboid/processes/manager.rb +262 -0
- data/lib/cuboid/processes/schedulers.rb +128 -0
- data/lib/cuboid/report.rb +220 -0
- data/lib/cuboid/rest/server.rb +165 -0
- data/lib/cuboid/rest/server/instance_helpers.rb +99 -0
- data/lib/cuboid/rest/server/routes/dispatcher.rb +41 -0
- data/lib/cuboid/rest/server/routes/grid.rb +41 -0
- data/lib/cuboid/rest/server/routes/instances.rb +131 -0
- data/lib/cuboid/rest/server/routes/scheduler.rb +140 -0
- data/lib/cuboid/rpc/client.rb +3 -0
- data/lib/cuboid/rpc/client/base.rb +58 -0
- data/lib/cuboid/rpc/client/dispatcher.rb +58 -0
- data/lib/cuboid/rpc/client/instance.rb +100 -0
- data/lib/cuboid/rpc/client/instance/service.rb +37 -0
- data/lib/cuboid/rpc/client/scheduler.rb +46 -0
- data/lib/cuboid/rpc/serializer.rb +92 -0
- data/lib/cuboid/rpc/server/active_options.rb +38 -0
- data/lib/cuboid/rpc/server/application_wrapper.rb +138 -0
- data/lib/cuboid/rpc/server/base.rb +63 -0
- data/lib/cuboid/rpc/server/dispatcher.rb +317 -0
- data/lib/cuboid/rpc/server/dispatcher/node.rb +247 -0
- data/lib/cuboid/rpc/server/dispatcher/service.rb +145 -0
- data/lib/cuboid/rpc/server/instance.rb +338 -0
- data/lib/cuboid/rpc/server/output.rb +92 -0
- data/lib/cuboid/rpc/server/scheduler.rb +482 -0
- data/lib/cuboid/ruby.rb +4 -0
- data/lib/cuboid/ruby/array.rb +17 -0
- data/lib/cuboid/ruby/hash.rb +41 -0
- data/lib/cuboid/ruby/object.rb +32 -0
- data/lib/cuboid/snapshot.rb +186 -0
- data/lib/cuboid/state.rb +94 -0
- data/lib/cuboid/state/application.rb +309 -0
- data/lib/cuboid/state/options.rb +27 -0
- data/lib/cuboid/support.rb +11 -0
- data/lib/cuboid/support/buffer.rb +3 -0
- data/lib/cuboid/support/buffer/autoflush.rb +61 -0
- data/lib/cuboid/support/buffer/base.rb +91 -0
- data/lib/cuboid/support/cache.rb +7 -0
- data/lib/cuboid/support/cache/base.rb +226 -0
- data/lib/cuboid/support/cache/least_cost_replacement.rb +77 -0
- data/lib/cuboid/support/cache/least_recently_pushed.rb +21 -0
- data/lib/cuboid/support/cache/least_recently_used.rb +31 -0
- data/lib/cuboid/support/cache/preference.rb +31 -0
- data/lib/cuboid/support/cache/random_replacement.rb +20 -0
- data/lib/cuboid/support/crypto.rb +2 -0
- data/lib/cuboid/support/crypto/rsa_aes_cbc.rb +86 -0
- data/lib/cuboid/support/database.rb +5 -0
- data/lib/cuboid/support/database/base.rb +177 -0
- data/lib/cuboid/support/database/categorized_queue.rb +195 -0
- data/lib/cuboid/support/database/hash.rb +300 -0
- data/lib/cuboid/support/database/queue.rb +149 -0
- data/lib/cuboid/support/filter.rb +3 -0
- data/lib/cuboid/support/filter/base.rb +110 -0
- data/lib/cuboid/support/filter/set.rb +29 -0
- data/lib/cuboid/support/glob.rb +27 -0
- data/lib/cuboid/support/mixins.rb +8 -0
- data/lib/cuboid/support/mixins/observable.rb +99 -0
- data/lib/cuboid/support/mixins/parts.rb +20 -0
- data/lib/cuboid/support/mixins/profiler.rb +93 -0
- data/lib/cuboid/support/mixins/spec_instances.rb +65 -0
- data/lib/cuboid/support/mixins/terminal.rb +57 -0
- data/lib/cuboid/system.rb +119 -0
- data/lib/cuboid/system/platforms.rb +84 -0
- data/lib/cuboid/system/platforms/linux.rb +26 -0
- data/lib/cuboid/system/platforms/mixins/unix.rb +46 -0
- data/lib/cuboid/system/platforms/osx.rb +25 -0
- data/lib/cuboid/system/platforms/windows.rb +81 -0
- data/lib/cuboid/system/slots.rb +143 -0
- data/lib/cuboid/ui/output.rb +52 -0
- data/lib/cuboid/ui/output_interface.rb +43 -0
- data/lib/cuboid/ui/output_interface/abstract.rb +68 -0
- data/lib/cuboid/ui/output_interface/controls.rb +84 -0
- data/lib/cuboid/ui/output_interface/error_logging.rb +119 -0
- data/lib/cuboid/ui/output_interface/implemented.rb +58 -0
- data/lib/cuboid/ui/output_interface/personalization.rb +62 -0
- data/lib/cuboid/utilities.rb +155 -0
- data/lib/cuboid/version.rb +4 -3
- data/lib/version +1 -0
- data/logs/placeholder +0 -0
- data/spec/cuboid/application/parts/data_spec.rb +12 -0
- data/spec/cuboid/application/parts/report_spec.rb +6 -0
- data/spec/cuboid/application/parts/state_spec.rb +192 -0
- data/spec/cuboid/application/runtime_spec.rb +21 -0
- data/spec/cuboid/application_spec.rb +37 -0
- data/spec/cuboid/data/application_spec.rb +22 -0
- data/spec/cuboid/data_spec.rb +47 -0
- data/spec/cuboid/error_spec.rb +23 -0
- data/spec/cuboid/option_groups/datastore_spec.rb +54 -0
- data/spec/cuboid/option_groups/dispatcher_spec.rb +12 -0
- data/spec/cuboid/option_groups/output_spec.rb +11 -0
- data/spec/cuboid/option_groups/paths_spec.rb +184 -0
- data/spec/cuboid/option_groups/report_spec.rb +26 -0
- data/spec/cuboid/option_groups/rpc_spec.rb +53 -0
- data/spec/cuboid/option_groups/snapshot_spec.rb +26 -0
- data/spec/cuboid/option_groups/system.rb +12 -0
- data/spec/cuboid/options_spec.rb +218 -0
- data/spec/cuboid/report_spec.rb +221 -0
- data/spec/cuboid/rest/server_spec.rb +1205 -0
- data/spec/cuboid/rpc/client/base_spec.rb +151 -0
- data/spec/cuboid/rpc/client/dispatcher_spec.rb +13 -0
- data/spec/cuboid/rpc/client/instance_spec.rb +38 -0
- data/spec/cuboid/rpc/server/active_options_spec.rb +21 -0
- data/spec/cuboid/rpc/server/base_spec.rb +60 -0
- data/spec/cuboid/rpc/server/dispatcher/node_spec.rb +222 -0
- data/spec/cuboid/rpc/server/dispatcher/service_spec.rb +112 -0
- data/spec/cuboid/rpc/server/dispatcher_spec.rb +317 -0
- data/spec/cuboid/rpc/server/instance_spec.rb +307 -0
- data/spec/cuboid/rpc/server/output_spec.rb +32 -0
- data/spec/cuboid/rpc/server/scheduler_spec.rb +400 -0
- data/spec/cuboid/ruby/array_spec.rb +77 -0
- data/spec/cuboid/ruby/hash_spec.rb +63 -0
- data/spec/cuboid/ruby/object_spec.rb +22 -0
- data/spec/cuboid/snapshot_spec.rb +123 -0
- data/spec/cuboid/state/application_spec.rb +538 -0
- data/spec/cuboid/state/options_spec.rb +37 -0
- data/spec/cuboid/state_spec.rb +53 -0
- data/spec/cuboid/support/buffer/autoflush_spec.rb +78 -0
- data/spec/cuboid/support/buffer/base_spec.rb +193 -0
- data/spec/cuboid/support/cache/least_cost_replacement_spec.rb +61 -0
- data/spec/cuboid/support/cache/least_recently_pushed_spec.rb +90 -0
- data/spec/cuboid/support/cache/least_recently_used_spec.rb +80 -0
- data/spec/cuboid/support/cache/preference_spec.rb +37 -0
- data/spec/cuboid/support/cache/random_replacement_spec.rb +42 -0
- data/spec/cuboid/support/crypto/rsa_aes_cbc_spec.rb +28 -0
- data/spec/cuboid/support/database/categorized_queue_spec.rb +327 -0
- data/spec/cuboid/support/database/hash_spec.rb +204 -0
- data/spec/cuboid/support/database/scheduler_spec.rb +325 -0
- data/spec/cuboid/support/filter/set_spec.rb +19 -0
- data/spec/cuboid/support/glob_spec.rb +75 -0
- data/spec/cuboid/support/mixins/observable_spec.rb +95 -0
- data/spec/cuboid/system/platforms/linux_spec.rb +31 -0
- data/spec/cuboid/system/platforms/osx_spec.rb +32 -0
- data/spec/cuboid/system/platforms/windows_spec.rb +41 -0
- data/spec/cuboid/system/slots_spec.rb +202 -0
- data/spec/cuboid/system_spec.rb +105 -0
- data/spec/cuboid/utilities_spec.rb +131 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/support/factories/placeholder +0 -0
- data/spec/support/factories/scan_report.rb +18 -0
- data/spec/support/fixtures/empty/placeholder +0 -0
- data/spec/support/fixtures/executables/node.rb +50 -0
- data/spec/support/fixtures/mock_app.rb +61 -0
- data/spec/support/fixtures/mock_app/test_service.rb +64 -0
- data/spec/support/fixtures/services/echo.rb +64 -0
- data/spec/support/helpers/framework.rb +3 -0
- data/spec/support/helpers/matchers.rb +5 -0
- data/spec/support/helpers/misc.rb +3 -0
- data/spec/support/helpers/paths.rb +15 -0
- data/spec/support/helpers/request_helpers.rb +38 -0
- data/spec/support/helpers/requires.rb +8 -0
- data/spec/support/helpers/resets.rb +52 -0
- data/spec/support/helpers/web_server.rb +15 -0
- data/spec/support/lib/factory.rb +107 -0
- data/spec/support/lib/web_server_client.rb +41 -0
- data/spec/support/lib/web_server_dispatcher.rb +25 -0
- data/spec/support/lib/web_server_manager.rb +118 -0
- data/spec/support/logs/placeholder +0 -0
- data/spec/support/pems/cacert.pem +37 -0
- data/spec/support/pems/client/cert.pem +37 -0
- data/spec/support/pems/client/foo-cert.pem +39 -0
- data/spec/support/pems/client/foo-key.pem +51 -0
- data/spec/support/pems/client/key.pem +51 -0
- data/spec/support/pems/server/cert.pem +37 -0
- data/spec/support/pems/server/key.pem +51 -0
- data/spec/support/reports/placeholder +0 -0
- data/spec/support/shared/application.rb +10 -0
- data/spec/support/shared/component.rb +31 -0
- data/spec/support/shared/component/options/base.rb +187 -0
- data/spec/support/shared/option_group.rb +98 -0
- data/spec/support/shared/support/cache.rb +419 -0
- data/spec/support/shared/support/filter.rb +143 -0
- data/spec/support/shared/system/platforms/base.rb +25 -0
- data/spec/support/shared/system/platforms/mixins/unix.rb +37 -0
- data/spec/support/snapshots/placeholder +0 -0
- metadata +566 -21
- data/.gitignore +0 -8
- data/bin/console +0 -15
- data/bin/setup +0 -8
data/lib/cuboid/ruby.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Array
|
2
|
+
|
3
|
+
# @param [#to_s, Array<#to_s>] tags
|
4
|
+
#
|
5
|
+
# @return [Bool]
|
6
|
+
# `true` if `self` contains any of the `tags` when objects of both `self`
|
7
|
+
# and `tags` are converted to `String`.
|
8
|
+
def includes_tags?( tags )
|
9
|
+
return false if !tags
|
10
|
+
|
11
|
+
tags = [tags].flatten.compact.map( &:to_s )
|
12
|
+
return false if tags.empty?
|
13
|
+
|
14
|
+
(self.flatten.compact.map( &:to_s ) & tags).any?
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
if !method_defined?( :to_h )
|
4
|
+
alias :to_h :to_hash
|
5
|
+
end
|
6
|
+
|
7
|
+
# Converts the hash keys to strings.
|
8
|
+
#
|
9
|
+
# @param [Boolean] recursively
|
10
|
+
# Go through the Hash recursively?
|
11
|
+
#
|
12
|
+
# @return [Hash]
|
13
|
+
# Hash with +self+'s keys recursively converted to strings.
|
14
|
+
def my_stringify_keys( recursively = true )
|
15
|
+
stringified = {}
|
16
|
+
each do |k, v|
|
17
|
+
stringified[k.to_s] = (recursively && v.is_a?( Hash ) ?
|
18
|
+
v.my_stringify_keys : v)
|
19
|
+
end
|
20
|
+
stringified
|
21
|
+
end
|
22
|
+
|
23
|
+
# Converts the hash keys to symbols.
|
24
|
+
#
|
25
|
+
# @param [Boolean] recursively
|
26
|
+
# Go through the Hash recursively?
|
27
|
+
#
|
28
|
+
# @return [Hash]
|
29
|
+
# Hash with +self+'s keys recursively converted to symbols.
|
30
|
+
def my_symbolize_keys( recursively = true )
|
31
|
+
symbolize = {}
|
32
|
+
each do |k, v|
|
33
|
+
k = k.respond_to?(:to_sym) ? k.to_sym : k
|
34
|
+
|
35
|
+
symbolize[k] = (recursively && v.is_a?( Hash ) ?
|
36
|
+
v.my_symbolize_keys : v)
|
37
|
+
end
|
38
|
+
symbolize
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Overloads the {Object} class providing a {#deep_clone} method.
|
2
|
+
#
|
3
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
4
|
+
class Object
|
5
|
+
|
6
|
+
# Deep-clones self using a Marshal dump-load.
|
7
|
+
#
|
8
|
+
# @return [Object]
|
9
|
+
# Duplicate of self.
|
10
|
+
def deep_clone
|
11
|
+
Marshal.load( Marshal.dump( self ) )
|
12
|
+
end
|
13
|
+
|
14
|
+
def rpc_clone
|
15
|
+
if self.class.respond_to?( :from_rpc_data )
|
16
|
+
self.class.from_rpc_data(
|
17
|
+
Cuboid::RPC::Serializer.serializer.load(
|
18
|
+
Cuboid::RPC::Serializer.serializer.dump( to_rpc_data )
|
19
|
+
)
|
20
|
+
)
|
21
|
+
else
|
22
|
+
Cuboid::RPC::Serializer.serializer.load(
|
23
|
+
Cuboid::RPC::Serializer.serializer.dump( self )
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_rpc_data_or_self
|
29
|
+
respond_to?( :to_rpc_data ) ? to_rpc_data : self
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'zip'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
require_relative 'data'
|
5
|
+
require_relative 'state'
|
6
|
+
|
7
|
+
module Cuboid
|
8
|
+
|
9
|
+
# Stores and provides access to the state of the system.
|
10
|
+
#
|
11
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
12
|
+
class Snapshot
|
13
|
+
|
14
|
+
# {Snapshot} error namespace.
|
15
|
+
#
|
16
|
+
# All {Snapshot} errors inherit from and live under it.
|
17
|
+
#
|
18
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
19
|
+
class Error < Cuboid::Error
|
20
|
+
|
21
|
+
# Raised when trying to read an invalid snapshot file.
|
22
|
+
#
|
23
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
24
|
+
class InvalidFile < Error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
EXTENSION = 'csf'
|
29
|
+
|
30
|
+
class <<self
|
31
|
+
|
32
|
+
# @return [Hash]
|
33
|
+
# Metadata associated with the {.load loaded} snapshot.
|
34
|
+
attr_accessor :metadata
|
35
|
+
|
36
|
+
# @return [String]
|
37
|
+
# Location of the {.load loaded} snapshot.
|
38
|
+
attr_accessor :location
|
39
|
+
|
40
|
+
def reset
|
41
|
+
@metadata = nil
|
42
|
+
@location = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Bool]
|
46
|
+
# `true` if this is a restored snapshot, `false` otherwise.
|
47
|
+
def restored?
|
48
|
+
!!location
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Hash]
|
52
|
+
# Snapshot summary information.
|
53
|
+
def summary
|
54
|
+
{
|
55
|
+
data: Data.statistics,
|
56
|
+
state: State.statistics
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param [String] location
|
61
|
+
# Location of the snapshot.
|
62
|
+
#
|
63
|
+
# @return [String]
|
64
|
+
# Location of the snapshot.
|
65
|
+
def dump( location )
|
66
|
+
FileUtils.rm_rf( location )
|
67
|
+
|
68
|
+
directory = get_temporary_directory
|
69
|
+
|
70
|
+
FileUtils.rm_rf( directory )
|
71
|
+
FileUtils.mkdir_p( directory )
|
72
|
+
|
73
|
+
begin
|
74
|
+
Data.dump( "#{directory}/data/" )
|
75
|
+
State.dump( "#{directory}/state/" )
|
76
|
+
|
77
|
+
compress directory, location
|
78
|
+
|
79
|
+
# Append metadata to the end of the file.
|
80
|
+
metadata = Marshal.dump( prepare_metadata )
|
81
|
+
File.open( location, 'ab' ) do |f|
|
82
|
+
f.write [metadata, metadata.size].pack( 'a*N' )
|
83
|
+
end
|
84
|
+
|
85
|
+
location
|
86
|
+
ensure
|
87
|
+
FileUtils.rm_rf( directory )
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param [String] snapshot
|
92
|
+
# Location of the snapshot to load.
|
93
|
+
#
|
94
|
+
# @return [Snapshot]
|
95
|
+
# `self`
|
96
|
+
#
|
97
|
+
# @raise [Error::InvalidFile]
|
98
|
+
# When trying to read an invalid file.
|
99
|
+
def load( snapshot )
|
100
|
+
directory = get_temporary_directory
|
101
|
+
|
102
|
+
@location = snapshot
|
103
|
+
@metadata = read_metadata( snapshot )
|
104
|
+
|
105
|
+
extract( snapshot, directory )
|
106
|
+
|
107
|
+
Data.load( "#{directory}/data/" )
|
108
|
+
State.load( "#{directory}/state/" )
|
109
|
+
|
110
|
+
self
|
111
|
+
ensure
|
112
|
+
|
113
|
+
# Don't delete the directory immediately because there are disk DBs that
|
114
|
+
# use those files.
|
115
|
+
Kernel.at_exit do
|
116
|
+
FileUtils.rm_rf( directory )
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# @param [String] snapshot
|
121
|
+
# Location of the snapshot.
|
122
|
+
#
|
123
|
+
# @return [Hash]
|
124
|
+
# Metadata associated with the given snapshot.
|
125
|
+
#
|
126
|
+
# @raise [Error::InvalidFile]
|
127
|
+
# When trying to read an invalid file.
|
128
|
+
def read_metadata( snapshot )
|
129
|
+
File.open( snapshot, 'rb' ) do |f|
|
130
|
+
f.seek -4, IO::SEEK_END
|
131
|
+
metadata_size = f.read( 4 ).unpack( 'N' ).first
|
132
|
+
|
133
|
+
f.seek -metadata_size-4, IO::SEEK_END
|
134
|
+
Marshal.load( f.read( metadata_size ) )
|
135
|
+
end
|
136
|
+
rescue => e
|
137
|
+
ne = Error::InvalidFile.new( "Invalid snapshot: #{snapshot} (#{e})" )
|
138
|
+
ne.set_backtrace e.backtrace
|
139
|
+
raise ne
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def prepare_metadata
|
145
|
+
{
|
146
|
+
timestamp: Time.now,
|
147
|
+
version: Cuboid::VERSION,
|
148
|
+
summary: summary
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
def get_temporary_directory
|
153
|
+
"#{Options.paths.tmpdir}/Cuboid_Snapshot_#{Utilities.generate_token}/"
|
154
|
+
end
|
155
|
+
|
156
|
+
def extract( archive, directory )
|
157
|
+
Zip::File.open( archive ) do |zip_file|
|
158
|
+
zip_file.each do |f|
|
159
|
+
f_path = File.join( directory, f.name )
|
160
|
+
FileUtils.mkdir_p( File.dirname( f_path ) )
|
161
|
+
zip_file.extract( f, f_path ) unless File.exist?( f_path )
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
directory
|
166
|
+
end
|
167
|
+
|
168
|
+
def compress( directory, archive )
|
169
|
+
# Globs on Windows don't accept \ as a separator since it's an escape character.
|
170
|
+
directory = directory.gsub( '\\', '/' ) + '/'
|
171
|
+
directory.gsub!( /\/+/, '/' )
|
172
|
+
|
173
|
+
Zip::File.open( archive, Zip::File::CREATE ) do |zipfile|
|
174
|
+
Dir[directory + '**/**'].each do |file|
|
175
|
+
zipfile.add( file.sub( directory, '' ), file )
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
archive
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
reset
|
185
|
+
end
|
186
|
+
end
|
data/lib/cuboid/state.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module Cuboid
|
2
|
+
|
3
|
+
# Stores and provides access to the state of the system.
|
4
|
+
#
|
5
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
6
|
+
class State
|
7
|
+
|
8
|
+
# {State} error namespace.
|
9
|
+
#
|
10
|
+
# All {State} errors inherit from and live under it.
|
11
|
+
#
|
12
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
13
|
+
class Error < Cuboid::Error
|
14
|
+
end
|
15
|
+
|
16
|
+
require_relative 'state/options'
|
17
|
+
require_relative 'state/application'
|
18
|
+
|
19
|
+
class <<self
|
20
|
+
|
21
|
+
# @return [Options]
|
22
|
+
attr_accessor :options
|
23
|
+
|
24
|
+
# @return [Framework]
|
25
|
+
attr_accessor :application
|
26
|
+
|
27
|
+
def reset
|
28
|
+
@options = Options.new
|
29
|
+
@application = Application.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def statistics
|
33
|
+
stats = {}
|
34
|
+
each do |attribute|
|
35
|
+
stats[attribute] = send(attribute).statistics
|
36
|
+
end
|
37
|
+
stats
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param [String] directory
|
41
|
+
# Location of the dump directory.
|
42
|
+
#
|
43
|
+
# @return [String]
|
44
|
+
# Location of the directory.
|
45
|
+
def dump( directory )
|
46
|
+
FileUtils.mkdir_p( directory )
|
47
|
+
|
48
|
+
each do |name, state|
|
49
|
+
state.dump( "#{directory}/#{name}/" )
|
50
|
+
end
|
51
|
+
|
52
|
+
directory
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param [String] directory
|
56
|
+
# Location of the dump directory.
|
57
|
+
#
|
58
|
+
# @return [State]
|
59
|
+
# `self`
|
60
|
+
def load( directory )
|
61
|
+
each do |name, state|
|
62
|
+
send( "#{name}=", state.class.load( "#{directory}/#{name}/" ) )
|
63
|
+
end
|
64
|
+
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
# Clears all states.
|
69
|
+
def clear
|
70
|
+
each { |_, state| state.clear }
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def each( &block )
|
77
|
+
accessors.each do |attr|
|
78
|
+
block.call attr, send( attr )
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def accessors
|
83
|
+
instance_variables.map do |ivar|
|
84
|
+
attribute = "#{ivar.to_s.gsub('@','')}"
|
85
|
+
next if !methods.include?( :"#{attribute}=" )
|
86
|
+
attribute
|
87
|
+
end.compact.map(&:to_sym)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
reset
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,309 @@
|
|
1
|
+
module Cuboid
|
2
|
+
class State
|
3
|
+
|
4
|
+
# State information for {Cuboid::Framework}.
|
5
|
+
#
|
6
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
7
|
+
class Application
|
8
|
+
|
9
|
+
# {Framework} error namespace.
|
10
|
+
#
|
11
|
+
# All {Framework} errors inherit from and live under it.
|
12
|
+
#
|
13
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
14
|
+
class Error < State::Error
|
15
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
16
|
+
class StateNotSuspendable < Error
|
17
|
+
end
|
18
|
+
|
19
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
20
|
+
class StateNotAbortable < Error
|
21
|
+
end
|
22
|
+
|
23
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
24
|
+
class InvalidStatusMessage < Error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Symbol]
|
29
|
+
attr_accessor :status
|
30
|
+
|
31
|
+
# @return [Bool]
|
32
|
+
attr_accessor :running
|
33
|
+
|
34
|
+
# @return [Array<String>]
|
35
|
+
attr_reader :status_messages
|
36
|
+
|
37
|
+
attr_accessor :runtime
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
@running = false
|
41
|
+
@pre_pause_status = nil
|
42
|
+
|
43
|
+
@pause_signals = Set.new
|
44
|
+
|
45
|
+
@status_messages = []
|
46
|
+
end
|
47
|
+
|
48
|
+
def statistics
|
49
|
+
{
|
50
|
+
runtime: !!@runtime
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Hash{Symbol=>String}]
|
55
|
+
# All possible {#status_messages} by type.
|
56
|
+
def available_status_messages
|
57
|
+
{
|
58
|
+
suspending: 'Will suspend as soon as the current page is audited.',
|
59
|
+
saving_snapshot: 'Saving snapshot at: %s',
|
60
|
+
snapshot_location: 'Snapshot location: %s',
|
61
|
+
aborting: 'Aborting the scan.',
|
62
|
+
timed_out: 'Scan timed out.'
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
# Sets a message as {#status_messages}.
|
67
|
+
#
|
68
|
+
# @param (see #add_status_message)
|
69
|
+
# @return (see #add_status_message)
|
70
|
+
def set_status_message( *args )
|
71
|
+
clear_status_messages
|
72
|
+
add_status_message( *args )
|
73
|
+
end
|
74
|
+
|
75
|
+
# Pushes a message to {#status_messages}.
|
76
|
+
#
|
77
|
+
# @param [String, Symbol] message
|
78
|
+
# Status message. If `Symbol`, it will be grabbed from
|
79
|
+
# {#available_status_messages}.
|
80
|
+
# @param [String, Numeric] sprintf
|
81
|
+
# `sprintf` arguments.
|
82
|
+
def add_status_message( message, *sprintf )
|
83
|
+
if message.is_a? Symbol
|
84
|
+
if !available_status_messages.include?( message )
|
85
|
+
fail Error::InvalidStatusMessage,
|
86
|
+
"Could not find status message for: '#{message}'"
|
87
|
+
end
|
88
|
+
|
89
|
+
message = available_status_messages[message] % sprintf
|
90
|
+
end
|
91
|
+
|
92
|
+
@status_messages << message.to_s
|
93
|
+
end
|
94
|
+
|
95
|
+
# Clears {#status_messages}.
|
96
|
+
def clear_status_messages
|
97
|
+
@status_messages.clear
|
98
|
+
end
|
99
|
+
|
100
|
+
def running?
|
101
|
+
!!@running
|
102
|
+
end
|
103
|
+
|
104
|
+
def timed_out
|
105
|
+
@status = :timed_out
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
|
109
|
+
def timed_out?
|
110
|
+
@status == :timed_out
|
111
|
+
end
|
112
|
+
|
113
|
+
# @param [Bool] block
|
114
|
+
# `true` if the method should block until an abortion has completed,
|
115
|
+
# `false` otherwise.
|
116
|
+
#
|
117
|
+
# @return [Bool]
|
118
|
+
# `true` if the abort request was successful, `false` if the system is
|
119
|
+
# already {#suspended?} or is {#suspending?}.
|
120
|
+
#
|
121
|
+
# @raise [StateNotAbortable]
|
122
|
+
# When not {#running?}.
|
123
|
+
def abort
|
124
|
+
return false if aborting? || aborted?
|
125
|
+
|
126
|
+
if !running?
|
127
|
+
fail Error::StateNotAbortable, "Cannot abort idle state: #{status}"
|
128
|
+
end
|
129
|
+
|
130
|
+
set_status_message :aborting
|
131
|
+
@status = :aborting
|
132
|
+
@abort = true
|
133
|
+
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
137
|
+
# @return [Bool]
|
138
|
+
# `true` if a {#abort} signal is in place , `false` otherwise.
|
139
|
+
def abort?
|
140
|
+
!!@abort
|
141
|
+
end
|
142
|
+
|
143
|
+
# Signals a completed abort operation.
|
144
|
+
def aborted
|
145
|
+
@abort = false
|
146
|
+
@status = :aborted
|
147
|
+
nil
|
148
|
+
end
|
149
|
+
|
150
|
+
# @return [Bool]
|
151
|
+
# `true` if the system has been aborted, `false` otherwise.
|
152
|
+
def aborted?
|
153
|
+
@status == :aborted
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return [Bool]
|
157
|
+
# `true` if the system is being aborted, `false` otherwise.
|
158
|
+
def aborting?
|
159
|
+
@status == :aborting
|
160
|
+
end
|
161
|
+
|
162
|
+
# @return [Bool]
|
163
|
+
# `true` if the system has completed successfully, `false` otherwise.
|
164
|
+
def done?
|
165
|
+
@status == :done
|
166
|
+
end
|
167
|
+
|
168
|
+
# @param [Bool] block
|
169
|
+
# `true` if the method should block until a suspend has completed,
|
170
|
+
# `false` otherwise.
|
171
|
+
#
|
172
|
+
# @return [Bool]
|
173
|
+
# `true` if the suspend request was successful, `false` if the system is
|
174
|
+
# already {#suspended?} or is {#suspending?}.
|
175
|
+
#
|
176
|
+
# @raise [StateNotSuspendable]
|
177
|
+
# When {#paused?} or {#pausing?}.
|
178
|
+
def suspend
|
179
|
+
return false if suspending? || suspended?
|
180
|
+
|
181
|
+
if paused? || pausing?
|
182
|
+
fail Error::StateNotSuspendable, 'Cannot suspend a paused state.'
|
183
|
+
end
|
184
|
+
|
185
|
+
if !running?
|
186
|
+
fail Error::StateNotSuspendable, "Cannot suspend idle state: #{status}"
|
187
|
+
end
|
188
|
+
|
189
|
+
set_status_message :suspending
|
190
|
+
@status = :suspending
|
191
|
+
@suspend = true
|
192
|
+
|
193
|
+
true
|
194
|
+
end
|
195
|
+
|
196
|
+
# @return [Bool]
|
197
|
+
# `true` if an {#abort} signal is in place , `false` otherwise.
|
198
|
+
def suspend?
|
199
|
+
!!@suspend
|
200
|
+
end
|
201
|
+
|
202
|
+
# Signals a completed suspension.
|
203
|
+
def suspended
|
204
|
+
@suspend = false
|
205
|
+
@status = :suspended
|
206
|
+
nil
|
207
|
+
end
|
208
|
+
|
209
|
+
# @return [Bool]
|
210
|
+
# `true` if the system has been suspended, `false` otherwise.
|
211
|
+
def suspended?
|
212
|
+
@status == :suspended
|
213
|
+
end
|
214
|
+
|
215
|
+
# @return [Bool]
|
216
|
+
# `true` if the system is being suspended, `false` otherwise.
|
217
|
+
def suspending?
|
218
|
+
@status == :suspending
|
219
|
+
end
|
220
|
+
|
221
|
+
# @param [Bool] block
|
222
|
+
# `true` if the method should block until the pause has completed,
|
223
|
+
# `false` otherwise.
|
224
|
+
#
|
225
|
+
# @return [TrueClass]
|
226
|
+
# Pauses the framework on a best effort basis, might take a while to take
|
227
|
+
# effect.
|
228
|
+
def pause
|
229
|
+
@pre_pause_status ||= @status if !paused? && !pausing?
|
230
|
+
|
231
|
+
if !paused?
|
232
|
+
@status = :pausing
|
233
|
+
end
|
234
|
+
|
235
|
+
@pause_signals << :nil
|
236
|
+
|
237
|
+
paused if !running?
|
238
|
+
true
|
239
|
+
end
|
240
|
+
|
241
|
+
# Signals that the system has been paused..
|
242
|
+
def paused
|
243
|
+
clear_status_messages
|
244
|
+
@status = :paused
|
245
|
+
end
|
246
|
+
|
247
|
+
# @return [Bool]
|
248
|
+
# `true` if the framework is paused.
|
249
|
+
def paused?
|
250
|
+
@status == :paused
|
251
|
+
end
|
252
|
+
|
253
|
+
# @return [Bool]
|
254
|
+
# `true` if the system is being paused, `false` otherwise.
|
255
|
+
def pausing?
|
256
|
+
@status == :pausing
|
257
|
+
end
|
258
|
+
|
259
|
+
# @return [Bool]
|
260
|
+
# `true` if the framework should pause, `false` otherwise.
|
261
|
+
def pause?
|
262
|
+
@pause_signals.any?
|
263
|
+
end
|
264
|
+
|
265
|
+
# Resumes a paused system
|
266
|
+
#
|
267
|
+
# @return [Bool]
|
268
|
+
# `true` if the system is resumed, `false` if there are more {#pause}
|
269
|
+
# signals pending.
|
270
|
+
def resume
|
271
|
+
@status = :resuming
|
272
|
+
@pause_signals.clear
|
273
|
+
|
274
|
+
true
|
275
|
+
end
|
276
|
+
|
277
|
+
def resumed
|
278
|
+
@status = @pre_pause_status
|
279
|
+
@pre_pause_status = nil
|
280
|
+
|
281
|
+
true
|
282
|
+
end
|
283
|
+
|
284
|
+
def dump( directory )
|
285
|
+
FileUtils.mkdir_p( directory )
|
286
|
+
|
287
|
+
d = Cuboid::Application.serializer.dump( @runtime )
|
288
|
+
IO.binwrite( "#{directory}/runtime", d )
|
289
|
+
end
|
290
|
+
|
291
|
+
def self.load( directory )
|
292
|
+
application = new
|
293
|
+
application.runtime = Cuboid::Application.serializer.load( IO.binread( "#{directory}/runtime" ) )
|
294
|
+
application
|
295
|
+
end
|
296
|
+
|
297
|
+
def clear
|
298
|
+
@pause_signals.clear
|
299
|
+
|
300
|
+
@running = false
|
301
|
+
@pre_pause_status = nil
|
302
|
+
|
303
|
+
@runtime = nil
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|
309
|
+
end
|