talia_core 0.4.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/README.rdoc +41 -0
- data/bin/talia +33 -0
- data/lib/JXslt/jxslt.rb +60 -0
- data/lib/acts_as_roled.rb +11 -0
- data/lib/core_ext/platform.rb +9 -0
- data/lib/core_ext/string.rb +6 -0
- data/lib/core_ext.rb +1 -0
- data/lib/custom_template.rb +4 -0
- data/lib/loader_helper.rb +62 -0
- data/lib/mysql.rb +1214 -0
- data/lib/progressbar.rb +236 -0
- data/lib/role.rb +12 -0
- data/lib/talia_cl/command_line.rb +39 -0
- data/lib/talia_cl/commands/standalone/cl_options.rb +9 -0
- data/lib/talia_cl/commands/standalone/standalone_generate.rb +75 -0
- data/lib/talia_cl/commands/standalone.rb +25 -0
- data/lib/talia_cl/commands/talia_console/cl_options.rb +55 -0
- data/lib/talia_cl/commands/talia_console/console_commands.rb +37 -0
- data/lib/talia_cl/commands/talia_console/talia_commands.rb +131 -0
- data/lib/talia_cl/commands/talia_console.rb +47 -0
- data/lib/talia_cl/core_commands.rb +11 -0
- data/lib/talia_cl.rb +47 -0
- data/lib/talia_core/active_source.rb +372 -0
- data/lib/talia_core/active_source_parts/class_methods.rb +378 -0
- data/lib/talia_core/active_source_parts/predicate_handler.rb +89 -0
- data/lib/talia_core/active_source_parts/rdf.rb +131 -0
- data/lib/talia_core/active_source_parts/sql_helper.rb +36 -0
- data/lib/talia_core/active_source_parts/xml/base_builder.rb +47 -0
- data/lib/talia_core/active_source_parts/xml/generic_reader.rb +363 -0
- data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +88 -0
- data/lib/talia_core/active_source_parts/xml/source_builder.rb +73 -0
- data/lib/talia_core/active_source_parts/xml/source_reader.rb +20 -0
- data/lib/talia_core/agent.rb +14 -0
- data/lib/talia_core/background_jobs/job.rb +82 -0
- data/lib/talia_core/background_jobs/progress_job.rb +68 -0
- data/lib/talia_core/collection.rb +13 -0
- data/lib/talia_core/data_types/data_loader.rb +92 -0
- data/lib/talia_core/data_types/data_record.rb +105 -0
- data/lib/talia_core/data_types/delayed_copier.rb +76 -0
- data/lib/talia_core/data_types/file_record.rb +59 -0
- data/lib/talia_core/data_types/file_store.rb +306 -0
- data/lib/talia_core/data_types/iip_data.rb +153 -0
- data/lib/talia_core/data_types/iip_loader.rb +127 -0
- data/lib/talia_core/data_types/image_data.rb +32 -0
- data/lib/talia_core/data_types/media_link.rb +19 -0
- data/lib/talia_core/data_types/mime_mapping.rb +45 -0
- data/lib/talia_core/data_types/path_helpers.rb +77 -0
- data/lib/talia_core/data_types/pdf_data.rb +42 -0
- data/lib/talia_core/data_types/simple_text.rb +36 -0
- data/lib/talia_core/data_types/temp_file_handling.rb +85 -0
- data/lib/talia_core/data_types/xml_data.rb +169 -0
- data/lib/talia_core/dc_resource.rb +20 -0
- data/lib/talia_core/dummy_handler.rb +34 -0
- data/lib/talia_core/dummy_source.rb +20 -0
- data/lib/talia_core/errors.rb +25 -0
- data/lib/talia_core/initializer.rb +427 -0
- data/lib/talia_core/ordered_source.rb +228 -0
- data/lib/talia_core/rails_ext/actionpack/action_controller/record_identifier.rb +13 -0
- data/lib/talia_core/rails_ext/actionpack/action_controller.rb +1 -0
- data/lib/talia_core/rails_ext/actionpack.rb +1 -0
- data/lib/talia_core/rails_ext.rb +1 -0
- data/lib/talia_core/rdf_import.rb +90 -0
- data/lib/talia_core/rdf_resource.rb +159 -0
- data/lib/talia_core/semantic_collection_item.rb +93 -0
- data/lib/talia_core/semantic_collection_wrapper.rb +324 -0
- data/lib/talia_core/semantic_property.rb +7 -0
- data/lib/talia_core/semantic_relation.rb +67 -0
- data/lib/talia_core/source.rb +323 -0
- data/lib/talia_core/source_transfer_object.rb +38 -0
- data/lib/talia_core/workflow/base.rb +15 -0
- data/lib/talia_core/workflow/publication_workflow.rb +62 -0
- data/lib/talia_core/workflow.rb +300 -0
- data/lib/talia_core.rb +9 -0
- data/lib/talia_dependencies.rb +12 -0
- data/lib/talia_util/bar_progressor.rb +15 -0
- data/lib/talia_util/configuration/config_file.rb +48 -0
- data/lib/talia_util/configuration/database_config.rb +40 -0
- data/lib/talia_util/configuration/mysql_database_setup.rb +104 -0
- data/lib/talia_util/data_import.rb +91 -0
- data/lib/talia_util/image_conversions.rb +82 -0
- data/lib/talia_util/import_job_helper.rb +132 -0
- data/lib/talia_util/io_helper.rb +54 -0
- data/lib/talia_util/progressable.rb +38 -0
- data/lib/talia_util/progressbar.rb +236 -0
- data/lib/talia_util/rdf_update.rb +80 -0
- data/lib/talia_util/some_sigla.xml +1960 -0
- data/lib/talia_util/test_helpers.rb +151 -0
- data/lib/talia_util/util.rb +226 -0
- data/lib/talia_util/yaml_import.rb +80 -0
- data/lib/talia_util.rb +13 -0
- data/lib/user.rb +116 -0
- data/lib/version.rb +15 -0
- data/test/core_ext/string_test.rb +11 -0
- data/test/custom_template_test.rb +8 -0
- data/test/talia_core/active_source_predicate_test.rb +54 -0
- data/test/talia_core/active_source_rdf_test.rb +89 -0
- data/test/talia_core/active_source_test.rb +631 -0
- data/test/talia_core/data_types/data_loader_test.rb +123 -0
- data/test/talia_core/data_types/data_record_test.rb +40 -0
- data/test/talia_core/data_types/file_record_test.rb +171 -0
- data/test/talia_core/data_types/iip_data_test.rb +130 -0
- data/test/talia_core/data_types/image_data_test.rb +88 -0
- data/test/talia_core/data_types/pdf_data_test.rb +68 -0
- data/test/talia_core/data_types/xml_data_test.rb +134 -0
- data/test/talia_core/generic_xml_test.rb +83 -0
- data/test/talia_core/initializer_test.rb +36 -0
- data/test/talia_core/ordered_source_test.rb +398 -0
- data/test/talia_core/rdf_resource_test.rb +115 -0
- data/test/talia_core/semantic_collection_item_test.rb +129 -0
- data/test/talia_core/source_reader_test.rb +33 -0
- data/test/talia_core/source_test.rb +484 -0
- data/test/talia_core/source_transfer_object_test.rb +24 -0
- data/test/talia_core/workflow/publication_workflow_test.rb +242 -0
- data/test/talia_core/workflow/user_class_for_workflow.rb +35 -0
- data/test/talia_core/workflow/workflow_base_test.rb +21 -0
- data/test/talia_core/workflow_test.rb +19 -0
- data/test/talia_util/import_job_helper_test.rb +46 -0
- data/test/test_helper.rb +68 -0
- metadata +262 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
module TaliaCore #:nodoc:
|
|
2
|
+
module Workflow #:nodoc:
|
|
3
|
+
class InvalidState < Exception #:nodoc:
|
|
4
|
+
end
|
|
5
|
+
class NoInitialState < Exception #:nodoc:
|
|
6
|
+
end
|
|
7
|
+
class NoAuthorizedException < Exception #:nodoc:
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def self.included(base) #:nodoc:
|
|
12
|
+
base.extend WorkflowMacro
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module SupportingClasses
|
|
16
|
+
class State
|
|
17
|
+
attr_reader :name
|
|
18
|
+
|
|
19
|
+
def initialize(name, opts)
|
|
20
|
+
@name, @opts = name, opts
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def entering(record)
|
|
24
|
+
enteract = @opts[:enter]
|
|
25
|
+
record.send(:run_transition_action, enteract) if enteract
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def entered(record)
|
|
29
|
+
afteractions = @opts[:after]
|
|
30
|
+
return unless afteractions
|
|
31
|
+
Array(afteractions).each do |afteract|
|
|
32
|
+
record.send(:run_transition_action, afteract)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def exited(record)
|
|
37
|
+
exitact = @opts[:exit]
|
|
38
|
+
record.send(:run_transition_action, exitact) if exitact
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class StateTransition
|
|
43
|
+
attr_reader :from, :to, :opts
|
|
44
|
+
|
|
45
|
+
def initialize(opts)
|
|
46
|
+
@from, @to, @guard = opts[:from], opts[:to], opts[:guard]
|
|
47
|
+
@opts = opts
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def guard(obj, args)
|
|
51
|
+
@guard ? obj.send(:run_transition_action, @guard, args) : true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def on_transition(obj, args = nil)
|
|
55
|
+
action = @opts[:on_transition]
|
|
56
|
+
obj.send(:run_transition_action, action, args) if action
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def perform(record, args = nil)
|
|
60
|
+
return false unless guard(record, args)
|
|
61
|
+
loopback = record.current_state == to
|
|
62
|
+
states = record.class.read_inheritable_attribute(:states)
|
|
63
|
+
next_state = states[to]
|
|
64
|
+
old_state = states[record.current_state]
|
|
65
|
+
|
|
66
|
+
# permform action
|
|
67
|
+
on_transition(record, args)
|
|
68
|
+
|
|
69
|
+
next_state.entering(record) unless loopback
|
|
70
|
+
|
|
71
|
+
record.update_attribute(record.class.state_column, to.to_s)
|
|
72
|
+
|
|
73
|
+
next_state.entered(record) unless loopback
|
|
74
|
+
old_state.exited(record) unless loopback
|
|
75
|
+
true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def ==(obj)
|
|
79
|
+
@from == obj.from && @to == obj.to
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
class Event
|
|
84
|
+
attr_reader :name
|
|
85
|
+
attr_reader :transitions
|
|
86
|
+
attr_reader :opts
|
|
87
|
+
|
|
88
|
+
def initialize(name, opts, transition_table, &block)
|
|
89
|
+
@name = name.to_sym
|
|
90
|
+
@transitions = transition_table[@name] = []
|
|
91
|
+
instance_eval(&block) if block
|
|
92
|
+
@opts = opts
|
|
93
|
+
@opts.freeze
|
|
94
|
+
@transitions.freeze
|
|
95
|
+
freeze
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def next_states(record)
|
|
99
|
+
@transitions.select { |t| t.from == record.current_state }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def fire(record, user, args = nil)
|
|
103
|
+
# check user role
|
|
104
|
+
unless @opts[:require_role].nil?
|
|
105
|
+
raise NoAuthorizedException unless user.authorized_as?(@opts[:require_role])
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# perform transition
|
|
109
|
+
next_states(record).each do |transition|
|
|
110
|
+
break true if transition.perform(record, args)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def transitions(trans_opts)
|
|
115
|
+
Array(trans_opts[:from]).each do |s|
|
|
116
|
+
@transitions << SupportingClasses::StateTransition.new(trans_opts.merge({:from => s.to_sym}))
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
module WorkflowMacro
|
|
123
|
+
# Configuration options are
|
|
124
|
+
#
|
|
125
|
+
# * +column+ - specifies the column name to use for keeping the state (default: state)
|
|
126
|
+
# * +property+ - specifies the column name to use for keeping the property of current state (default: state_properties)
|
|
127
|
+
# * +initial+ - specifies an initial state for newly created objects (required)
|
|
128
|
+
def workflow_machine(opts)
|
|
129
|
+
self.extend(ClassMethods)
|
|
130
|
+
raise NoInitialState unless opts[:initial]
|
|
131
|
+
|
|
132
|
+
write_inheritable_attribute :states, {}
|
|
133
|
+
write_inheritable_attribute :initial_state, opts[:initial]
|
|
134
|
+
write_inheritable_attribute :initial_state_properties, opts[:initial_properties] || {}
|
|
135
|
+
write_inheritable_attribute :transition_table, {}
|
|
136
|
+
write_inheritable_attribute :event_table, {}
|
|
137
|
+
write_inheritable_attribute :state_column, opts[:column] || 'state'
|
|
138
|
+
write_inheritable_attribute :state_properties_column, opts[:properties] || 'state_properties'
|
|
139
|
+
|
|
140
|
+
class_inheritable_reader :initial_state
|
|
141
|
+
class_inheritable_reader :initial_state_properties
|
|
142
|
+
class_inheritable_reader :state_column
|
|
143
|
+
class_inheritable_reader :state_properties_column
|
|
144
|
+
class_inheritable_reader :transition_table
|
|
145
|
+
class_inheritable_reader :event_table
|
|
146
|
+
|
|
147
|
+
self.send(:include, TaliaCore::Workflow::InstanceMethods)
|
|
148
|
+
|
|
149
|
+
before_create :set_initial_state, :set_initial_state_properties
|
|
150
|
+
after_create :run_initial_state_actions
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
module InstanceMethods
|
|
155
|
+
def state_properties
|
|
156
|
+
Marshal.load(self.send(self.class.state_properties_column))
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def state_properties=(value)
|
|
160
|
+
write_attribute self.class.state_properties_column, Marshal.dump(value)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def set_initial_state #:nodoc:
|
|
164
|
+
write_attribute self.class.state_column, self.class.initial_state.to_s
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def set_initial_state_properties #:nodoc:
|
|
168
|
+
write_attribute self.class.state_properties_column, Marshal.dump(self.class.initial_state_properties)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def run_initial_state_actions
|
|
172
|
+
initial = self.class.read_inheritable_attribute(:states)[self.class.initial_state.to_sym]
|
|
173
|
+
initial.entering(self)
|
|
174
|
+
initial.entered(self)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Returns the current state the object is in, as a Ruby symbol.
|
|
178
|
+
def current_state
|
|
179
|
+
self.send(self.class.state_column).to_sym
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Returns what the next state for a given event would be, as a Ruby symbol.
|
|
183
|
+
def next_state_for_event(event)
|
|
184
|
+
ns = next_states_for_event(event)
|
|
185
|
+
ns.empty? ? nil : ns.first.to
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def next_states_for_event(event)
|
|
189
|
+
self.class.read_inheritable_attribute(:transition_table)[event.to_sym].select do |s|
|
|
190
|
+
s.from == current_state
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def run_transition_action(action, args = nil)
|
|
195
|
+
Symbol === action ? self.method(action).call(args) : action.call(self)
|
|
196
|
+
end
|
|
197
|
+
private :run_transition_action
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
module ClassMethods
|
|
201
|
+
# Returns an array of all known states.
|
|
202
|
+
def states
|
|
203
|
+
read_inheritable_attribute(:states).keys
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Define an event. This takes a block which describes all valid transitions
|
|
207
|
+
# for this event.
|
|
208
|
+
#
|
|
209
|
+
# Example:
|
|
210
|
+
#
|
|
211
|
+
# class Order < ActiveRecord::Base
|
|
212
|
+
# acts_as_state_machine :initial => :open
|
|
213
|
+
#
|
|
214
|
+
# state :open
|
|
215
|
+
# state :closed
|
|
216
|
+
#
|
|
217
|
+
# event :close_order do
|
|
218
|
+
# transitions :to => :closed, :from => :open
|
|
219
|
+
# end
|
|
220
|
+
# end
|
|
221
|
+
#
|
|
222
|
+
# +transitions+ takes a hash where <tt>:to</tt> is the state to transition
|
|
223
|
+
# to and <tt>:from</tt> is a state (or Array of states) from which this
|
|
224
|
+
# event can be fired.
|
|
225
|
+
#
|
|
226
|
+
# This creates an instance method used for firing the event. The method
|
|
227
|
+
# created is the name of the event followed by an exclamation point (!).
|
|
228
|
+
# Example: <tt>order.close_order!</tt>.
|
|
229
|
+
def event(event, opts={}, &block)
|
|
230
|
+
tt = read_inheritable_attribute(:transition_table)
|
|
231
|
+
|
|
232
|
+
et = read_inheritable_attribute(:event_table)
|
|
233
|
+
e = et[event.to_sym] = SupportingClasses::Event.new(event, opts, tt, &block)
|
|
234
|
+
define_method("#{event.to_s}!") { |user, *args| e.fire(self, user, args) }
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Define a state of the system. +state+ can take an optional Proc object
|
|
238
|
+
# which will be executed every time the system transitions into that
|
|
239
|
+
# state. The proc will be passed the current object.
|
|
240
|
+
#
|
|
241
|
+
# Example:
|
|
242
|
+
#
|
|
243
|
+
# class Order < ActiveRecord::Base
|
|
244
|
+
# acts_as_state_machine :initial => :open
|
|
245
|
+
#
|
|
246
|
+
# state :open
|
|
247
|
+
# state :closed, Proc.new { |o| Mailer.send_notice(o) }
|
|
248
|
+
# end
|
|
249
|
+
def state(name, opts={})
|
|
250
|
+
state = SupportingClasses::State.new(name.to_sym, opts)
|
|
251
|
+
read_inheritable_attribute(:states)[name.to_sym] = state
|
|
252
|
+
|
|
253
|
+
define_method("#{state.name}?") { current_state == state.name }
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Wraps ActiveRecord::Base.find to conveniently find all records in
|
|
257
|
+
# a given state. Options:
|
|
258
|
+
#
|
|
259
|
+
# * +number+ - This is just :first or :all from ActiveRecord +find+
|
|
260
|
+
# * +state+ - The state to find
|
|
261
|
+
# * +args+ - The rest of the args are passed down to ActiveRecord +find+
|
|
262
|
+
def find_in_state(number, state, *args)
|
|
263
|
+
with_state_scope state do
|
|
264
|
+
find(number, *args)
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Wraps ActiveRecord::Base.count to conveniently count all records in
|
|
269
|
+
# a given state. Options:
|
|
270
|
+
#
|
|
271
|
+
# * +state+ - The state to find
|
|
272
|
+
# * +args+ - The rest of the args are passed down to ActiveRecord +find+
|
|
273
|
+
def count_in_state(state, *args)
|
|
274
|
+
with_state_scope state do
|
|
275
|
+
count(*args)
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Wraps ActiveRecord::Base.calculate to conveniently calculate all records in
|
|
280
|
+
# a given state. Options:
|
|
281
|
+
#
|
|
282
|
+
# * +state+ - The state to find
|
|
283
|
+
# * +args+ - The rest of the args are passed down to ActiveRecord +calculate+
|
|
284
|
+
def calculate_in_state(state, *args)
|
|
285
|
+
with_state_scope state do
|
|
286
|
+
calculate(*args)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
protected
|
|
291
|
+
def with_state_scope(state)
|
|
292
|
+
raise InvalidState unless states.include?(state)
|
|
293
|
+
|
|
294
|
+
with_scope :find => {:conditions => ["#{table_name}.#{state_column} = ?", state.to_s]} do
|
|
295
|
+
yield if block_given?
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
data/lib/talia_core.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# TaliaCore loader
|
|
2
|
+
require File.dirname(__FILE__) + '/loader_helper'
|
|
3
|
+
|
|
4
|
+
# This is also needed for local loading
|
|
5
|
+
RAILS_GEM_VERSION = '2.3.4' unless defined? RAILS_GEM_VERSION
|
|
6
|
+
|
|
7
|
+
# Stuff we may need to load from sources/uninstalled versions
|
|
8
|
+
TLoad::require_module("assit", "assit", "/../../assit") unless(defined?(assit))
|
|
9
|
+
TLoad::require_module("activerdf", "active_rdf", "/../../ActiveRDF")
|
|
10
|
+
TLoad::require_module("semantic_naming", "semantic_naming", "/../../semantic_naming")
|
|
11
|
+
|
|
12
|
+
require 'version'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'progressbar')
|
|
2
|
+
|
|
3
|
+
module TaliaUtil
|
|
4
|
+
|
|
5
|
+
# Helper class for command-line progress bars as progressor objects
|
|
6
|
+
class BarProgressor
|
|
7
|
+
|
|
8
|
+
def self.run_with_progress(message, size)
|
|
9
|
+
progress = ProgressBar.new(message, size)
|
|
10
|
+
yield(progress)
|
|
11
|
+
progress.finish
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module TaliaUtil
|
|
4
|
+
module Configuration
|
|
5
|
+
|
|
6
|
+
# This is an object representation of a configuration file, the elements
|
|
7
|
+
# of the file can be directly accessed using dynamic getters/setters on the
|
|
8
|
+
# the class.
|
|
9
|
+
class ConfigFile
|
|
10
|
+
|
|
11
|
+
# Initialize from the given template
|
|
12
|
+
def initialize(template)
|
|
13
|
+
@config_doc = YAML::load_file(template)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Write the configuration to the given file
|
|
17
|
+
def write(file)
|
|
18
|
+
open(file, 'w') { |io| io.puts(@config_doc.to_yaml) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def [](id)
|
|
22
|
+
@config_doc[id]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Automatically creates "accessors" for the config properties.
|
|
26
|
+
def method_missing(method, *params)
|
|
27
|
+
method = method.to_s
|
|
28
|
+
assign = method[-1..-1] == '=' # True if last char is a =
|
|
29
|
+
|
|
30
|
+
result = nil
|
|
31
|
+
|
|
32
|
+
if(assign)
|
|
33
|
+
return super if(params.size != 1)
|
|
34
|
+
result = @config_doc[method[0..-2]] = params[0]
|
|
35
|
+
else
|
|
36
|
+
return super if(params.size != 0)
|
|
37
|
+
result = @config_doc[method]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
result
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/config_file'
|
|
2
|
+
|
|
3
|
+
module TaliaUtil
|
|
4
|
+
module Configuration
|
|
5
|
+
|
|
6
|
+
# This contains some special methods for database config files
|
|
7
|
+
class DatabaseConfig < ConfigFile
|
|
8
|
+
|
|
9
|
+
def initialize(template)
|
|
10
|
+
@environments = ['test', 'development', 'production']
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Set the credentials for all environments
|
|
15
|
+
def set_credentials(db_user, db_pass)
|
|
16
|
+
@environments.each do |env|
|
|
17
|
+
@config_doc[env]['username'] = db_user
|
|
18
|
+
@config_doc[env]['password'] = db_pass
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Sets the database adapter for all environments
|
|
23
|
+
def set_adapter(db_adapter)
|
|
24
|
+
@environments.each { |env| @config_doc[env]['adapter'] = db_adapter }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Sets the database names based on the given application name
|
|
28
|
+
def set_database_names(app_name)
|
|
29
|
+
@environments.each { |env| @config_doc[env]['database'] = "#{app_name}_#{env}" }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Sets the socket file for the db
|
|
33
|
+
def set_socket(socket)
|
|
34
|
+
@environments.each { |env| @config_doc[env]['socket'] = socket }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
|
|
3
|
+
module TaliaUtil
|
|
4
|
+
module Configuration
|
|
5
|
+
|
|
6
|
+
# This contains some methods to set mysql databases on a production system
|
|
7
|
+
# from scratch. Setting the root password will apply immediately, the SQL
|
|
8
|
+
# operations will be cached and applied in one go.
|
|
9
|
+
class MysqlDatabaseSetup
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@sql_statements = []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_accessor :host
|
|
16
|
+
attr_accessor :app_name
|
|
17
|
+
attr_accessor :sock
|
|
18
|
+
attr_accessor :db_prefix # Prefix for having multiple databases on one install
|
|
19
|
+
|
|
20
|
+
# Set the root user/pw
|
|
21
|
+
def root_credentials(root_user = 'root', root_pw = nil)
|
|
22
|
+
@root_user = root_user
|
|
23
|
+
@root_pw = root_pw
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Set the normal user/pw
|
|
27
|
+
def rails_credentials(rails_user, rails_pw)
|
|
28
|
+
@rails_user = rails_user
|
|
29
|
+
@rails_pw = rails_pw
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Assign a new root password
|
|
34
|
+
def assign_root_pw(new_root_pw)
|
|
35
|
+
success = mysqladmin("password #{new_root_pw}")
|
|
36
|
+
@root_pw = new_root_pw if(success)
|
|
37
|
+
success
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Create the given database and set the permssions on it
|
|
41
|
+
def create_database(database)
|
|
42
|
+
raise(ArgumentError, "Credentials incomplete") unless(@rails_user && @rails_pw)
|
|
43
|
+
@sql_statements << "CREATE DATABASE #{database};"
|
|
44
|
+
@sql_statements << "GRANT ALL ON #{database}.* TO '#{@rails_user}'@'#{@host || 'localhost'}' IDENTIFIED BY '#{@rails_pw}'"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Creates the default databases for the application. You can call back a
|
|
48
|
+
# block for each db to do something depending on the success of the
|
|
49
|
+
# operation
|
|
50
|
+
def create_default_databases
|
|
51
|
+
raise(ArgumentError, "App name not set") unless(@app_name)
|
|
52
|
+
%w(production test development).each do |db_suffix|
|
|
53
|
+
db_name = "#{db_prefix}#{@app_name}_#{db_suffix}"
|
|
54
|
+
create_database(db_name)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Executes all stored statements
|
|
59
|
+
def execute
|
|
60
|
+
execute_as_root do |connection|
|
|
61
|
+
connection.transaction do
|
|
62
|
+
@sql_statements.each do |statement|
|
|
63
|
+
connection.execute(statement)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
# Call the mysqladmin command (as root)
|
|
72
|
+
def mysqladmin(command)
|
|
73
|
+
if(@root_pw)
|
|
74
|
+
system("mysqladmin -u #{@root_user} #{command}")
|
|
75
|
+
else
|
|
76
|
+
system("mysqladmin -u #{@root_user} -p#{@root_pw} #{command}")
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Calls sql commands on the database using root credentials. The open
|
|
81
|
+
# database (ActiveRecord) connection will be passed. This will open
|
|
82
|
+
# the given database.
|
|
83
|
+
def execute_as_root(database = nil)
|
|
84
|
+
ActiveRecord::Base.establish_connection(root_con_opts(database))
|
|
85
|
+
yield(ActiveRecord::Base.connection)
|
|
86
|
+
ActiveRecord::Base.remove_connection
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# options for root connection
|
|
90
|
+
def root_con_opts(database)
|
|
91
|
+
{
|
|
92
|
+
:adapter => "mysql",
|
|
93
|
+
:host => @host || "localhost",
|
|
94
|
+
:username => @root_user,
|
|
95
|
+
:password => @root_pw,
|
|
96
|
+
:database => database,
|
|
97
|
+
:socket => @sock || '/tmp/mysql.sock'
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
|
|
3
|
+
module TaliaUtil
|
|
4
|
+
|
|
5
|
+
# Import data files into the Talia store. This can be used to bootstrap
|
|
6
|
+
# simple installations
|
|
7
|
+
class DataImport
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
|
|
11
|
+
# Import files with the given type. This is a simple import feature,
|
|
12
|
+
# it's assumed that the file (without extension is named like the
|
|
13
|
+
# Source it should be assigned to.
|
|
14
|
+
def import(files, type)
|
|
15
|
+
|
|
16
|
+
# First get the class for the data type and the directory
|
|
17
|
+
data_klass = get_data_class(type)
|
|
18
|
+
replace = ENV['replace_files'] && (ENV['replace_files'] == "yes")
|
|
19
|
+
|
|
20
|
+
progress = ProgressBar.new("Importing #{data_klass}", files.size)
|
|
21
|
+
not_found = []
|
|
22
|
+
created = 0
|
|
23
|
+
|
|
24
|
+
files.each do |file|
|
|
25
|
+
# Get the basename without extension and additions. This strips off
|
|
26
|
+
# everything after the first point or - character. Examples:
|
|
27
|
+
# book.html
|
|
28
|
+
# book-picture.jpg
|
|
29
|
+
# => Will all be assigned to "book"
|
|
30
|
+
name = File.basename(file).gsub(/[-|\.].+$/, '')
|
|
31
|
+
if(TaliaCore::Source.exists?(name))
|
|
32
|
+
src = TaliaCore::Source.find(name)
|
|
33
|
+
|
|
34
|
+
# Get the filename with extension
|
|
35
|
+
file_name = File.basename(file)
|
|
36
|
+
|
|
37
|
+
# Create the record if necessary
|
|
38
|
+
unless(data = src.data_records.find_by_location(file_name))
|
|
39
|
+
data = data_klass.new
|
|
40
|
+
File.open(file) do |io|
|
|
41
|
+
data.create_from_data(file_name, io)
|
|
42
|
+
end
|
|
43
|
+
src.data_records << data
|
|
44
|
+
src.save!
|
|
45
|
+
data.save!
|
|
46
|
+
created += 1
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
not_found << file
|
|
50
|
+
end
|
|
51
|
+
progress.inc
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
progress.finish
|
|
55
|
+
puts "Done, #{not_found.size} of #{files.size} files had no record associated."
|
|
56
|
+
puts "#{created} new records created."
|
|
57
|
+
puts "\nNot found:" unless(not_found.size == 0)
|
|
58
|
+
not_found.each { |file| puts file}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# Get the data class for the type. That does some sanity checks
|
|
63
|
+
def get_data_class(type)
|
|
64
|
+
data_klass = nil
|
|
65
|
+
begin
|
|
66
|
+
data_klass = TaliaCore::DataTypes.const_get(type)
|
|
67
|
+
rescue Exception => e
|
|
68
|
+
puts("Could get the data type #{type}: #{e}")
|
|
69
|
+
Util.print_options
|
|
70
|
+
exit(1)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Do the basic check
|
|
74
|
+
unless(data_klass && data_klass.kind_of?(Class) && data_klass.method_defined?('data_directory'))
|
|
75
|
+
puts("Cannot create data class from #{type}")
|
|
76
|
+
exit(1)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Now check if we are a subclass of the data class
|
|
80
|
+
my_instance = data_klass.new
|
|
81
|
+
|
|
82
|
+
unless(my_instance.kind_of?(TaliaCore::DataTypes::DataRecord))
|
|
83
|
+
puts("The class #{data_klass} is not a DataRecord, can't create data for it.")
|
|
84
|
+
exit(1)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
data_klass
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|