marty 0.5.12
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +84 -0
- data/Rakefile +29 -0
- data/app/assets/javascripts/marty/application.js +15 -0
- data/app/assets/stylesheets/marty/application.css +13 -0
- data/app/components/marty/api_auth_view.rb +32 -0
- data/app/components/marty/auth_app.rb +55 -0
- data/app/components/marty/auth_app.rb~ +51 -0
- data/app/components/marty/auth_app/javascripts/auth_app.js +91 -0
- data/app/components/marty/auth_app/javascripts/auth_app.js~ +91 -0
- data/app/components/marty/cm_form_panel.rb~ +5 -0
- data/app/components/marty/cm_grid_panel.rb~ +35 -0
- data/app/components/marty/data_import_view.rb~ +142 -0
- data/app/components/marty/extras/layout.rb +46 -0
- data/app/components/marty/extras/layout.rb~ +46 -0
- data/app/components/marty/extras/misc.rb +18 -0
- data/app/components/marty/form.rb +6 -0
- data/app/components/marty/grid.rb +45 -0
- data/app/components/marty/grid_append_only.rb +12 -0
- data/app/components/marty/import_type_view.rb +53 -0
- data/app/components/marty/live_search_grid_panel.rb +46 -0
- data/app/components/marty/live_search_grid_panel.rb~ +49 -0
- data/app/components/marty/main_auth_app.rb +269 -0
- data/app/components/marty/main_auth_app.rb~ +238 -0
- data/app/components/marty/mcfly_grid_panel.rb +62 -0
- data/app/components/marty/mcfly_grid_panel.rb~ +80 -0
- data/app/components/marty/new_posting_form.rb +46 -0
- data/app/components/marty/new_posting_form.rb~ +46 -0
- data/app/components/marty/new_posting_window.rb +21 -0
- data/app/components/marty/new_posting_window.rb~ +21 -0
- data/app/components/marty/panel.rb +12 -0
- data/app/components/marty/pivot_grid.rb +52 -0
- data/app/components/marty/pivot_grid/endpoints.rb +45 -0
- data/app/components/marty/pivot_grid/javascripts/extensions.js +150 -0
- data/app/components/marty/pivot_grid/javascripts/pivot_grid.js +86 -0
- data/app/components/marty/pivot_grid/services.rb +44 -0
- data/app/components/marty/posting_grid.rb +139 -0
- data/app/components/marty/posting_grid.rb~ +140 -0
- data/app/components/marty/posting_window.rb +27 -0
- data/app/components/marty/promise_view.rb +177 -0
- data/app/components/marty/promise_view.rb~ +157 -0
- data/app/components/marty/promise_view/stylesheets/promise_view.css +26 -0
- data/app/components/marty/promise_view/stylesheets/promise_view.css~ +15 -0
- data/app/components/marty/report_form.rb +225 -0
- data/app/components/marty/report_form.rb~ +217 -0
- data/app/components/marty/report_select.rb +145 -0
- data/app/components/marty/report_select.rb~ +133 -0
- data/app/components/marty/reporting.rb +39 -0
- data/app/components/marty/reporting.rb~ +39 -0
- data/app/components/marty/script_detail.rb~ +430 -0
- data/app/components/marty/script_form.rb +233 -0
- data/app/components/marty/script_form.rb~ +233 -0
- data/app/components/marty/script_form/javascripts/Ext.ux.form.field.CodeMirror.js +698 -0
- data/app/components/marty/script_form/javascripts/Ext.ux.form.field.CodeMirror.js~ +909 -0
- data/app/components/marty/script_form/javascripts/codemirror.js +3130 -0
- data/app/components/marty/script_form/javascripts/mode/clike/clike.js +284 -0
- data/app/components/marty/script_form/javascripts/mode/clike/index.html +102 -0
- data/app/components/marty/script_form/javascripts/mode/clike/scala.html +766 -0
- data/app/components/marty/script_form/javascripts/mode/clojure/clojure.js +206 -0
- data/app/components/marty/script_form/javascripts/mode/clojure/index.html +67 -0
- data/app/components/marty/script_form/javascripts/mode/coffeescript/LICENSE +22 -0
- data/app/components/marty/script_form/javascripts/mode/coffeescript/coffeescript.js +346 -0
- data/app/components/marty/script_form/javascripts/mode/coffeescript/index.html +728 -0
- data/app/components/marty/script_form/javascripts/mode/commonlisp/commonlisp.js +101 -0
- data/app/components/marty/script_form/javascripts/mode/commonlisp/index.html +165 -0
- data/app/components/marty/script_form/javascripts/mode/css/css.js +448 -0
- data/app/components/marty/script_form/javascripts/mode/css/index.html +58 -0
- data/app/components/marty/script_form/javascripts/mode/css/test.js +501 -0
- data/app/components/marty/script_form/javascripts/mode/delorean/delorean.js +189 -0
- data/app/components/marty/script_form/javascripts/mode/diff/diff.js +32 -0
- data/app/components/marty/script_form/javascripts/mode/diff/index.html +105 -0
- data/app/components/marty/script_form/javascripts/mode/ecl/ecl.js +203 -0
- data/app/components/marty/script_form/javascripts/mode/ecl/index.html +42 -0
- data/app/components/marty/script_form/javascripts/mode/erlang/erlang.js +463 -0
- data/app/components/marty/script_form/javascripts/mode/erlang/index.html +63 -0
- data/app/components/marty/script_form/javascripts/mode/gfm/gfm.js +150 -0
- data/app/components/marty/script_form/javascripts/mode/gfm/index.html +48 -0
- data/app/components/marty/script_form/javascripts/mode/go/go.js +170 -0
- data/app/components/marty/script_form/javascripts/mode/go/index.html +73 -0
- data/app/components/marty/script_form/javascripts/mode/groovy/groovy.js +210 -0
- data/app/components/marty/script_form/javascripts/mode/groovy/index.html +72 -0
- data/app/components/marty/script_form/javascripts/mode/haskell/haskell.js +242 -0
- data/app/components/marty/script_form/javascripts/mode/haskell/index.html +61 -0
- data/app/components/marty/script_form/javascripts/mode/haxe/haxe.js +429 -0
- data/app/components/marty/script_form/javascripts/mode/haxe/index.html +91 -0
- data/app/components/marty/script_form/javascripts/mode/htmlembedded/htmlembedded.js +72 -0
- data/app/components/marty/script_form/javascripts/mode/htmlembedded/index.html +50 -0
- data/app/components/marty/script_form/javascripts/mode/htmlmixed/htmlmixed.js +84 -0
- data/app/components/marty/script_form/javascripts/mode/htmlmixed/index.html +52 -0
- data/app/components/marty/script_form/javascripts/mode/javascript/index.html +78 -0
- data/app/components/marty/script_form/javascripts/mode/javascript/javascript.js +361 -0
- data/app/components/marty/script_form/javascripts/mode/jinja2/index.html +38 -0
- data/app/components/marty/script_form/javascripts/mode/jinja2/jinja2.js +42 -0
- data/app/components/marty/script_form/javascripts/mode/less/index.html +740 -0
- data/app/components/marty/script_form/javascripts/mode/less/less.js +266 -0
- data/app/components/marty/script_form/javascripts/mode/lua/index.html +73 -0
- data/app/components/marty/script_form/javascripts/mode/lua/lua.js +140 -0
- data/app/components/marty/script_form/javascripts/mode/markdown/index.html +343 -0
- data/app/components/marty/script_form/javascripts/mode/markdown/markdown.js +382 -0
- data/app/components/marty/script_form/javascripts/mode/markdown/test.js +1084 -0
- data/app/components/marty/script_form/javascripts/mode/mysql/index.html +42 -0
- data/app/components/marty/script_form/javascripts/mode/mysql/mysql.js +186 -0
- data/app/components/marty/script_form/javascripts/mode/ntriples/index.html +33 -0
- data/app/components/marty/script_form/javascripts/mode/ntriples/ntriples.js +172 -0
- data/app/components/marty/script_form/javascripts/mode/ocaml/index.html +130 -0
- data/app/components/marty/script_form/javascripts/mode/ocaml/ocaml.js +114 -0
- data/app/components/marty/script_form/javascripts/mode/pascal/LICENSE +7 -0
- data/app/components/marty/script_form/javascripts/mode/pascal/index.html +49 -0
- data/app/components/marty/script_form/javascripts/mode/pascal/pascal.js +94 -0
- data/app/components/marty/script_form/javascripts/mode/perl/LICENSE +19 -0
- data/app/components/marty/script_form/javascripts/mode/perl/index.html +63 -0
- data/app/components/marty/script_form/javascripts/mode/perl/perl.js +816 -0
- data/app/components/marty/script_form/javascripts/mode/php/index.html +49 -0
- data/app/components/marty/script_form/javascripts/mode/php/php.js +148 -0
- data/app/components/marty/script_form/javascripts/mode/pig/index.html +43 -0
- data/app/components/marty/script_form/javascripts/mode/pig/pig.js +172 -0
- data/app/components/marty/script_form/javascripts/mode/plsql/index.html +63 -0
- data/app/components/marty/script_form/javascripts/mode/plsql/plsql.js +217 -0
- data/app/components/marty/script_form/javascripts/mode/properties/index.html +41 -0
- data/app/components/marty/script_form/javascripts/mode/properties/properties.js +63 -0
- data/app/components/marty/script_form/javascripts/mode/python/LICENSE.txt +21 -0
- data/app/components/marty/script_form/javascripts/mode/python/index.html +123 -0
- data/app/components/marty/script_form/javascripts/mode/python/python.js +338 -0
- data/app/components/marty/script_form/javascripts/mode/r/LICENSE +24 -0
- data/app/components/marty/script_form/javascripts/mode/r/index.html +74 -0
- data/app/components/marty/script_form/javascripts/mode/r/r.js +141 -0
- data/app/components/marty/script_form/javascripts/mode/rpm/changes/changes.js +19 -0
- data/app/components/marty/script_form/javascripts/mode/rpm/changes/index.html +54 -0
- data/app/components/marty/script_form/javascripts/mode/rpm/spec/index.html +100 -0
- data/app/components/marty/script_form/javascripts/mode/rpm/spec/spec.css +5 -0
- data/app/components/marty/script_form/javascripts/mode/rpm/spec/spec.js +66 -0
- data/app/components/marty/script_form/javascripts/mode/rst/index.html +526 -0
- data/app/components/marty/script_form/javascripts/mode/rst/rst.js +326 -0
- data/app/components/marty/script_form/javascripts/mode/ruby/LICENSE +24 -0
- data/app/components/marty/script_form/javascripts/mode/ruby/index.html +172 -0
- data/app/components/marty/script_form/javascripts/mode/ruby/ruby.js +195 -0
- data/app/components/marty/script_form/javascripts/mode/rust/index.html +49 -0
- data/app/components/marty/script_form/javascripts/mode/rust/rust.js +432 -0
- data/app/components/marty/script_form/javascripts/mode/scheme/index.html +65 -0
- data/app/components/marty/script_form/javascripts/mode/scheme/scheme.js +230 -0
- data/app/components/marty/script_form/javascripts/mode/shell/index.html +50 -0
- data/app/components/marty/script_form/javascripts/mode/shell/shell.js +118 -0
- data/app/components/marty/script_form/javascripts/mode/sieve/LICENSE +23 -0
- data/app/components/marty/script_form/javascripts/mode/sieve/index.html +81 -0
- data/app/components/marty/script_form/javascripts/mode/sieve/sieve.js +156 -0
- data/app/components/marty/script_form/javascripts/mode/smalltalk/index.html +56 -0
- data/app/components/marty/script_form/javascripts/mode/smalltalk/smalltalk.js +139 -0
- data/app/components/marty/script_form/javascripts/mode/smarty/index.html +83 -0
- data/app/components/marty/script_form/javascripts/mode/smarty/smarty.js +148 -0
- data/app/components/marty/script_form/javascripts/mode/sparql/index.html +41 -0
- data/app/components/marty/script_form/javascripts/mode/sparql/sparql.js +143 -0
- data/app/components/marty/script_form/javascripts/mode/stex/index.html +98 -0
- data/app/components/marty/script_form/javascripts/mode/stex/stex.js +182 -0
- data/app/components/marty/script_form/javascripts/mode/stex/test.js +343 -0
- data/app/components/marty/script_form/javascripts/mode/tiddlywiki/index.html +141 -0
- data/app/components/marty/script_form/javascripts/mode/tiddlywiki/tiddlywiki.css +14 -0
- data/app/components/marty/script_form/javascripts/mode/tiddlywiki/tiddlywiki.js +384 -0
- data/app/components/marty/script_form/javascripts/mode/tiki/index.html +83 -0
- data/app/components/marty/script_form/javascripts/mode/tiki/tiki.css +26 -0
- data/app/components/marty/script_form/javascripts/mode/tiki/tiki.js +309 -0
- data/app/components/marty/script_form/javascripts/mode/vb/LICENSE.txt +21 -0
- data/app/components/marty/script_form/javascripts/mode/vb/index.html +89 -0
- data/app/components/marty/script_form/javascripts/mode/vb/vb.js +260 -0
- data/app/components/marty/script_form/javascripts/mode/vbscript/index.html +43 -0
- data/app/components/marty/script_form/javascripts/mode/vbscript/vbscript.js +26 -0
- data/app/components/marty/script_form/javascripts/mode/velocity/index.html +104 -0
- data/app/components/marty/script_form/javascripts/mode/velocity/velocity.js +146 -0
- data/app/components/marty/script_form/javascripts/mode/verilog/index.html +211 -0
- data/app/components/marty/script_form/javascripts/mode/verilog/verilog.js +194 -0
- data/app/components/marty/script_form/javascripts/mode/xml/index.html +45 -0
- data/app/components/marty/script_form/javascripts/mode/xml/xml.js +318 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/LICENSE +20 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/index.html +223 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/test/index.html +27 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/test/testBase.js +42 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/test/testEmptySequenceKeyword.js +16 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/test/testMultiAttr.js +16 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/test/testNamespaces.js +91 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/test/testProcessingInstructions.js +16 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/test/testQuotes.js +19 -0
- data/app/components/marty/script_form/javascripts/mode/xquery/xquery.js +451 -0
- data/app/components/marty/script_form/javascripts/mode/yaml/index.html +68 -0
- data/app/components/marty/script_form/javascripts/mode/yaml/yaml.js +95 -0
- data/app/components/marty/script_form/javascripts/util/closetag.js +164 -0
- data/app/components/marty/script_form/javascripts/util/dialog.css +27 -0
- data/app/components/marty/script_form/javascripts/util/dialog.js +70 -0
- data/app/components/marty/script_form/javascripts/util/foldcode.js +196 -0
- data/app/components/marty/script_form/javascripts/util/formatting.js +193 -0
- data/app/components/marty/script_form/javascripts/util/javascript-hint.js +134 -0
- data/app/components/marty/script_form/javascripts/util/loadmode.js +51 -0
- data/app/components/marty/script_form/javascripts/util/match-highlighter.js +44 -0
- data/app/components/marty/script_form/javascripts/util/multiplex.js +77 -0
- data/app/components/marty/script_form/javascripts/util/overlay.js +54 -0
- data/app/components/marty/script_form/javascripts/util/pig-hint.js +123 -0
- data/app/components/marty/script_form/javascripts/util/runmode-standalone.js +90 -0
- data/app/components/marty/script_form/javascripts/util/runmode.js +53 -0
- data/app/components/marty/script_form/javascripts/util/search.js +118 -0
- data/app/components/marty/script_form/javascripts/util/searchcursor.js +119 -0
- data/app/components/marty/script_form/javascripts/util/simple-hint.css +16 -0
- data/app/components/marty/script_form/javascripts/util/simple-hint.js +97 -0
- data/app/components/marty/script_form/javascripts/util/xml-hint.js +137 -0
- data/app/components/marty/script_form/stylesheets/codemirror.css +172 -0
- data/app/components/marty/script_form/stylesheets/delorean.css +10 -0
- data/app/components/marty/script_form/stylesheets/theme/ambiance.css +81 -0
- data/app/components/marty/script_form/stylesheets/theme/blackboard.css +25 -0
- data/app/components/marty/script_form/stylesheets/theme/cobalt.css +18 -0
- data/app/components/marty/script_form/stylesheets/theme/eclipse.css +25 -0
- data/app/components/marty/script_form/stylesheets/theme/elegant.css +10 -0
- data/app/components/marty/script_form/stylesheets/theme/erlang-dark.css +21 -0
- data/app/components/marty/script_form/stylesheets/theme/lesser-dark.css +44 -0
- data/app/components/marty/script_form/stylesheets/theme/monokai.css +28 -0
- data/app/components/marty/script_form/stylesheets/theme/neat.css +9 -0
- data/app/components/marty/script_form/stylesheets/theme/night.css +21 -0
- data/app/components/marty/script_form/stylesheets/theme/rubyblue.css +21 -0
- data/app/components/marty/script_form/stylesheets/theme/vibrant-ink.css +27 -0
- data/app/components/marty/script_form/stylesheets/theme/xq-dark.css +46 -0
- data/app/components/marty/script_grid.rb +104 -0
- data/app/components/marty/script_grid.rb~ +99 -0
- data/app/components/marty/script_tester.rb +114 -0
- data/app/components/marty/script_tester.rb~ +213 -0
- data/app/components/marty/scripting.rb +132 -0
- data/app/components/marty/scripting.rb~ +124 -0
- data/app/components/marty/select_report.rb~ +143 -0
- data/app/components/marty/simple_app.rb +97 -0
- data/app/components/marty/simple_app.rb~ +101 -0
- data/app/components/marty/simple_app/javascripts/simple_app.js +50 -0
- data/app/components/marty/simple_app/javascripts/statusbar_ext.js +8 -0
- data/app/components/marty/tag_grid.rb +83 -0
- data/app/components/marty/tag_grid.rb~ +89 -0
- data/app/components/marty/tree_panel.rb~ +256 -0
- data/app/components/marty/tree_panel/javascripts/tree_panel.js~ +317 -0
- data/app/components/marty/user_pivot.rb +128 -0
- data/app/components/marty/user_view.rb +181 -0
- data/app/components/marty/user_view.rb~ +188 -0
- data/app/controllers/marty/application_controller.rb +124 -0
- data/app/controllers/marty/application_controller.rb~ +133 -0
- data/app/controllers/marty/components_controller.rb +41 -0
- data/app/controllers/marty/components_controller.rb~ +37 -0
- data/app/controllers/marty/job_controller.rb +28 -0
- data/app/controllers/marty/job_controller.rb~ +28 -0
- data/app/controllers/marty/rpc_controller.rb +64 -0
- data/app/controllers/marty/rpc_controller.rb~ +61 -0
- data/app/helpers/marty/application_helper.rb +4 -0
- data/app/helpers/marty/script_set.rb +57 -0
- data/app/helpers/marty/script_set.rb~ +59 -0
- data/app/models/marty/api_auth.rb +44 -0
- data/app/models/marty/api_auth.rb~ +48 -0
- data/app/models/marty/base.rb +4 -0
- data/app/models/marty/data_change.rb +179 -0
- data/app/models/marty/data_change.rb~ +141 -0
- data/app/models/marty/enum.rb +22 -0
- data/app/models/marty/enum.rb~ +16 -0
- data/app/models/marty/import_type.rb +44 -0
- data/app/models/marty/import_type.rb~ +48 -0
- data/app/models/marty/poop.rb~ +169 -0
- data/app/models/marty/posting.rb +101 -0
- data/app/models/marty/posting.rb~ +86 -0
- data/app/models/marty/posting_type.rb +12 -0
- data/app/models/marty/posting_type.rb~ +21 -0
- data/app/models/marty/promise.rb +252 -0
- data/app/models/marty/promise.rb~ +196 -0
- data/app/models/marty/role.rb +6 -0
- data/app/models/marty/role.rb~ +10 -0
- data/app/models/marty/script.rb +144 -0
- data/app/models/marty/script.rb~ +62 -0
- data/app/models/marty/tag.rb +96 -0
- data/app/models/marty/tag.rb~ +91 -0
- data/app/models/marty/token.rb +30 -0
- data/app/models/marty/user.rb +146 -0
- data/app/models/marty/user.rb~ +148 -0
- data/app/models/marty/user_role.rb +7 -0
- data/app/models/marty/user_role.rb~ +13 -0
- data/app/views/layouts/marty/application.html.erb +12 -0
- data/app/views/layouts/marty/application.html.erb~ +11 -0
- data/config/locales/en.yml +134 -0
- data/config/routes.rb +6 -0
- data/config/routes.rb~ +10 -0
- data/db/migrate/001_create_marty_scripts.rb +14 -0
- data/db/migrate/003_create_marty_users.rb +12 -0
- data/db/migrate/004_create_marty_roles.rb +7 -0
- data/db/migrate/005_create_marty_user_roles.rb +14 -0
- data/db/migrate/006_create_marty_tokens.rb +14 -0
- data/db/migrate/008_create_marty_posting_types.rb +7 -0
- data/db/migrate/019_create_marty_postings.rb +18 -0
- data/db/migrate/019_create_marty_postings.rb~ +19 -0
- data/db/migrate/068_create_marty_import_types.rb +12 -0
- data/db/migrate/069_create_marty_import_synonyms.rb +15 -0
- data/db/migrate/070_create_versions.rb +18 -0
- data/db/migrate/071_add_object_changes_column_to_versions.rb +9 -0
- data/db/migrate/072_add_validation_function_to_import_types.rb +6 -0
- data/db/migrate/073_add_preprocess_function_to_import_types.rb +5 -0
- data/db/migrate/090_create_delayed_jobs.rb +22 -0
- data/db/migrate/091_create_marty_promises.rb +36 -0
- data/db/migrate/095_create_marty_tags.rb +14 -0
- data/db/migrate/095_create_marty_tags.rb~ +19 -0
- data/db/migrate/096_add_user_roles_to_import_types.rb +11 -0
- data/db/migrate/097_drop_versions.rb +9 -0
- data/db/migrate/098_create_marty_api_auths.rb +20 -0
- data/db/seeds.rb +48 -0
- data/lib/marty.rb +18 -0
- data/lib/marty.rb~ +13 -0
- data/lib/marty/content_handler.rb +97 -0
- data/lib/marty/content_handler.rb~ +93 -0
- data/lib/marty/data_conversion.rb +298 -0
- data/lib/marty/data_exporter.rb +150 -0
- data/lib/marty/data_exporter.rb~ +137 -0
- data/lib/marty/data_importer.rb +122 -0
- data/lib/marty/data_importer.rb~ +114 -0
- data/lib/marty/data_row_processor.rb~ +206 -0
- data/lib/marty/drop_folder_hook.rb~ +17 -0
- data/lib/marty/engine.rb +10 -0
- data/lib/marty/folder_hook.rb~ +9 -0
- data/lib/marty/lazy_column_loader.rb +57 -0
- data/lib/marty/lazy_column_loader.rb~ +47 -0
- data/lib/marty/mcfly_query.rb +189 -0
- data/lib/marty/mcfly_query.rb~ +188 -0
- data/lib/marty/migrations.rb +108 -0
- data/lib/marty/migrations.rb~ +65 -0
- data/lib/marty/monkey.rb +163 -0
- data/lib/marty/monkey.rb~ +160 -0
- data/lib/marty/permissions.rb +64 -0
- data/lib/marty/permissions.rb~ +69 -0
- data/lib/marty/promise.rb~ +41 -0
- data/lib/marty/promise_job.rb +123 -0
- data/lib/marty/promise_job.rb~ +121 -0
- data/lib/marty/promise_proxy.rb +94 -0
- data/lib/marty/promise_proxy.rb~ +69 -0
- data/lib/marty/railtie.rb +5 -0
- data/lib/marty/relation.rb +39 -0
- data/lib/marty/util.rb +110 -0
- data/lib/marty/util.rb~ +80 -0
- data/lib/marty/version.rb +3 -0
- data/lib/marty/version.rb~ +3 -0
- data/lib/marty/xl.rb +527 -0
- data/lib/marty/xl.rb~ +526 -0
- data/lib/pyxll/README.txt +19 -0
- data/lib/pyxll/README.txt~ +16 -0
- data/lib/pyxll/gemini.py +155 -0
- data/lib/pyxll/gemini.py~ +110 -0
- data/lib/pyxll/pyxll.cfg +12 -0
- data/lib/pyxll/pyxll.cfg~ +12 -0
- data/lib/pyxll/sample.xlsx +0 -0
- data/lib/tasks/marty_tasks.rake +37 -0
- metadata +517 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
class Marty::Promise < Marty::Base
|
|
2
|
+
|
|
3
|
+
# default timeout (seconds) to wait for promise values
|
|
4
|
+
DEFAULT_PROMISE_TIMEOUT = 30
|
|
5
|
+
|
|
6
|
+
# default timeout (seconds) to wait for jobs to start
|
|
7
|
+
DEFAULT_JOB_TIMEOUT = 10
|
|
8
|
+
|
|
9
|
+
attr_accessible :title,
|
|
10
|
+
:cformat,
|
|
11
|
+
:parent_id,
|
|
12
|
+
:job_id,
|
|
13
|
+
:status,
|
|
14
|
+
:result,
|
|
15
|
+
:start_dt,
|
|
16
|
+
:end_dt
|
|
17
|
+
|
|
18
|
+
serialize :result, Hash
|
|
19
|
+
|
|
20
|
+
validates_presence_of :title
|
|
21
|
+
|
|
22
|
+
has_many :children, foreign_key: 'parent_id', class_name: "Marty::Promise"
|
|
23
|
+
belongs_to :parent, class_name: "Marty::Promise"
|
|
24
|
+
|
|
25
|
+
def raw_conn
|
|
26
|
+
self.class.connection.raw_connection
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def pg_notify
|
|
30
|
+
raw_conn.async_exec("NOTIFY promise_#{id}")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def set_start
|
|
34
|
+
log "LOGLOG #{Rails.logger}"
|
|
35
|
+
|
|
36
|
+
if self.start_dt || self.result != {}
|
|
37
|
+
Marty::Util.logger.error("promise already started: #{self}")
|
|
38
|
+
return
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# mark promise as started
|
|
42
|
+
self.start_dt = DateTime.now
|
|
43
|
+
self.save!
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def set_result(res)
|
|
47
|
+
log "SETRES #{Process.pid} #{res} #{self}"
|
|
48
|
+
|
|
49
|
+
# promise must have been started and not yet ended
|
|
50
|
+
if !self.start_dt || self.end_dt || self.result != {}
|
|
51
|
+
log "SETERR #{Process.pid} #{self}"
|
|
52
|
+
Marty::Util.logger.error("unexpected promise state: #{self}")
|
|
53
|
+
return
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
raise "bad result" unless res.is_a?(Hash)
|
|
57
|
+
|
|
58
|
+
self.status = res["error"].nil?
|
|
59
|
+
self.result = res
|
|
60
|
+
|
|
61
|
+
# update title/format from result hash (somewhat hacky)
|
|
62
|
+
self.title = res["title"].to_s if res["title"]
|
|
63
|
+
self.cformat = res["format"].to_s if res["format"]
|
|
64
|
+
|
|
65
|
+
# mark promise as ended
|
|
66
|
+
self.end_dt = DateTime.now
|
|
67
|
+
self.save!
|
|
68
|
+
|
|
69
|
+
log "NOTIFY #{Process.pid}"
|
|
70
|
+
pg_notify
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def to_s
|
|
74
|
+
inspect
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def log(msg)
|
|
78
|
+
open('/tmp/dj.out', 'a') { |f| f.puts msg }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def wait_for_my_notify(timeout)
|
|
82
|
+
while true do
|
|
83
|
+
# FIXME: we keep using the same timeout. The timeout should be
|
|
84
|
+
# reduced by total time spent here.
|
|
85
|
+
n = raw_conn.wait_for_notify(timeout)
|
|
86
|
+
return n if !n || n=="promise_#{id}"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def latest
|
|
91
|
+
# latest uncached version
|
|
92
|
+
Marty::Promise.uncached {Marty::Promise.find(id)}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def work_off_job(job)
|
|
96
|
+
# Create a temporary worker to work off the job
|
|
97
|
+
Delayed::Job.where(id: job.id).
|
|
98
|
+
update_all(locked_at: Delayed::Job.db_time_now, locked_by: "Temp")
|
|
99
|
+
w = Delayed::Worker.new
|
|
100
|
+
w.run(job)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def wait_for_result(timeout)
|
|
104
|
+
return self.result if self.result != {}
|
|
105
|
+
|
|
106
|
+
# FIXME: instead of using latest(), should look at how delayed
|
|
107
|
+
# jobs are loaded. i.e. use reset+reload.
|
|
108
|
+
|
|
109
|
+
begin
|
|
110
|
+
# start listening on promise's notification
|
|
111
|
+
raw_conn.exec("LISTEN promise_#{id}")
|
|
112
|
+
|
|
113
|
+
last = latest
|
|
114
|
+
|
|
115
|
+
# if job hasn't started yet, wait for it to start
|
|
116
|
+
if !last.start_dt
|
|
117
|
+
log "AAAA #{Process.pid} #{last}"
|
|
118
|
+
|
|
119
|
+
job = Delayed::Job.find_by_id(last.job_id)
|
|
120
|
+
job.reload if job # paranoid
|
|
121
|
+
|
|
122
|
+
if !job && job.locked_at
|
|
123
|
+
# job has been locked, so it looks like it started already
|
|
124
|
+
# and we need to wait for it.
|
|
125
|
+
wait_for_my_notify(Marty::Promise::DEFAULT_JOB_TIMEOUT)
|
|
126
|
+
else
|
|
127
|
+
# work off the job instead of waiting for a real worker to
|
|
128
|
+
# pick it up.
|
|
129
|
+
log "OFFF #{Process.pid} #{last}"
|
|
130
|
+
work_off_job(job)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
last = latest
|
|
134
|
+
|
|
135
|
+
# we waited for it but it never started. So, mark it with a
|
|
136
|
+
# timeout error.
|
|
137
|
+
if !last.start_dt
|
|
138
|
+
log "TO11 #{Process.pid} #{last}"
|
|
139
|
+
return {"error" => "promise #{last.id} timed out (never started)"}
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# reload promise in case out copy doesn't have a result yet
|
|
144
|
+
last = latest unless last.end_dt
|
|
145
|
+
|
|
146
|
+
# at this point, we know the promise has already started
|
|
147
|
+
if !last.end_dt
|
|
148
|
+
wait_for_my_notify(timeout)
|
|
149
|
+
log "UUUU #{Process.pid} #{id} #{Time.now.to_f}"
|
|
150
|
+
last = latest
|
|
151
|
+
|
|
152
|
+
log "XXXX #{Process.pid} #{Time.now.to_f} #{last}"
|
|
153
|
+
|
|
154
|
+
if !last.end_dt
|
|
155
|
+
log "TO22 #{Process.pid} #{last}"
|
|
156
|
+
return {"error" => "promise #{last.id} timed out (didn't end)"}
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
log "RRRR #{Process.pid} #{last} #{Time.now.to_f}"
|
|
161
|
+
|
|
162
|
+
last.result
|
|
163
|
+
ensure
|
|
164
|
+
# Stop listening to the promise notifications
|
|
165
|
+
raw_conn.exec("UNLISTEN promise_#{id}")
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
class Marty::Posting < Marty::Base
|
|
2
|
+
has_mcfly append_only: true
|
|
3
|
+
|
|
4
|
+
mcfly_validates_uniqueness_of :name
|
|
5
|
+
validates_presence_of :name, :posting_type_id, :comment
|
|
6
|
+
|
|
7
|
+
belongs_to :user, class_name: "Marty::User"
|
|
8
|
+
belongs_to :posting_type
|
|
9
|
+
|
|
10
|
+
def self.make_name(posting_type, dt)
|
|
11
|
+
return 'NOW' if Mcfly.is_infinity(dt)
|
|
12
|
+
|
|
13
|
+
return unless posting_type
|
|
14
|
+
|
|
15
|
+
# If no dt is provided (which is the usual non-testing case), we
|
|
16
|
+
# use Time.now.strftime to name the posting. This has the effect
|
|
17
|
+
# of using the host's timezone. i.e. since we're in PST8PDT, names
|
|
18
|
+
# will be based off of the Pacific TZ.
|
|
19
|
+
dt ||= Time.now
|
|
20
|
+
"#{posting_type.name}-#{dt.strftime('%Y%m%d-%H%M')}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
before_validation :set_posting_name
|
|
24
|
+
def set_posting_name
|
|
25
|
+
posting_type = Marty::PostingType.find_by_id(self.posting_type_id)
|
|
26
|
+
self.name = self.class.make_name(posting_type, self.created_dt)
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.do_create(type_name, dt, comment)
|
|
31
|
+
posting_type = Marty::PostingType.find_by_name(type_name)
|
|
32
|
+
|
|
33
|
+
raise "unknown posting type #{name}" unless posting_type
|
|
34
|
+
|
|
35
|
+
o = new
|
|
36
|
+
o.posting_type = posting_type
|
|
37
|
+
o.comment = comment
|
|
38
|
+
o.created_dt = dt
|
|
39
|
+
o.save!
|
|
40
|
+
o
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Not using mcfly_lookup since we don't want these time-warp markers
|
|
44
|
+
# time-warped. FIXME: perhaps this should use mcfly_lookup since we
|
|
45
|
+
# may allow deletion of postings. i.e. a new one with same name
|
|
46
|
+
# might be created. Or, use regular validates_uniqueness_of instead
|
|
47
|
+
# of mcfly_validates_uniqueness_of.
|
|
48
|
+
delorean_fn :lookup, sig: 1 do
|
|
49
|
+
|name|
|
|
50
|
+
self.find_by_name(name)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
delorean_fn :lookup_dt, sig: 1 do
|
|
54
|
+
|name|
|
|
55
|
+
lookup(name).try(:created_dt)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
delorean_fn :first_match, sig: [1, 2] do
|
|
59
|
+
|dt, posting_type=nil|
|
|
60
|
+
raise "bad posting type" if
|
|
61
|
+
posting_type && !posting_type.is_a?(Marty::PostingType)
|
|
62
|
+
|
|
63
|
+
q = where("created_dt <= ?", dt)
|
|
64
|
+
q = q.where(posting_type_id: posting_type.id) if posting_type
|
|
65
|
+
q.order("created_dt DESC").first
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
delorean_fn :get_latest, sig: [1, 2] do
|
|
69
|
+
|limit, is_test=nil|
|
|
70
|
+
# IMPORTANT: is_test arg is ignored (KEEP for backward compat.)
|
|
71
|
+
|
|
72
|
+
where("created_dt <> 'infinity'").
|
|
73
|
+
order("created_dt DESC").limit(limit).to_a
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
delorean_fn :get_latest_by_type, sig: [2, 2] do
|
|
77
|
+
|limit, posting_types=[]|
|
|
78
|
+
raise "missing posting types list" unless posting_types
|
|
79
|
+
raise "bad posting types list" unless posting_types.is_a?(Array)
|
|
80
|
+
|
|
81
|
+
joins(:posting_type).where("created_dt <> 'infinity'").
|
|
82
|
+
where(marty_posting_types: { name: posting_types } ).
|
|
83
|
+
order("created_dt DESC").limit(limit || 1).to_a
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
delorean_fn :get_last, sig: [0, 1] do
|
|
87
|
+
|posting_type=nil|
|
|
88
|
+
|
|
89
|
+
raise "bad posting type" if
|
|
90
|
+
posting_type && !posting_type.is_a?(Marty::PostingType)
|
|
91
|
+
|
|
92
|
+
q = where("created_dt <> 'infinity'")
|
|
93
|
+
q = q.where(posting_type_id: posting_type.id) if posting_type
|
|
94
|
+
q.order("created_dt DESC").first
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
delorean_fn :is_today, sig: 1 do
|
|
98
|
+
|posting|
|
|
99
|
+
posting.created_dt.to_date == Date.today
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
class Marty::Posting < Marty::Base
|
|
2
|
+
has_mcfly append_only: true
|
|
3
|
+
|
|
4
|
+
mcfly_validates_uniqueness_of :name
|
|
5
|
+
validates_presence_of :name, :posting_type_id, :comment
|
|
6
|
+
|
|
7
|
+
belongs_to :user, class_name: "Marty::User"
|
|
8
|
+
belongs_to :posting_type
|
|
9
|
+
|
|
10
|
+
def self.make_name(posting_type, dt)
|
|
11
|
+
return 'NOW' if Mcfly.is_infinity(dt)
|
|
12
|
+
|
|
13
|
+
return unless posting_type
|
|
14
|
+
|
|
15
|
+
# If no dt is provided (which is the usual non-testing case), we
|
|
16
|
+
# use Time.now.strftime to name the posting. This has the effect
|
|
17
|
+
# of using the host's timezone. i.e. since we're in PST8PDT, names
|
|
18
|
+
# will be based off of the Pacific TZ.
|
|
19
|
+
dt ||= Time.now
|
|
20
|
+
"#{posting_type.name}-#{dt.strftime('%Y%m%d-%H%M')}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
before_validation :set_posting_name
|
|
24
|
+
def set_posting_name
|
|
25
|
+
posting_type = Marty::PostingType.find_by_id(self.posting_type_id)
|
|
26
|
+
self.name = self.class.make_name(posting_type, self.created_dt)
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.do_create(type_name, dt, comment)
|
|
31
|
+
posting_type = Marty::PostingType.find_by_name(type_name)
|
|
32
|
+
|
|
33
|
+
raise "unknown posting type #{name}" unless posting_type
|
|
34
|
+
|
|
35
|
+
o = new
|
|
36
|
+
o.posting_type = posting_type
|
|
37
|
+
o.comment = comment
|
|
38
|
+
o.created_dt = dt
|
|
39
|
+
o.save!
|
|
40
|
+
o
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Not using mcfly_lookup since we don't want these time-warp markers
|
|
44
|
+
# time-warped. FIXME: perhaps this should use mcfly_lookup since we
|
|
45
|
+
# may allow deletion of postings. i.e. a new one with same name
|
|
46
|
+
# might be created. Or, use regular validates_uniqueness_of instead
|
|
47
|
+
# of mcfly_validates_uniqueness_of.
|
|
48
|
+
delorean_fn :lookup, sig: 1 do
|
|
49
|
+
|name|
|
|
50
|
+
self.find_by_name(name)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
delorean_fn :lookup_dt, sig: 1 do
|
|
54
|
+
|name|
|
|
55
|
+
lookup(name).try(:created_dt)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
delorean_fn :first_match, sig: 1 do
|
|
59
|
+
|dt|
|
|
60
|
+
where("created_dt <= ?", dt).order("created_dt DESC").first
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
delorean_fn :get_latest, sig: [1, 2] do
|
|
64
|
+
|limit, is_test=nil|
|
|
65
|
+
# IMPORTANT: is_test arg is ignored (KEEP for backward compat.)
|
|
66
|
+
|
|
67
|
+
where("created_dt <> 'infinity'").
|
|
68
|
+
order("created_dt DESC").limit(limit).to_a
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
delorean_fn :get_last, sig: [0, 1] do
|
|
72
|
+
|posting_type=nil|
|
|
73
|
+
|
|
74
|
+
raise "bad posting type" if
|
|
75
|
+
posting_type && !posting_type.is_a?(Marty::PostingType)
|
|
76
|
+
|
|
77
|
+
q = where("created_dt <> 'infinity'")
|
|
78
|
+
q = q.where(posting_type_id: posting_type.id) if posting_type
|
|
79
|
+
q.order("created_dt DESC").first
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
delorean_fn :is_today, sig: 1 do
|
|
83
|
+
|posting|
|
|
84
|
+
posting.created_dt.to_date == Date.today
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class Marty::PostingType < Marty::Base
|
|
2
|
+
extend Marty::Enum
|
|
3
|
+
|
|
4
|
+
validates_presence_of :name
|
|
5
|
+
validates_uniqueness_of :name
|
|
6
|
+
|
|
7
|
+
# NOTE: lookup fn for backward compat -- to index enums, use []
|
|
8
|
+
delorean_fn :lookup, sig: 1 do
|
|
9
|
+
|name|
|
|
10
|
+
self.find_by_name(name)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class Marty::PostingType < Marty::Base
|
|
2
|
+
extend Marty::Enum
|
|
3
|
+
|
|
4
|
+
<<<<<<< HEAD
|
|
5
|
+
# attr_accessible :name
|
|
6
|
+
=======
|
|
7
|
+
>>>>>>> master
|
|
8
|
+
validates_presence_of :name
|
|
9
|
+
validates_uniqueness_of :name
|
|
10
|
+
|
|
11
|
+
delorean_fn :lookup, sig: 1 do
|
|
12
|
+
|name|
|
|
13
|
+
self.find_by_name(name)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.seed
|
|
17
|
+
['BASE', 'CLOSE', 'INTRA', 'RULE'].each { |type|
|
|
18
|
+
create name: type
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
class Marty::Promise < Marty::Base
|
|
2
|
+
class MarshalResult
|
|
3
|
+
def dump(v)
|
|
4
|
+
Marshal.dump(v)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def load(v)
|
|
8
|
+
# Marshal.load can't handle nil
|
|
9
|
+
v ? Marshal.load(v) : {}
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# default timeout (seconds) to wait for promise values
|
|
14
|
+
DEFAULT_PROMISE_TIMEOUT = Rails.configuration.marty.promise_timeout || 30
|
|
15
|
+
|
|
16
|
+
# default timeout (seconds) to wait for jobs to start
|
|
17
|
+
DEFAULT_JOB_TIMEOUT = Rails.configuration.marty.job_timeout || 10
|
|
18
|
+
|
|
19
|
+
lazy_load :result
|
|
20
|
+
|
|
21
|
+
serialize :result, MarshalResult.new
|
|
22
|
+
|
|
23
|
+
validates_presence_of :title
|
|
24
|
+
|
|
25
|
+
has_many :children,
|
|
26
|
+
foreign_key: 'parent_id',
|
|
27
|
+
class_name: "Marty::Promise",
|
|
28
|
+
dependent: :destroy
|
|
29
|
+
|
|
30
|
+
belongs_to :parent, class_name: "Marty::Promise"
|
|
31
|
+
belongs_to :user, class_name: "Marty::User"
|
|
32
|
+
|
|
33
|
+
def self.cleanup(all=false)
|
|
34
|
+
begin
|
|
35
|
+
where('start_dt < ? AND parent_id IS NULL',
|
|
36
|
+
DateTime.now - (all ? 0.hours : 4.hours)).destroy_all
|
|
37
|
+
rescue => exc
|
|
38
|
+
Marty::Util.logger.error("promise GC error: #{exc}")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class VirtualRoot
|
|
43
|
+
def self.primary_key
|
|
44
|
+
'id'
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def id
|
|
48
|
+
'root'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def user_id
|
|
52
|
+
0
|
|
53
|
+
end
|
|
54
|
+
alias_method :job_id, :user_id
|
|
55
|
+
|
|
56
|
+
def result
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
[:start_dt, :end_dt].each { |m| alias_method m, :result }
|
|
60
|
+
|
|
61
|
+
def status
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def self.root
|
|
67
|
+
VirtualRoot.new
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.children_for_id(id, search_order)
|
|
71
|
+
if id == 'root'
|
|
72
|
+
where(parent_id: nil).live_search(search_order).order(id: :desc).includes(:children, :user)
|
|
73
|
+
else
|
|
74
|
+
find(id).children.live_search(search_order).order(id: :desc).includes(:children, :user)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def leaf
|
|
79
|
+
children.empty?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def raw_conn
|
|
83
|
+
self.class.connection.raw_connection
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def pg_notify
|
|
87
|
+
raw_conn.async_exec("NOTIFY promise_#{id}")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def set_start
|
|
91
|
+
if self.start_dt || self.result != {}
|
|
92
|
+
Marty::Util.logger.error("promise already started: #{self}")
|
|
93
|
+
return
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# mark promise as started
|
|
97
|
+
self.start_dt = DateTime.now
|
|
98
|
+
self.save!
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def set_result(res)
|
|
102
|
+
# log "SETRES #{Process.pid} #{self}"
|
|
103
|
+
|
|
104
|
+
# promise must have been started and not yet ended
|
|
105
|
+
if !self.start_dt || self.end_dt || self.result != {}
|
|
106
|
+
# log "SETERR #{Process.pid} #{self}"
|
|
107
|
+
Marty::Util.logger.error("unexpected promise state: #{self}")
|
|
108
|
+
return
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
raise "bad result" unless res.is_a?(Hash)
|
|
112
|
+
|
|
113
|
+
self.status = res["error"].nil?
|
|
114
|
+
self.result = res
|
|
115
|
+
|
|
116
|
+
# update title/format from result hash (somewhat hacky)
|
|
117
|
+
self.title = res["title"].to_s if res["title"]
|
|
118
|
+
self.cformat = res["format"].to_s if res["format"]
|
|
119
|
+
|
|
120
|
+
# mark promise as ended
|
|
121
|
+
self.end_dt = DateTime.now
|
|
122
|
+
self.save!
|
|
123
|
+
|
|
124
|
+
# log "NOTIFY #{Process.pid}"
|
|
125
|
+
pg_notify
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def to_s
|
|
129
|
+
inspect
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# def log(msg)
|
|
133
|
+
# open('/tmp/dj.out', 'a') { |f| f.puts msg }
|
|
134
|
+
# end
|
|
135
|
+
|
|
136
|
+
def wait_for_my_notify(timeout)
|
|
137
|
+
while true do
|
|
138
|
+
# FIXME: we keep using the same timeout. The timeout should be
|
|
139
|
+
# reduced by total time spent here.
|
|
140
|
+
n = raw_conn.wait_for_notify(timeout)
|
|
141
|
+
return n if !n || n=="promise_#{id}"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def latest
|
|
146
|
+
# FIXME: Not sure if this is idiomatic. What's the best way to
|
|
147
|
+
# force AR to reload the promise object? reset+reload doesn't
|
|
148
|
+
# seems to work.
|
|
149
|
+
|
|
150
|
+
# get latest uncached version
|
|
151
|
+
Marty::Promise.uncached {Marty::Promise.find(id)}
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.job_by_id(job_id)
|
|
155
|
+
Delayed::Job.uncached {Delayed::Job.find_by_id(job_id)}
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def work_off_job(job)
|
|
159
|
+
# Create a temporary worker to work off the job
|
|
160
|
+
Delayed::Job.where(id: job.id).
|
|
161
|
+
update_all(locked_at: Delayed::Job.db_time_now, locked_by: "Temp")
|
|
162
|
+
w = Delayed::Worker.new
|
|
163
|
+
w.run(job)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def wait_for_result(timeout)
|
|
167
|
+
return self.result if self.result != {}
|
|
168
|
+
|
|
169
|
+
begin
|
|
170
|
+
# start listening on promise's notification
|
|
171
|
+
raw_conn.exec("LISTEN promise_#{id}")
|
|
172
|
+
|
|
173
|
+
last = latest
|
|
174
|
+
|
|
175
|
+
# if job hasn't started yet, wait for it to start
|
|
176
|
+
if !last.start_dt
|
|
177
|
+
job = Marty::Promise.job_by_id(last.job_id)
|
|
178
|
+
|
|
179
|
+
# log "AAAA #{Process.pid} #{last} #{job}"
|
|
180
|
+
|
|
181
|
+
if !job || job.locked_at
|
|
182
|
+
# job has been locked, so it looks like it started already
|
|
183
|
+
# and we need to wait for it.
|
|
184
|
+
wait_for_my_notify(Marty::Promise::DEFAULT_JOB_TIMEOUT)
|
|
185
|
+
else
|
|
186
|
+
# work off the job instead of waiting for a real worker to
|
|
187
|
+
# pick it up.
|
|
188
|
+
# log "OFF0 #{Process.pid} #{last}"
|
|
189
|
+
begin
|
|
190
|
+
work_off_job(job)
|
|
191
|
+
rescue => exc
|
|
192
|
+
# log "OFFERR #{exc}"
|
|
193
|
+
res = Delorean::Engine.grok_runtime_exception(exc)
|
|
194
|
+
last.set_result(res)
|
|
195
|
+
end
|
|
196
|
+
# log "OFF1 #{Process.pid} #{last}"
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
last = latest
|
|
200
|
+
|
|
201
|
+
# we waited for it but it never started. So, mark it with a
|
|
202
|
+
# timeout error.
|
|
203
|
+
if !last.start_dt
|
|
204
|
+
# log "TO11 #{Process.pid} #{last}"
|
|
205
|
+
return {"error" => "promise #{last.id} timed out (never started)"}
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# reload promise in case out copy doesn't have a result yet
|
|
210
|
+
last = latest unless last.end_dt
|
|
211
|
+
|
|
212
|
+
# at this point, we know the promise has already started
|
|
213
|
+
if !last.end_dt
|
|
214
|
+
wait_for_my_notify(timeout)
|
|
215
|
+
# log "UUUU #{Process.pid} #{id} #{Time.now.to_f}"
|
|
216
|
+
last = latest
|
|
217
|
+
|
|
218
|
+
# log "XXXX #{Process.pid} #{Time.now.to_f} #{last}"
|
|
219
|
+
|
|
220
|
+
if !last.end_dt
|
|
221
|
+
# log "TO22 #{Process.pid} #{last}"
|
|
222
|
+
return {"error" => "promise #{last.id} timed out (didn't end)"}
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# log "RRRR #{Process.pid} #{last} #{Time.now.to_f}"
|
|
227
|
+
|
|
228
|
+
last.result
|
|
229
|
+
ensure
|
|
230
|
+
# Stop listening to the promise notifications
|
|
231
|
+
raw_conn.exec("UNLISTEN promise_#{id}")
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Support UI live search -- FIXME: hacky to have UI scoping here
|
|
236
|
+
scope :live_search, lambda { |search_text|
|
|
237
|
+
return if !search_text || search_text.strip.length < 1
|
|
238
|
+
|
|
239
|
+
# Searches user login/firstname/lastname
|
|
240
|
+
query = [
|
|
241
|
+
"marty_users.login ILIKE ?",
|
|
242
|
+
"marty_users.firstname ILIKE ?",
|
|
243
|
+
"marty_users.lastname ILIKE ?",
|
|
244
|
+
"marty_roles.name ILIKE ?",
|
|
245
|
+
].join(' OR ')
|
|
246
|
+
|
|
247
|
+
st = "%#{search_text}%"
|
|
248
|
+
# Convert "Role Name" or "Role name" to "role_name" (underscore is key)
|
|
249
|
+
st2 = "%#{search_text.titleize.gsub(/\s/, '').underscore}%"
|
|
250
|
+
joins({:user => :roles}).where(query, st, st, st, st2).distinct
|
|
251
|
+
}
|
|
252
|
+
end
|