inventory_refresh 0.3.5 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +25 -30
  3. data/.github/workflows/ci.yaml +58 -0
  4. data/.rubocop.yml +3 -3
  5. data/.rubocop_cc.yml +3 -4
  6. data/.rubocop_local.yml +5 -2
  7. data/.whitesource +3 -0
  8. data/CHANGELOG.md +19 -0
  9. data/Gemfile +10 -4
  10. data/README.md +1 -2
  11. data/Rakefile +2 -2
  12. data/inventory_refresh.gemspec +9 -10
  13. data/lib/inventory_refresh/application_record_iterator.rb +25 -12
  14. data/lib/inventory_refresh/graph/topological_sort.rb +24 -26
  15. data/lib/inventory_refresh/graph.rb +2 -2
  16. data/lib/inventory_refresh/inventory_collection/builder.rb +37 -15
  17. data/lib/inventory_refresh/inventory_collection/data_storage.rb +9 -0
  18. data/lib/inventory_refresh/inventory_collection/helpers/initialize_helper.rb +147 -38
  19. data/lib/inventory_refresh/inventory_collection/helpers/questions_helper.rb +48 -4
  20. data/lib/inventory_refresh/inventory_collection/index/proxy.rb +35 -3
  21. data/lib/inventory_refresh/inventory_collection/index/type/base.rb +8 -0
  22. data/lib/inventory_refresh/inventory_collection/index/type/local_db.rb +2 -0
  23. data/lib/inventory_refresh/inventory_collection/index/type/skeletal.rb +1 -0
  24. data/lib/inventory_refresh/inventory_collection/reference.rb +1 -0
  25. data/lib/inventory_refresh/inventory_collection/references_storage.rb +17 -0
  26. data/lib/inventory_refresh/inventory_collection/scanner.rb +91 -3
  27. data/lib/inventory_refresh/inventory_collection/serialization.rb +16 -10
  28. data/lib/inventory_refresh/inventory_collection.rb +122 -64
  29. data/lib/inventory_refresh/inventory_object.rb +74 -40
  30. data/lib/inventory_refresh/inventory_object_lazy.rb +17 -10
  31. data/lib/inventory_refresh/null_logger.rb +2 -2
  32. data/lib/inventory_refresh/persister.rb +43 -93
  33. data/lib/inventory_refresh/save_collection/base.rb +4 -2
  34. data/lib/inventory_refresh/save_collection/saver/base.rb +114 -15
  35. data/lib/inventory_refresh/save_collection/saver/batch.rb +17 -0
  36. data/lib/inventory_refresh/save_collection/saver/concurrent_safe_batch.rb +129 -51
  37. data/lib/inventory_refresh/save_collection/saver/default.rb +57 -0
  38. data/lib/inventory_refresh/save_collection/saver/partial_upsert_helper.rb +2 -19
  39. data/lib/inventory_refresh/save_collection/saver/retention_helper.rb +68 -3
  40. data/lib/inventory_refresh/save_collection/saver/sql_helper.rb +125 -0
  41. data/lib/inventory_refresh/save_collection/saver/sql_helper_update.rb +10 -6
  42. data/lib/inventory_refresh/save_collection/saver/sql_helper_upsert.rb +28 -16
  43. data/lib/inventory_refresh/save_collection/sweeper.rb +17 -93
  44. data/lib/inventory_refresh/save_collection/topological_sort.rb +5 -5
  45. data/lib/inventory_refresh/save_inventory.rb +5 -12
  46. data/lib/inventory_refresh/target.rb +73 -0
  47. data/lib/inventory_refresh/target_collection.rb +92 -0
  48. data/lib/inventory_refresh/version.rb +1 -1
  49. data/lib/inventory_refresh.rb +2 -0
  50. metadata +42 -39
  51. data/.travis.yml +0 -23
  52. data/lib/inventory_refresh/exception.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3857cdbe06fef13ec5e2a34a2dc53d879d64e318f3ed30ec1f9292f3f18c8806
