1 2 3 4 5 6 7 8 9 10 11 12 13 14 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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
# frozen_string_literal: true
module ExpandVariables
VariableExpansionError = Class.new(StandardError)
VARIABLES_REGEXP = /\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/
class << self
def expand(value, variables, expand_file_refs: true, fail_on_masked: false)
replace_with(value, variables) do |collection, last_match|
match_or_blank_value(
collection, last_match, expand_file_refs: expand_file_refs, fail_on_masked: fail_on_masked
)
end
end
def expand_existing(value, variables, expand_file_refs: true, fail_on_masked: false)
replace_with(value, variables) do |collection, last_match|
match_or_original_value(
collection, last_match, expand_file_refs: expand_file_refs, fail_on_masked: fail_on_masked
)
end
end
def possible_var_reference?(value)
return unless value
%w[$ %].any? { |symbol| value.include?(symbol) }
end
private
def replace_with(value, variables)
# We lazily fabricate the variables collection in case there is no variable in the value string.
# `collection` needs to be initialized to nil here
# so that it is memoized in the closure block for `gsub`.
collection = nil
value.gsub(VARIABLES_REGEXP) do
collection ||= Gitlab::Ci::Variables::Collection.fabricate(variables)
yield(collection, Regexp.last_match)
end
end
def match_or_blank_value(collection, last_match, expand_file_refs:, fail_on_masked:)
match = last_match[1] || last_match[2]
replacement = collection[match]
if replacement.nil?
nil
elsif fail_on_masked && replacement.masked?
raise VariableExpansionError, 'masked variables cannot be expanded'
elsif replacement.file?
expand_file_refs ? replacement.value : last_match
else
replacement.value
end
end
def match_or_original_value(collection, last_match, expand_file_refs:, fail_on_masked:)
match_or_blank_value(
collection, last_match, expand_file_refs: expand_file_refs, fail_on_masked: fail_on_masked
) || last_match[0]
end
end
end
|