incline 0.1.5
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/.gitignore +13 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +186 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +208 -0
- data/Rakefile +37 -0
- data/app/assets/fonts/incline/.keep +0 -0
- data/app/assets/images/incline/.keep +0 -0
- data/app/assets/images/incline/barcode-B.svg +181 -0
- data/app/assets/javascripts/incline/activate_classed_items.js +11 -0
- data/app/assets/javascripts/incline/application.js +30 -0
- data/app/assets/javascripts/incline/bootstrap-datepicker.js +1800 -0
- data/app/assets/javascripts/incline/datatables.js +22193 -0
- data/app/assets/javascripts/incline/escapeHtml.js +10 -0
- data/app/assets/javascripts/incline/inline_actions.js +479 -0
- data/app/assets/javascripts/incline/jquery.doubleScroll.js +112 -0
- data/app/assets/javascripts/incline/jquery.number.js +764 -0
- data/app/assets/javascripts/incline/regexMask.js +27 -0
- data/app/assets/javascripts/incline/select2/i18n/en.js +3 -0
- data/app/assets/javascripts/incline/select2/select2.full.js +6436 -0
- data/app/assets/stylesheets/incline/application.css +18 -0
- data/app/assets/stylesheets/incline/bootstrap-theme.min.css +5 -0
- data/app/assets/stylesheets/incline/custom.scss +279 -0
- data/app/assets/stylesheets/incline/datatables.css +494 -0
- data/app/assets/stylesheets/incline/datepicker3.css +790 -0
- data/app/assets/stylesheets/incline/select2.css +484 -0
- data/app/controllers/incline/access_groups_controller.rb +127 -0
- data/app/controllers/incline/access_test_controller.rb +30 -0
- data/app/controllers/incline/account_activations_controller.rb +28 -0
- data/app/controllers/incline/application_controller.rb +11 -0
- data/app/controllers/incline/contact_controller.rb +34 -0
- data/app/controllers/incline/password_resets_controller.rb +113 -0
- data/app/controllers/incline/security_controller.rb +100 -0
- data/app/controllers/incline/sessions_controller.rb +50 -0
- data/app/controllers/incline/users_controller.rb +304 -0
- data/app/controllers/incline/welcome_controller.rb +19 -0
- data/app/helpers/incline/.keep +0 -0
- data/app/mailers/incline/application_mailer_base.rb +11 -0
- data/app/mailers/incline/contact_form.rb +19 -0
- data/app/mailers/incline/user_mailer.rb +45 -0
- data/app/models/incline/access_group.rb +121 -0
- data/app/models/incline/access_group_group_member.rb +12 -0
- data/app/models/incline/access_group_user_member.rb +10 -0
- data/app/models/incline/action_group.rb +12 -0
- data/app/models/incline/action_security.rb +222 -0
- data/app/models/incline/contact_message.rb +37 -0
- data/app/models/incline/disable_info.rb +20 -0
- data/app/models/incline/password_reset.rb +14 -0
- data/app/models/incline/password_reset_request.rb +14 -0
- data/app/models/incline/user.rb +437 -0
- data/app/models/incline/user_login_history.rb +30 -0
- data/app/views/incline/access_groups/_details.json.jbuilder +10 -0
- data/app/views/incline/access_groups/_form.html.erb +19 -0
- data/app/views/incline/access_groups/_list.html.erb +60 -0
- data/app/views/incline/access_groups/_messages.json.jbuilder +6 -0
- data/app/views/incline/access_groups/edit.html.erb +2 -0
- data/app/views/incline/access_groups/index.html.erb +6 -0
- data/app/views/incline/access_groups/index.json.jbuilder +16 -0
- data/app/views/incline/access_groups/new.html.erb +2 -0
- data/app/views/incline/access_groups/show.html.erb +9 -0
- data/app/views/incline/access_groups/show.json.jbuilder +11 -0
- data/app/views/incline/contact/new.html.erb +22 -0
- data/app/views/incline/contact_form/contact.html.erb +16 -0
- data/app/views/incline/contact_form/contact.text.erb +13 -0
- data/app/views/incline/password_resets/edit.html.erb +16 -0
- data/app/views/incline/password_resets/new.html.erb +12 -0
- data/app/views/incline/security/_details.json.jbuilder +7 -0
- data/app/views/incline/security/_form.html.erb +20 -0
- data/app/views/incline/security/_list.html.erb +89 -0
- data/app/views/incline/security/_messages.json.jbuilder +6 -0
- data/app/views/incline/security/edit.html.erb +2 -0
- data/app/views/incline/security/index.html.erb +6 -0
- data/app/views/incline/security/index.json.jbuilder +16 -0
- data/app/views/incline/security/show.html.erb +31 -0
- data/app/views/incline/security/show.json.jbuilder +11 -0
- data/app/views/incline/sessions/new.html.erb +26 -0
- data/app/views/incline/user_mailer/account_activation.html.erb +7 -0
- data/app/views/incline/user_mailer/account_activation.text.erb +6 -0
- data/app/views/incline/user_mailer/invalid_password_reset.html.erb +3 -0
- data/app/views/incline/user_mailer/invalid_password_reset.text.erb +5 -0
- data/app/views/incline/user_mailer/password_reset.html.erb +8 -0
- data/app/views/incline/user_mailer/password_reset.text.erb +7 -0
- data/app/views/incline/users/_details.json.jbuilder +32 -0
- data/app/views/incline/users/_form.html.erb +21 -0
- data/app/views/incline/users/_list.html.erb +102 -0
- data/app/views/incline/users/_messages.json.jbuilder +6 -0
- data/app/views/incline/users/disable_confirm.html.erb +19 -0
- data/app/views/incline/users/edit.html.erb +5 -0
- data/app/views/incline/users/index.html.erb +6 -0
- data/app/views/incline/users/index.json.jbuilder +16 -0
- data/app/views/incline/users/new.html.erb +5 -0
- data/app/views/incline/users/show.html.erb +12 -0
- data/app/views/incline/users/show.json.jbuilder +11 -0
- data/app/views/incline/welcome/home.html.erb +5 -0
- data/app/views/layouts/application.html.erb +1 -0
- data/app/views/layouts/incline/_account_menu.html.erb +18 -0
- data/app/views/layouts/incline/_app_menu_anon.html.erb +1 -0
- data/app/views/layouts/incline/_app_menu_authenticated.html.erb +1 -0
- data/app/views/layouts/incline/_footer.html.erb +13 -0
- data/app/views/layouts/incline/_header.html.erb +21 -0
- data/app/views/layouts/incline/_html_mailer.html.erb +5 -0
- data/app/views/layouts/incline/_incline_app.html.erb +25 -0
- data/app/views/layouts/incline/_messages.html.erb +3 -0
- data/app/views/layouts/incline/_shim.html.erb +3 -0
- data/app/views/layouts/incline/_text_mailer.text.erb +1 -0
- data/app/views/layouts/incline/application.html.erb +1 -0
- data/app/views/layouts/mailer.html.erb +2 -0
- data/app/views/layouts/mailer.text.erb +2 -0
- data/bin/rails +12 -0
- data/bin/test_scaffold.sh +10 -0
- data/config/routes.rb +61 -0
- data/db/migrate/20170511230126_create_incline_users.rb +26 -0
- data/db/migrate/20170515003052_create_incline_access_groups.rb +10 -0
- data/db/migrate/20170515003221_create_incline_user_login_histories.rb +12 -0
- data/db/migrate/20170515150908_create_incline_access_group_user_members.rb +11 -0
- data/db/migrate/20170515151058_create_incline_access_group_group_members.rb +11 -0
- data/db/migrate/20170517193432_add_comments_to_incline_user.rb +5 -0
- data/db/migrate/20170622132700_create_incline_action_securities.rb +16 -0
- data/db/migrate/20170622172712_create_incline_action_groups.rb +11 -0
- data/db/migrate/20170622195742_add_non_standard_to_action_security.rb +5 -0
- data/db/migrate/20170622230422_add_visible_to_action_security.rb +5 -0
- data/db/seeds.rb +81 -0
- data/exe/new_incline_app +42 -0
- data/lib/generators/incline/install_generator.rb +259 -0
- data/lib/generators/incline/templates/_app_menu_anon.html.erb +1 -0
- data/lib/generators/incline/templates/_app_menu_authenticated.html.erb +1 -0
- data/lib/generators/incline/templates/incline_application.css +17 -0
- data/lib/generators/incline/templates/incline_application.html.erb +1 -0
- data/lib/generators/incline/templates/incline_application.js +12 -0
- data/lib/generators/incline/templates/incline_database.yml +25 -0
- data/lib/generators/incline/templates/incline_email.yml +20 -0
- data/lib/generators/incline/templates/incline_mailer.html.erb +2 -0
- data/lib/generators/incline/templates/incline_mailer.text.erb +2 -0
- data/lib/generators/incline/templates/incline_users.yml +64 -0
- data/lib/generators/incline/templates/incline_version.rb +3 -0
- data/lib/incline/auth_engine_base.rb +52 -0
- data/lib/incline/data_tables_request.rb +336 -0
- data/lib/incline/date_time_formats.rb +6 -0
- data/lib/incline/engine.rb +212 -0
- data/lib/incline/errors.rb +15 -0
- data/lib/incline/extensions/action_controller_base.rb +526 -0
- data/lib/incline/extensions/action_mailer_base.rb +66 -0
- data/lib/incline/extensions/action_view_base.rb +489 -0
- data/lib/incline/extensions/active_record_base.rb +308 -0
- data/lib/incline/extensions/application.rb +137 -0
- data/lib/incline/extensions/application_configuration.rb +50 -0
- data/lib/incline/extensions/connection_adapter.rb +55 -0
- data/lib/incline/extensions/date_time_value.rb +123 -0
- data/lib/incline/extensions/date_value.rb +77 -0
- data/lib/incline/extensions/decimal_value.rb +55 -0
- data/lib/incline/extensions/erb_scaffold_generator.rb +31 -0
- data/lib/incline/extensions/float_value.rb +59 -0
- data/lib/incline/extensions/form_builder.rb +617 -0
- data/lib/incline/extensions/integer_value.rb +54 -0
- data/lib/incline/extensions/jbuilder_generator.rb +38 -0
- data/lib/incline/extensions/jbuilder_template.rb +39 -0
- data/lib/incline/extensions/main_app.rb +40 -0
- data/lib/incline/extensions/numeric.rb +63 -0
- data/lib/incline/extensions/object.rb +31 -0
- data/lib/incline/extensions/resource_route_generator.rb +53 -0
- data/lib/incline/extensions/session.rb +113 -0
- data/lib/incline/extensions/string.rb +50 -0
- data/lib/incline/extensions/test_case.rb +764 -0
- data/lib/incline/extensions/time_zone_converter.rb +40 -0
- data/lib/incline/global_status.rb +236 -0
- data/lib/incline/helpers/route_hash_formatter.rb +46 -0
- data/lib/incline/json_log_formatter.rb +96 -0
- data/lib/incline/json_logger.rb +17 -0
- data/lib/incline/log.rb +153 -0
- data/lib/incline/number_formats.rb +17 -0
- data/lib/incline/recaptcha.rb +346 -0
- data/lib/incline/user_manager.rb +212 -0
- data/lib/incline/validators/email_validator.rb +45 -0
- data/lib/incline/validators/ip_address_validator.rb +32 -0
- data/lib/incline/validators/recaptcha_validator.rb +37 -0
- data/lib/incline/validators/safe_name_validator.rb +31 -0
- data/lib/incline/version.rb +3 -0
- data/lib/incline/work_path.rb +75 -0
- data/lib/incline.rb +197 -0
- data/lib/tasks/incline_tasks.rake +4 -0
- data/lib/templates/erb/scaffold/_form.html.erb +43 -0
- data/lib/templates/erb/scaffold/_list.html.erb +81 -0
- data/lib/templates/erb/scaffold/edit.html.erb +1 -0
- data/lib/templates/erb/scaffold/index.html.erb +6 -0
- data/lib/templates/erb/scaffold/new.html.erb +1 -0
- data/lib/templates/erb/scaffold/show.html.erb +34 -0
- data/lib/templates/jbuilder/scaffold/_details.json.jbuilder +20 -0
- data/lib/templates/jbuilder/scaffold/index.json.jbuilder +16 -0
- data/lib/templates/jbuilder/scaffold/show.json.jbuilder +16 -0
- data/lib/templates/rails/scaffold_controller/controller.rb +128 -0
- data/test/controllers/incline/access_groups_controller_test.rb +65 -0
- data/test/controllers/incline/access_test_controller_test.rb +53 -0
- data/test/controllers/incline/contact_controller_test.rb +32 -0
- data/test/controllers/incline/security_controller_test.rb +39 -0
- data/test/controllers/incline/welcome_controller_test.rb +16 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/javascripts/application.js +12 -0
- data/test/dummy/app/assets/stylesheets/application.css +17 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.keep +0 -0
- data/test/dummy/app/models/.keep +0 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +1 -0
- data/test/dummy/app/views/layouts/incline/_app_menu_anon.html.erb +1 -0
- data/test/dummy/app/views/layouts/incline/_app_menu_authenticated.html.erb +1 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +2 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +2 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +38 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +34 -0
- data/test/dummy/config/email.yml +24 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +45 -0
- data/test/dummy/config/environments/production.rb +85 -0
- data/test/dummy/config/environments/test.rb +44 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +6 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/schema.rb +108 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/extensions/action_controller_base_extensions_test.rb +21 -0
- data/test/extensions/action_mailer_base_extensions_test.rb +20 -0
- data/test/extensions/action_view_base_extensions_test.rb +267 -0
- data/test/extensions/active_record_extensions_test.rb +173 -0
- data/test/extensions/application_configuration_extensions_test.rb +46 -0
- data/test/extensions/application_extensions_test.rb +23 -0
- data/test/extensions/connection_adapter_extensions_test.rb +54 -0
- data/test/extensions/date_time_value_extensions_test.rb +104 -0
- data/test/extensions/date_value_extensions_test.rb +102 -0
- data/test/extensions/decimal_value_extensions_test.rb +85 -0
- data/test/extensions/erb_scaffold_generator_extensions_test.rb +17 -0
- data/test/extensions/float_value_extensions_test.rb +78 -0
- data/test/extensions/form_builder_extensions_test.rb +28 -0
- data/test/extensions/integer_value_extensions_test.rb +78 -0
- data/test/extensions/jbuilder_generator_extensions_test.rb +21 -0
- data/test/extensions/jbuilder_template_extensions_test.rb +47 -0
- data/test/extensions/main_app_extensions_test.rb +55 -0
- data/test/extensions/numeric_extensions_test.rb +76 -0
- data/test/extensions/object_extensions_test.rb +104 -0
- data/test/extensions/session_extensions_test.rb +69 -0
- data/test/extensions/string_extensions_test.rb +32 -0
- data/test/extensions/test_case_extensions_test.rb +538 -0
- data/test/extensions/time_zone_converter_extensions_test.rb +10 -0
- data/test/fixtures/incline/access_group_group_members.yml +1 -0
- data/test/fixtures/incline/access_group_user_members.yml +1 -0
- data/test/fixtures/incline/access_groups.yml +13 -0
- data/test/fixtures/incline/action_groups.yml +6 -0
- data/test/fixtures/incline/action_securities.yml +18 -0
- data/test/fixtures/incline/user_login_histories.yml +1 -0
- data/test/fixtures/incline/users.yml +64 -0
- data/test/incline_test.rb +63 -0
- data/test/integration/incline/users_edit_test.rb +180 -0
- data/test/integration/incline/users_login_test.rb +105 -0
- data/test/integration/incline/users_signup_test.rb +147 -0
- data/test/integration/navigation_test.rb +11 -0
- data/test/lib/data_tables_request_test.rb +245 -0
- data/test/lib/date_time_formats_test.rb +111 -0
- data/test/lib/global_status_test.rb +89 -0
- data/test/lib/json_log_formatter_test.rb +43 -0
- data/test/lib/log_test.rb +36 -0
- data/test/lib/recaptcha_test.rb +75 -0
- data/test/lib/user_manager_test.rb +47 -0
- data/test/lib/work_path_test.rb +18 -0
- data/test/models/incline/access_group_group_member_test.rb +30 -0
- data/test/models/incline/access_group_test.rb +60 -0
- data/test/models/incline/access_group_user_member_test.rb +29 -0
- data/test/models/incline/action_group_test.rb +27 -0
- data/test/models/incline/action_security_test.rb +176 -0
- data/test/models/incline/contact_message_test.rb +66 -0
- data/test/models/incline/disable_info_test.rb +29 -0
- data/test/models/incline/password_reset_request_test.rb +35 -0
- data/test/models/incline/password_reset_test.rb +51 -0
- data/test/models/incline/user_login_history_test.rb +31 -0
- data/test/models/incline/user_test.rb +91 -0
- data/test/test_helper.rb +42 -0
- data/test/validators/email_validator_test.rb +102 -0
- data/test/validators/ip_address_validator_test.rb +107 -0
- data/test/validators/recaptcha_validator_test.rb +57 -0
- data/test/validators/safe_name_validator_test.rb +101 -0
- metadata +584 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
|
|
3
|
+
module Incline::Extensions
|
|
4
|
+
##
|
|
5
|
+
# Patches the TimeZoneConverter to call super.
|
|
6
|
+
module TimeZoneConverter
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Patches the TimeZoneConverter to call super.
|
|
10
|
+
def self.included(base)
|
|
11
|
+
base.class_eval do
|
|
12
|
+
|
|
13
|
+
undef type_cast_from_user
|
|
14
|
+
|
|
15
|
+
def type_cast_from_user(value)
|
|
16
|
+
if value.is_a?(::Array)
|
|
17
|
+
value.map { |v| type_cast_from_user(v) }
|
|
18
|
+
else
|
|
19
|
+
# Convert to time first.
|
|
20
|
+
value = super
|
|
21
|
+
|
|
22
|
+
# Then convert the time zone if necessary.
|
|
23
|
+
if value.respond_to?(:in_time_zone)
|
|
24
|
+
begin
|
|
25
|
+
value.in_time_zone
|
|
26
|
+
rescue ArgumentError
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter.include Incline::Extensions::TimeZoneConverter
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
module Incline
|
|
2
|
+
##
|
|
3
|
+
# An interface to a global status/lock file.
|
|
4
|
+
#
|
|
5
|
+
# The global status/lock file is a simple two line file.
|
|
6
|
+
# The first line is the global status message.
|
|
7
|
+
# The second line is the global status progress.
|
|
8
|
+
#
|
|
9
|
+
# The real magic comes when we take advantage of exclusive locks.
|
|
10
|
+
# The process that will be managing the status takes an exclusive lock on the status/lock file.
|
|
11
|
+
# This prevents any other process from taking an exclusive lock.
|
|
12
|
+
# It does not prevent other processes from reading from the file.
|
|
13
|
+
#
|
|
14
|
+
# So the main process can update the file at any time, until it releases the lock.
|
|
15
|
+
# The other processes can read the file at any time, and test for the lock state to determine if the main
|
|
16
|
+
# process is still busy.
|
|
17
|
+
#
|
|
18
|
+
#
|
|
19
|
+
class GlobalStatus
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# Creates a new GlobalStatus object.
|
|
23
|
+
def initialize
|
|
24
|
+
@handle = nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Gets the path to the global status/lock file.
|
|
29
|
+
def status_file_path
|
|
30
|
+
@status_file_path ||= WorkPath.path_for('global_lock')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Determines if this instance has a lock on the status/lock file.
|
|
35
|
+
def have_lock?
|
|
36
|
+
!!@handle
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# Determines if any process has a lock on the status/lock file.
|
|
41
|
+
def is_locked?
|
|
42
|
+
return true if have_lock?
|
|
43
|
+
begin
|
|
44
|
+
return true unless acquire_lock
|
|
45
|
+
ensure
|
|
46
|
+
release_lock
|
|
47
|
+
end
|
|
48
|
+
false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
##
|
|
52
|
+
# Gets the current status message from the status/lock file.
|
|
53
|
+
def get_message
|
|
54
|
+
get_status[:message]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
# Gets the current progress from the status/lock file.
|
|
59
|
+
def get_percentage
|
|
60
|
+
r = get_status[:percent]
|
|
61
|
+
r.blank? ? nil : r.to_i
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# Gets the current status from the status/lock file.
|
|
66
|
+
#
|
|
67
|
+
# Returns a hash with three elements:
|
|
68
|
+
#
|
|
69
|
+
# message::
|
|
70
|
+
# The current status message.
|
|
71
|
+
#
|
|
72
|
+
# percent::
|
|
73
|
+
# The current status progress.
|
|
74
|
+
#
|
|
75
|
+
# locked::
|
|
76
|
+
# The current lock state of the status/lock file. (true for locked, false for unlocked)
|
|
77
|
+
#
|
|
78
|
+
def get_status
|
|
79
|
+
r = {}
|
|
80
|
+
if have_lock?
|
|
81
|
+
@handle.rewind
|
|
82
|
+
r[:message] = (@handle.eof? ? 'The current process is busy.' : @handle.readline.strip)
|
|
83
|
+
r[:percent] = (@handle.eof? ? '' : @handle.readline.strip)
|
|
84
|
+
r[:locked] = true
|
|
85
|
+
elsif is_locked?
|
|
86
|
+
if File.exist?(status_file_path)
|
|
87
|
+
begin
|
|
88
|
+
File.open(status_file_path, 'r') do |f|
|
|
89
|
+
r[:message] = (f.eof? ? 'The system is busy.' : f.readline.strip)
|
|
90
|
+
r[:percent] = (f.eof? ? '' : f.readline.strip)
|
|
91
|
+
end
|
|
92
|
+
rescue
|
|
93
|
+
r[:message] = 'The system appears busy.'
|
|
94
|
+
r[:percent] = ''
|
|
95
|
+
end
|
|
96
|
+
else
|
|
97
|
+
r[:message] = 'No status file.'
|
|
98
|
+
r[:percent] = ''
|
|
99
|
+
end
|
|
100
|
+
r[:locked] = true
|
|
101
|
+
else
|
|
102
|
+
r[:message] = 'The system is no longer busy.'
|
|
103
|
+
r[:percent] = '-'
|
|
104
|
+
r[:locked] = false
|
|
105
|
+
end
|
|
106
|
+
r
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
##
|
|
110
|
+
# Sets the status message if this instance has a lock on the status/lock file.
|
|
111
|
+
#
|
|
112
|
+
# Returns true after successfully setting the message.
|
|
113
|
+
# Returns false if this instance does not currently hold the lock.
|
|
114
|
+
#
|
|
115
|
+
def set_message(value)
|
|
116
|
+
return false unless have_lock?
|
|
117
|
+
cur = get_status
|
|
118
|
+
set_status(value, cur[:percent])
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
##
|
|
122
|
+
# Sets the status progress if this instance has a lock on the status/lock file.
|
|
123
|
+
#
|
|
124
|
+
# Returns true after successfully setting the progress.
|
|
125
|
+
# Returns false if this instance does not currently hold the lock.
|
|
126
|
+
#
|
|
127
|
+
def set_percentage(value)
|
|
128
|
+
return false unless have_lock?
|
|
129
|
+
cur = get_status
|
|
130
|
+
set_status(cur[:message], value)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
##
|
|
134
|
+
# Sets the status message and progress if this instance has a lock on the status/lock file.
|
|
135
|
+
#
|
|
136
|
+
# Returns true after successfully setting the status.
|
|
137
|
+
# Returns false if this instance does not currently hold the lock.
|
|
138
|
+
#
|
|
139
|
+
def set_status(message, percentage)
|
|
140
|
+
return false unless have_lock?
|
|
141
|
+
@handle.rewind
|
|
142
|
+
@handle.truncate 0
|
|
143
|
+
@handle.write(message.to_s.strip + "\n")
|
|
144
|
+
@handle.write(percentage.to_s.strip + "\n")
|
|
145
|
+
@handle.flush
|
|
146
|
+
true
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
##
|
|
150
|
+
# Releases the lock on the status/lock file if this instance holds the lock.
|
|
151
|
+
#
|
|
152
|
+
# Returns true.
|
|
153
|
+
#
|
|
154
|
+
def release_lock
|
|
155
|
+
return true unless @handle
|
|
156
|
+
set_message ''
|
|
157
|
+
@handle.flock(File::LOCK_UN)
|
|
158
|
+
@handle.close
|
|
159
|
+
@handle = nil
|
|
160
|
+
true
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
##
|
|
164
|
+
# Acquires the lock on the status/lock file.
|
|
165
|
+
#
|
|
166
|
+
# Returns true on success or if this instance already holds the lock.
|
|
167
|
+
# Returns false if another process holds the lock.
|
|
168
|
+
#
|
|
169
|
+
def acquire_lock
|
|
170
|
+
return true if @handle
|
|
171
|
+
begin
|
|
172
|
+
@handle = File.open(status_file_path, File::RDWR | File::CREAT)
|
|
173
|
+
raise StandardError.new('Already locked') unless @handle.flock(File::LOCK_EX | File::LOCK_NB)
|
|
174
|
+
@handle.rewind
|
|
175
|
+
@handle.truncate 0
|
|
176
|
+
rescue
|
|
177
|
+
if @handle
|
|
178
|
+
@handle.flock(File::LOCK_UN)
|
|
179
|
+
@handle.close
|
|
180
|
+
end
|
|
181
|
+
@handle = nil
|
|
182
|
+
end
|
|
183
|
+
!!@handle
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
##
|
|
187
|
+
# Determines if any process currently holds the lock on the status/lock file.
|
|
188
|
+
#
|
|
189
|
+
# Returns true if the file is locked, otherwise returns false.
|
|
190
|
+
#
|
|
191
|
+
def self.locked?
|
|
192
|
+
global_instance.is_locked?
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
##
|
|
196
|
+
# Gets the current status from the status/lock file.
|
|
197
|
+
#
|
|
198
|
+
# See #get_status for a description of the returned hash.
|
|
199
|
+
#
|
|
200
|
+
def self.current
|
|
201
|
+
global_instance.get_status
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
##
|
|
205
|
+
# Runs the provided block with a lock on the status/lock file.
|
|
206
|
+
#
|
|
207
|
+
# If a lock can be acquired, a GlobalStatus object is yielded to the block.
|
|
208
|
+
# The lock will automatically be released when the block exits.
|
|
209
|
+
#
|
|
210
|
+
# If a lock cannot be acquire, then false is yielded to the block.
|
|
211
|
+
# The block needs to test for this case to ensure that the appropriate
|
|
212
|
+
# error handling is performed.
|
|
213
|
+
#
|
|
214
|
+
def self.lock_for(&block)
|
|
215
|
+
return unless block_given?
|
|
216
|
+
status = GlobalStatus.new
|
|
217
|
+
if status.acquire_lock
|
|
218
|
+
begin
|
|
219
|
+
yield status
|
|
220
|
+
ensure
|
|
221
|
+
status.release_lock
|
|
222
|
+
end
|
|
223
|
+
else
|
|
224
|
+
yield false
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
private
|
|
229
|
+
|
|
230
|
+
def self.global_instance
|
|
231
|
+
@global_instance ||= GlobalStatus.new
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Incline::Helpers
|
|
2
|
+
##
|
|
3
|
+
# A "formatter" that simply collects formatted route data.
|
|
4
|
+
class RouteHashFormatter
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# Creates a new hash formatter for the route inspector.
|
|
8
|
+
def initialize
|
|
9
|
+
@buffer = []
|
|
10
|
+
@engine = ''
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Gets the resulting hash from the route inspector.
|
|
15
|
+
def result
|
|
16
|
+
@buffer
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Analyzes the section title to get the current engine name.
|
|
21
|
+
def section_title(title)
|
|
22
|
+
@engine = title.include?(' ') ? title.rpartition(' ')[2] : title
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# Does nothing for this formatter.
|
|
27
|
+
def header(routes)
|
|
28
|
+
# no need for a header
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Does nothing for this formatter.
|
|
33
|
+
def no_routes
|
|
34
|
+
# no need to do anything here either.
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# Adds the specified routes to the resulting hash.
|
|
39
|
+
def section(routes)
|
|
40
|
+
routes.each do |r|
|
|
41
|
+
@buffer << r.symbolize_keys.merge(engine: @engine)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
|
|
3
|
+
module Incline
|
|
4
|
+
##
|
|
5
|
+
# A log formatter that writes entries in JSON format (each line is a valid JSON object).
|
|
6
|
+
class JsonLogFormatter < ::Logger::Formatter
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Regular expressions used to auto-classify any matching message as a debug message.
|
|
10
|
+
AUTO_DEBUG_PATTERNS = [
|
|
11
|
+
/^rendered\s/i,
|
|
12
|
+
/started\sget\s"\/assets/i
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Overrides the default formatter behavior to log a JSON line.
|
|
17
|
+
def call(sev, time, _, msg) #:nodoc:
|
|
18
|
+
level = ({
|
|
19
|
+
Logger::DEBUG => 'DEBUG',
|
|
20
|
+
Logger::INFO => 'INFO',
|
|
21
|
+
Logger::WARN => 'WARN',
|
|
22
|
+
Logger::ERROR => 'ERROR',
|
|
23
|
+
Logger::FATAL => 'FATAL',
|
|
24
|
+
}[sev] || sev.to_s).upcase
|
|
25
|
+
|
|
26
|
+
if msg.present? && AUTO_DEBUG_PATTERNS.find{|pattern| msg =~ pattern}
|
|
27
|
+
return '' if debug_skip?
|
|
28
|
+
level = 'DEBUG'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if msg.present?
|
|
32
|
+
# And we'll expand exceptions so we get as much info as possible.
|
|
33
|
+
# If you just want the message, make sure you just pass the message.
|
|
34
|
+
if msg.is_a?(::Exception)
|
|
35
|
+
msg = "#{msg.message} (#{msg.class})\n#{(msg.backtrace || []).join("\n")}"
|
|
36
|
+
elsif !msg.is_a?(::String)
|
|
37
|
+
msg = msg.inspect
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
msg = rm_fmt msg
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
level: level,
|
|
44
|
+
time: time.strftime('%Y-%m-%d %H:%M:%S'),
|
|
45
|
+
message: msg,
|
|
46
|
+
app_name: app_name,
|
|
47
|
+
app_version: app_version,
|
|
48
|
+
process_id: Process.pid,
|
|
49
|
+
}.to_json + "\r\n"
|
|
50
|
+
else
|
|
51
|
+
''
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def app_name
|
|
58
|
+
if Object.const_defined?(:Rails)
|
|
59
|
+
Rails&.application&.app_name || 'Unknown'
|
|
60
|
+
else
|
|
61
|
+
'Unknown'
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def app_version
|
|
66
|
+
if Object.const_defined?(:Rails)
|
|
67
|
+
Rails&.application&.app_version || '0.0.0'
|
|
68
|
+
else
|
|
69
|
+
'0.0.0'
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def debug_skip?
|
|
74
|
+
if Object.const_defined?(:Rails)
|
|
75
|
+
(Rails&.logger&.level).to_s.to_i > 0
|
|
76
|
+
else
|
|
77
|
+
false
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def rm_fmt(msg)
|
|
82
|
+
msg
|
|
83
|
+
.gsub(/\e\[(\d+;?)*[ABCDEFGHfu]/, "\n") # any of the "set cursor position" CSI commands.
|
|
84
|
+
.gsub(/\e\[=?(\d+;?)*[A-Za-z]/,'') # \e[#;#;#A or \e[=#;#;#A basically all the CSI commands except ...
|
|
85
|
+
.gsub(/\e\[(\d+;"[^"]+";?)+p/, '') # \e[#;"A"p
|
|
86
|
+
.gsub(/\e[NOc]./,'?') # any of the alternate character set commands.
|
|
87
|
+
.gsub(/\e[P_\]^X][^\e\a]*(\a|(\e\\))/,'') # any string command
|
|
88
|
+
.gsub(/[\x00\x08\x0B\x0C\x0E-\x1F]/, '') # any non-printable characters (notice \x0A (LF) and \x0D (CR) are left as is).
|
|
89
|
+
.gsub("\t", ' ') # turn tabs into spaces.
|
|
90
|
+
.gsub("\r\n", "\n") # all CRLF to LF
|
|
91
|
+
.gsub("\r", "\n") # all CR to LF
|
|
92
|
+
.strip # remove trailing and leading whitespace
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'active_support/logger'
|
|
2
|
+
require 'incline/json_log_formatter'
|
|
3
|
+
|
|
4
|
+
module Incline
|
|
5
|
+
##
|
|
6
|
+
# Overrides the default formatter for the base logger.
|
|
7
|
+
class JsonLogger < ::ActiveSupport::Logger
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Sets the formatter to Incline::JsonLogFormatter.
|
|
11
|
+
def initialize(*args)
|
|
12
|
+
super
|
|
13
|
+
@formatter = ::Incline::JsonLogFormatter.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/incline/log.rb
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
require 'ansi/code'
|
|
2
|
+
|
|
3
|
+
module Incline
|
|
4
|
+
##
|
|
5
|
+
# A logging wrapper to tag log messages with location information.
|
|
6
|
+
class Log
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Logs a debug message.
|
|
10
|
+
def self.debug(msg = nil, &block)
|
|
11
|
+
safe_log :debug, msg, &block
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# Logs an info message.
|
|
16
|
+
def self.info(msg = nil, &block)
|
|
17
|
+
safe_log :info, msg, &block
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Logs a warning message.
|
|
22
|
+
def self.warn(msg = nil, &block)
|
|
23
|
+
safe_log :warn, msg, &block
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Logs an error message.
|
|
28
|
+
def self.error(msg = nil, &block)
|
|
29
|
+
safe_log :error, msg, &block
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# Gets a list of paths that are considered root paths for logging purposes.
|
|
34
|
+
def self.root_paths
|
|
35
|
+
@root_paths ||=
|
|
36
|
+
begin
|
|
37
|
+
[
|
|
38
|
+
Rails.root.to_s,
|
|
39
|
+
File.expand_path('../../../', __FILE__)
|
|
40
|
+
]
|
|
41
|
+
.map{|v| v[-1] == '/' ? v : "#{v}/"}
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
# Set output to go to a file.
|
|
47
|
+
#
|
|
48
|
+
# If a +file+ is specified, it will be used for output. This will bypass Rails logging.
|
|
49
|
+
# If +file+ is set to false or nil then the default logging behavior will be used.
|
|
50
|
+
def self.set_output(file)
|
|
51
|
+
if file
|
|
52
|
+
if file.respond_to?(:puts)
|
|
53
|
+
@output = file
|
|
54
|
+
@rails = nil
|
|
55
|
+
elsif file.is_a?(::String)
|
|
56
|
+
@output = File.open(file, 'wt')
|
|
57
|
+
@rails = nil
|
|
58
|
+
else
|
|
59
|
+
raise ArgumentError, 'The file parameter must be an IO-like object, a string path, or a false value.'
|
|
60
|
+
end
|
|
61
|
+
else
|
|
62
|
+
# reset behavior
|
|
63
|
+
remove_instance_variable(:@output) if instance_variable_defined?(:@output)
|
|
64
|
+
remove_instance_variable(:@rails) if instance_variable_defined?(:@rails)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# Gets the current logging output.
|
|
70
|
+
def self.get_output
|
|
71
|
+
rails&.logger || output
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def self.output
|
|
77
|
+
# always returns something.
|
|
78
|
+
(instance_variable_defined?(:@output) ? instance_variable_get(:@output) : $stderr) || $stderr
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.skip?(level)
|
|
82
|
+
filt_level = (log_level || 0)
|
|
83
|
+
if filt_level > 0
|
|
84
|
+
return true if level == :debug
|
|
85
|
+
return true if level == :info && filt_level > 1
|
|
86
|
+
return true if level == :warn && filt_level > 2
|
|
87
|
+
end
|
|
88
|
+
false
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.rails
|
|
92
|
+
unless instance_variable_defined?(:@rails)
|
|
93
|
+
@rails = Object.const_defined?(:Rails) ? Object.const_get(:Rails) : nil
|
|
94
|
+
end
|
|
95
|
+
@rails
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def self.log_level
|
|
99
|
+
rails&.logger&.level
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def self.safe_log(level, msg)
|
|
103
|
+
return '' if skip?(level)
|
|
104
|
+
|
|
105
|
+
# by allowing a block, we can defer message processing and skip it altogether when the level is being silenced.
|
|
106
|
+
msg = yield if block_given?
|
|
107
|
+
|
|
108
|
+
c = caller_locations(2,1)[0]
|
|
109
|
+
c = "#{relative_path(c.path)}:#{c.lineno}:in `#{c.base_label}`"
|
|
110
|
+
msg = "[#{c}] #{msg_to_str(msg)}"
|
|
111
|
+
|
|
112
|
+
if rails&.logger
|
|
113
|
+
rails.logger.send level, msg
|
|
114
|
+
else
|
|
115
|
+
level = case level
|
|
116
|
+
when :error
|
|
117
|
+
ANSI.ansi level.to_s.upcase, :bright, :red
|
|
118
|
+
when :warn
|
|
119
|
+
ANSI.ansi level.to_s.upcase, :yellow
|
|
120
|
+
when :info
|
|
121
|
+
ANSI.ansi level.to_s.upcase, :bright, :white
|
|
122
|
+
else
|
|
123
|
+
level.to_s.upcase
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
output.puts "#{level}: #{msg}"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
msg
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def self.relative_path(path)
|
|
133
|
+
path = path.to_s
|
|
134
|
+
root_paths.each do |rp|
|
|
135
|
+
if path[rp]
|
|
136
|
+
return path[rp.length..-1]
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
path
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def self.msg_to_str(msg)
|
|
143
|
+
if msg.is_a?(::Exception)
|
|
144
|
+
"#{msg.message} (#{msg.class})\n#{(msg.backtrace || []).join("\n")}"
|
|
145
|
+
elsif msg.is_a?(::String)
|
|
146
|
+
msg
|
|
147
|
+
else
|
|
148
|
+
msg.inspect
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Incline
|
|
2
|
+
module NumberFormats
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# Verifies a number with comma delimiters included.
|
|
6
|
+
#
|
|
7
|
+
# 1,234,567.89e0
|
|
8
|
+
WITH_DELIMITERS = /\A[+-]?(0|[1-9][0-9]{0,2}(,[0-9]{3})*)(\.[0-9]*)?(e\d+)?\z/i
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
# Verifies a number without comma delimiters included.
|
|
12
|
+
#
|
|
13
|
+
# 1234567.89e0
|
|
14
|
+
WITHOUT_DELIMITERS = /\A[+-]?([0-9]+)(\.[0-9]*)?(e\d+)?\z/i
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|