4
- data.tar.gz: 1186216b8f4b4dac97ac1f8ce79f561cc95bfb54760106e5a4ef14e949659ffa
3
+ metadata.gz: b3393dbd829d48263fc51a06fa2c659045239142f4f325a2c894296eb640045d
4
+ data.tar.gz: eea18674f3145f38ead40f221d62cb158e66174860509c4bc669713a1b7f2bb7
5
5
  SHA512:
6
- metadata.gz: 74d98dd7e85cd8313b53126c8adbec786c1bf5f24a2f4ca73040f90798c6e025c42cc275eea824c47777c866426945f22b26fb41660781a57dfddf18ed88acd1
7
- data.tar.gz: 05141e34f57af8b4772acb0ad239d9c311d68fe3bc709ed0c34d090697a1091ee408540bd75c2481b309798db82da4015752a505dbcb5f38d21fef67a69470cc
6
+ metadata.gz: eb24a4daf33a937c914536dd93ad192aaf5a81fb7528888b3d22f12a46c2180634efa7d992a2f810a5c0479f341991080e9d54e115e8e5e7c58b5cc80a917e47
7
+ data.tar.gz: 9a0d525bd2df33aa7892d75968c95ac41afcd0a974f5376025e94f2d328097b652e93acc57bba43ed5451c26dd39f8180f6c9429d16ed49a4c09fdb50ada21b1
data/.codeclimate.yml CHANGED
@@ -1,18 +1,21 @@
1
- ---
2
- exclude_paths:
3
- - ".git/"
4
- - "**.xml"
5
- - "**.yaml"
6
- - "**.yml"
7
- - "locale/"
8
- - "spec/"
9
- - "tools/"
10
- engines:
1
+ prepare:
2
+ fetch:
3
+ - url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/.rubocop_base.yml
4
+ path: ".rubocop_base.yml"
5
+ - url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/.rubocop_cc_base.yml
6
+ path: ".rubocop_cc_base.yml"
7
+ - url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/styles/base.yml
8
+ path: styles/base.yml
9
+ - url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/styles/cc_base.yml
10
+ path: styles/cc_base.yml
11
+ plugins:
12
+ rubocop:
13
+ enabled: true
14
+ config: ".rubocop_cc.yml"
15
+ channel: rubocop-0-82
11
16
  brakeman:
12
- # very slow :sad_panda:
13
17
  enabled: false
14
18
  bundler-audit:
15
- # requires Gemfile.lock
16
19
  enabled: false
17
20
  csslint:
18
21
  enabled: false
@@ -24,25 +27,17 @@ engines:
24
27
  - javascript
25
28
  eslint:
26
29
  enabled: false
27
- channel: "eslint-3"
30
+ channel: eslint-3
28
31
  fixme:
29
- # let's enable later
30
32
  enabled: false
31
33
  markdownlint:
32
- # let's enable later
33
34
  enabled: false
