diff --git a/library/lineinfile b/library/lineinfile index 6378e774c4a..ef8f6a015f4 100644 --- a/library/lineinfile +++ b/library/lineinfile @@ -61,11 +61,20 @@ options: default: EOF description: - Used with C(state=present). If specified, the line will be inserted - after the specified regular expression. Two special values are - available; C(BOF) for inserting the line at the beginning of the - file, and C(EOF) for inserting the line at the end of the file. - choices: [ 'BOF', 'EOF', '*regex*' ] + after the specified regular expression. A special value is + available; C(EOF) for inserting the line at the end of the file. + choices: [ EOF, *regex* ] default: EOF + insertbefore: + required: false + default: BOF + description: + - Used with C(state=present). If specified, the line will be inserted + before the specified regular expression. A value is available; + C(BOF) for inserting the line at the beginning of the + file. + choices: [ BOF, *regex* ] + default: BOF create: required: false choices: [ yes, no ] @@ -85,9 +94,10 @@ examples: - code: "lineinfile: \\\"dest=/etc/sudoers state=present regexp='^%wheel' line ='%wheel ALL=(ALL) NOPASSWD: ALL'\\\"" - code: 'lineinfile: dest=/etc/sudoers state=absent regexp="^%wheel"' - code: 'lineinfile: dest=/etc/httpd/conf/httpd.conf regexp="^Listen " insertafter="^#Listen " line="Listen 8080"' + - code: 'lineinfile: dest=/etc/services regexp="^# port for http" insertbefore="^www.*80/tcp" line="# port for http by default"' """ -def present(module, dest, regexp, line, insertafter, create, backup): +def present(module, dest, regexp, line, insertafter, insertbefore, create, backup): if os.path.isdir(dest): module.fail_json(rc=256, msg='Destination %s is a directory !' % dest) @@ -107,18 +117,31 @@ def present(module, dest, regexp, line, insertafter, create, backup): if not mre.search(line): module.fail_json(msg="usage error: line= doesn't match regexp (%s)" % regexp) - if insertafter in ('BOF', 'EOF'): - iare = None - else: - iare = re.compile(insertafter) + if insertbefore and insertafter: + module.fail_json(msg="usage error: \"insertbefore\" and \"insertafter\" cannot be combined") + + if insertafter in ('BOF', 'EOF', False): + if insertbefore in ('BOF', False): + insre = None + else: + insre = re.compile(insertbefore) + else: + insre = re.compile(insertafter) + + # index[0] is the line num where regexp has been found + # index[1] is the line num where insertafter/inserbefore has been found index = [-1, -1] for lineno in range(0, len(lines)): if mre.search(lines[lineno]): index[0] = lineno - elif iare is not None and iare.search(lines[lineno]): - # + 1 for the next line - index[1] = lineno + 1 + elif insre is not None and insre.search(lines[lineno]): + if insertafter: + # + 1 for the next line + index[1] = lineno + 1 + if insertbefore: + # + 1 for the previous line + index[1] = lineno # Regexp matched a line in the file if index[0] != -1: @@ -130,16 +153,17 @@ def present(module, dest, regexp, line, insertafter, create, backup): msg = 'line replaced' changed = True # Add it to the beginning of the file - elif insertafter == 'BOF': + # we keep insertafter == 'BOF' for backwards compatibility, but it should be removed eventually + elif insertbefore == 'BOF' or insertafter == 'BOF': lines.insert(0, line + os.linesep) msg = 'line added' changed = True - # Add it to the end of the file if requested or if insertafter= didn't match + # Add it to the end of the file if requested or if insertafter=/insertbefore didn't match elif insertafter == 'EOF' or index[1] == -1: lines.append(line + os.linesep) msg = 'line added' changed = True - # insertafter= matched + # insertafter/insertbefore= matched else: lines.insert(index[1], line + os.linesep) msg = 'line added' @@ -185,7 +209,8 @@ def main(): state=dict(default='present', choices=['absent', 'present']), regexp=dict(required=True), line=dict(aliases=['value']), - insertafter=dict(default='EOF'), + insertafter=dict(default=False), + insertbefore=dict(default=False), create=dict(default=False, choices=BOOLEANS), backup=dict(default=False, choices=BOOLEANS), ), @@ -199,7 +224,7 @@ def main(): if 'line' not in params: module.fail_json(msg='line= is required with state=present') present(module, params['dest'], params['regexp'], params['line'], - params['insertafter'], create, backup) + params['insertafter'], params['insertbefore'], create, backup) else: absent(module, params['dest'], params['regexp'], backup)