eco-helpers 3.0.37 → 3.1.1
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/.rubocop.yml +1 -0
- data/CHANGELOG.md +116 -1
- data/lib/eco/api/common/loaders/base.rb +2 -2
- data/lib/eco/api/common/loaders/case_base.rb +2 -0
- data/lib/eco/api/common/loaders/config/block.rb +78 -0
- data/lib/eco/api/common/loaders/config/workflow/mailer.rb +39 -7
- data/lib/eco/api/common/loaders/config.rb +3 -26
- data/lib/eco/api/common/loaders/error_handler.rb +2 -0
- data/lib/eco/api/common/loaders/parser.rb +1 -4
- data/lib/eco/api/common/people/entries.rb +23 -6
- data/lib/eco/api/common/people/entry_factory.rb +1 -1
- data/lib/eco/api/common/people/person_entry.rb +104 -27
- data/lib/eco/api/common/people/person_parser.rb +50 -16
- data/lib/eco/api/common/people/supervisor_helpers.rb +12 -6
- data/lib/eco/api/common/session/base_session.rb +75 -81
- data/lib/eco/api/common/session/environment.rb +49 -55
- data/lib/eco/api/common/session/file_manager.rb +132 -135
- data/lib/eco/api/common/session/helpers/prompt_user.rb +23 -30
- data/lib/eco/api/common/session/helpers.rb +10 -15
- data/lib/eco/api/common/session/logger/cache.rb +89 -96
- data/lib/eco/api/common/session/logger/channels.rb +24 -32
- data/lib/eco/api/common/session/logger/log.rb +38 -46
- data/lib/eco/api/common/session/logger.rb +50 -54
- data/lib/eco/api/common/session/mailer/aws_provider.rb +63 -71
- data/lib/eco/api/common/session/mailer/provider_base.rb +43 -48
- data/lib/eco/api/common/session/mailer/sendgrid_provider.rb +101 -109
- data/lib/eco/api/common/session/mailer.rb +78 -83
- data/lib/eco/api/common/session/s3_uploader.rb +132 -138
- data/lib/eco/api/common/session/sftp.rb +202 -208
- data/lib/eco/api/common.rb +0 -3
- data/lib/eco/api/custom/mailer.rb +4 -2
- data/lib/eco/api/error/handlers.rb +1 -1
- data/lib/eco/api/microcases/people/apply_changes/set_core/core_excluded.rb +8 -2
- data/lib/eco/api/microcases/people/manage/search.rb +1 -1
- data/lib/eco/api/organization/people/similarity.rb +3 -3
- data/lib/eco/api/session/batch/base_policy.rb +42 -27
- data/lib/eco/api/session/batch/launcher/mode_size.rb +6 -1
- data/lib/eco/api/session/batch/launcher.rb +16 -3
- data/lib/eco/api/session/config/api.rb +4 -3
- data/lib/eco/api/session/config/apis/one_off.rb +1 -1
- data/lib/eco/api/session/config/files.rb +13 -12
- data/lib/eco/api/session/config/workflow.rb +1 -373
- data/lib/eco/api/session/config.rb +30 -9
- data/lib/eco/api/usecases/base_case/model.rb +6 -6
- data/lib/eco/api/usecases/base_case.rb +1 -1
- data/lib/eco/api/usecases/cli.rb +1 -1
- data/lib/eco/api/usecases/default/locations/tagtree_extract_case.rb +8 -9
- data/lib/eco/api/usecases/default_cases/to_csv_case.rb +4 -1
- data/lib/eco/api/usecases/graphql/samples/location/command/dsl.rb +2 -2
- data/lib/eco/api/usecases/lib/base/env.rb +21 -23
- data/lib/eco/api/usecases/lib/files/file_pattern.rb +41 -14
- data/lib/eco/api/usecases/lib/files/input_file.rb +110 -0
- data/lib/eco/api/usecases/lib/files/sftp.rb +5 -2
- data/lib/eco/api/usecases/lib/files.rb +1 -0
- data/lib/eco/api/usecases/lib/locations/base.rb +23 -0
- data/lib/eco/api/usecases/lib/locations/mapping.rb +94 -0
- data/lib/eco/api/usecases/lib/locations.rb +7 -0
- data/lib/eco/api/usecases/lib/people/base.rb +20 -0
- data/lib/eco/api/usecases/lib/people.rb +6 -0
- data/lib/eco/api/usecases/lib.rb +2 -0
- data/lib/eco/api/usecases/ooze_cases.rb +1 -1
- data/lib/eco/api/usecases/ooze_samples/register_export_case.rb +1 -0
- data/lib/eco/api/usecases/ooze_samples/register_update_case.rb +1 -0
- data/lib/eco/api/usecases/samples/drivers/sftp_sample.rb +2 -0
- data/lib/eco/api/usecases/samples/drivers/url_pull_sample.rb +8 -2
- data/lib/eco/api/usecases/service/sftp/with_target_config.rb +0 -33
- data/lib/eco/api/usecases/service/sftp.rb +7 -1
- data/lib/eco/api/usecases/use_case.rb +3 -2
- data/lib/eco/api/usecases/workflow.rb +5 -0
- data/lib/eco/api/usecases.rb +12 -5
- data/lib/eco/cli/scripting/args_helpers.rb +1 -9
- data/lib/eco/cli_default/options.rb +98 -68
- data/lib/eco/cli_default/workflow/end.rb +22 -0
- data/lib/eco/cli_default/workflow/launch_jobs.rb +14 -0
- data/lib/eco/cli_default/workflow/load/data.rb +27 -0
- data/lib/eco/cli_default/workflow/load/input.rb +28 -0
- data/lib/eco/cli_default/workflow/load.rb +13 -0
- data/lib/eco/cli_default/workflow/options.rb +10 -0
- data/lib/eco/cli_default/workflow/post_launch.rb +65 -0
- data/lib/eco/cli_default/workflow/report.rb +17 -0
- data/lib/eco/cli_default/workflow/rescued_exception.rb +21 -0
- data/lib/eco/cli_default/workflow/usecases.rb +23 -0
- data/lib/eco/cli_default/workflow.rb +24 -180
- data/lib/eco/data/count_trace.rb +51 -0
- data/lib/eco/data/files/content.rb +39 -0
- data/lib/eco/data/files/directory.rb +78 -45
- data/lib/eco/data/files/encoding.rb +12 -21
- data/lib/eco/data/files/file_pattern.rb +15 -8
- data/lib/eco/data/files/folder.rb +196 -0
- data/lib/eco/data/files/relative_path.rb +54 -0
- data/lib/eco/data/files/timestamp.rb +18 -0
- data/lib/eco/data/files.rb +46 -5
- data/lib/eco/data/fuzzy_match.rb +1 -1
- data/lib/eco/data/hashes/array_diff.rb +11 -5
- data/lib/eco/data/hashes/diff_result/meta.rb +12 -4
- data/lib/eco/data/locations/node_diff/accessors.rb +1 -1
- data/lib/eco/data/mapper.rb +5 -1
- data/lib/eco/data.rb +1 -0
- data/lib/eco/language/delegation/delegating_missing.rb +1 -1
- data/lib/eco/language/delegation/delegating_missing_const.rb +1 -1
- data/lib/eco/language/delegation/delegating_missing_on_class.rb +1 -1
- data/lib/eco/language/delegation/for_delegator/delegated_class.rb +1 -1
- data/lib/eco/language/klass/auto_loader.rb +129 -0
- data/lib/eco/language/klass/builder.rb +6 -6
- data/lib/eco/language/klass/const.rb +19 -0
- data/lib/eco/language/klass/helpers_built.rb +3 -1
- data/lib/eco/language/klass/hierarchy.rb +5 -1
- data/lib/eco/language/klass/naming.rb +5 -2
- data/lib/eco/language/klass/resolver.rb +21 -6
- data/lib/eco/language/klass/uid.rb +12 -0
- data/lib/eco/language/klass/when_inherited.rb +30 -6
- data/lib/eco/language/klass.rb +5 -2
- data/lib/eco/language/methods/access_modifier.rb +23 -0
- data/lib/eco/language/methods/instance_method_helpers.rb +6 -1
- data/lib/eco/language/methods.rb +1 -0
- data/lib/eco/language/models/hierarchy.rb +41 -0
- data/lib/eco/language/models/workflow.rb +385 -0
- data/lib/eco/language/models.rb +2 -1
- data/lib/eco/version.rb +1 -1
- metadata +31 -7
- data/lib/eco/api/common/class_auto_loader.rb +0 -114
- data/lib/eco/api/common/class_helpers.rb +0 -9
- data/lib/eco/api/common/class_hierarchy.rb +0 -45
- data/lib/eco/data/files/helpers.rb +0 -152
- data/lib/eco/language/models/class_helpers.rb +0 -136
@@ -1,4 +1,3 @@
|
|
1
|
-
class Eco::CliDefault::Workflow < Eco::API::Common::Loaders::Workflow
|
2
1
|
# @todo The ones below:
|
3
2
|
# 1. Identify the target model earlier (required_data?),
|
4
3
|
# provided that we can granulate the workflow.
|
@@ -12,183 +11,28 @@ class Eco::CliDefault::Workflow < Eco::API::Common::Loaders::Workflow
|
|
12
11
|
# 5. Right on the load:data stage, set the io model
|
13
12
|
# based on (1).
|
14
13
|
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
input_is_required = some_input_case?(io) || options.dig(:input, :entries_from)
|
40
|
-
missing_input = !input || input.empty?
|
41
|
-
next unless missing_input && input_is_required
|
42
|
-
|
43
|
-
if options.dig(:input, :entries_from)
|
44
|
-
io.new(input: cli.config.input.get(io: io))
|
45
|
-
else
|
46
|
-
opt_case = cli_input_cases(io).values.first.option
|
47
|
-
io.new(input: cli.config.input.get(io: io, option: opt_case))
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
wf_in.on(:filter) do
|
52
|
-
next unless input && !input.empty?
|
53
|
-
|
54
|
-
io.new(input: cli.config.input_filters.process(io: io))
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
wf_load.before(:data) do
|
59
|
-
# @todo model should be set to the target model
|
60
|
-
# based on the main use case that requires data!
|
61
|
-
io.new(model: :people)
|
62
|
-
end
|
63
|
-
|
64
|
-
wf_load.with(:data) do |wf_peo|
|
65
|
-
wf_peo.on(:get) do
|
66
|
-
next unless some_data_case?(io) || options.dig(:people, :get)
|
67
|
-
|
68
|
-
io.new(data: cli.config.people(io: io))
|
69
|
-
end
|
70
|
-
|
71
|
-
wf_peo.on(:filter) do
|
72
|
-
next unless data && !data.empty?
|
73
|
-
|
74
|
-
io.new(data: cli.config.people_filters.process(io: io))
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
before(:usecases) do
|
80
|
-
# save partial entries -> should be native to session.workflow
|
81
|
-
get_people = options.dig(:people, :get)
|
82
|
-
partial_update = get_people && get_people[:type] == :partial
|
83
|
-
|
84
|
-
if !options[:dry_run] && partial_update
|
85
|
-
partial_file = session.config.people.partial_cache
|
86
|
-
session.file_manager.save_json(io.data, partial_file, :timestamp)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
on(:usecases) do
|
91
|
-
next if cli_usecases.process(io: io)
|
92
|
-
|
93
|
-
log(:info) { 'No update operation specified... quitting' }
|
94
|
-
exit 0
|
95
|
-
end
|
96
|
-
|
97
|
-
before(:launch_jobs) do
|
98
|
-
available_args = cli.config.available_option_args
|
99
|
-
SCR.stop_on_unknown!(all_available: available_args)
|
100
|
-
end
|
101
|
-
|
102
|
-
on(:launch_jobs) do
|
103
|
-
session.jobs_launch(simulate: options[:dry_run])
|
104
|
-
end
|
105
|
-
|
106
|
-
before(:post_launch) do |wf_post|
|
107
|
-
next wf_post.skip! if session.post_launch.empty?
|
108
|
-
|
109
|
-
run_it = !options[:dry_run] || options.dig(:post_launch, :run)
|
110
|
-
unless run_it
|
111
|
-
wf_post.skip!
|
112
|
-
|
113
|
-
log(:info) {
|
114
|
-
msg = 'Although there are post_launch cases, they will NOT be RUN'
|
115
|
-
msg << ', because we are in dry-run (simulate).' if options[:dry_run]
|
116
|
-
msg
|
117
|
-
}
|
118
|
-
|
119
|
-
next
|
120
|
-
end
|
121
|
-
|
122
|
-
get_people = options.dig(:people, :get)
|
123
|
-
partial_update = get_people && get_people[:type] == :partial
|
124
|
-
refresh_data = !options[:dry_run] && partial_update
|
125
|
-
|
126
|
-
unless refresh_data
|
127
|
-
log(:info) {
|
128
|
-
msg = 'Although there are post_launch cases, data will not be refreshed before their run'
|
129
|
-
if io.options[:dry_run]
|
130
|
-
msg << ', because we are in dry-run (simulate).'
|
131
|
-
elsif !partial_update
|
132
|
-
msg << ', because it is not a partial update (-get-partial option not present).'
|
133
|
-
end
|
134
|
-
msg
|
135
|
-
}
|
136
|
-
|
137
|
-
next
|
138
|
-
end
|
139
|
-
|
140
|
-
# get target people afresh
|
141
|
-
peo_aux = session.micro.people_refresh(
|
142
|
-
people: data,
|
143
|
-
include_created: true
|
144
|
-
)
|
145
|
-
io.base.new(data: peo_aux)
|
146
|
-
end
|
147
|
-
|
148
|
-
with(:post_launch) do |wf_post|
|
149
|
-
wf_post.on(:usecases) do |_wf_pu, io|
|
150
|
-
session.post_launch.each do |use|
|
151
|
-
use.launch(io: io).base
|
152
|
-
rescue Eco::API::UseCases::BaseIO::MissingParameter => err
|
153
|
-
raise unless err.required == :people
|
154
|
-
|
155
|
-
log(:debug) {
|
156
|
-
"Skipping use case '#{use.name}' -- no base people detected for the current run"
|
157
|
-
}
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
wf_post.on(:launch_jobs) do |_wf_pl, _io|
|
162
|
-
session.jobs_launch(simulate: options[:dry_run])
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
on(:report) do |_wf_rep, io|
|
167
|
-
if (file = options.dig(:report, :people, :csv))
|
168
|
-
options.deep_merge!(export: {
|
169
|
-
options: {internal_names: true, nice_header: true, split_schemas: true},
|
170
|
-
file: {name: file, format: :csv}
|
171
|
-
})
|
172
|
-
|
173
|
-
aux_io = io.new(data: data.updated_or_created)
|
174
|
-
session.process_case('to-csv', io: aux_io, type: :export)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
on(:end) do
|
179
|
-
get_people = options.dig(:people, :get)
|
180
|
-
partial_update = get_people && get_people[:type] == :partial
|
181
|
-
|
182
|
-
unless !options[:end_get] || options[:dry_run] || partial_update
|
183
|
-
if !some_update_case?(io)
|
184
|
-
# Prevent getting people when there were no use cases that used them
|
185
|
-
log(:info) {
|
186
|
-
"Won't be recaching people, as there haven't been any targetted updates"
|
187
|
-
}
|
188
|
-
elsif !people
|
189
|
-
people = session.micro.people_cache
|
190
|
-
io.new(data: people)
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
14
|
+
class Eco::CliDefault::Workflow < Eco::API::Common::Loaders::Workflow
|
15
|
+
require_relative 'workflow/rescued_exception'
|
16
|
+
require_relative 'workflow/options'
|
17
|
+
require_relative 'workflow/load'
|
18
|
+
require_relative 'workflow/usecases'
|
19
|
+
require_relative 'workflow/launch_jobs'
|
20
|
+
require_relative 'workflow/post_launch'
|
21
|
+
require_relative 'workflow/report'
|
22
|
+
require_relative 'workflow/end'
|
23
|
+
|
24
|
+
[
|
25
|
+
RescuedException,
|
26
|
+
Options,
|
27
|
+
Load,
|
28
|
+
Usecases,
|
29
|
+
LaunchJobs,
|
30
|
+
PostLaunch,
|
31
|
+
Report,
|
32
|
+
End
|
33
|
+
].each do |wf_config|
|
34
|
+
wf_config.config_copy(to: self, all: true)
|
35
|
+
end
|
36
|
+
|
37
|
+
config_apply!(all: true)
|
194
38
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Eco
|
2
|
+
module Data
|
3
|
+
class CountTrace
|
4
|
+
include Eco::Language::Delegation::DelegatingMissing
|
5
|
+
|
6
|
+
delegating_missing_to :subject
|
7
|
+
|
8
|
+
attr_reader :trace
|
9
|
+
|
10
|
+
def initialize(subject)
|
11
|
+
@subject = subject
|
12
|
+
@trace = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset!
|
16
|
+
@trace.clear
|
17
|
+
end
|
18
|
+
|
19
|
+
def trace!(value, count: 1)
|
20
|
+
trace[value] ||= 0
|
21
|
+
trace[value] += count
|
22
|
+
end
|
23
|
+
|
24
|
+
def report!(msg: nil, level: :warn)
|
25
|
+
str_report(msg: msg).tap do |str|
|
26
|
+
log(level.to_sym) { str }
|
27
|
+
|
28
|
+
reset!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def str_report(msg: nil)
|
33
|
+
return if trace.empty?
|
34
|
+
|
35
|
+
msg ||= ''
|
36
|
+
sorted = trace.sort_by {|value, count| [count * -1, value]}
|
37
|
+
|
38
|
+
msg << "\n * "
|
39
|
+
msg << sorted.map.with_index do |(value, count), idx|
|
40
|
+
"#{idx}. (#{count}) '#{value}'"
|
41
|
+
end.join("\n * ")
|
42
|
+
|
43
|
+
msg
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :subject
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Eco
|
2
|
+
module Data
|
3
|
+
module Files
|
4
|
+
module Content
|
5
|
+
include Eco::Language::AuxiliarLogger
|
6
|
+
include Encoding
|
7
|
+
|
8
|
+
# It offers a resilient way to read content from a file
|
9
|
+
# @tolerance [Integer] the number of allowed encoding errors.
|
10
|
+
# @return [String] the content of the file
|
11
|
+
def get_file_content(file, encoding: nil, tolerance: 5)
|
12
|
+
read_with_tolerance(file, encoding: encoding, tolerance: tolerance)
|
13
|
+
end
|
14
|
+
|
15
|
+
def read_with_tolerance(file, encoding:, tolerance: 5)
|
16
|
+
content = get_file_content_with_encoding(file, encoding: encoding)
|
17
|
+
return unless content
|
18
|
+
|
19
|
+
content.scrub do |bytes|
|
20
|
+
replacement = "<#{bytes.unpack1('H*')}>"
|
21
|
+
|
22
|
+
if tolerance <= 0
|
23
|
+
log(:error) {
|
24
|
+
"There were more than 5 encoding errors in the file '#{file}'."
|
25
|
+
}
|
26
|
+
return content
|
27
|
+
else
|
28
|
+
tolerance -= 1
|
29
|
+
log(:error) {
|
30
|
+
"Encoding problem in file '#{file}': '#{replacement}'."
|
31
|
+
}
|
32
|
+
replacement
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -3,45 +3,43 @@ module Eco
|
|
3
3
|
module Files
|
4
4
|
class Directory
|
5
5
|
class << self
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
subpath = nil
|
15
|
-
begin
|
16
|
-
parts.each do |curr|
|
17
|
-
subpath = subpath ? File.join(subpath, curr) : curr
|
18
|
-
Dir.mkdir(subpath) unless Files.dir_exists?(subpath)
|
19
|
-
end
|
20
|
-
rescue Exception => e
|
21
|
-
pp e
|
22
|
-
return false
|
23
|
-
end
|
24
|
-
true
|
6
|
+
# rubocop:disable Style/SpecialGlobalVars
|
7
|
+
|
8
|
+
def script_subfolder
|
9
|
+
basename = File.basename($0, File.extname($0))
|
10
|
+
path = File.dirname($0)
|
11
|
+
|
12
|
+
File.join(path, basename)
|
25
13
|
end
|
14
|
+
|
15
|
+
# rubocop:enable Style/SpecialGlobalVars
|
26
16
|
end
|
27
17
|
|
28
18
|
attr_reader :dir_path
|
29
19
|
|
30
20
|
def initialize(dir_path = Dir.pwd)
|
31
|
-
dir_path = script_subfolder if dir_path == :script
|
32
|
-
|
21
|
+
dir_path = self.class.script_subfolder if dir_path == :script
|
22
|
+
|
23
|
+
msg = "Cannot initialize with directory: '#{dir_path}'"
|
24
|
+
raise ArgumentError, msg if !dir_path || dir_path.is_a?(Symbol)
|
25
|
+
|
33
26
|
@dir_path = dir_path
|
34
27
|
end
|
35
28
|
|
36
|
-
def
|
37
|
-
|
29
|
+
def exist?
|
30
|
+
Dir.exist?(@dir_path)
|
38
31
|
end
|
39
32
|
|
40
|
-
def create
|
41
|
-
return
|
42
|
-
|
43
|
-
|
44
|
-
|
33
|
+
def create(exception: false)
|
34
|
+
return full_path if exist?
|
35
|
+
|
36
|
+
FileUtils.mkdir_p(@dir_path)
|
37
|
+
|
38
|
+
true
|
39
|
+
rescue StandardError => err
|
40
|
+
raise if exception
|
41
|
+
pp err
|
42
|
+
false
|
45
43
|
end
|
46
44
|
|
47
45
|
def full_path
|
@@ -49,29 +47,48 @@ module Eco
|
|
49
47
|
end
|
50
48
|
|
51
49
|
def dir_files(file: nil, pattern: dir_pattern)
|
52
|
-
find =
|
53
|
-
Dir.glob(find).sort
|
50
|
+
find = file_pattern(file || pattern)
|
51
|
+
Dir.glob(find).sort # rubocop:disable Lint/RedundantDirGlobSort
|
54
52
|
end
|
55
53
|
|
54
|
+
# @params files_list [Array]
|
55
|
+
# @params file [String]
|
56
|
+
# @return [String] the last modified file.
|
56
57
|
def newest_file(files_list = nil, file: nil)
|
57
|
-
files_list
|
58
|
-
|
58
|
+
files_list ||= dir_files(file: file)
|
59
|
+
|
60
|
+
return unless files_list.is_a?(Array)
|
61
|
+
return unless files_list.length.positive?
|
62
|
+
|
59
63
|
files_list.max_by {|f| File.mtime(f) }
|
60
64
|
end
|
61
65
|
|
66
|
+
# Resolves the `filename` path.
|
67
|
+
# @return [String] the file path (relative or absolute)
|
62
68
|
def file(filename, should_exist: false)
|
63
|
-
return
|
69
|
+
return unless filename
|
70
|
+
|
71
|
+
# as incoming absolute path
|
64
72
|
if File.expand_path(filename) == filename
|
65
|
-
return filename
|
73
|
+
return filename unless should_exist
|
74
|
+
return filename if File.exist?(filename)
|
66
75
|
end
|
67
76
|
|
68
|
-
|
69
|
-
|
77
|
+
# as relative path to this directory
|
78
|
+
file = to_relative_path(filename)
|
79
|
+
return file unless should_exist
|
80
|
+
return file if File.exist?(file)
|
70
81
|
|
82
|
+
# as interpreted to be an absolute path
|
71
83
|
file = File.expand_path(filename)
|
72
|
-
return file
|
84
|
+
return file unless should_exist
|
85
|
+
file if File.exist?(file)
|
86
|
+
end
|
73
87
|
|
74
|
-
|
88
|
+
def file?(filename)
|
89
|
+
return true if file_abolute_path_exist?(filename)
|
90
|
+
|
91
|
+
file_relative_path_exist?(filename)
|
75
92
|
end
|
76
93
|
|
77
94
|
def join(*args)
|
@@ -81,21 +98,37 @@ module Eco
|
|
81
98
|
|
82
99
|
private
|
83
100
|
|
101
|
+
def to_relative_path(filename)
|
102
|
+
return unless filename
|
103
|
+
|
104
|
+
FilePattern.new(
|
105
|
+
filename
|
106
|
+
).resolve(dir: @dir_path)
|
107
|
+
end
|
108
|
+
|
109
|
+
def file_abolute_path_exist?(filename)
|
110
|
+
return false unless filename
|
111
|
+
|
112
|
+
File.exist?(filename)
|
113
|
+
end
|
114
|
+
|
115
|
+
def file_relative_path_exist?(filename)
|
116
|
+
return false unless filename
|
117
|
+
|
118
|
+
File.exist?(to_relative_path(filename))
|
119
|
+
end
|
120
|
+
|
84
121
|
def file_pattern(value)
|
85
122
|
case value
|
86
|
-
when
|
123
|
+
when FilePattern
|
87
124
|
value
|
88
125
|
else
|
89
|
-
|
126
|
+
FilePattern.new(value).pattern(@dir_path)
|
90
127
|
end
|
91
128
|
end
|
92
129
|
|
93
130
|
def dir_pattern
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
def script_subfolder
|
98
|
-
Files.script_subfolder
|
131
|
+
FilePattern.new.pattern(@dir_path)
|
99
132
|
end
|
100
133
|
end
|
101
134
|
end
|
@@ -6,9 +6,12 @@ module Eco
|
|
6
6
|
|
7
7
|
BOM_BYTES = [239, 187, 191].freeze
|
8
8
|
|
9
|
-
def
|
10
|
-
return false
|
11
|
-
File.
|
9
|
+
def bom?(path)
|
10
|
+
return false unless path
|
11
|
+
return false unless File.file?(path)
|
12
|
+
return false if File.empty?(path)
|
13
|
+
|
14
|
+
File.open(path, 'rb') do |f|
|
12
15
|
bytes = f.read(3)
|
13
16
|
return bytes.unpack('C*') == BOM_BYTES
|
14
17
|
end
|
@@ -24,7 +27,7 @@ module Eco
|
|
24
27
|
end
|
25
28
|
|
26
29
|
bom_enc = encoding && encoding.split('|')[0] == 'bom'
|
27
|
-
if
|
30
|
+
if bom?(file) || bom_enc
|
28
31
|
content = remove_bom(File.read(file, encoding: 'utf-8'))
|
29
32
|
encoding = 'utf-8'
|
30
33
|
else
|
@@ -33,7 +36,7 @@ module Eco
|
|
33
36
|
|
34
37
|
return unless content
|
35
38
|
|
36
|
-
content = content.encode(
|
39
|
+
content = content.encode('utf-8') unless encoding.include?('utf-8')
|
37
40
|
content
|
38
41
|
end
|
39
42
|
|
@@ -50,32 +53,20 @@ module Eco
|
|
50
53
|
end
|
51
54
|
|
52
55
|
def encoding(path)
|
53
|
-
|
56
|
+
bom?(path) ? 'bom' : 'utf-8'
|
54
57
|
end
|
55
58
|
|
56
59
|
# Gives the parameter as it should
|
57
60
|
def scoped_encoding(path)
|
58
|
-
unless
|
61
|
+
unless File.exist?(path)
|
59
62
|
log(:error) { "File does not exist: #{path}" }
|
60
|
-
return
|
63
|
+
return
|
61
64
|
end
|
62
65
|
|
63
66
|
encoding ||= encoding(path)
|
64
|
-
encoding = "#{encoding}|utf-8" if encoding ==
|
67
|
+
encoding = "#{encoding}|utf-8" if encoding == 'bom'
|
65
68
|
encoding
|
66
69
|
end
|
67
|
-
|
68
|
-
def file_exists?(file)
|
69
|
-
return false unless file
|
70
|
-
|
71
|
-
File.exist?(file) || File.exist?(File.expand_path(file))
|
72
|
-
end
|
73
|
-
|
74
|
-
def file_empty?(path)
|
75
|
-
return true unless File.file?(path)
|
76
|
-
|
77
|
-
File.zero?(path)
|
78
|
-
end
|
79
70
|
end
|
80
71
|
end
|
81
72
|
end
|
@@ -1,30 +1,37 @@
|
|
1
1
|
module Eco
|
2
2
|
module Data
|
3
3
|
module Files
|
4
|
+
# Helper class to build regex patterns relative to a source folder.
|
4
5
|
class FilePattern
|
5
|
-
def initialize(file =
|
6
|
+
def initialize(file = '')
|
6
7
|
@source_file = file
|
7
8
|
end
|
8
9
|
|
9
|
-
def resolve(dir: nil, start:
|
10
|
+
def resolve(dir: nil, start: '')
|
10
11
|
pattern(dir).gsub('*', start)
|
11
12
|
end
|
12
13
|
|
13
14
|
def match?(file, dir: nil)
|
14
|
-
/#{Regexp.escape(
|
15
|
+
/#{Regexp.escape(pattern(dir))}/i.match?(file)
|
15
16
|
end
|
16
17
|
|
17
18
|
def any?(files, dir: nil)
|
18
19
|
return false unless files.is_a?(Array)
|
19
|
-
|
20
|
+
|
21
|
+
files.any? { |file| match?(file, dir: dir) }
|
20
22
|
end
|
21
23
|
|
22
24
|
def pattern(dir = nil)
|
23
|
-
return File.join(dir,
|
25
|
+
return File.join(dir, '*') if @source_file.to_s.empty?
|
26
|
+
|
24
27
|
filename = File.basename(@source_file)
|
25
|
-
path
|
26
|
-
|
27
|
-
|
28
|
+
path = File.dirname(@source_file)
|
29
|
+
|
30
|
+
path = File.join(dir, path) if dir
|
31
|
+
|
32
|
+
wildcard = '*'
|
33
|
+
wildcard = '' if filename =~ /\*/
|
34
|
+
|
28
35
|
File.join(path, wildcard + filename)
|
29
36
|
end
|
30
37
|
end
|