marty 2.5.2 → 2.5.4
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 +5 -5
- data/.gitignore +4 -0
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +11 -589
- data/Gemfile +9 -9
- data/Gemfile.lock +1 -1
- data/Rakefile +1 -3
- data/app/components/marty/api_auth_view.rb +3 -3
- data/app/components/marty/api_config_view.rb +8 -8
- data/app/components/marty/api_log_view.rb +16 -20
- data/app/components/marty/auth_app.rb +6 -6
- data/app/components/marty/base_rule_view.rb +27 -19
- data/app/components/marty/config_view.rb +12 -9
- data/app/components/marty/data_grid_view.rb +26 -26
- data/app/components/marty/delorean_rule_view.rb +0 -1
- data/app/components/marty/event_view.rb +27 -27
- data/app/components/marty/extras/layout.rb +26 -26
- data/app/components/marty/extras/misc.rb +2 -2
- data/app/components/marty/grid.rb +13 -13
- data/app/components/marty/grid_append_only.rb +0 -1
- data/app/components/marty/import_type_view.rb +13 -13
- data/app/components/marty/import_view.rb +17 -16
- data/app/components/marty/log_view.rb +16 -14
- data/app/components/marty/main_auth_app.rb +59 -59
- data/app/components/marty/main_auth_app/client/main_auth_app.js +3 -3
- data/app/components/marty/mcfly_grid_panel.rb +10 -10
- data/app/components/marty/new_posting_form.rb +11 -11
- data/app/components/marty/new_posting_window.rb +0 -1
- data/app/components/marty/posting_grid.rb +12 -13
- data/app/components/marty/promise_view.rb +6 -6
- data/app/components/marty/report_form.rb +50 -53
- data/app/components/marty/report_select.rb +27 -27
- data/app/components/marty/reporting.rb +4 -4
- data/app/components/marty/script_form.rb +40 -42
- data/app/components/marty/script_grid.rb +24 -24
- data/app/components/marty/script_tester.rb +40 -42
- data/app/components/marty/scripting.rb +25 -27
- data/app/components/marty/simple_app.rb +24 -9
- data/app/components/marty/tag_grid.rb +12 -13
- data/app/components/marty/user_view.rb +35 -35
- data/app/controllers/marty/application_controller.rb +3 -4
- data/app/controllers/marty/components_controller.rb +1 -1
- data/app/controllers/marty/delayed_job_controller.rb +1 -0
- data/app/controllers/marty/diagnostic/controller.rb +4 -6
- data/app/controllers/marty/job_controller.rb +6 -6
- data/app/controllers/marty/report_controller.rb +11 -11
- data/app/controllers/marty/rpc_controller.rb +15 -16
- data/app/helpers/marty/script_set.rb +4 -4
- data/app/models/marty/api_auth.rb +4 -5
- data/app/models/marty/api_config.rb +1 -1
- data/app/models/marty/base.rb +9 -8
- data/app/models/marty/base_rule.rb +18 -13
- data/app/models/marty/config.rb +4 -5
- data/app/models/marty/data_grid.rb +157 -181
- data/app/models/marty/delorean_rule.rb +63 -62
- data/app/models/marty/enum.rb +1 -1
- data/app/models/marty/event.rb +56 -59
- data/app/models/marty/helper.rb +38 -6
- data/app/models/marty/import_type.rb +6 -6
- data/app/models/marty/log.rb +3 -2
- data/app/models/marty/name_validator.rb +3 -2
- data/app/models/marty/pg_enum.rb +3 -4
- data/app/models/marty/posting.rb +20 -24
- data/app/models/marty/promise.rb +28 -30
- data/app/models/marty/script.rb +30 -28
- data/app/models/marty/tag.rb +8 -8
- data/app/models/marty/token.rb +2 -2
- data/app/models/marty/user.rb +24 -23
- data/app/models/marty/vw_promise.rb +10 -11
- data/config/routes.rb +2 -2
- data/delorean/blame_report.dl +268 -0
- data/{spec/dummy/delorean/fields.dl → delorean/marty_fields.dl} +8 -0
- data/delorean/table_report.dl +34 -0
- data/docker-compose.dummy.yml +2 -3
- data/lib/marty/aws/base.rb +8 -8
- data/lib/marty/aws/request.rb +4 -4
- data/lib/marty/cache_adapters/mcfly_ruby_cache.rb +1 -0
- data/lib/marty/content_handler.rb +25 -25
- data/lib/marty/data_change.rb +49 -71
- data/lib/marty/data_conversion.rb +20 -28
- data/lib/marty/data_exporter.rb +25 -28
- data/lib/marty/data_importer.rb +25 -27
- data/lib/marty/engine.rb +1 -2
- data/lib/marty/json_schema.rb +22 -24
- data/lib/marty/logger.rb +6 -9
- data/lib/marty/mcfly_model.rb +20 -24
- data/lib/marty/migrations.rb +37 -35
- data/lib/marty/monkey.rb +33 -33
- data/lib/marty/permissions.rb +18 -18
- data/lib/marty/promise_job.rb +17 -17
- data/lib/marty/promise_proxy.rb +6 -6
- data/lib/marty/relation.rb +6 -7
- data/lib/marty/rpc_call.rb +13 -12
- data/lib/marty/rule_script_set.rb +32 -28
- data/lib/marty/schema_helper.rb +37 -51
- data/lib/marty/util.rb +25 -24
- data/lib/marty/version.rb +1 -1
- data/lib/marty/xl.rb +121 -115
- data/make-dummy.mk +3 -0
- data/marty.gemspec +21 -21
- data/other/marty/api/base.rb +34 -35
- data/other/marty/diagnostic/aws/ec2_instance.rb +8 -8
- data/other/marty/diagnostic/base.rb +13 -14
- data/other/marty/diagnostic/collection.rb +2 -1
- data/other/marty/diagnostic/connections.rb +8 -6
- data/other/marty/diagnostic/database.rb +1 -0
- data/other/marty/diagnostic/delayed_job_version.rb +7 -9
- data/other/marty/diagnostic/delayed_job_worker_total_count.rb +1 -1
- data/other/marty/diagnostic/delayed_job_workers.rb +1 -1
- data/other/marty/diagnostic/environment_variables.rb +17 -15
- data/other/marty/diagnostic/fatal.rb +1 -1
- data/other/marty/diagnostic/node.rb +5 -9
- data/other/marty/diagnostic/nodes.rb +7 -5
- data/other/marty/diagnostic/packer.rb +7 -7
- data/other/marty/diagnostic/reporter.rb +24 -27
- data/other/marty/diagnostic/version.rb +3 -5
- data/script/rails +2 -1
- data/spec/controllers/application_controller_spec.rb +6 -6
- data/spec/controllers/delayed_job_controller_spec.rb +4 -4
- data/spec/controllers/diagnostic/controller_spec.rb +59 -60
- data/spec/controllers/job_controller_spec.rb +68 -69
- data/spec/controllers/rpc_controller_spec.rb +353 -359
- data/spec/controllers/rpc_import_spec.rb +15 -16
- data/spec/dummy/delorean/blame_report.dl +110 -15
- data/spec/dummy/delorean/data_report.dl +4 -4
- data/spec/dummy/delorean/marty_fields.dl +63 -0
- data/spec/dummy/delorean/table_report.dl +34 -0
- data/spec/features/auth_app_spec.rb +1 -2
- data/spec/features/data_import_spec.rb +2 -3
- data/spec/features/enum_spec.rb +42 -46
- data/spec/features/jobs_dashboard_spec.rb +14 -8
- data/spec/features/log_view_spec.rb +40 -43
- data/spec/features/reporting_spec.rb +15 -15
- data/spec/features/rule_spec.rb +195 -190
- data/spec/features/scripting_spec.rb +17 -20
- data/spec/features/scripting_test_spec.rb +32 -33
- data/spec/features/user_view_spec.rb +15 -17
- data/spec/job_helper.rb +11 -11
- data/spec/lib/data_blame_spec.rb +82 -0
- data/spec/lib/data_exporter_spec.rb +31 -32
- data/spec/lib/data_importer_spec.rb +382 -395
- data/spec/lib/delorean_query_spec.rb +117 -119
- data/spec/lib/json_schema_spec.rb +382 -392
- data/spec/lib/logger_spec.rb +23 -24
- data/spec/lib/mcfly_model_spec.rb +112 -109
- data/spec/lib/migrations_spec.rb +10 -10
- data/spec/lib/struct_compare_spec.rb +6 -6
- data/spec/lib/table_report_spec.rb +90 -0
- data/spec/lib/xl_spec.rb +63 -65
- data/spec/lib/xl_styles_spec.rb +16 -19
- data/spec/models/api_auth_spec.rb +30 -30
- data/spec/models/config_spec.rb +32 -32
- data/spec/models/data_grid_spec.rb +642 -655
- data/spec/models/event_spec.rb +96 -88
- data/spec/models/import_type_spec.rb +20 -20
- data/spec/models/posting_spec.rb +35 -35
- data/spec/models/promise_spec.rb +5 -5
- data/spec/models/rule_spec.rb +280 -269
- data/spec/models/script_spec.rb +27 -18
- data/spec/models/user_spec.rb +9 -9
- data/spec/other/diagnostic/base_spec.rb +20 -19
- data/spec/other/diagnostic/collection_spec.rb +6 -5
- data/spec/other/diagnostic/delayed_job_version_spec.rb +1 -1
- data/spec/other/diagnostic/delayed_job_workers_spec.rb +8 -8
- data/spec/other/diagnostic/reporter_spec.rb +31 -33
- data/spec/spec_helper.rb +5 -5
- data/spec/support/chromedriver.rb +3 -5
- data/spec/support/components/netzke_combobox.rb +1 -1
- data/spec/support/components/netzke_grid.rb +17 -17
- data/spec/support/custom_matchers.rb +2 -2
- data/spec/support/download_helper.rb +1 -1
- data/spec/support/helper.rb +1 -2
- data/spec/support/netzke.rb +31 -31
- data/spec/support/performance_helper.rb +8 -8
- data/spec/support/post_run_logger.rb +1 -2
- data/spec/support/setup.rb +1 -4
- data/spec/support/shared_connection.rb +2 -2
- data/spec/support/structure_compare.rb +21 -22
- data/spec/support/suite.rb +1 -2
- data/spec/support/users.rb +5 -6
- metadata +32 -26
data/app/models/marty/helper.rb
CHANGED
|
@@ -1,21 +1,53 @@
|
|
|
1
1
|
class Marty::Helper
|
|
2
2
|
include Delorean::Model
|
|
3
3
|
|
|
4
|
-
delorean_fn :sleep, sig: 1 do
|
|
5
|
-
|seconds|
|
|
4
|
+
delorean_fn :sleep, sig: 1 do |seconds|
|
|
6
5
|
Kernel.sleep seconds
|
|
7
6
|
end
|
|
8
7
|
|
|
9
|
-
delorean_fn :range_step, sig: 3 do
|
|
10
|
-
|rstart, rend, step|
|
|
8
|
+
delorean_fn :range_step, sig: 3 do |rstart, rend, step|
|
|
11
9
|
(rstart..rend).step(step).to_a
|
|
12
10
|
end
|
|
13
11
|
|
|
14
|
-
delorean_fn :my_ip, sig:0 do
|
|
12
|
+
delorean_fn :my_ip, sig: 0 do
|
|
15
13
|
Marty::Diagnostic::Node.my_ip
|
|
16
14
|
end
|
|
17
15
|
|
|
18
|
-
delorean_fn :git, sig:0 do
|
|
16
|
+
delorean_fn :git, sig: 0 do
|
|
19
17
|
[my_ip, ENV['DELAYED_VER']]
|
|
20
18
|
end
|
|
19
|
+
|
|
20
|
+
delorean_fn :infinity_dt, sig: 1 do |pt|
|
|
21
|
+
Mcfly.is_infinity pt
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
delorean_fn :constantize, sig: 1 do |class_name|
|
|
25
|
+
raise 'bad class_name' unless class_name.is_a?(String)
|
|
26
|
+
|
|
27
|
+
class_name.constantize
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
delorean_fn :get_column_types, sig: 1 do |klass|
|
|
31
|
+
Marty::DataConversion.col_types(klass)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
delorean_fn :parse_csv_to_hash, sig: 3 do |txt, comma_sep, types|
|
|
35
|
+
txt ||= ''
|
|
36
|
+
headers, *rows = CSV.parse(txt.strip,
|
|
37
|
+
headers: true,
|
|
38
|
+
col_sep: (comma_sep ? ',' : "\t")).to_a
|
|
39
|
+
rows.map do |row|
|
|
40
|
+
headers.zip(row).each_with_object({}) do |(h, v), res|
|
|
41
|
+
res[h] = v.blank? ? nil :
|
|
42
|
+
Marty::DataConversion.convert(v, (types[h] || 'text').to_sym)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
delorean_fn :to_csv, sig: [1, 2] do |*args|
|
|
48
|
+
# NOTE: can't use |data, config| due to delorean_fn weirdness.
|
|
49
|
+
data, config = args
|
|
50
|
+
|
|
51
|
+
Marty::DataExporter.to_csv(data, config)
|
|
52
|
+
end
|
|
21
53
|
end
|
|
@@ -4,7 +4,7 @@ class Marty::ImportType < Marty::Base
|
|
|
4
4
|
klass = entry.get_model_class
|
|
5
5
|
|
|
6
6
|
unless klass.is_a?(Class) && klass < ActiveRecord::Base
|
|
7
|
-
entry.errors.add :base,
|
|
7
|
+
entry.errors.add :base, 'bad model name'
|
|
8
8
|
return
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -12,19 +12,19 @@ class Marty::ImportType < Marty::Base
|
|
|
12
12
|
entry.cleaner_function,
|
|
13
13
|
entry.validation_function,
|
|
14
14
|
entry.preprocess_function,
|
|
15
|
-
].each
|
|
15
|
+
].each do |func|
|
|
16
16
|
entry.errors.add(:base, "unknown class method #{func}") if
|
|
17
17
|
func && !klass.respond_to?(func.to_sym)
|
|
18
|
-
|
|
18
|
+
end
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
before_validation do
|
|
23
23
|
# Fix issue with blank strings in popup edit form or grid
|
|
24
24
|
# being interpreted as a function
|
|
25
|
-
self.cleaner_function = nil if
|
|
26
|
-
self.validation_function = nil if
|
|
27
|
-
self.preprocess_function = nil if
|
|
25
|
+
self.cleaner_function = nil if cleaner_function.blank?
|
|
26
|
+
self.validation_function = nil if validation_function.blank?
|
|
27
|
+
self.preprocess_function = nil if preprocess_function.blank?
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
belongs_to :role
|
data/app/models/marty/log.rb
CHANGED
|
@@ -9,7 +9,7 @@ class Marty::Log < Marty::Base
|
|
|
9
9
|
message: message,
|
|
10
10
|
details: details,
|
|
11
11
|
timestamp: Time.zone.now)
|
|
12
|
-
rescue => e
|
|
12
|
+
rescue StandardError => e
|
|
13
13
|
Marty::Util.logger.error("Marty::Logger failure: #{e.message}")
|
|
14
14
|
end
|
|
15
15
|
true
|
|
@@ -18,6 +18,7 @@ class Marty::Log < Marty::Base
|
|
|
18
18
|
def self.cleanup(days_to_keep)
|
|
19
19
|
raise "Must give numeric value. (Got '#{days_to_keep}')" unless
|
|
20
20
|
(Float(days_to_keep) rescue false)
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
where('timestamp <= ?', Time.zone.now - days_to_keep.to_i.days).delete_all
|
|
22
23
|
end
|
|
23
24
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
class Marty::NameValidator < ActiveModel::Validator
|
|
2
2
|
def validate(entry)
|
|
3
|
-
raise
|
|
3
|
+
raise 'need field option' unless options[:field]
|
|
4
|
+
|
|
4
5
|
field = options[:field].to_sym
|
|
5
6
|
value = entry.send(field)
|
|
6
7
|
|
|
@@ -9,7 +10,7 @@ class Marty::NameValidator < ActiveModel::Validator
|
|
|
9
10
|
# disallow leading, trailing, >1 internal spaces, special chars (|)
|
|
10
11
|
if value =~ /\A\s|\s\z|\A.*\s\s.*\z|.*\|.*/
|
|
11
12
|
entry.errors[field] <<
|
|
12
|
-
I18n.t(
|
|
13
|
+
I18n.t('activerecord.errors.messages.extraneous_spaces')
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
end
|
data/app/models/marty/pg_enum.rb
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
module Marty::PgEnum
|
|
2
|
-
|
|
3
|
-
def [](i0, i1=nil)
|
|
2
|
+
def [](i0, i1 = nil)
|
|
4
3
|
# if i1 is provided, then i0 is a pt and we ignore it.
|
|
5
4
|
index = (i1 || i0).to_s
|
|
6
5
|
|
|
7
|
-
raise "no such #{
|
|
6
|
+
raise "no such #{name}: '#{index}'" unless
|
|
8
7
|
self::VALUES.include?(index)
|
|
9
8
|
|
|
10
9
|
index
|
|
11
10
|
end
|
|
12
11
|
|
|
13
|
-
def get_all(pt=nil)
|
|
12
|
+
def get_all(pt = nil)
|
|
14
13
|
self::VALUES.map(&:to_s)
|
|
15
14
|
end
|
|
16
15
|
|
data/app/models/marty/posting.rb
CHANGED
|
@@ -4,7 +4,7 @@ class Marty::Posting < Marty::Base
|
|
|
4
4
|
mcfly_validates_uniqueness_of :name
|
|
5
5
|
validates_presence_of :name, :posting_type_id, :comment
|
|
6
6
|
|
|
7
|
-
belongs_to :user, class_name:
|
|
7
|
+
belongs_to :user, class_name: 'Marty::User'
|
|
8
8
|
belongs_to :posting_type
|
|
9
9
|
|
|
10
10
|
def self.make_name(posting_type, dt)
|
|
@@ -22,8 +22,8 @@ class Marty::Posting < Marty::Base
|
|
|
22
22
|
|
|
23
23
|
before_validation :set_posting_name
|
|
24
24
|
def set_posting_name
|
|
25
|
-
posting_type = Marty::PostingType.find_by_id(
|
|
26
|
-
self.name = self.class.make_name(posting_type,
|
|
25
|
+
posting_type = Marty::PostingType.find_by_id(posting_type_id)
|
|
26
|
+
self.name = self.class.make_name(posting_type, created_dt)
|
|
27
27
|
true
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -41,7 +41,7 @@ class Marty::Posting < Marty::Base
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def self.get_struct_attrs
|
|
44
|
-
self.struct_attrs ||= super + [
|
|
44
|
+
self.struct_attrs ||= super + ['created_dt', 'name']
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
# Not using mcfly_lookup since we don't want these time-warp markers
|
|
@@ -49,43 +49,39 @@ class Marty::Posting < Marty::Base
|
|
|
49
49
|
# may allow deletion of postings. i.e. a new one with same name
|
|
50
50
|
# might be created. Or, use regular validates_uniqueness_of instead
|
|
51
51
|
# of mcfly_validates_uniqueness_of.
|
|
52
|
-
delorean_fn :lookup, sig: 1 do
|
|
53
|
-
|name|
|
|
52
|
+
delorean_fn :lookup, sig: 1 do |name|
|
|
54
53
|
p = select(get_struct_attrs).find_by_name(name)
|
|
55
54
|
make_openstruct(p)
|
|
56
55
|
end
|
|
57
56
|
|
|
58
|
-
delorean_fn :lookup_dt, sig: 1 do
|
|
59
|
-
|name|
|
|
57
|
+
delorean_fn :lookup_dt, sig: 1 do |name|
|
|
60
58
|
find_by_name(name).try(:created_dt)
|
|
61
59
|
end
|
|
62
60
|
|
|
63
|
-
delorean_fn :first_match, sig: [1, 2] do
|
|
64
|
-
|
|
65
|
-
raise "bad posting type" if
|
|
61
|
+
delorean_fn :first_match, sig: [1, 2] do |dt, posting_type = nil|
|
|
62
|
+
raise 'bad posting type' if
|
|
66
63
|
posting_type && !posting_type.is_a?(Marty::PostingType)
|
|
67
64
|
|
|
68
|
-
q = where(
|
|
65
|
+
q = where('created_dt <= ?', dt)
|
|
69
66
|
q = q.where(posting_type_id: posting_type.id) if posting_type
|
|
70
|
-
q.order(
|
|
67
|
+
q.order('created_dt DESC').first.attributes
|
|
71
68
|
end
|
|
72
69
|
|
|
73
|
-
def self.get_latest(limit, is_test=nil)
|
|
70
|
+
def self.get_latest(limit, is_test = nil)
|
|
74
71
|
# IMPORTANT: is_test arg is ignored (KEEP for backward compat.)
|
|
75
72
|
|
|
76
|
-
q=where("created_dt <> 'infinity'").
|
|
77
|
-
order(
|
|
73
|
+
q = where("created_dt <> 'infinity'").
|
|
74
|
+
order('created_dt DESC').limit(limit)
|
|
78
75
|
end
|
|
79
76
|
|
|
80
|
-
delorean_fn :get_latest_by_type, sig: [1, 2] do
|
|
81
|
-
|
|
82
|
-
raise
|
|
83
|
-
raise "bad posting types list" unless posting_types.is_a?(Array)
|
|
77
|
+
delorean_fn :get_latest_by_type, sig: [1, 2] do |limit, posting_types = []|
|
|
78
|
+
raise 'missing posting types list' unless posting_types
|
|
79
|
+
raise 'bad posting types list' unless posting_types.is_a?(Array)
|
|
84
80
|
|
|
85
|
-
q=joins(:posting_type).where("created_dt <> 'infinity'").
|
|
86
|
-
where(marty_posting_types: { name: posting_types }
|
|
81
|
+
q = joins(:posting_type).where("created_dt <> 'infinity'").
|
|
82
|
+
where(marty_posting_types: { name: posting_types }).
|
|
87
83
|
select(get_struct_attrs).
|
|
88
|
-
order(
|
|
89
|
-
q.map
|
|
84
|
+
order('created_dt DESC').limit(limit || 1)
|
|
85
|
+
q.map(&:attributes)
|
|
90
86
|
end
|
|
91
87
|
end
|
data/app/models/marty/promise.rb
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
class Marty::Promise < Marty::Base
|
|
2
|
-
|
|
3
2
|
# default timeout (seconds) to wait for promise values
|
|
4
3
|
DEFAULT_PROMISE_TIMEOUT = Rails.configuration.marty.promise_timeout || 30
|
|
5
4
|
|
|
6
5
|
# default timeout (seconds) to wait for jobs to start
|
|
7
6
|
DEFAULT_JOB_TIMEOUT = Rails.configuration.marty.job_timeout || 10
|
|
8
7
|
|
|
9
|
-
def result(force=false)
|
|
8
|
+
def result(force = false)
|
|
10
9
|
res = super()
|
|
11
10
|
Marty::Promise.load_result(res, force)
|
|
12
11
|
end
|
|
13
12
|
|
|
14
|
-
def self.load_result(obj, force=false)
|
|
13
|
+
def self.load_result(obj, force = false)
|
|
15
14
|
if force && obj.respond_to?(:__force__)
|
|
16
15
|
obj = obj.__force__
|
|
17
16
|
end
|
|
18
17
|
|
|
19
18
|
case obj
|
|
20
19
|
when Array
|
|
21
|
-
obj.map {|x| load_result(x, force)}
|
|
20
|
+
obj.map { |x| load_result(x, force) }
|
|
22
21
|
when Hash
|
|
23
22
|
p = obj['__promise__']
|
|
24
23
|
|
|
25
|
-
if p && obj.length==1
|
|
24
|
+
if p && obj.length == 1
|
|
26
25
|
load_result(Marty::PromiseProxy.new(*p), force)
|
|
27
26
|
else
|
|
28
27
|
obj.each_with_object({}) { |(k, v), h| h[k] = load_result(v, force) }
|
|
@@ -34,21 +33,19 @@ class Marty::Promise < Marty::Base
|
|
|
34
33
|
|
|
35
34
|
has_many :children,
|
|
36
35
|
foreign_key: 'parent_id',
|
|
37
|
-
class_name:
|
|
36
|
+
class_name: 'Marty::Promise',
|
|
38
37
|
dependent: :destroy
|
|
39
38
|
|
|
40
39
|
validates_presence_of :title
|
|
41
40
|
|
|
42
|
-
belongs_to :parent, class_name:
|
|
43
|
-
belongs_to :user, class_name:
|
|
41
|
+
belongs_to :parent, class_name: 'Marty::Promise'
|
|
42
|
+
belongs_to :user, class_name: 'Marty::User'
|
|
44
43
|
|
|
45
|
-
def self.cleanup(all=false)
|
|
46
|
-
begin
|
|
44
|
+
def self.cleanup(all = false)
|
|
47
45
|
where('start_dt < ? AND parent_id IS NULL',
|
|
48
46
|
DateTime.now - (all ? 0.hours : 4.hours)).destroy_all
|
|
49
|
-
|
|
47
|
+
rescue StandardError => exc
|
|
50
48
|
Marty::Util.logger.error("promise GC error: #{exc}")
|
|
51
|
-
end
|
|
52
49
|
end
|
|
53
50
|
|
|
54
51
|
def raw_conn
|
|
@@ -60,38 +57,38 @@ class Marty::Promise < Marty::Base
|
|
|
60
57
|
end
|
|
61
58
|
|
|
62
59
|
def set_start
|
|
63
|
-
if
|
|
60
|
+
if start_dt || result != {}
|
|
64
61
|
Marty::Util.logger.error("promise already started: #{self}")
|
|
65
62
|
return
|
|
66
63
|
end
|
|
67
64
|
|
|
68
65
|
# mark promise as started
|
|
69
66
|
self.start_dt = DateTime.now
|
|
70
|
-
|
|
67
|
+
save!
|
|
71
68
|
end
|
|
72
69
|
|
|
73
70
|
def set_result(res)
|
|
74
71
|
# log "SETRES #{Process.pid} #{self}"
|
|
75
72
|
|
|
76
73
|
# promise must have been started and not yet ended
|
|
77
|
-
if !
|
|
74
|
+
if !start_dt || end_dt || result != {}
|
|
78
75
|
# log "SETERR #{Process.pid} #{self}"
|
|
79
76
|
Marty::Util.logger.error("unexpected promise state: #{self}")
|
|
80
77
|
return
|
|
81
78
|
end
|
|
82
79
|
|
|
83
|
-
raise
|
|
80
|
+
raise 'bad result' unless res.is_a?(Hash)
|
|
84
81
|
|
|
85
|
-
self.status = res[
|
|
82
|
+
self.status = res['error'].nil?
|
|
86
83
|
self.result = res
|
|
87
84
|
|
|
88
85
|
# update title/format from result hash (somewhat hacky)
|
|
89
|
-
self.title = res[
|
|
90
|
-
self.cformat = res[
|
|
86
|
+
self.title = res['title'].to_s if res['title']
|
|
87
|
+
self.cformat = res['format'].to_s if res['format']
|
|
91
88
|
|
|
92
89
|
# mark promise as ended
|
|
93
90
|
self.end_dt = DateTime.now
|
|
94
|
-
|
|
91
|
+
save!
|
|
95
92
|
|
|
96
93
|
# log "NOTIFY #{Process.pid}"
|
|
97
94
|
pg_notify
|
|
@@ -106,11 +103,11 @@ class Marty::Promise < Marty::Base
|
|
|
106
103
|
# end
|
|
107
104
|
|
|
108
105
|
def wait_for_my_notify(timeout)
|
|
109
|
-
while true
|
|
106
|
+
while true
|
|
110
107
|
# FIXME: we keep using the same timeout. The timeout should be
|
|
111
108
|
# reduced by total time spent here.
|
|
112
109
|
n = raw_conn.wait_for_notify(timeout)
|
|
113
|
-
return n if !n || n=="promise_#{id}"
|
|
110
|
+
return n if !n || n == "promise_#{id}"
|
|
114
111
|
end
|
|
115
112
|
end
|
|
116
113
|
|
|
@@ -120,17 +117,17 @@ class Marty::Promise < Marty::Base
|
|
|
120
117
|
# seems to work.
|
|
121
118
|
|
|
122
119
|
# get latest uncached version
|
|
123
|
-
Marty::Promise.uncached {Marty::Promise.find(id)}
|
|
120
|
+
Marty::Promise.uncached { Marty::Promise.find(id) }
|
|
124
121
|
end
|
|
125
122
|
|
|
126
123
|
def self.job_by_id(job_id)
|
|
127
|
-
Delayed::Job.uncached {Delayed::Job.find_by_id(job_id)}
|
|
124
|
+
Delayed::Job.uncached { Delayed::Job.find_by_id(job_id) }
|
|
128
125
|
end
|
|
129
126
|
|
|
130
127
|
def work_off_job(job)
|
|
131
128
|
# Create a temporary worker to work off the job
|
|
132
129
|
Delayed::Job.where(id: job.id).
|
|
133
|
-
update_all(locked_at: Delayed::Job.db_time_now, locked_by:
|
|
130
|
+
update_all(locked_at: Delayed::Job.db_time_now, locked_by: 'Temp')
|
|
134
131
|
w = Delayed::Worker.new
|
|
135
132
|
w.run(job)
|
|
136
133
|
end
|
|
@@ -138,7 +135,7 @@ class Marty::Promise < Marty::Base
|
|
|
138
135
|
def wait_for_result(timeout)
|
|
139
136
|
# FIXME: Not sure that comparing result with empty hash if a good idea
|
|
140
137
|
# perhaps it's better to use .present? or .blank?
|
|
141
|
-
return
|
|
138
|
+
return result if result != {}
|
|
142
139
|
|
|
143
140
|
begin
|
|
144
141
|
# start listening on promise's notification
|
|
@@ -150,7 +147,8 @@ class Marty::Promise < Marty::Base
|
|
|
150
147
|
if !last.start_dt
|
|
151
148
|
job = Marty::Promise.job_by_id(last.job_id)
|
|
152
149
|
|
|
153
|
-
# FIXME: this block is needed since a lot of specs rely on
|
|
150
|
+
# FIXME: this block is needed since a lot of specs rely on
|
|
151
|
+
# delayed job being runned in the same thread as promise
|
|
154
152
|
# Can be deleted later and replaces with simple timeout below
|
|
155
153
|
if !job || job.locked_at
|
|
156
154
|
# job has been locked, so it looks like it started already
|
|
@@ -162,7 +160,7 @@ class Marty::Promise < Marty::Base
|
|
|
162
160
|
# log "OFF0 #{Process.pid} #{last}"
|
|
163
161
|
begin
|
|
164
162
|
work_off_job(job)
|
|
165
|
-
rescue => exc
|
|
163
|
+
rescue StandardError => exc
|
|
166
164
|
# log "OFFERR #{exc}"
|
|
167
165
|
res = Delorean::Engine.grok_runtime_exception(exc)
|
|
168
166
|
last.set_result(res)
|
|
@@ -179,7 +177,7 @@ class Marty::Promise < Marty::Base
|
|
|
179
177
|
# timeout error.
|
|
180
178
|
if !last.start_dt
|
|
181
179
|
# log "TO11 #{Process.pid} #{last}"
|
|
182
|
-
return {
|
|
180
|
+
return { 'error' => "promise #{last.id} timed out (never started)" }
|
|
183
181
|
end
|
|
184
182
|
end
|
|
185
183
|
|
|
@@ -192,7 +190,7 @@ class Marty::Promise < Marty::Base
|
|
|
192
190
|
last = latest
|
|
193
191
|
|
|
194
192
|
if !last.end_dt
|
|
195
|
-
return {
|
|
193
|
+
return { 'error' => "promise #{last.id} timed out (didn't end)" }
|
|
196
194
|
end
|
|
197
195
|
end
|
|
198
196
|
|
data/app/models/marty/script.rb
CHANGED
|
@@ -3,24 +3,23 @@ class Marty::Script < Marty::Base
|
|
|
3
3
|
|
|
4
4
|
validates_presence_of :name, :body
|
|
5
5
|
mcfly_validates_uniqueness_of :name
|
|
6
|
-
validates_format_of :name,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
6
|
+
validates_format_of :name,
|
|
7
|
+
with: /\A[A-Z][a-zA-Z0-9]*\z/,
|
|
8
|
+
message: I18n.t('script.save_error')
|
|
10
9
|
|
|
11
|
-
belongs_to :user, class_name:
|
|
10
|
+
belongs_to :user, class_name: 'Marty::User'
|
|
12
11
|
|
|
13
12
|
gen_mcfly_lookup :lookup, [:name], cache: true
|
|
14
13
|
|
|
15
14
|
# find script by name/tag (not cached)
|
|
16
|
-
def self.find_script(sname, tag=nil)
|
|
15
|
+
def self.find_script(sname, tag = nil)
|
|
17
16
|
tag = Marty::Tag.map_to_tag(tag)
|
|
18
17
|
Marty::Script.mcfly_pt(tag.created_dt).find_by(name: sname)
|
|
19
18
|
end
|
|
20
19
|
|
|
21
20
|
def find_tag
|
|
22
21
|
# find the first tag created after this script.
|
|
23
|
-
Marty::Tag.where(
|
|
22
|
+
Marty::Tag.where('created_dt >= ?', created_dt).order(:created_dt).first
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
def self.create_script(name, body)
|
|
@@ -31,7 +30,7 @@ class Marty::Script < Marty::Base
|
|
|
31
30
|
script
|
|
32
31
|
end
|
|
33
32
|
|
|
34
|
-
def self.load_a_script(sname, body, dt=nil)
|
|
33
|
+
def self.load_a_script(sname, body, dt = nil)
|
|
35
34
|
s = Marty::Script.find_by(obsoleted_dt: 'infinity', name: sname)
|
|
36
35
|
|
|
37
36
|
if !s
|
|
@@ -47,28 +46,27 @@ class Marty::Script < Marty::Base
|
|
|
47
46
|
end
|
|
48
47
|
end
|
|
49
48
|
|
|
50
|
-
def self.load_script_bodies(bodies, dt=nil)
|
|
51
|
-
bodies.each
|
|
52
|
-
|sname, body|
|
|
49
|
+
def self.load_script_bodies(bodies, dt = nil)
|
|
50
|
+
bodies.each do |sname, body|
|
|
53
51
|
load_a_script(sname, body, dt)
|
|
54
|
-
|
|
52
|
+
end
|
|
55
53
|
|
|
56
54
|
# Create a new tag if scripts were modified after the last tag
|
|
57
55
|
tag = Marty::Tag.get_latest1
|
|
58
|
-
latest = Marty::Script.order(
|
|
56
|
+
latest = Marty::Script.order('created_dt DESC').first
|
|
59
57
|
|
|
60
58
|
tag_time = (dt || [latest.try(:created_dt), Time.now].compact.max) +
|
|
61
59
|
1.second
|
|
62
60
|
|
|
63
61
|
# If no tag_time is provided, the tag created_dt will be the same
|
|
64
62
|
# as the scripts.
|
|
65
|
-
tag = Marty::Tag.do_create(tag_time,
|
|
63
|
+
tag = Marty::Tag.do_create(tag_time, 'tagged from load scripts') if
|
|
66
64
|
!(tag && latest) || tag.created_dt <= latest.created_dt
|
|
67
65
|
|
|
68
66
|
tag
|
|
69
67
|
end
|
|
70
68
|
|
|
71
|
-
def self.load_scripts(path=nil, dt=nil)
|
|
69
|
+
def self.load_scripts(path = nil, dt = nil)
|
|
72
70
|
files = get_script_filenames(path)
|
|
73
71
|
|
|
74
72
|
bodies = read_script_files(files)
|
|
@@ -77,10 +75,10 @@ class Marty::Script < Marty::Base
|
|
|
77
75
|
end
|
|
78
76
|
|
|
79
77
|
def self.read_script_files(files)
|
|
80
|
-
files.collect
|
|
78
|
+
files.collect do |fpath|
|
|
81
79
|
fname = File.basename(fpath)[0..-4].camelize
|
|
82
80
|
[fname, File.read(fpath)]
|
|
83
|
-
|
|
81
|
+
end
|
|
84
82
|
end
|
|
85
83
|
|
|
86
84
|
def self.get_script_filenames(paths = nil)
|
|
@@ -90,7 +88,7 @@ class Marty::Script < Marty::Base
|
|
|
90
88
|
paths.each do |path|
|
|
91
89
|
Dir.glob("#{path}/*.dl").each do |filename|
|
|
92
90
|
basename = File.basename(filename)
|
|
93
|
-
filenames[basename] = filename unless filenames.
|
|
91
|
+
filenames[basename] = filename unless filenames.key?(basename)
|
|
94
92
|
end
|
|
95
93
|
end
|
|
96
94
|
|
|
@@ -114,15 +112,15 @@ class Marty::Script < Marty::Base
|
|
|
114
112
|
|
|
115
113
|
def self.delete_scripts
|
|
116
114
|
ActiveRecord::Base.connection.
|
|
117
|
-
execute(
|
|
115
|
+
execute('ALTER TABLE marty_scripts DISABLE TRIGGER USER;')
|
|
118
116
|
Marty::Script.delete_all
|
|
119
117
|
ActiveRecord::Base.connection.
|
|
120
|
-
execute(
|
|
118
|
+
execute('ALTER TABLE marty_scripts ENABLE TRIGGER USER;')
|
|
121
119
|
end
|
|
122
120
|
|
|
123
|
-
delorean_fn :eval_to_hash, sig: 5 do
|
|
124
|
-
|
|
125
|
-
|
|
121
|
+
delorean_fn :eval_to_hash, sig: 5 do |dt, script, node, attrs, params|
|
|
122
|
+
tag = Marty::Tag.find_match(dt) if dt.present?
|
|
123
|
+
raise("no tag for #{dt}") if tag.nil? && dt.present?
|
|
126
124
|
|
|
127
125
|
engine = Marty::ScriptSet.new(tag).get_engine(script)
|
|
128
126
|
# IMPORTANT: engine evals (e.g. eval_to_hash) modify the
|
|
@@ -134,11 +132,16 @@ class Marty::Script < Marty::Base
|
|
|
134
132
|
# current tag can caused problems.
|
|
135
133
|
end
|
|
136
134
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
# evaluate script's node attribute (attr) with the given params. dt
|
|
136
|
+
# is used to determine which script tag to use. The latest tag is
|
|
137
|
+
# used if dt is nil.
|
|
138
|
+
delorean_fn :evaluate, sig: 5 do |dt, script, node, attr, params|
|
|
139
|
+
tag = Marty::Tag.find_match(dt) if dt.present?
|
|
140
|
+
raise("no tag for #{dt}") if tag.nil? && dt.present?
|
|
140
141
|
|
|
142
|
+
# nil tag, uses the latest one
|
|
141
143
|
engine = Marty::ScriptSet.new(tag).get_engine(script)
|
|
144
|
+
|
|
142
145
|
# IMPORTANT: engine evals (e.g. eval_to_hash) modify the
|
|
143
146
|
# params, but it is possible that we may be passing in
|
|
144
147
|
# a frozen hash. To avoid performance impacts, we should first check if
|
|
@@ -146,8 +149,7 @@ class Marty::Script < Marty::Base
|
|
|
146
149
|
engine.evaluate(node, attr, params.frozen? ? params.dup : params.clone)
|
|
147
150
|
end
|
|
148
151
|
|
|
149
|
-
delorean_fn :pretty_print, sig: 1 do
|
|
150
|
-
|id|
|
|
152
|
+
delorean_fn :pretty_print, sig: 1 do |id|
|
|
151
153
|
script = find_by_id id
|
|
152
154
|
|
|
153
155
|
next "unknown script #{id}" unless script
|