34
- rubocop:
35
- enabled: true
36
- config: '.rubocop_cc.yml'
37
- channel: rubocop-0-69
38
- prepare:
39
- fetch:
40
- - url: "https://raw.githubusercontent.com/ManageIQ/guides/master/.rubocop_base.yml"
41
- path: ".rubocop_base.yml"
42
- - url: "https://raw.githubusercontent.com/ManageIQ/guides/master/.rubocop_cc_base.yml"
43
- path: ".rubocop_cc_base.yml"
44
- ratings:
45
- paths:
46
- - Gemfile.lock
47
- - "**.rake"
48
- - "**.rb"
35
+ exclude_patterns:
36
+ - ".git/"
37
+ - "**.xml"
38
+ - "**.yaml"
39
+ - "**.yml"
40
+ - locale/
41
+ - spec/
42
+ - tools/
43
+ version: '2'
@@ -0,0 +1,58 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ schedule:
7
+ - cron: '0 0 * * 0'
8
+
9
+ jobs:
10
+ ci:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby-version:
15
+ - '2.7'
16
+ - '3.0'
17
+ rails-version:
18
+ # rails 6.1 supports ruby >= 2.5
19
+ - '6.1'
20
+ include:
21
+ # rails 5.2 (EOL 6/22) supports ruby < 2.7 (2.6 EOL 3/22)
22
+ - ruby-version: '2.5'
23
+ rails-version: '5.2'
24
+ # rails 6.0 (security EOL 6/23?) supports ruby < 2.8 (2.7 EOL 3/23?;)
25
+ - ruby-version: '2.6'
26
+ rails-version: '6.0'
27
+ - ruby-version: '2.7'
28
+ rails-version: '6.0'
29
+ services:
30
+ postgres:
31
+ image: manageiq/postgresql:10
32
+ env:
33
+ POSTGRESQL_USER: root
34
+ POSTGRESQL_PASSWORD: smartvm
35
+ POSTGRESQL_DATABASE: inventory_refresh_dummy_test
36
+ options: --health-cmd pg_isready --health-interval 2s --health-timeout 5s --health-retries 5
37
+ ports:
38
+ - 5432:5432
39
+ env:
40
+ TEST_RAILS_VERSION: ${{ matrix.rails-version }}
41
+ PGHOST: localhost
42
+ PGPASSWORD: smartvm
43
+ CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
44
+ steps:
45
+ - uses: actions/checkout@v2
46
+ - name: Set up Ruby
47
+ uses: ruby/setup-ruby@v1
48
+ with:
49
+ ruby-version: ${{ matrix.ruby-version }}
50
+ bundler-cache: true
51
+ - name: Prepare tests
52
+ run: bundle exec rake spec:setup
53
+ - name: Run tests
54
+ run: bundle exec rake
55
+ - name: Report code coverage
56
+ if: ${{ github.ref == 'refs/heads/master' && matrix.ruby-version == '2.7' && matrix.rails-version == '6.1' }}
57
+ continue-on-error: true
58
+ uses: paambaati/codeclimate-action@v3.0.0
data/.rubocop.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  inherit_from:
2
- - https://raw.githubusercontent.com/ManageIQ/guides/master/.rubocop_base.yml
3
- # put all local rubocop config into .rubocop_local.yml as it will be loaded by .rubocop_cc.yml as well
4
- - .rubocop_local.yml
2
+ - ".rubocop_local.yml"
3
+ inherit_gem:
4
+ manageiq-style: ".rubocop_base.yml"
data/.rubocop_cc.yml CHANGED
@@ -1,5 +1,4 @@
1
1
  inherit_from:
