fig 2.0.0.pre.alpha.11 → 2.0.0.pre.alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/fig/command/options/parser.rb +1 -1
- data/lib/fig/command/options.rb +19 -0
- data/lib/fig/command.rb +23 -0
- data/lib/fig/include_backtrace.rb +27 -2
- data/lib/fig/operating_system.rb +85 -38
- data/lib/fig/repository.rb +41 -28
- data/lib/fig/runtime_environment.rb +57 -4
- data/lib/fig/spec_utils.rb +8 -0
- data/lib/fig/statement/override.rb +20 -0
- data/lib/fig/verbose_logging.rb +67 -0
- data/lib/fig/version.rb +1 -1
- data/spec/command/publishing_spec.rb +12 -0
- data/spec/verbose_logging_spec.rb +170 -0
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f1364feade70b2eff4e25aec350a9cf3f39a874a2b9b05f110039ea3c16c760
|
4
|
+
data.tar.gz: '09924664a67b47b7f9fcb744509a661bfdc341546fde5610ce9782889fe0629b'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18829c02bca0163f2ebc14144fc77662d202133d01906ffa6947a58959f889fb69c5cbbba09e0aafe534f4812cf28cbd27c840cc3a2253bea7658d2fb7ee1ac8
|
7
|
+
data.tar.gz: e062c0df9429ae9df726f40e502c6a58e8e356fe4e0f0a7c9992489fdc4edca1b4f834ba50453e949b5071649d1ca9709b43b67eceedd8053f57e01fce9e10d2
|
@@ -94,7 +94,7 @@ Standard options (represented as "[...]" above):
|
|
94
94
|
|
95
95
|
[-l | --login]
|
96
96
|
|
97
|
-
[--log-level LEVEL] [--log-config PATH | --log-to-stdout]
|
97
|
+
[--log-level LEVEL] [--log-config PATH | --log-to-stdout] [--verbose]
|
98
98
|
[--figrc PATH] [--no-figrc] [--no-remote-figrc]
|
99
99
|
|
100
100
|
[--suppress-vcs-comments-in-published-packages]
|
data/lib/fig/command/options.rb
CHANGED
@@ -79,6 +79,7 @@ class Fig::Command::Options
|
|
79
79
|
attr_reader :suppress_retrieves
|
80
80
|
attr_reader :update_lock_response
|
81
81
|
attr_reader :variable_to_get
|
82
|
+
attr_reader :verbose
|
82
83
|
attr_accessor :version_message
|
83
84
|
attr_accessor :version_plain
|
84
85
|
|
@@ -177,6 +178,10 @@ class Fig::Command::Options
|
|
177
178
|
return @suppress_warning_unused_retrieve
|
178
179
|
end
|
179
180
|
|
181
|
+
def suppress_warning_unused_override?()
|
182
|
+
return @suppress_warning_unused_override
|
183
|
+
end
|
184
|
+
|
180
185
|
private
|
181
186
|
|
182
187
|
EXTRA_OPTIONS_DESCRIPTION = <<-'END_DESCRIPTION'
|
@@ -741,6 +746,13 @@ Running commands:
|
|
741
746
|
@log_level = log_level
|
742
747
|
end
|
743
748
|
|
749
|
+
@parser.on(
|
750
|
+
'--verbose',
|
751
|
+
'enable verbose output with timing information'
|
752
|
+
) do
|
753
|
+
@verbose = true
|
754
|
+
end
|
755
|
+
|
744
756
|
@update_lock_response = nil # Nil means wait, but warn.
|
745
757
|
update_lock_responses = [:wait, :fail, :ignore]
|
746
758
|
response_list = update_lock_responses.join(', ')
|
@@ -774,6 +786,13 @@ Running commands:
|
|
774
786
|
@suppress_warning_unused_retrieve = true
|
775
787
|
end
|
776
788
|
|
789
|
+
@parser.on(
|
790
|
+
'--suppress-warning-unused-override',
|
791
|
+
%q<don't complain about an override statement that isn't used>
|
792
|
+
) do
|
793
|
+
@suppress_warning_unused_override = true
|
794
|
+
end
|
795
|
+
|
777
796
|
return
|
778
797
|
end
|
779
798
|
|
data/lib/fig/command.rb
CHANGED
@@ -22,6 +22,7 @@ require 'fig/runtime_environment'
|
|
22
22
|
require 'fig/statement/configuration'
|
23
23
|
require 'fig/update_lock'
|
24
24
|
require 'fig/user_input_error'
|
25
|
+
require 'fig/verbose_logging'
|
25
26
|
require 'fig/working_directory_maintainer'
|
26
27
|
|
27
28
|
module Fig; end
|
@@ -46,6 +47,11 @@ class Fig::Command
|
|
46
47
|
Fig::Logging.initialize_pre_configuration(
|
47
48
|
@options.log_to_stdout(), @options.log_level(),
|
48
49
|
)
|
50
|
+
|
51
|
+
# Enable verbose logging if requested
|
52
|
+
if @options.verbose
|
53
|
+
Fig::VerboseLogging.enable_verbose!
|
54
|
+
end
|
49
55
|
|
50
56
|
actions = @options.actions()
|
51
57
|
if actions.empty?
|
@@ -188,6 +194,15 @@ class Fig::Command
|
|
188
194
|
return ! suppressed_warnings.include?('unused retrieve')
|
189
195
|
end
|
190
196
|
|
197
|
+
def check_for_unused_overrides?()
|
198
|
+
return false if @options.suppress_warning_unused_override?
|
199
|
+
|
200
|
+
suppressed_warnings = @application_configuration['suppress warnings']
|
201
|
+
return true if not suppressed_warnings
|
202
|
+
|
203
|
+
return ! suppressed_warnings.include?('unused override')
|
204
|
+
end
|
205
|
+
|
191
206
|
def configure()
|
192
207
|
set_up_update_lock()
|
193
208
|
|
@@ -344,6 +359,14 @@ class Fig::Command
|
|
344
359
|
}
|
345
360
|
end
|
346
361
|
|
362
|
+
if check_for_unused_overrides?
|
363
|
+
Fig::AtExit.add {
|
364
|
+
if ! @suppress_further_error_messages
|
365
|
+
@environment.check_for_unused_overrides
|
366
|
+
end
|
367
|
+
}
|
368
|
+
end
|
369
|
+
|
347
370
|
return
|
348
371
|
end
|
349
372
|
|
@@ -17,6 +17,7 @@ class Fig::IncludeBacktrace
|
|
17
17
|
@parent = parent
|
18
18
|
@descriptor = descriptor
|
19
19
|
@overrides = {}
|
20
|
+
@override_statements = {} # map package_name -> Statement::Override
|
20
21
|
end
|
21
22
|
|
22
23
|
def add_override(statement)
|
@@ -34,14 +35,25 @@ class Fig::IncludeBacktrace
|
|
34
35
|
end
|
35
36
|
|
36
37
|
@overrides[package_name] = new_version
|
38
|
+
@override_statements[package_name] = statement
|
39
|
+
statement.added_to_environment(true)
|
37
40
|
end
|
38
41
|
|
39
42
|
# Returns a version.
|
40
43
|
def get_override(package_name, default_version = nil)
|
41
44
|
version = @overrides[package_name]
|
42
|
-
|
45
|
+
if version
|
46
|
+
statement = @override_statements[package_name]
|
47
|
+
statement.referenced(true) if statement
|
48
|
+
return version
|
49
|
+
end
|
43
50
|
|
44
|
-
|
51
|
+
if @parent
|
52
|
+
result = @parent.get_override(package_name, default_version)
|
53
|
+
# If parent provided an override, it will mark its own statement as referenced
|
54
|
+
return result
|
55
|
+
end
|
56
|
+
|
45
57
|
return default_version
|
46
58
|
end
|
47
59
|
|
@@ -73,4 +85,17 @@ class Fig::IncludeBacktrace
|
|
73
85
|
|
74
86
|
stack << @descriptor
|
75
87
|
end
|
88
|
+
|
89
|
+
# Collect all override statements from this backtrace level and parents
|
90
|
+
def collect_override_statements(statements = [])
|
91
|
+
if @parent
|
92
|
+
@parent.collect_override_statements(statements)
|
93
|
+
end
|
94
|
+
|
95
|
+
@override_statements.values.each do |statement|
|
96
|
+
statements << statement
|
97
|
+
end
|
98
|
+
|
99
|
+
return statements
|
100
|
+
end
|
76
101
|
end
|
data/lib/fig/operating_system.rb
CHANGED
@@ -24,6 +24,7 @@ require 'fig/protocol/artifactory'
|
|
24
24
|
require 'fig/repository_error'
|
25
25
|
require 'fig/url'
|
26
26
|
require 'fig/user_input_error'
|
27
|
+
require 'fig/verbose_logging'
|
27
28
|
|
28
29
|
module Fig; end
|
29
30
|
|
@@ -99,16 +100,20 @@ class Fig::OperatingSystem
|
|
99
100
|
end
|
100
101
|
|
101
102
|
def download_list(url)
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
103
|
+
Fig::VerboseLogging.time_operation("listing packages from #{url}") do
|
104
|
+
begin
|
105
|
+
protocol, uri = decode_protocol url
|
106
|
+
|
107
|
+
result = protocol.download_list uri
|
108
|
+
log_repository_operation("listed", url, "#{result.size} entries")
|
109
|
+
result
|
110
|
+
rescue SocketError => error
|
111
|
+
Fig::Logging.debug error.message
|
112
|
+
raise Fig::NetworkError.new "#{url}: #{error.message}"
|
113
|
+
rescue Errno::ETIMEDOUT => error
|
114
|
+
Fig::Logging.debug error.message
|
115
|
+
raise Fig::NetworkError.new "#{url}: #{error.message}"
|
116
|
+
end
|
112
117
|
end
|
113
118
|
end
|
114
119
|
|
@@ -124,15 +129,23 @@ class Fig::OperatingSystem
|
|
124
129
|
# Returns whether the file was not downloaded because the file already
|
125
130
|
# exists and is already up-to-date.
|
126
131
|
def download(url, path, prompt_for_login)
|
127
|
-
|
132
|
+
Fig::VerboseLogging.time_operation("downloading #{File.basename(url)}") do
|
133
|
+
protocol, uri = decode_protocol url
|
128
134
|
|
129
|
-
|
135
|
+
FileUtils.mkdir_p(File.dirname path)
|
130
136
|
|
131
|
-
|
137
|
+
result = protocol.download uri, path, prompt_for_login
|
138
|
+
if File.exist?(path)
|
139
|
+
size = File.size(path)
|
140
|
+
log_asset_operation("downloaded", path, size)
|
141
|
+
end
|
142
|
+
result
|
143
|
+
end
|
132
144
|
end
|
133
145
|
|
134
146
|
# Returns the basename and full path to the download.
|
135
147
|
def download_resource(url, download_directory)
|
148
|
+
log_asset_operation("downloading", url)
|
136
149
|
FileUtils.mkdir_p(download_directory)
|
137
150
|
|
138
151
|
basename = CGI.unescape Fig::URL.parse(url).path.split('/').last
|
@@ -144,6 +157,7 @@ class Fig::OperatingSystem
|
|
144
157
|
end
|
145
158
|
|
146
159
|
def download_and_unpack_archive(url, download_directory, unpack_directory)
|
160
|
+
log_asset_operation("downloading", url)
|
147
161
|
basename, path = download_resource(url, download_directory)
|
148
162
|
|
149
163
|
case path
|
@@ -224,32 +238,37 @@ class Fig::OperatingSystem
|
|
224
238
|
# .tgz
|
225
239
|
# .zip
|
226
240
|
def unpack_archive(directory, archive_path)
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
if running_on_windows
|
237
|
-
check_archive_entry_for_windows entry, archive_path
|
238
|
-
end
|
241
|
+
Fig::VerboseLogging.time_operation("extracting archive #{File.basename(archive_path)}") do
|
242
|
+
FileUtils.mkdir_p directory
|
243
|
+
archive_size = File.size(archive_path) if File.exist?(archive_path)
|
244
|
+
log_asset_operation("extracting", archive_path, archive_size)
|
245
|
+
|
246
|
+
Dir.chdir(directory) do
|
247
|
+
if ! File.exist? archive_path
|
248
|
+
raise Fig::RepositoryError.new "#{archive_path} does not exist."
|
249
|
+
end
|
239
250
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
251
|
+
running_on_windows = Fig::OperatingSystem.windows?
|
252
|
+
::Archive.read_open_filename(archive_path) do |reader|
|
253
|
+
while entry = reader.next_header
|
254
|
+
if running_on_windows
|
255
|
+
check_archive_entry_for_windows entry, archive_path
|
256
|
+
end
|
257
|
+
|
258
|
+
begin
|
259
|
+
reader.extract(entry)
|
260
|
+
rescue Archive::Error => exception
|
261
|
+
# Nice how the error message doesn't include any information about
|
262
|
+
# what was having the problem.
|
263
|
+
message = exception.message.sub(/^Extract archive failed: /, '')
|
264
|
+
new_exception =
|
265
|
+
Fig::RepositoryError.new(
|
266
|
+
"Could not extract #{entry.pathname} from #{archive_path}: #{message}"
|
267
|
+
)
|
268
|
+
|
269
|
+
new_exception.set_backtrace exception.backtrace
|
270
|
+
raise new_exception
|
271
|
+
end
|
253
272
|
end
|
254
273
|
end
|
255
274
|
end
|
@@ -363,4 +382,32 @@ class Fig::OperatingSystem
|
|
363
382
|
|
364
383
|
return
|
365
384
|
end
|
385
|
+
|
386
|
+
def log_repository_operation(operation, url_or_path, details = nil)
|
387
|
+
message = "repository #{operation}: #{url_or_path}"
|
388
|
+
message += " (#{details})" if details
|
389
|
+
Fig::VerboseLogging.verbose message
|
390
|
+
end
|
391
|
+
|
392
|
+
private
|
393
|
+
|
394
|
+
def log_asset_operation(operation, asset_path, size_bytes = nil)
|
395
|
+
message = "asset #{operation}: #{asset_path}"
|
396
|
+
message += " (#{format_bytes(size_bytes)})" if size_bytes
|
397
|
+
Fig::VerboseLogging.verbose message
|
398
|
+
end
|
399
|
+
|
400
|
+
def format_bytes(bytes)
|
401
|
+
return nil unless bytes
|
402
|
+
|
403
|
+
if bytes < 1024
|
404
|
+
"#{bytes}B"
|
405
|
+
elsif bytes < 1024 * 1024
|
406
|
+
"#{(bytes / 1024.0).round(1)}KB"
|
407
|
+
elsif bytes < 1024 * 1024 * 1024
|
408
|
+
"#{(bytes / (1024.0 * 1024)).round(1)}MB"
|
409
|
+
else
|
410
|
+
"#{(bytes / (1024.0 * 1024 * 1024)).round(1)}GB"
|
411
|
+
end
|
412
|
+
end
|
366
413
|
end
|
data/lib/fig/repository.rb
CHANGED
@@ -15,6 +15,7 @@ require 'fig/parser'
|
|
15
15
|
require 'fig/repository_error'
|
16
16
|
require 'fig/repository_package_publisher'
|
17
17
|
require 'fig/url'
|
18
|
+
require 'fig/verbose_logging'
|
18
19
|
|
19
20
|
module Fig; end
|
20
21
|
|
@@ -79,9 +80,12 @@ class Fig::Repository
|
|
79
80
|
def list_remote_packages
|
80
81
|
check_remote_repository_format()
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
83
|
+
Fig::VerboseLogging.time_operation("listing remote packages from #{remote_download_url()}") do
|
84
|
+
paths = @operating_system.download_list(remote_download_url())
|
85
|
+
filtered_paths = paths.reject { |path| path =~ %r< ^ #{METADATA_SUBDIRECTORY} / >xs }
|
86
|
+
Fig::VerboseLogging.verbose "found #{filtered_paths.size} packages at #{remote_download_url()}"
|
87
|
+
filtered_paths
|
88
|
+
end
|
85
89
|
end
|
86
90
|
|
87
91
|
def get_package(
|
@@ -296,25 +300,27 @@ class Fig::Repository
|
|
296
300
|
end
|
297
301
|
|
298
302
|
def update_package(descriptor)
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
303
|
+
Fig::VerboseLogging.time_operation("downloading package #{descriptor.to_string}") do
|
304
|
+
temp_dir = package_download_temp_dir(descriptor)
|
305
|
+
begin
|
306
|
+
install_package(descriptor, temp_dir)
|
307
|
+
rescue Fig::FileNotFoundError => error
|
308
|
+
if @updating_package_definition
|
309
|
+
Fig::Logging.fatal \
|
310
|
+
"Package #{descriptor.to_string} not found in remote repository. (Was looking for #{error.path}.)"
|
311
|
+
else
|
312
|
+
Fig::Logging.fatal \
|
313
|
+
"Part of package #{descriptor.to_string} was not downloadable. (Was attempting to get #{error.path}.)"
|
314
|
+
end
|
310
315
|
|
311
|
-
|
312
|
-
|
313
|
-
|
316
|
+
raise Fig::RepositoryError.new
|
317
|
+
rescue StandardError => exception
|
318
|
+
Fig::Logging.fatal %Q<Install of #{descriptor.to_string} failed: #{exception}>
|
314
319
|
|
315
|
-
|
316
|
-
|
317
|
-
|
320
|
+
raise Fig::RepositoryError.new
|
321
|
+
ensure
|
322
|
+
FileUtils.rm_rf(temp_dir)
|
323
|
+
end
|
318
324
|
end
|
319
325
|
|
320
326
|
return
|
@@ -423,6 +429,7 @@ class Fig::Repository
|
|
423
429
|
|
424
430
|
def download_assets(package, descriptor, temporary_package, temporary_runtime)
|
425
431
|
remote_package_directory = remote_directory_for_package(descriptor)
|
432
|
+
|
426
433
|
package.archive_locations.each do
|
427
434
|
|archive_location|
|
428
435
|
|
@@ -431,10 +438,14 @@ class Fig::Repository
|
|
431
438
|
remote_package_directory, [archive_location]
|
432
439
|
)
|
433
440
|
end
|
434
|
-
|
435
|
-
|
436
|
-
|
441
|
+
|
442
|
+
Fig::VerboseLogging.time_operation("downloading and unpacking archive #{File.basename(archive_location)}") do
|
443
|
+
@operating_system.download_and_unpack_archive(
|
444
|
+
archive_location, temporary_package, temporary_runtime
|
445
|
+
)
|
446
|
+
end
|
437
447
|
end
|
448
|
+
|
438
449
|
package.resource_locations.each do
|
439
450
|
|resource_location|
|
440
451
|
|
@@ -444,12 +455,14 @@ class Fig::Repository
|
|
444
455
|
)
|
445
456
|
end
|
446
457
|
|
447
|
-
basename
|
448
|
-
|
449
|
-
|
450
|
-
|
458
|
+
Fig::VerboseLogging.time_operation("downloading resource #{File.basename(resource_location)}") do
|
459
|
+
basename, path =
|
460
|
+
@operating_system.download_resource(
|
461
|
+
resource_location, temporary_package
|
462
|
+
)
|
451
463
|
|
452
|
-
|
464
|
+
@operating_system.copy path, File.join(temporary_runtime, basename)
|
465
|
+
end
|
453
466
|
end
|
454
467
|
|
455
468
|
return
|
@@ -15,6 +15,7 @@ require 'fig/statement/override'
|
|
15
15
|
require 'fig/statement/path'
|
16
16
|
require 'fig/statement/set'
|
17
17
|
require 'fig/user_input_error'
|
18
|
+
require 'fig/verbose_logging'
|
18
19
|
|
19
20
|
module Fig; end
|
20
21
|
|
@@ -41,6 +42,7 @@ class Fig::RuntimeEnvironment
|
|
41
42
|
@retrieves = {}
|
42
43
|
@named_packages = {}
|
43
44
|
@working_directory_maintainer = working_directory_maintainer
|
45
|
+
@all_override_statements = []
|
44
46
|
end
|
45
47
|
|
46
48
|
# Returns the value of an environment variable
|
@@ -94,6 +96,7 @@ class Fig::RuntimeEnvironment
|
|
94
96
|
return
|
95
97
|
end
|
96
98
|
|
99
|
+
log_config_processing(package.name, package.version, config_name)
|
97
100
|
Fig::Logging.debug(
|
98
101
|
"Applying #{package.to_descriptive_string_with_config config_name}, package depth #{current_package_depth}."
|
99
102
|
)
|
@@ -173,6 +176,7 @@ class Fig::RuntimeEnvironment
|
|
173
176
|
include_file_config(package, statement, backtrace, current_package_depth)
|
174
177
|
when Fig::Statement::Override
|
175
178
|
backtrace.add_override(statement)
|
179
|
+
@all_override_statements << statement
|
176
180
|
end
|
177
181
|
|
178
182
|
return
|
@@ -193,6 +197,15 @@ class Fig::RuntimeEnvironment
|
|
193
197
|
end
|
194
198
|
end
|
195
199
|
|
200
|
+
def check_for_unused_overrides()
|
201
|
+
@all_override_statements.each do |statement|
|
202
|
+
if statement.loaded_but_not_referenced?
|
203
|
+
Fig::Logging.warn \
|
204
|
+
%Q<Override "#{statement.package_name}/#{statement.version}"#{statement.position_string} was never used.>
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
196
209
|
private
|
197
210
|
|
198
211
|
def include_config(
|
@@ -206,7 +219,9 @@ class Fig::RuntimeEnvironment
|
|
206
219
|
include_statement.included_package.nil? && @suppress_includes == :all
|
207
220
|
|
208
221
|
package, resolved_descriptor, new_backtrace =
|
209
|
-
determine_included_package starting_package, include_statement, backtrace
|
222
|
+
determine_included_package starting_package, include_statement, backtrace, current_package_depth
|
223
|
+
|
224
|
+
log_package_include(resolved_descriptor, current_package_depth)
|
210
225
|
|
211
226
|
return if
|
212
227
|
@suppress_includes == :cross_package \
|
@@ -225,13 +240,13 @@ class Fig::RuntimeEnvironment
|
|
225
240
|
package,
|
226
241
|
resolved_descriptor.config || Fig::Package::DEFAULT_CONFIG,
|
227
242
|
new_backtrace,
|
228
|
-
next_package_depth
|
243
|
+
next_package_depth
|
229
244
|
)
|
230
245
|
|
231
246
|
return
|
232
247
|
end
|
233
248
|
|
234
|
-
def determine_included_package(starting_package, include_statement, backtrace)
|
249
|
+
def determine_included_package(starting_package, include_statement, backtrace, current_package_depth = 0)
|
235
250
|
descriptor = include_statement.descriptor
|
236
251
|
|
237
252
|
if ! include_statement.included_package.nil?
|
@@ -250,6 +265,9 @@ class Fig::RuntimeEnvironment
|
|
250
265
|
)
|
251
266
|
override = backtrace.get_override(override_package_name)
|
252
267
|
if override
|
268
|
+
log_override_applied(
|
269
|
+
override_package_name, descriptor.version, override, current_package_depth
|
270
|
+
)
|
253
271
|
resolved_descriptor =
|
254
272
|
Fig::PackageDescriptor.new(
|
255
273
|
override_package_name, override, descriptor.config
|
@@ -276,7 +294,6 @@ class Fig::RuntimeEnvironment
|
|
276
294
|
including_package, include_file_statement, backtrace, current_package_depth
|
277
295
|
)
|
278
296
|
return if @suppress_includes.is_a? Symbol
|
279
|
-
|
280
297
|
full_path = include_file_statement.full_path_relative_to including_package
|
281
298
|
|
282
299
|
descriptor =
|
@@ -583,4 +600,40 @@ class Fig::RuntimeEnvironment
|
|
583
600
|
message + ( stacktrace.empty? ? '' : "\n#{stacktrace}" )
|
584
601
|
)
|
585
602
|
end
|
603
|
+
|
604
|
+
private
|
605
|
+
|
606
|
+
def log_config_processing(package_name, version, config_name)
|
607
|
+
if package_name && !package_name.empty?
|
608
|
+
Fig::VerboseLogging.verbose "processing config #{config_name} for package #{package_name}/#{version || '<no version>'}"
|
609
|
+
else
|
610
|
+
Fig::VerboseLogging.verbose "processing config #{config_name} for command-line package"
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
def log_package_include(package_descriptor, depth)
|
615
|
+
# Skip logging for synthetic/unnamed packages at root level
|
616
|
+
if depth == 0 && package_descriptor.respond_to?(:name) &&
|
617
|
+
(package_descriptor.name.nil? || package_descriptor.name.empty?)
|
618
|
+
return
|
619
|
+
end
|
620
|
+
|
621
|
+
indent = " " * depth
|
622
|
+
if package_descriptor.respond_to?(:to_string)
|
623
|
+
descriptor_string = package_descriptor.to_string
|
624
|
+
elsif package_descriptor.respond_to?(:name) && package_descriptor.respond_to?(:version)
|
625
|
+
name = package_descriptor.name || "<unnamed>"
|
626
|
+
version = package_descriptor.version || "<no version>"
|
627
|
+
config = package_descriptor.config || "default"
|
628
|
+
descriptor_string = "#{name}/#{version}:#{config}"
|
629
|
+
else
|
630
|
+
descriptor_string = package_descriptor.to_s
|
631
|
+
end
|
632
|
+
Fig::VerboseLogging.verbose "#{indent}including package: #{descriptor_string}"
|
633
|
+
end
|
634
|
+
|
635
|
+
def log_override_applied(package_name, original_version, override_version, depth)
|
636
|
+
indent = " " * depth
|
637
|
+
Fig::VerboseLogging.verbose "#{indent}override applied: #{package_name}/#{original_version} -> #{package_name}/#{override_version}"
|
638
|
+
end
|
586
639
|
end
|
data/lib/fig/spec_utils.rb
CHANGED
@@ -18,6 +18,14 @@ require 'fig/external_program'
|
|
18
18
|
require 'fig/figrc'
|
19
19
|
require 'fig/logging'
|
20
20
|
require 'fig/repository'
|
21
|
+
require 'fig/verbose_logging'
|
22
|
+
|
23
|
+
# Reset verbose logging state before each test to prevent test pollution
|
24
|
+
RSpec.configure do |config|
|
25
|
+
config.before(:each) do
|
26
|
+
Fig::VerboseLogging.disable_verbose!
|
27
|
+
end
|
28
|
+
end
|
21
29
|
|
22
30
|
FIG_SPEC_BASE_DIRECTORY = Dir.mktmpdir 'fig-rspec-'
|
23
31
|
at_exit { FileUtils.rm_rf FIG_SPEC_BASE_DIRECTORY }
|
@@ -35,6 +35,26 @@ class Fig::Statement::Override < Fig::Statement
|
|
35
35
|
@version = version
|
36
36
|
end
|
37
37
|
|
38
|
+
def loaded_but_not_referenced?()
|
39
|
+
return added_to_environment? && ! referenced?
|
40
|
+
end
|
41
|
+
|
42
|
+
def added_to_environment?()
|
43
|
+
return @added_to_environment
|
44
|
+
end
|
45
|
+
|
46
|
+
def added_to_environment(yea_or_nay)
|
47
|
+
@added_to_environment = yea_or_nay
|
48
|
+
end
|
49
|
+
|
50
|
+
def referenced?()
|
51
|
+
return @referenced
|
52
|
+
end
|
53
|
+
|
54
|
+
def referenced(yea_or_nay)
|
55
|
+
@referenced = yea_or_nay
|
56
|
+
end
|
57
|
+
|
38
58
|
def statement_type()
|
39
59
|
return 'override'
|
40
60
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'fig/logging'
|
4
|
+
|
5
|
+
module Fig; end
|
6
|
+
|
7
|
+
# Core verbose logging infrastructure with timing support
|
8
|
+
module Fig::VerboseLogging
|
9
|
+
@@verbose_enabled = false
|
10
|
+
|
11
|
+
def self.enable_verbose!
|
12
|
+
@@verbose_enabled = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.disable_verbose!
|
16
|
+
@@verbose_enabled = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.verbose_enabled?
|
20
|
+
@@verbose_enabled
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.should_log_verbose?
|
24
|
+
@@verbose_enabled || Fig::Logging.debug?
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.verbose(message)
|
28
|
+
return unless should_log_verbose?
|
29
|
+
|
30
|
+
if Fig::Logging.info?
|
31
|
+
Fig::Logging.info "[VERBOSE] #{message}"
|
32
|
+
else
|
33
|
+
# fallback to stderr if logging is completely disabled
|
34
|
+
$stderr.puts "[VERBOSE] #{message}" if @@verbose_enabled
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.time_operation(operation_name, &block)
|
39
|
+
return yield unless should_log_verbose?
|
40
|
+
|
41
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
42
|
+
verbose "starting #{operation_name}"
|
43
|
+
|
44
|
+
begin
|
45
|
+
result = yield
|
46
|
+
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
47
|
+
verbose "completed #{operation_name} in #{format_duration(duration)}"
|
48
|
+
result
|
49
|
+
rescue => error
|
50
|
+
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
51
|
+
verbose "failed #{operation_name} after #{format_duration(duration)}: #{error.class.name}: #{error.message}"
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.format_duration(seconds)
|
57
|
+
if seconds < 1.0
|
58
|
+
"#{(seconds * 1000).round(1)}ms"
|
59
|
+
elsif seconds < 60.0
|
60
|
+
"#{seconds.round(2)}s"
|
61
|
+
else
|
62
|
+
minutes = (seconds / 60).floor
|
63
|
+
remaining_seconds = seconds - (minutes * 60)
|
64
|
+
"#{minutes}m #{remaining_seconds.round(1)}s"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/fig/version.rb
CHANGED
@@ -591,6 +591,18 @@ describe 'Fig' do
|
|
591
591
|
fig(%w<--update-if-missing --include foo/1.2.3 -- hello.bat>)[0].should ==
|
592
592
|
'cheese'
|
593
593
|
end
|
594
|
+
|
595
|
+
it 'warns on unused override' do
|
596
|
+
input = <<-END
|
597
|
+
config default
|
598
|
+
override unused-package/1.0.0
|
599
|
+
set WHATEVER=SOMETHING
|
600
|
+
end
|
601
|
+
END
|
602
|
+
out, err, exit_code = fig(%w<--update-if-missing>, input)
|
603
|
+
|
604
|
+
err.should =~ /Override "unused-package\/1\.0\.0".*was never used/
|
605
|
+
end
|
594
606
|
end
|
595
607
|
end
|
596
608
|
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
4
|
+
|
5
|
+
require 'fig/verbose_logging'
|
6
|
+
require 'fig/logging'
|
7
|
+
|
8
|
+
describe 'Fig::VerboseLogging' do
|
9
|
+
before(:each) do
|
10
|
+
# Reset verbose state and capture output
|
11
|
+
Fig::VerboseLogging.class_variable_set(:@@verbose_enabled, false)
|
12
|
+
@log_output = StringIO.new
|
13
|
+
@stderr_output = StringIO.new
|
14
|
+
|
15
|
+
allow(Fig::Logging).to receive(:info) do |message|
|
16
|
+
@log_output.puts(message) if Fig::Logging.info?
|
17
|
+
end
|
18
|
+
|
19
|
+
allow($stderr).to receive(:puts) do |message|
|
20
|
+
@stderr_output.puts(message)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.time_operation' do
|
25
|
+
it 'logs timing when verbose is enabled' do
|
26
|
+
Fig::VerboseLogging.enable_verbose!
|
27
|
+
allow(Fig::Logging).to receive(:info?).and_return(true)
|
28
|
+
|
29
|
+
result = Fig::VerboseLogging.time_operation('test operation') do
|
30
|
+
sleep(0.01) # Small delay to ensure measurable time
|
31
|
+
'test result'
|
32
|
+
end
|
33
|
+
|
34
|
+
expect(result).to eq('test result')
|
35
|
+
log_content = @log_output.string
|
36
|
+
expect(log_content).to include('[VERBOSE] starting test operation')
|
37
|
+
expect(log_content).to include('[VERBOSE] completed test operation in')
|
38
|
+
expect(log_content).to match(/\d+(\.\d+)?ms/)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'logs timing when debug logging is enabled (even without verbose flag)' do
|
42
|
+
allow(Fig::Logging).to receive(:debug?).and_return(true)
|
43
|
+
allow(Fig::Logging).to receive(:info?).and_return(true)
|
44
|
+
|
45
|
+
result = Fig::VerboseLogging.time_operation('test operation') do
|
46
|
+
'test result'
|
47
|
+
end
|
48
|
+
|
49
|
+
expect(result).to eq('test result')
|
50
|
+
log_content = @log_output.string
|
51
|
+
expect(log_content).to include('[VERBOSE] starting test operation')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'does not log when neither verbose nor debug is enabled' do
|
55
|
+
allow(Fig::Logging).to receive(:debug?).and_return(false)
|
56
|
+
allow(Fig::Logging).to receive(:info?).and_return(true)
|
57
|
+
|
58
|
+
result = Fig::VerboseLogging.time_operation('test operation') do
|
59
|
+
'test result'
|
60
|
+
end
|
61
|
+
|
62
|
+
expect(result).to eq('test result')
|
63
|
+
expect(@log_output.string).to be_empty
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'falls back to stderr when logging is disabled but verbose is enabled' do
|
67
|
+
Fig::VerboseLogging.enable_verbose!
|
68
|
+
allow(Fig::Logging).to receive(:info?).and_return(false)
|
69
|
+
|
70
|
+
result = Fig::VerboseLogging.time_operation('test operation') do
|
71
|
+
'test result'
|
72
|
+
end
|
73
|
+
|
74
|
+
expect(result).to eq('test result')
|
75
|
+
stderr_content = @stderr_output.string
|
76
|
+
expect(stderr_content).to include('[VERBOSE] starting test operation')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'logs failure timing on exceptions' do
|
80
|
+
Fig::VerboseLogging.enable_verbose!
|
81
|
+
allow(Fig::Logging).to receive(:info?).and_return(true)
|
82
|
+
|
83
|
+
expect do
|
84
|
+
Fig::VerboseLogging.time_operation('failing operation') do
|
85
|
+
raise StandardError, 'test error'
|
86
|
+
end
|
87
|
+
end.to raise_error(StandardError, 'test error')
|
88
|
+
|
89
|
+
log_content = @log_output.string
|
90
|
+
expect(log_content).to include('[VERBOSE] starting failing operation')
|
91
|
+
expect(log_content).to include('[VERBOSE] failed failing operation after')
|
92
|
+
expect(log_content).to include('StandardError: test error')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '.verbose' do
|
97
|
+
it 'logs messages when verbose is enabled' do
|
98
|
+
Fig::VerboseLogging.enable_verbose!
|
99
|
+
allow(Fig::Logging).to receive(:info?).and_return(true)
|
100
|
+
|
101
|
+
Fig::VerboseLogging.verbose('test message')
|
102
|
+
|
103
|
+
log_content = @log_output.string
|
104
|
+
expect(log_content).to include('[VERBOSE] test message')
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'logs messages when debug logging is enabled (even without verbose flag)' do
|
108
|
+
allow(Fig::Logging).to receive(:debug?).and_return(true)
|
109
|
+
allow(Fig::Logging).to receive(:info?).and_return(true)
|
110
|
+
|
111
|
+
Fig::VerboseLogging.verbose('test message')
|
112
|
+
|
113
|
+
log_content = @log_output.string
|
114
|
+
expect(log_content).to include('[VERBOSE] test message')
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'does not log when neither verbose nor debug is enabled' do
|
118
|
+
allow(Fig::Logging).to receive(:debug?).and_return(false)
|
119
|
+
allow(Fig::Logging).to receive(:info?).and_return(true)
|
120
|
+
|
121
|
+
Fig::VerboseLogging.verbose('test message')
|
122
|
+
|
123
|
+
expect(@log_output.string).to be_empty
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'falls back to stderr when logging is disabled but verbose is enabled' do
|
127
|
+
Fig::VerboseLogging.enable_verbose!
|
128
|
+
allow(Fig::Logging).to receive(:info?).and_return(false)
|
129
|
+
|
130
|
+
Fig::VerboseLogging.verbose('test message')
|
131
|
+
|
132
|
+
stderr_content = @stderr_output.string
|
133
|
+
expect(stderr_content).to include('[VERBOSE] test message')
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '.should_log_verbose?' do
|
138
|
+
it 'returns true when verbose is enabled' do
|
139
|
+
Fig::VerboseLogging.enable_verbose!
|
140
|
+
expect(Fig::VerboseLogging.should_log_verbose?).to be true
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'returns true when debug logging is enabled' do
|
144
|
+
allow(Fig::Logging).to receive(:debug?).and_return(true)
|
145
|
+
expect(Fig::VerboseLogging.should_log_verbose?).to be true
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'returns false when neither verbose nor debug is enabled' do
|
149
|
+
allow(Fig::Logging).to receive(:debug?).and_return(false)
|
150
|
+
expect(Fig::VerboseLogging.should_log_verbose?).to be false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe 'format helpers' do
|
155
|
+
it 'formats durations correctly' do
|
156
|
+
# Test private method via time_operation
|
157
|
+
Fig::VerboseLogging.enable_verbose!
|
158
|
+
allow(Fig::Logging).to receive(:info?).and_return(true)
|
159
|
+
|
160
|
+
# Mock Process.clock_gettime to control duration
|
161
|
+
start_time = 1000.0
|
162
|
+
allow(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(start_time, start_time + 0.5)
|
163
|
+
|
164
|
+
Fig::VerboseLogging.time_operation('test') { 'result' }
|
165
|
+
|
166
|
+
log_content = @log_output.string
|
167
|
+
expect(log_content).to include('500.0ms') # 0.5 seconds formatted as milliseconds
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.pre.alpha.
|
4
|
+
version: 2.0.0.pre.alpha.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fig Folks
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-10-07 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: bcrypt_pbkdf
|
@@ -334,7 +334,7 @@ dependencies:
|
|
334
334
|
description: |-
|
335
335
|
Fig is a utility for configuring environments and managing dependencies across a team of developers. Given a list of packages and a command to run, Fig builds environment variables named in those packages (e.g., CLASSPATH), then executes the command in that environment. The caller's environment is not affected.
|
336
336
|
|
337
|
-
Built from git SHA1:
|
337
|
+
Built from git SHA1: f7a4d2d-dirty
|
338
338
|
email: maintainer@figpackagemanager.org
|
339
339
|
executables:
|
340
340
|
- fig
|
@@ -501,6 +501,7 @@ files:
|
|
501
501
|
- lib/fig/url.rb
|
502
502
|
- lib/fig/url_access_disallowed_error.rb
|
503
503
|
- lib/fig/user_input_error.rb
|
504
|
+
- lib/fig/verbose_logging.rb
|
504
505
|
- lib/fig/version.rb
|
505
506
|
- lib/fig/working_directory_maintainer.rb
|
506
507
|
- lib/fig/working_directory_metadata.rb
|
@@ -541,11 +542,12 @@ files:
|
|
541
542
|
- spec/statement/asset_spec.rb
|
542
543
|
- spec/statement/configuration_spec.rb
|
543
544
|
- spec/support/formatters/seed_spitter.rb
|
545
|
+
- spec/verbose_logging_spec.rb
|
544
546
|
- spec/working_directory_maintainer_spec.rb
|
545
547
|
licenses:
|
546
548
|
- BSD-3-Clause
|
547
549
|
metadata:
|
548
|
-
git_sha:
|
550
|
+
git_sha: f7a4d2d-dirty
|
549
551
|
rdoc_options: []
|
550
552
|
require_paths:
|
551
553
|
- lib
|
@@ -563,5 +565,5 @@ requirements: []
|
|
563
565
|
rubygems_version: 3.6.1
|
564
566
|
specification_version: 4
|
565
567
|
summary: 'Utility for configuring environments and managing dependencies across a
|
566
|
-
team of developers. Built from git SHA1:
|
568
|
+
team of developers. Built from git SHA1: f7a4d2d-dirty'
|
567
569
|
test_files: []
|