Coverage for lib/ansible/parsing/splitter.py : 82%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# (c) 2014 James Cammarata, <jcammarata@ansible.com> # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# Make coding more python3-ish
# Decode escapes adapted from rspeer's answer here: # http://stackoverflow.com/questions/4020539/process-escape-sequences-in-a-string-in-python ( \\U{0} # 8-digit hex escapes | \\u{1} # 4-digit hex escapes | \\x{2} # 2-digit hex escapes | \\N\{{[^}}]+\}} # Unicode characters by name | \\[\\'"abfnrtv] # Single-character escapes )'''.format(_HEXCHAR * 8, _HEXCHAR * 4, _HEXCHAR * 2), re.UNICODE | re.VERBOSE)
return codecs.decode(match.group(0), 'unicode-escape')
''' Convert a string of key/value items to a dict. If any free-form params are found and the check_raw option is set to True, they will be added to a new parameter called '_raw_params'. If check_raw is not enabled, they will simply be ignored. '''
except ValueError as ve: if 'no closing quotation' in str(ve).lower(): raise AnsibleParserError("error parsing argument string, try quoting the entire line.", orig_exc=ve) else: raise
except ValueError: # ran out of string, but we must have some escaped equals, # so replace those and append this to the list of raw params raw_params.append(x.replace('\\=', '=')) continue
# FIXME: make the retrieval of this list of shell/command # options a function, so the list is centralized raw_params.append(orig_x) else: else:
# recombine the free-form params, if any were found, and assign # them to a special option for use later by the shell/command module
''' the goal of this block is to determine if the quoted string is unterminated in which case it needs to be put back together ''' # the char before the current one, used to see if # the current character is escaped else:
''' this function counts the number of opening/closing blocks for a given opening/closing type and adjusts the current depth for that block based on the difference ''' cur_depth = 0
''' Splits args on whitespace, but intelligently reassembles those that may have been split over a jinja2 block or quotes.
When used in a remote module, we won't ever have to be concerned about jinja2 blocks, however this function is/will be used in the core portions as well before the args are templated.
example input: a=b c="foo bar" example output: ['a=b', 'c="foo bar"']
Basically this is a variation shlex that has some more intelligence for how Ansible needs to use it. '''
# the list of params parsed out of the arg string # this is going to be the result value when we are done
# Initial split on white space
# iterate over the tokens, and reassemble any that may have been # split on a space inside a jinja2 block. # ex if tokens are "{{", "foo", "}}" these go together
# These variables are used # to keep track of the state of the parsing, since blocks and quotes # may be nested within each other.
# now we loop over each split chunk, coalescing tokens if the white space # split occurred within quotes or a jinja2 block of some kind
# we split on spaces and newlines separately, so that we # can tell which character we split on for reassembly # inside quotation characters
# if we hit a line continuation character, but # we're not inside quotes, ignore it and continue # on to the next token while setting a flag line_continuation = True continue
# store the previous quoting state for checking later
# multiple conditions may append a token to the list of params, # so we keep track with this flag to make sure it only happens once # append means add to the end of the list, don't append means concatenate # it to the end of the last token
# if we're inside quotes now, but weren't before, append the token # to the end of the list, since we'll tack on more to it later # otherwise, if we're inside any jinja2 block, inside quotes, or we were # inside quotes (but aren't now) concat this token to the last param params[-1] = "%s%s" % (params[-1], token) else: params[-1] = "%s\n%s" % (params[-1], token)
# if the number of paired block tags is not the same, the depth has changed, so we calculate that here # and may append the current token to the params (if we haven't previously done so)
params.append(token) appended = True
# finally, if we're at zero depth for all blocks and not inside quotes, and have not # yet appended anything to the list of params, we do so now
# if this was the last token in the list, and we have more than # one item (meaning we split on newlines), add a newline back here # to preserve the original structure params[-1] += '\n'
# always clear the line continuation flag
# If we're done and things are not at zero depth or we're still inside quotes, # raise an error to indicate that the args were unbalanced raise AnsibleParserError(u"failed at splitting arguments, either an unbalanced jinja2 block or quotes: {0}".format(args))
|