2
- # this is downloaded by .codeclimate.yml
3
- - .rubocop_base.yml
4
- - .rubocop_cc_base.yml
5
- - .rubocop_local.yml
2
+ - ".rubocop_base.yml"
3
+ - ".rubocop_cc_base.yml"
4
+ - ".rubocop_local.yml"
data/.rubocop_local.yml CHANGED
@@ -1,2 +1,5 @@
1
- # GlobalVars:
2
- # AllowedVariables:
1
+ AllCops:
2
+ Exclude:
3
+ - spec/schema.rb
4
+ Rails:
5
+ Enabled: false
data/.whitesource ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "settingsInheritedFrom": "ManageIQ/whitesource-config@master"
3
+ }
data/CHANGELOG.md CHANGED
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ This project adheres to [Semantic Versioning](http://semver.org/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [1.0.0] - 2022-02-09
9
+ ### Changed
10
+ - Run rubocop -A (#102)
11
+ - Switch from travis to github actions (#104, #105)
12
+
13
+ ### Added
14
+ - **BREAKING** Add back support for non-concurrent-safe batch strategies (#101)
15
+ - Add support for Rails 6.1 (#103)
16
+ - Add bundler-inject (#106)
17
+
18
+ ### Fixed
19
+ - Fix InventoryCollection missing cache returns (#107)
data/Gemfile CHANGED
@@ -1,10 +1,16 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ plugin "bundler-inject", "~> 2.0"
4
+ require File.join(Bundler::Plugin.index.load_paths("bundler-inject")[0], "bundler-inject") rescue nil
4
5
 
5
6
  # Specify your gem's dependencies in inventory_refresh.gemspec
6
7
  gemspec
7
8
 
8
- # Load other additional Gemfiles
9
- # Developers can create a file ending in .rb under bundler.d/ to specify additional development dependencies
10
- Dir.glob(File.join(__dir__, 'bundler.d/*.rb')).each { |f| eval_gemfile(File.expand_path(f, __dir__)) }
9
+ case ENV['TEST_RAILS_VERSION']
10
+ when "5.2"
11
+ gem "activerecord", "~>5.2.6"
12
+ when "6.0"
13
+ gem "activerecord", "~>6.0.4"
14
+ when "6.1"
15
+ gem "activerecord", "~>6.1.4"
16
+ end
data/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # InventoryRefresh
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/inventory_refresh.svg)](http://badge.fury.io/rb/inventory_refresh)
4
- [![Build Status](https://travis-ci.org/ManageIQ/inventory_refresh.svg)](https://travis-ci.org/ManageIQ/inventory_refresh)
4
+ [![CI](https://github.com/ManageIQ/inventory_refresh/actions/workflows/ci.yaml/badge.svg)](https://github.com/ManageIQ/inventory_refresh/actions/workflows/ci.yaml)
5
5
  [![Code Climate](https://codeclimate.com/github/ManageIQ/inventory_refresh.svg)](https://codeclimate.com/github/ManageIQ/inventory_refresh)
6
6
  [![Test Coverage](https://codeclimate.com/github/ManageIQ/inventory_refresh/badges/coverage.svg)](https://codeclimate.com/github/ManageIQ/inventory_refresh/coverage)
7
- [![Security](https://hakiri.io/github/ManageIQ/inventory_refresh/master.svg)](https://hakiri.io/github/ManageIQ/inventory_refresh/master)
8
7
 
9
8
  [![Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ManageIQ/manageiq/providers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
10
9
 
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ namespace :spec do
12
12
 
13
13
  task :db_load_schema do
14
14
  require "active_record"
15
- with_connection(test_database_name) { load File.join(__dir__, %w{spec schema.rb}) }
15
+ with_connection(test_database_name) { load File.join(__dir__, %w[spec schema.rb]) }
16
16
  end
17
17
 
18
18
  desc "Setup test database"
@@ -20,7 +20,7 @@ namespace :spec do
20
20
 
21
21
  def connection_spec
22
22
  require 'yaml'
23
- @connection_spec ||= YAML.load_file(File.join(__dir__, %w(config database.yml)))
23
+ @connection_spec ||= YAML.load_file(File.join(__dir__, %w[config database.yml]))
24
24
  end
25
25
 
26
26
  def test_database_name
@@ -1,5 +1,4 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require "inventory_refresh/version"
5
4
 
@@ -8,30 +7,30 @@ Gem::Specification.new do |spec|
8
7
  spec.version = InventoryRefresh::VERSION
9
8
  spec.authors = ["ManageIQ Developers"]
10
9
 
11
- spec.summary = %q{Topological Inventory Persister}
12
- spec.description = %q{Topological Inventory Persister}
10
+ spec.summary = 'Topological Inventory Persister'
11
+ spec.description = 'Topological Inventory Persister'
13
12
  spec.homepage = "https://github.com/ManageIQ/inventory_refresh"
14
13
  spec.licenses = ["Apache-2.0"]
15
14
 
16
15
  # Specify which files should be added to the gem when it is released.
17
16
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
19
18
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
19
  end
21
20
  spec.bindir = "exe"
22
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
22
  spec.require_paths = ["lib"]
23
+ spec.metadata['rubygems_mfa_required'] = 'true'
24
24
 
25
- spec.add_dependency "activerecord", "~> 5.0"
26
- spec.add_dependency "more_core_extensions", "~> 3.5"
25
+ spec.add_dependency "activerecord", ">=5.0", "< 7.0"
26
+ spec.add_dependency "more_core_extensions", ">=3.5", "< 5"
27
27
  spec.add_dependency "pg", "> 0"
28
28
 
29
29
  spec.add_development_dependency "ancestry"
30
30
  spec.add_development_dependency "bundler", "~> 2.0"
31
31
  spec.add_development_dependency "factory_bot", "~> 4.11.1"
32
+ spec.add_development_dependency "manageiq-style"
32
33
  spec.add_development_dependency "rake", "~> 10.0"
33
34
  spec.add_development_dependency "rspec", "~> 3.0"
34
- spec.add_development_dependency "rubocop"
35
- spec.add_development_dependency "rubocop-performance"
36
- spec.add_development_dependency "simplecov"
35
+ spec.add_development_dependency "simplecov", ">= 0.21.2"
37
36
  end
@@ -1,12 +1,20 @@
1
1
  module InventoryRefresh
2
2
  class ApplicationRecordIterator
3
- attr_reader :inventory_collection
3
+ attr_reader :inventory_collection, :manager_uuids_set, :iterator, :query
4
4
 
5
- # An iterator that can fetch batches of the AR objects based on a set of attribute_indexes
5
+ # An iterator that can fetch batches of the AR objects based on a set of manager refs, or just mimics AR relation
6
+ # when given an iterator. Or given query, acts as iterator by selecting batches.
6
7
  #
7
8
  # @param inventory_collection [InventoryRefresh::InventoryCollection] Inventory collection owning the iterator
8
- def initialize(inventory_collection: nil)
9
+ # @param manager_uuids_set [Array<InventoryRefresh::InventoryCollection::Reference>] Array of references we want to
10
+ # fetch from the DB
11
+ # @param iterator [Proc] Block based iterator
12
+ # @query query [ActiveRecord::Relation] Existing query we want to use for querying the db
13
+ def initialize(inventory_collection: nil, manager_uuids_set: nil, iterator: nil, query: nil)
9
14
  @inventory_collection = inventory_collection
15
+ @manager_uuids_set = manager_uuids_set
16
+ @iterator = iterator
17
+ @query = query
10
18
  end
11
19
 
12
20
  # Iterator that mimics find_in_batches of ActiveRecord::Relation. This iterator serves for making more optimized query
@@ -17,22 +25,27 @@ module InventoryRefresh
17
25
  # and relation.where(:id => 500ids)
18
26
  #
19
27
  # @param batch_size [Integer] A batch size we want to fetch from DB
20
- # @param attributes_index [Hash{String => Hash}] Indexed hash with data we will be saving
21
28
  # @yield Code processing the batches
22
- def find_in_batches(batch_size: 1000, attributes_index: {})
23
- attributes_index.each_slice(batch_size) do |batch|
24
- yield(inventory_collection.db_collection_for_comparison_for(batch))
29
+ def find_in_batches(batch_size: 1000, &block)
30
+ if iterator
31
+ iterator.call(&block)
32
+ elsif query
33
+ manager_uuids_set.each_slice(batch_size) do |batch|
34
+ yield(query.where(inventory_collection.targeted_selection_for(batch)))
35
+ end
36
+ else
37
+ manager_uuids_set.each_slice(batch_size) do |batch|
38
+ yield(inventory_collection.db_collection_for_comparison_for(batch))
39
+ end
25
40
  end
26
41
  end
27
42
 
28
43
  # Iterator that mimics find_each of ActiveRecord::Relation using find_in_batches (see #find_in_batches)
29
44
  #
30
45
  # @yield Code processing the batches
31
- def find_each(attributes_index: {})
32
- find_in_batches(:attributes_index => attributes_index) do |batch|
33
- batch.each do |item|
34
- yield(item)
35
- end
46
+ def find_each(&block)
47
+ find_in_batches do |batch|
48
+ batch.each(&block)
36
49
  end
37
50
  end
38
51
  end
@@ -8,30 +8,30 @@ module InventoryRefresh
8
8
  @graph = graph
9
9
  end
10
10
 
11
- ################################################################################################################
12
- # Topological sort of the graph of the DTO collections to find the right order of saving DTO collections and
13
- # identify what DTO collections can be saved in parallel.
14
- # Does not mutate graph.
15
- #
16
- # @return [Array<Array>] Array of arrays(layers) of InventoryCollection objects
17
- ################################################################################################################
18
- # The expected input here is the directed acyclic Graph G (inventory_collections), consisting of Vertices(Nodes) V and
19
- # Edges E:
20
- # G = (V, E)
21
- #
22
- # The directed edge is defined as (u, v), where u is the dependency of v, i.e. arrow comes from u to v:
23
- # (u, v) ∈ E and u,v ∈ V
24
- #
25
- # S0 is a layer that has no dependencies:
26
- # S0 = { v ∈ V ∣ ∀u ∈ V.(u,v) ∉ E}
27
- #
28
- # Si+1 is a layer whose dependencies are in the sum of the previous layers from i to 0, cannot write
29
- # mathematical sum using U in text editor, so there is an alternative format using _(sum)
30
- # Si+1 = { v ∈ V ∣ ∀u ∈ V.(u,v) ∈ E → u ∈ _(sum(S0..Si))_ }
31
- #
32
- # Then each Si can have their Vertices(DTO collections) processed in parallel. This algorithm cannot
33
- # identify independent sub-graphs inside of the layers Si, so we can make the processing even more effective.
34
- ################################################################################################################
11
+ ################################################################################################################
12
+ # Topological sort of the graph of the DTO collections to find the right order of saving DTO collections and
13
+ # identify what DTO collections can be saved in parallel.
14
+ # Does not mutate graph.
15
+ #
16
+ # @return [Array<Array>] Array of arrays(layers) of InventoryCollection objects
17
+ ################################################################################################################
18
+ # The expected input here is the directed acyclic Graph G (inventory_collections), consisting of Vertices(Nodes) V and
19
+ # Edges E:
20
+ # G = (V, E)
21
+ #
22
+ # The directed edge is defined as (u, v), where u is the dependency of v, i.e. arrow comes from u to v:
23
+ # (u, v) ∈ E and u,v ∈ V
24
+ #
25
+ # S0 is a layer that has no dependencies:
26
+ # S0 = { v ∈ V ∣ ∀u ∈ V.(u,v) ∉ E}
27
+ #
28
+ # Si+1 is a layer whose dependencies are in the sum of the previous layers from i to 0, cannot write
29
+ # mathematical sum using U in text editor, so there is an alternative format using _(sum)
30
+ # Si+1 = { v ∈ V ∣ ∀u ∈ V.(u,v) ∈ E → u ∈ _(sum(S0..Si))_ }
31
+ #
32
+ # Then each Si can have their Vertices(DTO collections) processed in parallel. This algorithm cannot
33
+ # identify independent sub-graphs inside of the layers Si, so we can make the processing even more effective.
34
+ ################################################################################################################
35
35
  def topological_sort
36
36
  nodes = graph.nodes.dup
37
37
  edges = graph.edges
@@ -45,14 +45,12 @@ module InventoryRefresh
45
45
  max_depth -= 1
46
46
  if max_depth <= 0
47
47
  message = "Max depth reached while doing topological sort, your graph probably contains a cycle"
48
- #logger.error("#{message}:\n#{graph.to_graphviz}")
49
48
  raise "#{message} (see log)"
50
49
  end
51
50
 
52
51
  set, nodes = nodes.partition { |v| edges.select { |e| e.second == v }.all? { |e| sets.flatten.include?(e.first) } }
53
52
  if set.blank?
54
53
  message = "Blank dependency set while doing topological sort, your graph probably contains a cycle"
55
- #logger.error("#{message}:\n#{graph.to_graphviz}")
56
54
  raise "#{message} (see log)"
57
55
  end
58
56
 
@@ -37,7 +37,7 @@ module InventoryRefresh
37
37
  s << " #{node_names[from]} -> #{node_names[to]};"
38
38
  end
39
39
  s << "}"
40
- s.join("\n") + "\n"
40
+ "#{s.join("\n")}\n"
41
41
  end
42
42
 
43
43
  protected
@@ -147,7 +147,7 @@ module InventoryRefresh
147
147
  nodes.group_by { |n| n.respond_to?(:name) ? n.name.to_s : n.to_s }.each do |base_name, ns|
148
148
  ns.each_with_index do |n, i|
149
149
  name = ns.size == 1 ? base_name : "#{base_name}_#{i}"
150
- name = '"' + name.gsub(/["\\]/) { |c| "\\" + c } + '"' unless name =~ /^[A-Za-z0-9_]+$/
150
+ name = "\"#{name.gsub(/["\\]/) { |c| "\\#{c}" }}\"" unless /^[A-Za-z0-9_]+$/.match?(name)
151
151
  node_names[n] = name
152
152
  end
153
153
  end
@@ -4,17 +4,39 @@ module InventoryRefresh
4
4
  class MissingModelClassError < StandardError; end
5
5
 
6
6
  def self.allowed_properties
7
- %i(arel association
8
- attributes_blacklist attributes_whitelist batch_extra_attributes
9
- complete create_only custom_save_block
10
- custom_reconnect_block default_values
11
- dependency_attributes check_changed inventory_object_attributes
12
- manager_ref manager_ref_allowed_nil
13
- model_class name parent
14
- retention_strategy strategy
15
- secondary_refs
16
- update_only use_ar_object
17
- assert_graph_integrity).to_set
7
+ %i[
8
+ all_manager_uuids
9
+ arel
10
+ association
11
+ attributes_blacklist
12
+ attributes_whitelist
13
+ batch_extra_attributes
14
+ complete
15
+ create_only
16
+ custom_save_block
17
+ custom_reconnect_block
18
+ default_values
19
+ delete_method
20
+ dependency_attributes
21
+ check_changed
22
+ inventory_object_attributes
23
+ manager_ref
24
+ manager_ref_allowed_nil
25
+ manager_uuids
26
+ model_class
27
+ name
28
+ parent
29
+ parent_inventory_collections
30
+ retention_strategy
31
+ strategy
32
+ saver_strategy
33
+ secondary_refs
34
+ targeted
35
+ targeted_arel
36
+ update_only
37
+ use_ar_object
38
+ assert_graph_integrity
39
+ ].to_set
18
40
  end
19
41
 
20
42
  def allowed_properties
@@ -76,8 +98,8 @@ module InventoryRefresh
76
98
 
77
99
  send(@name.to_sym) if @name.respond_to?(:to_sym) && respond_to?(@name.to_sym)
78
100
 
79
- if @properties[:model_class].nil?
80
- add_properties(:model_class => auto_model_class) unless @options[:without_model_class]
101
+ if @properties[:model_class].nil? && !(@options[:without_model_class])
102
+ add_properties(:model_class => auto_model_class)
81
103
  end
82
104
  end
83
105
 
@@ -177,7 +199,7 @@ module InventoryRefresh
177
199
 
178
200
  def assert_allowed_property(name)
179
201
  unless allowed_properties.include?(name)
180
- raise "InventoryCollection property :#{name} is not allowed. Allowed properties are:\n#{self.allowed_properties.to_a.map(&:to_s).join(', ')}"
202
+ raise "InventoryCollection property :#{name} is not allowed. Allowed properties are:\n#{allowed_properties.to_a.map(&:to_s).join(', ')}"
181
203
  end
182
204
  end
183
205
 
@@ -216,7 +238,7 @@ module InventoryRefresh
216
238
  def auto_inventory_attributes
217
239
  return if @properties[:model_class].nil?
218
240
 
219
- (@properties[:model_class].new.methods - ar_base_class.methods).grep(/^[\w]+?\=$/).collect do |setter|
241
+ (@properties[:model_class].new.methods - ar_base_class.methods).grep(/^\w+?=$/).collect do |setter|
220
242
  setter.to_s[0..setter.length - 2].to_sym
221
243
  end
222
244
  end
@@ -70,6 +70,15 @@ module InventoryRefresh
70
70
  build(hash)
71
71
  end
72
72
 
73
+ # Finds InventoryObject.
74
+ #
75
+ # @param hash [Hash] Hash that needs to contain attributes defined in :manager_ref of the InventoryCollection
76
+ # @return [InventoryRefresh::InventoryObject] Found or built InventoryObject object
77
+ def find_in_data(hash)
78
+ _hash, _uuid, inventory_object = primary_index_scan(hash)
79
+ inventory_object
80
+ end
81
+
73
82
  # Finds of builds a new InventoryObject. By building it, we also put in into the InventoryCollection's storage.
74
83
  #
75
84
  # @param hash [Hash] Hash that needs to contain attributes defined in :manager_ref of the