Ravn::Tactical::
BoltPackage
class
A wrapper of convenience functions for reading and writing the Ravn
Bolt package on a compute pack.
- DEFAULT_NAME
The name of the default bolt package that is used if none has been uploaded yet.
- FILENAME
The name of the file the bolts package is contained in, relative to the configured mission directory.
- MAX_PACKAGE_VERSION
The maximum version number of the package format that is supported.
- TIMESTAMP_FORMAT
Strtime format for the timestamp field
- bolts R
The bolt library’s bolts
- name R
The bolt library’s human-readable name
- roles R
The bolt library’s roles as a Set of Ravn::Tactical::Roles
- timestamp R
The timestamp when the bolt library was exported from the Creator
Return a Pathname to the default file containing the BoltPackage
data.
43 def self::default_path
44 return Ravn::BDE.mission_directory + FILENAME
45 end
Returns true
if the bolts package file exists in the currently-configured mission directory.
114 def self::exists?
115 return self.default_path.exist?
116 end
load( path=self.default_path )
Load the BoltPackage
from the specified path
and return it.
49 def self::load( path=self.default_path )
50 path = Pathname( path )
51 raw = YAML.safe_load_file( path, symbolize_names: true ) or
52 raise "Failed to load %s" % [ path ]
53
54 fields = self.normalize_fields( raw )
55
56 return new( **fields )
57 end
new( name: DEFAULT_NAME, roles: [], bolts: {}, timestamp: Time.now )
Create a new BoltPackage
with the given name
,
120 def initialize( name: DEFAULT_NAME, roles: [], bolts: {}, timestamp: Time.now )
121 @name = name
122 @roles = roles.map {|name| Ravn::Tactical::Role.new(name) }.to_set
123 @timestamp = timestamp
124
125 @bolts = bolts.each_with_object( {} ) do |(id, bolt), acc|
126 bolt = bolt.is_a?( Ravn::Tactical::Bolt ) ? bolt : Ravn::Tactical::Bolt.new( **bolt )
127 bolt.id = id
128 acc[ id ] = bolt
129 end
130 end
Return an unsaved BoltPackage
derived from the default mission templates.
96 def self::new_with_defaults
97 segments = Set.new
98 bolts = {}
99
100 Ravn::Tactical::Mission.all_templates.each do |template|
101 segments.merge( template.segments.keys.map(&:to_s) )
102 bolts.merge!( template.bolts )
103 end
104
105 return new(
106 roles: segments,
107 bolts: bolts
108 )
109 end
Normalize the fields in the raw
bolt package data according to the version of the format it’s in and return the normalized Hash. Raises a Ravn::Tactical::BoltPackageError if raw
contains invalid or unsupported values.
64 def self::normalize_fields( raw )
65 package_version = raw.delete( :package_version ) or
66 raise Ravn::Tactical::BoltPackageError, "No package_version!"
67 self.log.debug "Raw data is format version %d" % [ package_version ]
68
69 normalized = {}
70 case package_version
71 when 1
72 normalized[ :name ] = raw[ :library ]
73 normalized[ :roles ] = raw[ :segments ]
74 normalized[ :bolts ] = raw[ :bolts ].transform_keys( &:to_s )
75
76 normalized[ :timestamp ] = Time.strptime( raw[:timestamp], TIMESTAMP_FORMAT )
77 else
78 raise Ravn::Tactical::BoltPackageError,
79 "unsupported package version %d" % [ package_version ]
80 end
81
82 return normalized
83 end
write_default( path=self.default_path )
Write a default set of bolts to the Bolt Package file. Raises an exception if the file already exists.
88 def self::write_default( path=self.default_path )
89 package = self.new_with_defaults
90 package.write_as_default
91 return package
92 end
Return true if other_object
is the same BoltPackage
as the receiver.
221 def ==( other_object )
222 return other_object.is_a?( self.class ) &&
223 other_object.fields == self.fields
224 end
Return a Hash of normalized values for the BoltPackage
suitable for writing to a file or to the network.
164 def fields
165 return {
166 package_version: MAX_PACKAGE_VERSION,
167 library: self.name,
168 timestamp: self.timestamp.strftime( TIMESTAMP_FORMAT ),
169 segments: self.roles.map( &:name ).sort,
170 bolts: self.bolts.transform_values( &:fields ),
171 }
172 end
Ravn::Inspection API – return the details of the BoltPackage
in human-readable form.
229 def inspect_details
230 return "%s [%s]: %d roles, %d bolts" % [
231 self.name,
232 self.timestamp,
233 self.roles.size,
234 self.bolts.size,
235 ]
236 end
Return the bolt package’s role as a Hash of Segments keyed by role name.
155 def role_segments_hash
156 return self.roles.each_with_object({}) do |role, hash|
157 hash[ role.name ] = { type: 'group', config: { members: [] } }
158 end
159 end
Check the contents of the BoltPackage
for validity, raising a Ravn::Tactical::BoltPackageError if there’s a problem.
177 def validate
178 self.validate_bolts
179 end
Validate the BoltPackage’s bolts, raising a Ravn::Tactical::BoltPackageError if one of them is not valid.
184 def validate_bolts
185 self.bolts.each do |bolt_id, bolt|
186 self.log.debug "Validating bolt %s: %p" % [ bolt_id, bolt ]
187 raise Ravn::Tactical::BoltPackageError, "invalid bolt %s" % [ bolt_id ] unless
188 bolt.valid?
189 end
190 end
write( path, replace: false )
Write the BoltPackage
to the given path
.
194 def write( path, replace: false )
195 path = Pathname( path )
196 path.unlink if replace && path.exist?
197
198 raise "Directory %s doesn not exist!" % [ path.dirname ] if !path.dirname.directory?
199
200 io = path.open( File::WRONLY|File::CREAT|File::EXCL, 0644 )
201 package = stringify_keys( self.fields )
202
203 self.log.warn "Writing a bolt package to %s" % [ path ]
204 YAML.safe_dump( package, io )
205
206 io.close
207 self.log.debug "Written file is %d bytes" % [ path.size ]
208 end
write_as_default( replace: false )
Write the BoltPackage
to the default path, overwriting an existing one if the replace
option is set.
213 def write_as_default( replace: false )
214 self.log.info "Writing package with timestamp %s as the default" % [ self.timestamp ]
215 path = self.class.default_path
216 self.write( path, replace: )
217 end