eco-helpers 2.5.3 → 2.5.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 +4 -4
- data/CHANGELOG.md +31 -2
- data/eco-helpers.gemspec +1 -1
- data/lib/eco/api/common/people/person_entry.rb +0 -1
- data/lib/eco/api/organization/tag_tree.rb +38 -9
- data/lib/eco/api/session/config/tagtree.rb +38 -14
- data/lib/eco/api/session/config.rb +8 -2
- data/lib/eco/api/usecases/default_cases/reinvite_trans_case.rb +2 -2
- data/lib/eco/api/usecases/graphql/helpers/base/case_env.rb +15 -0
- data/lib/eco/api/usecases/graphql/helpers/base.rb +3 -11
- data/lib/eco/api/usecases/graphql/helpers/location/base.rb +8 -2
- data/lib/eco/api/usecases/graphql/helpers/location/command.rb +14 -6
- data/lib/eco/api/usecases/graphql/utils/sftp.rb +74 -0
- data/lib/eco/api/usecases/graphql/utils.rb +6 -0
- data/lib/eco/api/usecases/graphql.rb +1 -0
- data/lib/eco/data/files/helpers.rb +3 -3
- data/lib/eco/data/hashes/array_diff.rb +11 -57
- data/lib/eco/data/hashes/diff_meta.rb +52 -0
- data/lib/eco/data/hashes/diff_result.rb +37 -25
- data/lib/eco/data/hashes.rb +1 -0
- data/lib/eco/data/locations/node_diff/accessors.rb +46 -0
- data/lib/eco/data/locations/node_diff/nodes_diff.rb +90 -0
- data/lib/eco/data/locations/node_diff/selectors.rb +20 -0
- data/lib/eco/data/locations/node_diff.rb +55 -0
- data/lib/eco/data/locations/node_level.rb +1 -4
- data/lib/eco/data/locations/node_plain.rb +2 -5
- data/lib/eco/data/locations.rb +1 -0
- data/lib/eco/version.rb +1 -1
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d241b7bc57bd81e9b3a6b1d71ecab5f7530b7b6df176301adc21584722f2b247
|
4
|
+
data.tar.gz: a8beafa1e6cd1e3425291121c55b78fe144f155021ab149148fcc6ce35569984
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bad589998061077bac0f6adb500fdbb9402b77578da68bf43a84f83101a2bf862213acb00707a363f5583c47ec94a876c367360c562043865e573232b272c4c
|
7
|
+
data.tar.gz: 7c33f358f5cbb7ab0b3118d7b0b20e86a9f686f2e1f49216e23bea5ab504ca4bb0bbb2eeab8bb37daf0d11b997af0160212ff7ab2d1fe382fa05a6b354529f48
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,37 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
-
## [2.5.
|
4
|
+
## [2.5.6] - 2023-08-xx
|
5
|
+
|
6
|
+
### Added
|
7
|
+
### Changed
|
8
|
+
### Fixed
|
9
|
+
|
10
|
+
## [2.5.5] - 2023-08-03
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- `Eco::API::Organization::TagTree` - **added/improved methods**
|
14
|
+
- `#as_json` new parameter `max_depth:` to be able to cut the tree
|
15
|
+
- `#active_tree` new method to exclude archived nodes.
|
16
|
+
- `#truncate` new method to obtain a tree cut to `max_depth:`
|
17
|
+
- `Eco::API::Session::Config::Tagtree`: **exposed** `include_archived:` (a.k.a. `inludeArchivedNodes`).
|
18
|
+
- This change states that `session.tagtree` does not retrieve archived nodes by default, while `session.live_tree` does retrieve archived nodes.
|
19
|
+
- This change required an update on the `ecoportal-api-graphql` **gem**
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
- `Eco::API::Organization::TagTree#path` - dups the result (rather than exposing the internal path array)
|
23
|
+
|
24
|
+
## [2.5.4] - 2023-07-27
|
25
|
+
|
26
|
+
### Added
|
27
|
+
- SFTP case helpers: `Eco::API::UseCases::GraphQL::Utils::Sftp`
|
28
|
+
- `Eco::Data::Locations::NodeDiff` and `Eco::Data::Locations::NodeDiff::NodeDiffs`
|
29
|
+
- Aim to identify changes in the locations structure
|
30
|
+
|
31
|
+
### Changed
|
32
|
+
- Some internal tidy up in `Eco::API::UseCases::GraphQL`
|
33
|
+
|
34
|
+
## [2.5.3] - 2023-07-19
|
5
35
|
|
6
36
|
### Added
|
7
37
|
- _GraphQL base case_ for **locations structure update**.
|
@@ -52,7 +82,6 @@ All notable changes to this project will be documented in this file.
|
|
52
82
|
- `Eco::API::Session::Config::Workflow#exit_handle`
|
53
83
|
- Allows to define a callback on `SystemExit` (`exit` call).
|
54
84
|
|
55
|
-
### Changed
|
56
85
|
### Fixed
|
57
86
|
- `Eco::API::Session::Config::Workflow` on `SystemExit` preserve original exit `status` value (i.e. `0`, `1`)
|
58
87
|
- It was changing an `exit 1` to be an `exit 0`
|
data/eco-helpers.gemspec
CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
|
33
33
|
spec.add_dependency 'ecoportal-api', '>= 0.9.4', '< 0.10'
|
34
34
|
spec.add_dependency 'ecoportal-api-v2', '>= 1.1.3', '< 1.2'
|
35
|
-
spec.add_dependency 'ecoportal-api-graphql', '>= 0.3.
|
35
|
+
spec.add_dependency 'ecoportal-api-graphql', '>= 0.3.9', '< 0.4'
|
36
36
|
spec.add_dependency 'aws-sdk-s3', '>= 1.83.0', '< 2'
|
37
37
|
spec.add_dependency 'aws-sdk-ses', '>= 1.36.0', '< 2'
|
38
38
|
spec.add_dependency 'dotenv', '>= 2.7.6', '< 3'
|
@@ -76,9 +76,23 @@ module Eco
|
|
76
76
|
@archived
|
77
77
|
end
|
78
78
|
|
79
|
+
def active?
|
80
|
+
!archived?
|
81
|
+
end
|
82
|
+
|
79
83
|
# @return [Eco::API::Organization::TagTree]
|
80
84
|
def dup
|
81
|
-
self.class.new(as_json)
|
85
|
+
self.class.new(as_json, name: name, id: id)
|
86
|
+
end
|
87
|
+
|
88
|
+
# @return [Eco::API::Organization::TagTree] with **non** `archived` nodes only
|
89
|
+
def active_tree
|
90
|
+
self.class.new(as_json(include_archived: false), name: name, id: id)
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [Eco::API::Organization::TagTree] with nodes up to `max_depth`
|
94
|
+
def truncate(max_depth: total_depth)
|
95
|
+
self.class.new(as_json(max_depth: max_depth), name: name, id: id)
|
82
96
|
end
|
83
97
|
|
84
98
|
# Iterate through all the nodes of this tree
|
@@ -161,11 +175,26 @@ module Eco
|
|
161
175
|
# Returns a tree of Hashes form nested via `nodes` (or just a list of hash nodes)
|
162
176
|
# @yield [node_json, node] block for custom output json model
|
163
177
|
# @yiledreturn [Hash] the custom json model.
|
164
|
-
# @include_children [Boolean] whether it should return a tree hash or just a list of hash nodes.
|
178
|
+
# @param include_children [Boolean] whether it should return a tree hash or just a list of hash nodes.
|
179
|
+
# @param include_archived [Boolean] whether it should include archived nodes.
|
180
|
+
# @param max_depth [Boolean] up to what level `depth` nodes should be included.
|
165
181
|
# @return [Array[Hash]] where `Hash` is a `node` (i.e. `{"tag" => TAG, "nodes": Array[Hash]}`)
|
166
|
-
def as_json(include_children: true, &block)
|
167
|
-
|
168
|
-
|
182
|
+
def as_json(include_children: true, include_archived: true, max_depth: total_depth, &block)
|
183
|
+
max_depth ||= total_depth
|
184
|
+
return nil if max_depth < depth
|
185
|
+
return [] if top? && !include_children
|
186
|
+
return nil if archived? && !include_archived
|
187
|
+
|
188
|
+
if include_children
|
189
|
+
child_nodes = nodes
|
190
|
+
child_nodes = child_nodes.select(&:active?) unless include_archived
|
191
|
+
kargs = {
|
192
|
+
include_children: include_children,
|
193
|
+
include_archived: include_archived,
|
194
|
+
max_depth: max_depth
|
195
|
+
}
|
196
|
+
children_json = child_nodes.map {|nd| nd.as_json(**kargs, &block)}.compact
|
197
|
+
end
|
169
198
|
|
170
199
|
if top?
|
171
200
|
children_json
|
@@ -180,8 +209,8 @@ module Eco
|
|
180
209
|
|
181
210
|
# Returns a plain list form of hash nodes.
|
182
211
|
# @return [Array[Hash]] where `Hash` is a plain `node`
|
183
|
-
def as_nodes_json
|
184
|
-
all_nodes.map {|nd| nd.as_json(include_children: false)}
|
212
|
+
def as_nodes_json(&block)
|
213
|
+
all_nodes.map {|nd| nd.as_json(include_children: false, &block)}
|
185
214
|
end
|
186
215
|
|
187
216
|
# @return [Boolean] `true` if there are tags in the node, `false` otherwise.
|
@@ -287,8 +316,8 @@ module Eco
|
|
287
316
|
# @param key [String] tag to find the path to.
|
288
317
|
# @return [Array<String>]
|
289
318
|
def path(key = nil)
|
290
|
-
return @path if !key
|
291
|
-
@hash_paths[key.upcase]
|
319
|
+
return @path.dup if !key
|
320
|
+
@hash_paths[key.upcase].dup
|
292
321
|
end
|
293
322
|
|
294
323
|
# Helper to assign tags to a person account.
|
@@ -3,18 +3,30 @@ module Eco
|
|
3
3
|
class Session
|
4
4
|
class Config
|
5
5
|
class TagTree < BaseConfig
|
6
|
+
class MissingTagtree < StandardError
|
7
|
+
end
|
8
|
+
|
6
9
|
attr_key :file
|
7
10
|
|
8
|
-
|
11
|
+
# @param include_archived [Boolean] whether or not it should include archived nodes.
|
12
|
+
# @return [Eco::API::Organization::TagTree]
|
13
|
+
def scope_tree(enviro: nil, include_archived: true, raise_on_missing: true)
|
9
14
|
return @tagtree if instance_variable_defined?(:@tagtree) && @tagtree.enviro == enviro
|
10
15
|
if tree_file = self.file
|
11
16
|
if (tree = file_manager.load_json(tree_file)) && !tree.empty?
|
12
17
|
@tagtree = Eco::API::Organization::TagTree.new(tree, enviro: enviro)
|
13
18
|
end
|
14
19
|
end
|
15
|
-
|
20
|
+
|
21
|
+
kargs = {
|
22
|
+
enviro: enviro,
|
23
|
+
includeArchivedNodes: include_archived
|
24
|
+
}
|
25
|
+
|
26
|
+
@tagtree ||= live_tree(**kargs).tap do |tree|
|
16
27
|
unless tree && !tree.empty?
|
17
|
-
|
28
|
+
msg = "Could not find a local or live locations structure."
|
29
|
+
raise MissingTagtree, msg
|
18
30
|
end
|
19
31
|
end
|
20
32
|
end
|
@@ -23,13 +35,18 @@ module Eco
|
|
23
35
|
# If `id` is provided, it only retrieves this locations structure.
|
24
36
|
def live_tree(id: nil, enviro: nil, include_archived: false, **kargs, &block)
|
25
37
|
return @live_tree if instance_variable_defined?(:@live_tree) && @live_tree.enviro == enviro
|
38
|
+
|
39
|
+
kargs = {
|
40
|
+
enviro: enviro,
|
41
|
+
includeArchivedNodes: include_archived
|
42
|
+
}.merge(kargs)
|
43
|
+
|
26
44
|
if id
|
27
|
-
args = {id: id
|
45
|
+
args = { id: id }.merge(kargs)
|
28
46
|
@live_tree = live_tree_get(**args, &block)
|
29
47
|
else
|
30
|
-
|
31
|
-
|
32
|
-
trees = live_trees(enviro: enviro, &block)
|
48
|
+
kargs
|
49
|
+
trees = live_trees(**kargs, &block)
|
33
50
|
@live_tree = trees.reject do |tree|
|
34
51
|
tree.empty?
|
35
52
|
end.max do |a,b|
|
@@ -45,26 +62,33 @@ module Eco
|
|
45
62
|
|
46
63
|
# Gets a single locations structure
|
47
64
|
# @note it does not memoize
|
65
|
+
# @param include_archived [Boolean] whether or not to include archived **nodes**
|
66
|
+
# @return [Eco::API::Organization::TagTree, NilClass]
|
48
67
|
def live_tree_get(id: nil, enviro: nil, include_archived: false, **kargs, &block)
|
49
68
|
return nil unless apis.active_api.version_available?(:graphql)
|
50
69
|
return nil unless graphql = apis.api(version: :graphql)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
70
|
+
|
71
|
+
kargs = {
|
72
|
+
id: id,
|
73
|
+
includeArchivedNodes: include_archived
|
74
|
+
}.merge(kargs)
|
75
|
+
|
76
|
+
return nil unless tree = graphql.currentOrganization.locationStructure(**kargs, &block)
|
55
77
|
args = { enviro: enviro, id: tree.id, name: tree.name }
|
56
78
|
Eco::API::Organization::TagTree.new(tree.treeify, **args)
|
57
79
|
end
|
58
80
|
|
59
81
|
# Retrieves all the location structures of the organisation
|
82
|
+
# @param include_archived [Boolean] whether or not to include archived **nodes**
|
83
|
+
# @return [Array<Eco::API::Organization::TagTree>]
|
60
84
|
def live_trees(enviro: nil, include_archived: false, **kargs, &block)
|
61
85
|
[].tap do |eco_trees|
|
62
86
|
next unless apis.active_api.version_available?(:graphql)
|
63
87
|
next unless graphql = apis.api(version: :graphql)
|
88
|
+
|
64
89
|
kargs = {
|
65
|
-
|
66
|
-
|
67
|
-
}.merge(kargs).slice(:includeArchived, :includeUnpublished)
|
90
|
+
includeArchivedNodes: include_archived
|
91
|
+
}.merge(kargs)
|
68
92
|
|
69
93
|
next unless trees = graphql.currentOrganization.locationStructures(**kargs, &block)
|
70
94
|
trees.each do |tree|
|
@@ -235,9 +235,15 @@ module Eco
|
|
235
235
|
end
|
236
236
|
|
237
237
|
# It uses the `tagtree.json` file and in its absence, if `graphql` enabled, the largest `life_tagtree`
|
238
|
+
# @note it does NOT include archived nodes by default.
|
239
|
+
# - This is for legacy (most usecases don't)
|
240
|
+
# @param include_archived [Boolean] whether or not it should include archived nodes.
|
238
241
|
# @return [Eco::API::Organization::TagTree]
|
239
|
-
def tagtree(enviro: nil)
|
240
|
-
|
242
|
+
def tagtree(enviro: nil, include_archived: false, raise_on_missing: true)
|
243
|
+
kargs = {
|
244
|
+
enviro: enviro, include_archived: include_archived, raise_on_missing: raise_on_missing
|
245
|
+
}
|
246
|
+
@tagtree ||= tagtree_config.scope_tree(**kargs)
|
241
247
|
end
|
242
248
|
|
243
249
|
# It obtains the first of the live tagtree in the org
|
@@ -12,9 +12,9 @@ class Eco::API::UseCases::DefaultCases::ReinviteTransCase < Eco::API::Common::Lo
|
|
12
12
|
invite = session.new_job("main", "invite", :update, usecase, :account)
|
13
13
|
users.each do |person|
|
14
14
|
if force_invite?
|
15
|
-
person.account.send_invites = true
|
16
|
-
else
|
17
15
|
person.account.force_send_invites = true
|
16
|
+
else
|
17
|
+
person.account.send_invites = true
|
18
18
|
end
|
19
19
|
invite.add(person)
|
20
20
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Eco::API::UseCases::GraphQL::Helpers::Base
|
2
|
+
# Basic stuff you would need in any use case
|
3
|
+
module CaseEnv
|
4
|
+
include Eco::Language::AuxiliarLogger
|
5
|
+
attr_reader :session, :options
|
6
|
+
|
7
|
+
def config
|
8
|
+
session.config
|
9
|
+
end
|
10
|
+
|
11
|
+
def simulate?
|
12
|
+
options.dig(:simulate)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,20 +1,12 @@
|
|
1
1
|
module Eco::API::UseCases::GraphQL::Helpers
|
2
2
|
module Base
|
3
|
-
|
4
|
-
|
3
|
+
require_relative 'base/case_env'
|
4
|
+
include Eco::API::UseCases::GraphQL::Helpers::Base::CaseEnv
|
5
5
|
|
6
6
|
def graphql
|
7
7
|
@graphql ||= session.api(version: :graphql)
|
8
8
|
end
|
9
9
|
|
10
|
-
def config
|
11
|
-
session.config
|
12
|
-
end
|
13
|
-
|
14
|
-
def simulate?
|
15
|
-
options.dig(:simulate)
|
16
|
-
end
|
17
|
-
|
18
10
|
# Keep a copy of the requests/responses for future reference
|
19
11
|
def backup(data, type:)
|
20
12
|
dry_run = simulate? ? "_dry_run" : ""
|
@@ -24,7 +16,7 @@ module Eco::API::UseCases::GraphQL::Helpers
|
|
24
16
|
end
|
25
17
|
|
26
18
|
def exit_error(msg)
|
27
|
-
|
19
|
+
log(:error) { msg }
|
28
20
|
exit(1)
|
29
21
|
end
|
30
22
|
end
|
@@ -68,7 +68,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
68
68
|
msg << "nor options(:source, :structure_id). "
|
69
69
|
msg << "Infering active locations structure."
|
70
70
|
log(:warn) { msg }
|
71
|
-
if self.current_tree =
|
71
|
+
if self.current_tree = session_live_tree
|
72
72
|
@target_structure_id = current_tree.id
|
73
73
|
end
|
74
74
|
end
|
@@ -81,7 +81,13 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
81
81
|
tree_init = current_tree
|
82
82
|
target_id = target_structure_id
|
83
83
|
return current_tree if current_tree != tree_init
|
84
|
-
self.current_tree =
|
84
|
+
self.current_tree = session_live_tree(id: target_id)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Unique access point to retrieve the live tree
|
88
|
+
# @note ensures archived nodes are retrieved.
|
89
|
+
def session_live_tree(id: nil)
|
90
|
+
session.live_tree(id: id, include_archived: true)
|
85
91
|
end
|
86
92
|
end
|
87
93
|
end
|
@@ -3,17 +3,25 @@ module Eco::API::UseCases::GraphQL::Helpers::Location
|
|
3
3
|
include Eco::Language::AuxiliarLogger
|
4
4
|
include Eco::API::UseCases::GraphQL::Helpers::Location::Base
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
# Whether to stop or continue on command fail
|
9
|
-
FORCE_CONTINUE = false
|
6
|
+
DEFAULT_COMMANDS_PER_PAGE = 45
|
7
|
+
DEFAULT_FORCE_CONTINUE = false
|
10
8
|
|
9
|
+
# Prevents each request from timing out
|
11
10
|
def commands_per_page
|
12
|
-
self.class
|
11
|
+
if self.class.const_defined?(:COMMANDS_PER_PAGE)
|
12
|
+
self.class::COMMANDS_PER_PAGE
|
13
|
+
else
|
14
|
+
DEFAULT_COMMANDS_PER_PAGE
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
18
|
+
# Whether to stop or continue on command fail
|
15
19
|
def force_continue?
|
16
|
-
self.class
|
20
|
+
if self.class.const_defined?(:FORCE_CONTINUE)
|
21
|
+
self.class::FORCE_CONTINUE
|
22
|
+
else
|
23
|
+
DEFAULT_FORCE_CONTINUE
|
24
|
+
end
|
17
25
|
end
|
18
26
|
|
19
27
|
# With given the commands, it generates the input of the endpoint mutation.
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Eco::API::UseCases::GraphQL::Utils
|
2
|
+
module Sftp
|
3
|
+
include Eco::API::UseCases::GraphQL::Helpers::Base::CaseEnv
|
4
|
+
|
5
|
+
|
6
|
+
def remote_subfolder
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def remote_folder(subfolder = remote_subfolder)
|
11
|
+
"#{sftp_config.remote_folder}/#{subfolder || ''}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def sftp_group_id
|
15
|
+
if self.class.const_defined?(:SFTP_GROUP)
|
16
|
+
self.class.const_get(:TARGET_STRUCTURE_ID)
|
17
|
+
elsif group_id = options.dig(:sftp, :group)
|
18
|
+
group_id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def upload(local_file, remote_folder: self.remote_folder, gid: sftp_group_id)
|
23
|
+
return false unless local_file && File.exists?(local_file)
|
24
|
+
dest_file = "#{remote_folder}/#{File.basename(local_file)}"
|
25
|
+
res = sftp_session.upload!(local_file, dest_file)
|
26
|
+
attrs = sftp_session.stat!(dest_file)
|
27
|
+
if gid && gid != attrs.gid
|
28
|
+
stat_res = sftp_session.setstat!(dest_file, {permissions: 0660, uid: attrs.uid, gid: gid})
|
29
|
+
end
|
30
|
+
logger.info("Uploaded '#{local_file}' (#{res})")
|
31
|
+
end
|
32
|
+
|
33
|
+
def ensure_remote_empty
|
34
|
+
files = with_remote_files
|
35
|
+
unless files.empty?
|
36
|
+
msg = "There are still files in the remote folder that will be deleted: '#{remote_folder}':\n"
|
37
|
+
msg += " • " + files.map do |file|
|
38
|
+
file.longname
|
39
|
+
end.join("\n • ") + "\n"
|
40
|
+
session.prompt_user("Do you want to proceed to delete? (Y/n):", explanation: msg, default: "Y", timeout: 3) do |response|
|
41
|
+
if response.upcase.start_with?("Y")
|
42
|
+
files.each do |file|
|
43
|
+
remote_full_path = to_remote_path(file.name)
|
44
|
+
res = sftp_session.remove(remote_full_path)
|
45
|
+
logger.info("Deleted remote file: '#{remote_full_path}' (#{res})")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def with_remote_files
|
53
|
+
sftp.files(remote_folder).each do |remote_file|
|
54
|
+
yield(remote_file) if block_given?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_remote_path(file, subfolder: nil)
|
59
|
+
remote_folder(subfolder) + "/" + file
|
60
|
+
end
|
61
|
+
|
62
|
+
def sftp_config
|
63
|
+
session.config.sftp
|
64
|
+
end
|
65
|
+
|
66
|
+
def sftp_session
|
67
|
+
sftp.sftp_session
|
68
|
+
end
|
69
|
+
|
70
|
+
def sftp
|
71
|
+
session.sftp
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -75,11 +75,11 @@ module Eco
|
|
75
75
|
Dir.exist?(path) || Dir.exist?(File.expand_path(path))
|
76
76
|
end
|
77
77
|
|
78
|
-
def timestamp(timestamp_pattern = DEFAULT_TIMESTAMP_PATTERN)
|
79
|
-
|
78
|
+
def timestamp(timestamp_pattern = DEFAULT_TIMESTAMP_PATTERN, date = Time.now)
|
79
|
+
date.strftime(timestamp_pattern)
|
80
80
|
end
|
81
81
|
|
82
|
-
def timestamp_file(filename, timestamp_pattern =
|
82
|
+
def timestamp_file(filename, timestamp_pattern =DEFAULT_TIMESTAMP_PATTERN)
|
83
83
|
file_pattern = Eco::Data::Files::FilePattern.new(filename)
|
84
84
|
file_pattern.resolve(start: timestamp(timestamp_pattern) + '_')
|
85
85
|
end
|
@@ -3,47 +3,16 @@ module Eco
|
|
3
3
|
module Hashes
|
4
4
|
class ArrayDiff
|
5
5
|
extend Eco::Language::Models::ClassHelpers
|
6
|
-
|
7
|
-
|
8
|
-
def key(value = nil)
|
9
|
-
return @key unless value
|
10
|
-
@key = value.to_s
|
11
|
-
end
|
12
|
-
|
13
|
-
def key?
|
14
|
-
!!@key
|
15
|
-
end
|
16
|
-
|
17
|
-
def compare(*attrs)
|
18
|
-
compared_attrs.push(*attrs.map(&:to_s)).uniq!
|
19
|
-
end
|
20
|
-
|
21
|
-
def case_sensitive(value = nil)
|
22
|
-
@case_sensitive = false unless instance_variable_defined?(:@case_sensitive)
|
23
|
-
return @case_sensitive unless value
|
24
|
-
@case_sensitive = !!value
|
25
|
-
end
|
26
|
-
|
27
|
-
def case_sensitive?
|
28
|
-
!!@case_sensitive
|
29
|
-
end
|
30
|
-
|
31
|
-
def compared_attrs
|
32
|
-
@compared_attrs ||= []
|
33
|
-
@compared_attrs
|
34
|
-
end
|
35
|
-
end
|
6
|
+
# We can change the `DiffResult` class (items)
|
7
|
+
class_resolver :diff_result_class, "Eco::Data::Hash::DiffResult"
|
36
8
|
|
37
9
|
include Eco::Language::AuxiliarLogger
|
38
10
|
|
39
11
|
attr_reader :source1, :source2
|
40
12
|
attr_reader :src_h1, :src_h2
|
41
13
|
|
42
|
-
|
43
|
-
|
44
|
-
def initialize(source1, source2, logger: nil, **kargs)
|
14
|
+
def initialize(source1, source2, logger: nil)
|
45
15
|
@logger = logger if logger
|
46
|
-
@options = kargs
|
47
16
|
@source1 = source1
|
48
17
|
@source2 = source2
|
49
18
|
@src_h1 = by_key(source1)
|
@@ -67,14 +36,11 @@ module Eco
|
|
67
36
|
!diffs.empty?
|
68
37
|
end
|
69
38
|
|
39
|
+
# All the items that contain the diff of a node.
|
40
|
+
# @return [Array<Eco::Data::Hash::DiffResult>]
|
70
41
|
def source_results
|
71
42
|
@source_results ||= paired_sources.each_with_object([]) do |(src1, src2), res|
|
72
|
-
|
73
|
-
key: key,
|
74
|
-
compare: compared_attrs,
|
75
|
-
case_sensitive: case_sensitive?
|
76
|
-
}
|
77
|
-
res << diff_result_class.new(src1, src2, **args)
|
43
|
+
res << diff_result_class.new(src1, src2)
|
78
44
|
end
|
79
45
|
end
|
80
46
|
|
@@ -91,35 +57,23 @@ module Eco
|
|
91
57
|
all_keys.map {|key| [src_h1[key], src_h2[key]]}
|
92
58
|
end
|
93
59
|
|
60
|
+
# @return [String] the `key` attribute of `diff_result_class`
|
94
61
|
def key
|
95
|
-
|
96
|
-
|
97
|
-
end.tap do |k|
|
98
|
-
raise "missing main key attr to pair records. Given: #{k}" unless k.is_a?(String)
|
62
|
+
diff_result_class.key.tap do |k|
|
63
|
+
raise "#{diff_result_class}: missing main key attr to pair records. Given: #{k}" unless k.is_a?(String)
|
99
64
|
end
|
100
65
|
end
|
101
66
|
|
102
67
|
def case_sensitive?
|
103
|
-
|
68
|
+
diff_result_class.case_sensitive?
|
104
69
|
end
|
105
70
|
|
106
71
|
def compared_attrs
|
107
|
-
|
108
|
-
self.class.compared_attrs
|
109
|
-
end.yield_self do |attrs|
|
110
|
-
raise "compared_attrs should be an array" unless attrs.is_a?(Array)
|
111
|
-
attrs.map(&:to_s)
|
112
|
-
end
|
72
|
+
diff_result_class.compared_attrs.map(&:to_s)
|
113
73
|
end
|
114
74
|
|
115
75
|
private
|
116
76
|
|
117
|
-
def options_or(opt)
|
118
|
-
opt = opt.to_sym
|
119
|
-
return @options[opt] if @options.key?(opt)
|
120
|
-
yield
|
121
|
-
end
|
122
|
-
|
123
77
|
def symbolize_keys(hash)
|
124
78
|
hash.each_with_object({}) do |(k, v), h|
|
125
79
|
h[k.to_sym] = v
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Eco
|
2
|
+
module Data
|
3
|
+
module Hashes
|
4
|
+
module DiffMeta
|
5
|
+
class << self
|
6
|
+
def included(base)
|
7
|
+
super(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# @param value [String, NilClass]
|
14
|
+
# @return [String] the attribute that is key of the node diff elements.
|
15
|
+
def key(value = nil)
|
16
|
+
return @key unless value
|
17
|
+
@key = value.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Boolean] is there a `key` attribute defined?
|
21
|
+
def key?
|
22
|
+
!!@key
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param attrs [Array<Symbol>, Array<String>]
|
26
|
+
# @return [Array<String>] the comparable attributes
|
27
|
+
def compare(*attrs)
|
28
|
+
compared_attrs.push(*attrs.map(&:to_s)).uniq!
|
29
|
+
compared_attrs
|
30
|
+
end
|
31
|
+
|
32
|
+
# Whether or not the diff calc of a node should be done case sensitive or insensitive.
|
33
|
+
def case_sensitive(value = nil)
|
34
|
+
@case_sensitive = false unless instance_variable_defined?(:@case_sensitive)
|
35
|
+
return @case_sensitive unless value
|
36
|
+
@case_sensitive = !!value
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Boolean] are comparisons of values done case sensitive?
|
40
|
+
def case_sensitive?
|
41
|
+
!!@case_sensitive
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Array<String>] the comparable attributes
|
45
|
+
def compared_attrs
|
46
|
+
@compared_attrs ||= []
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -2,19 +2,32 @@ module Eco
|
|
2
2
|
module Data
|
3
3
|
module Hashes
|
4
4
|
class DiffResult
|
5
|
-
|
5
|
+
extend Eco::Language::Models::ClassHelpers
|
6
|
+
include Eco::Data::Hashes::DiffMeta
|
7
|
+
|
8
|
+
inheritable_class_vars :key, :compared_attrs, :case_sensitive
|
9
|
+
|
6
10
|
attr_reader :src1, :src2
|
7
11
|
|
8
|
-
|
9
|
-
# - `:all` compares the matching attrs between both hashes only
|
10
|
-
def initialize(src1, src2, key:, compare: :all, case_sensitive: false)
|
11
|
-
@key = key
|
12
|
-
@compare = compare
|
13
|
-
@case_sensitive = case_sensitive
|
12
|
+
def initialize(src1, src2)
|
14
13
|
@src1 = src1
|
15
14
|
@src2 = src2
|
16
15
|
end
|
17
16
|
|
17
|
+
def key
|
18
|
+
self.class.key
|
19
|
+
end
|
20
|
+
|
21
|
+
def case_sensitive?
|
22
|
+
self.class.case_sensitive?
|
23
|
+
end
|
24
|
+
|
25
|
+
def dup(src1: nil, src2: nil)
|
26
|
+
src1 ||= self.src1
|
27
|
+
src2 ||= self.src2
|
28
|
+
self.class.new(src1.dup, src2.dup)
|
29
|
+
end
|
30
|
+
|
18
31
|
def new?
|
19
32
|
!src1 && !!src2
|
20
33
|
end
|
@@ -27,35 +40,39 @@ module Eco
|
|
27
40
|
!new? && !del? && diff?
|
28
41
|
end
|
29
42
|
|
43
|
+
# @note `diff_attrs` may not include the `key` attribute
|
44
|
+
# This is always included via `new?` (new key value) and `del?` (missing key value)
|
45
|
+
# @return [Boolean] was there any change?
|
30
46
|
def diff?
|
31
47
|
new? || del? || !diff_attrs.empty?
|
32
48
|
end
|
33
49
|
|
34
|
-
# Is the key attr value changing?
|
50
|
+
# Is the `key` attr value changing?
|
35
51
|
def key?
|
36
52
|
!(new? || del?) && diff_attr?(key)
|
37
53
|
end
|
38
54
|
|
55
|
+
# Is `attr` part of the attributes that change?
|
39
56
|
def diff_attr?(attr)
|
40
57
|
return true if new?
|
41
58
|
return true if del?
|
42
59
|
diff_attrs.include?(attr.to_s)
|
43
60
|
end
|
44
61
|
|
62
|
+
# @return [Value] the current value of `attr` (in `src2`)
|
45
63
|
def attr(attr)
|
46
64
|
return nil unless src2
|
47
65
|
src2[attr.to_s]
|
48
66
|
end
|
49
67
|
|
68
|
+
# @return [Value] the previous value of `attr` (in `src1`)
|
50
69
|
def attr_prev(attr)
|
51
70
|
return nil unless src1
|
52
71
|
src1[attr.to_s]
|
53
72
|
end
|
54
73
|
|
55
|
-
|
56
|
-
|
57
|
-
end
|
58
|
-
|
74
|
+
# @note the `key` attribute will always be added (even if there's no change)
|
75
|
+
# @return [Hash] hash with the differences as per `src2`
|
59
76
|
def diff_hash
|
60
77
|
target_attrs = [key] | compared_attrs
|
61
78
|
return src2.slice(*target_attrs) if new?
|
@@ -63,12 +80,14 @@ module Eco
|
|
63
80
|
src2.slice(key, *diff_attrs)
|
64
81
|
end
|
65
82
|
|
83
|
+
# @return [Array<Symbol>] hash with the differences as per `src2`
|
66
84
|
def diff_attrs
|
67
85
|
@diff_attrs ||= comparable_attrs.each_with_object([]) do |attr, out|
|
68
86
|
out << attr unless eq?(src1[attr], src2[attr])
|
69
87
|
end
|
70
88
|
end
|
71
89
|
|
90
|
+
# @return [Boolean] whether `val1` is equal to `val2`
|
72
91
|
def eq?(val1, val2)
|
73
92
|
return true if val1 == val2
|
74
93
|
return false if case_sensitive?
|
@@ -76,25 +95,18 @@ module Eco
|
|
76
95
|
val1.upcase == val2.upcase
|
77
96
|
end
|
78
97
|
|
79
|
-
|
80
|
-
|
81
|
-
end
|
82
|
-
|
98
|
+
# @note when is `new?` or to be deleted (`del?`), it returns empty array.
|
99
|
+
# @return [Array<String>] the set of attributes that are comparable in this instance.
|
83
100
|
def comparable_attrs
|
84
101
|
return [] if new? || del?
|
85
102
|
compared_attrs
|
86
103
|
end
|
87
104
|
|
105
|
+
# @return [Array<String>] the set of attributes that are comparable in this class.
|
88
106
|
def compared_attrs
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
src1.keys & src2.keys
|
93
|
-
elsif @compare.is_a?(Array)
|
94
|
-
@compare.map(&:to_s)
|
95
|
-
else
|
96
|
-
raise "Expecting 'compare' to be sym (:all) or Array<String>. Given: #{@compare.class}"
|
97
|
-
end
|
107
|
+
comp_attrs = self.class.compared_attrs.map(&:to_s).uniq
|
108
|
+
return comp_attrs unless comp_attrs.empty?
|
109
|
+
(src1&.keys || []) & (src2&.keys || [])
|
98
110
|
end
|
99
111
|
end
|
100
112
|
end
|
data/lib/eco/data/hashes.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
class Eco::Data::Locations::NodeDiff
|
2
|
+
module Accessors
|
3
|
+
class << self
|
4
|
+
def included(base)
|
5
|
+
super(base)
|
6
|
+
base.extend Eco::Language::Models::ClassHelpers
|
7
|
+
base.extend ClassMethods
|
8
|
+
base.inheritable_class_vars :exposed_attrs
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# Creates the defined accessor attributes against `NodeDiff`
|
14
|
+
# It also creates a method with question mark that evaluates true if **any** the attr changed.
|
15
|
+
# @note the defined attributes are expected to be the keys within
|
16
|
+
# the source Hashes that are being compared.
|
17
|
+
# @note accessing `src1` (prev) attributes, will have it's method as `prev_[attrName]`
|
18
|
+
def attr_expose(*attrs)
|
19
|
+
attrs.each do |attr|
|
20
|
+
meth = attr.to_sym
|
21
|
+
methp = "prev_#{meth}".to_sym
|
22
|
+
methq = "diff_#{meth}?".to_sym
|
23
|
+
|
24
|
+
define_method meth do
|
25
|
+
attr(meth)
|
26
|
+
end
|
27
|
+
|
28
|
+
define_method methp do
|
29
|
+
attr_prev(meth)
|
30
|
+
end
|
31
|
+
|
32
|
+
exposed_attrs |= [meth]
|
33
|
+
|
34
|
+
define_method methq do
|
35
|
+
diff_attr?(meth)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Keeps track on what attributes have been exposed.
|
41
|
+
def exposed_attrs
|
42
|
+
@exposed_attrs ||= []
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
class Eco::Data::Locations::NodeDiff
|
2
|
+
# Adjusts ArrayDiff for Nodes diffs in a location structure
|
3
|
+
class NodesDiff < Eco::Data::Hashes::ArrayDiff
|
4
|
+
extend Eco::Data::Locations::NodeDiff::Selectors
|
5
|
+
|
6
|
+
SELECTORS = %i[id name id_name insert unarchive update move archive]
|
7
|
+
selector *SELECTORS
|
8
|
+
|
9
|
+
class_resolver :diff_result_class, Eco::Data::Locations::NodeDiff
|
10
|
+
attr_reader :original_tree
|
11
|
+
|
12
|
+
def initialize(*args, original_tree:, **kargs, &block)
|
13
|
+
super(*args, **kargs, &block)
|
14
|
+
@original_tree = original_tree
|
15
|
+
end
|
16
|
+
|
17
|
+
def diffs
|
18
|
+
@diffs ||= super.select do |res|
|
19
|
+
res.unarchive? || res.id_name? || res.insert? || res.move? || res.archive?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def diffs_details
|
24
|
+
section = '#' * 10
|
25
|
+
msg = ''
|
26
|
+
if insert?
|
27
|
+
msg << " #{section} I N S E R T S #{section}\n"
|
28
|
+
msg << insert.map {|d| d.diff_hash.pretty_inspect}.join('')
|
29
|
+
end
|
30
|
+
|
31
|
+
if update?
|
32
|
+
msg << "\n #{section} U P D A T E S #{section}\n"
|
33
|
+
update.each do |d|
|
34
|
+
flags = ''
|
35
|
+
#flags << 'i' if d.id?
|
36
|
+
flags << 'n' if d.diff_name?
|
37
|
+
flags << 'm' if d.move?
|
38
|
+
flags << 'u' if d.unarchive?
|
39
|
+
msg << "<< #{flags} >> "
|
40
|
+
msg << d.diff_hash.pretty_inspect
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if archive?
|
45
|
+
msg << "\n #{section} A R C H I V E S #{section}\n"
|
46
|
+
msg << archive.map {|d| d.diff_hash.pretty_inspect}.join('')
|
47
|
+
end
|
48
|
+
|
49
|
+
msg
|
50
|
+
end
|
51
|
+
|
52
|
+
def diffs_summary
|
53
|
+
return "There were no differences identified" if diffs.empty?
|
54
|
+
msg = "Identified #{diffs.count} differences:\n"
|
55
|
+
msg << when_present(insert, '') do |count|
|
56
|
+
" • #{count} nodes to insert\n"
|
57
|
+
end
|
58
|
+
msg << when_present(update, '') do |count|
|
59
|
+
" • #{count} nodes to update\n"
|
60
|
+
end
|
61
|
+
# msg << when_present(id, '') do |count|
|
62
|
+
# " • #{count} nodes to change id\n"
|
63
|
+
# end
|
64
|
+
msg << when_present(name, '') do |count|
|
65
|
+
" • #{count} nodes to change name\n"
|
66
|
+
end
|
67
|
+
msg << when_present(move, '') do |count|
|
68
|
+
" • #{count} nodes to move\n"
|
69
|
+
end
|
70
|
+
msg << when_present(unarchive, '') do |count|
|
71
|
+
" • #{count} nodes to unarchive\n"
|
72
|
+
end
|
73
|
+
msg << when_present(archive, '') do |count|
|
74
|
+
" • #{count} nodes to archive\n"
|
75
|
+
end
|
76
|
+
msg
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def when_present(list, default = nil)
|
82
|
+
count = list.count
|
83
|
+
if count > 0
|
84
|
+
yield(count)
|
85
|
+
else
|
86
|
+
default
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Eco::Data::Locations::NodeDiff
|
2
|
+
module Selectors
|
3
|
+
# Creates selector methods on `diffs` (nodes that changed)
|
4
|
+
# It also creates a method with question mark that evaluates true if **any** diff matches.
|
5
|
+
# @note the selector method name with a question mark should exist in the `diff_result_class`
|
6
|
+
def selector(*attrs)
|
7
|
+
attrs.each do |attr|
|
8
|
+
meth = attr.to_sym
|
9
|
+
methq = "#{meth}?".to_sym
|
10
|
+
define_method meth do
|
11
|
+
diffs.select(&methq)
|
12
|
+
end
|
13
|
+
|
14
|
+
define_method methq do
|
15
|
+
diffs.any(&methq)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Eco::Data::Locations
|
2
|
+
# Differences between node before and after
|
3
|
+
# @note this works with `Hash` object where basic keys are:
|
4
|
+
# - `nodeId`
|
5
|
+
# - `name`
|
6
|
+
# - `parentId`
|
7
|
+
# - `archived`
|
8
|
+
# @note other properties can be part of the `Hash` although
|
9
|
+
# they may not influence the results.
|
10
|
+
class NodeDiff < Eco::Data::Hashes::DiffResult
|
11
|
+
require_relative 'node_diff/accessors'
|
12
|
+
require_relative 'node_diff/selectors'
|
13
|
+
require_relative 'node_diff/nodes_diff'
|
14
|
+
|
15
|
+
include Eco::Data::Locations::NodeDiff::Accessors
|
16
|
+
|
17
|
+
key :nodeId
|
18
|
+
compare :parentId, :name, :archived
|
19
|
+
case_sensitive false
|
20
|
+
|
21
|
+
attr_expose :nodeId, :name, :parentId, :archived
|
22
|
+
|
23
|
+
alias_method :insert?, :new?
|
24
|
+
|
25
|
+
alias_method :diff_name_src?, :diff_name?
|
26
|
+
# Has the property `name` changed?
|
27
|
+
def diff_name?
|
28
|
+
diff_name_src? && update?
|
29
|
+
end
|
30
|
+
alias_method :name?, :diff_name?
|
31
|
+
alias_method :id? , :diff_name? # currently a change of name is a change of id (tag)
|
32
|
+
#alias_method :id? , :key?
|
33
|
+
#alias_method :nodeId? , :id?
|
34
|
+
|
35
|
+
# Has any of `id` or `name` properties changed?
|
36
|
+
def id_name?
|
37
|
+
id? || diff_name?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Has the parent id changed?
|
41
|
+
def move?
|
42
|
+
update? && diff_parentId?
|
43
|
+
end
|
44
|
+
|
45
|
+
# Has the `archived` property changed and it was `true`?
|
46
|
+
def unarchive?
|
47
|
+
!archived && update? && diff_archived?
|
48
|
+
end
|
49
|
+
|
50
|
+
# Has the `archived` property changed and it was `false`?
|
51
|
+
def archive?
|
52
|
+
!prev_archived && (del? || archived)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -17,6 +17,8 @@ module Eco::Data::Locations
|
|
17
17
|
def id
|
18
18
|
clean_id(super)
|
19
19
|
end
|
20
|
+
# backwards compatibility
|
21
|
+
alias_method :tag, :id
|
20
22
|
|
21
23
|
def name
|
22
24
|
super || self.id
|
@@ -25,10 +27,5 @@ module Eco::Data::Locations
|
|
25
27
|
def parentId
|
26
28
|
self.parent_id
|
27
29
|
end
|
28
|
-
|
29
|
-
# backwards compatibility
|
30
|
-
def tag
|
31
|
-
id
|
32
|
-
end
|
33
30
|
end
|
34
31
|
end
|
data/lib/eco/data/locations.rb
CHANGED
data/lib/eco/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eco-helpers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.5.
|
4
|
+
version: 2.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oscar Segura
|
@@ -156,7 +156,7 @@ dependencies:
|
|
156
156
|
requirements:
|
157
157
|
- - ">="
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: 0.3.
|
159
|
+
version: 0.3.9
|
160
160
|
- - "<"
|
161
161
|
- !ruby/object:Gem::Version
|
162
162
|
version: '0.4'
|
@@ -166,7 +166,7 @@ dependencies:
|
|
166
166
|
requirements:
|
167
167
|
- - ">="
|
168
168
|
- !ruby/object:Gem::Version
|
169
|
-
version: 0.3.
|
169
|
+
version: 0.3.9
|
170
170
|
- - "<"
|
171
171
|
- !ruby/object:Gem::Version
|
172
172
|
version: '0.4'
|
@@ -592,6 +592,7 @@ files:
|
|
592
592
|
- lib/eco/api/usecases/graphql/base.rb
|
593
593
|
- lib/eco/api/usecases/graphql/helpers.rb
|
594
594
|
- lib/eco/api/usecases/graphql/helpers/base.rb
|
595
|
+
- lib/eco/api/usecases/graphql/helpers/base/case_env.rb
|
595
596
|
- lib/eco/api/usecases/graphql/helpers/location.rb
|
596
597
|
- lib/eco/api/usecases/graphql/helpers/location/base.rb
|
597
598
|
- lib/eco/api/usecases/graphql/helpers/location/command.rb
|
@@ -603,6 +604,8 @@ files:
|
|
603
604
|
- lib/eco/api/usecases/graphql/samples/location/command/dsl.rb
|
604
605
|
- lib/eco/api/usecases/graphql/samples/location/command/results.rb
|
605
606
|
- lib/eco/api/usecases/graphql/samples/location/dsl.rb
|
607
|
+
- lib/eco/api/usecases/graphql/utils.rb
|
608
|
+
- lib/eco/api/usecases/graphql/utils/sftp.rb
|
606
609
|
- lib/eco/api/usecases/ooze_cases.rb
|
607
610
|
- lib/eco/api/usecases/ooze_cases/export_register_case.rb
|
608
611
|
- lib/eco/api/usecases/ooze_samples.rb
|
@@ -670,6 +673,7 @@ files:
|
|
670
673
|
- lib/eco/data/fuzzy_match/string_helpers.rb
|
671
674
|
- lib/eco/data/hashes.rb
|
672
675
|
- lib/eco/data/hashes/array_diff.rb
|
676
|
+
- lib/eco/data/hashes/diff_meta.rb
|
673
677
|
- lib/eco/data/hashes/diff_result.rb
|
674
678
|
- lib/eco/data/locations.rb
|
675
679
|
- lib/eco/data/locations/convert.rb
|
@@ -681,6 +685,10 @@ files:
|
|
681
685
|
- lib/eco/data/locations/node_base/serial.rb
|
682
686
|
- lib/eco/data/locations/node_base/tag_validations.rb
|
683
687
|
- lib/eco/data/locations/node_base/treeify.rb
|
688
|
+
- lib/eco/data/locations/node_diff.rb
|
689
|
+
- lib/eco/data/locations/node_diff/accessors.rb
|
690
|
+
- lib/eco/data/locations/node_diff/nodes_diff.rb
|
691
|
+
- lib/eco/data/locations/node_diff/selectors.rb
|
684
692
|
- lib/eco/data/locations/node_level.rb
|
685
693
|
- lib/eco/data/locations/node_level/builder.rb
|
686
694
|
- lib/eco/data/locations/node_level/cleaner.rb
|