← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~bac/lpsetup/good-neighbors into lp:lpsetup

 

Brad Crittenden has proposed merging lp:~bac/lpsetup/good-neighbors into lp:lpsetup.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~bac/lpsetup/good-neighbors/+merge/118931

Wrap modifications to system files with a 'fence', a marker at the beginning of the change and one at the end.

An example:


ubuntu@bac-lpsetup-testing-lxc-ubuntu-0:~/.ssh$ more authorized_keys 
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAw/0eUFbwzycsbP8tNr5/VcIPGUJuLXIuI5urU9J4KwzKmehmwFRg6teNqaUK4kZyFCUC8lEduvjd1GSZcIM1D1lynt1T
gtVuAAw+vPawZGjdavAD7Jq5nNnC3zqdhsX2pKVqiXbbYz/XvsSHhKR6rDZhBlzdp2dzLLT57Kqczjs= bac@brazos
# --------------------lpsetup/lp-setup_0.2.2--------------------be7a6f4e-e1a3-11e1-91dd-00163e8d91da
# This file modified at 2012-08-08T21:55:18.943646UTC by lpsetup/lp-
# setup, version 0.2.2.
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF6TOiHgNFn03FhwslO+9pJ7R3W+wi/dk59rgNHkQ60+zENWuuA0+jnrriwwNF9am+NZfV98T8XgwqKYen0W+34aho
Jaa10kWxinH5u/5L8y34hK9scJgw7S2y3X8sjUeUU0xePrKAzFPcyUa6zNWao5El0EYeiN8JLePITfoxKCDOLeqJVngRJWWyHPPEIwbyOyMJQYj7h2S1nx37zDdb9ZZ3
ngv0Lq63+a/IBn1kFccjNKam7ldiwAtmxkpqYq7F0xexZIptycf6djLy5h3siwy2iGXz8ihRqSqFKlvZGBUT2Le66ZEr/1QMT/TJPpg06VIAqV/P1wZbJ0sOSgk1 roo
t@bac-lpsetup-testing-lxc-ubuntu-0

# --------------------lpsetup/lp-setup_0.2.2--------------------be7a6f4e-e1a3-11e1-91dd-00163e8d91da


The marker contains the program name and version number which will facilitate undoing partial file changes when a new version of lpsetup is run.  Each marker pair is unique, tagged with an UUID similar to the way MIME sections are marked to allow the markers to be selected and cut.

Some files that are written from scratch, not modified, still contain just the file header, not the fences as those files can be removed completely.  These are limited to the scripts created by the create_scripts function, e.g.

#!/usr/bin/env python
# Copyright 2012 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

# This file modified at 2012-08-09T12:04:57.380962UTC by ./lp-setup,
# version 0.2.2.

# Cleanup remnants of LXC containers from previous runs.




-- 
https://code.launchpad.net/~bac/lpsetup/good-neighbors/+merge/118931
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~bac/lpsetup/good-neighbors into lp:lpsetup.
=== modified file 'lpsetup/subcommands/inithost.py'
--- lpsetup/subcommands/inithost.py	2012-08-06 09:37:04 +0000
+++ lpsetup/subcommands/inithost.py	2012-08-09 12:21:19 +0000
@@ -50,11 +50,13 @@
     )
 from lpsetup.utils import (
     call,
-    get_file_header,
     render_to_file,
     running_in_container,
+    wrap_contents,
     )
 
+NEWLINE = '\n'
+
 
 def get_version_path():
     return '/var/lib/lpsetup/' + get_version()
@@ -124,7 +126,8 @@
         (known_hosts, known_host_contents, 'a'),
         ]
     for filename, contents, mode in files_to_write:
-        write_file_contents(filename, contents, mode, header=get_file_header())
+        wrapped = wrap_contents(contents)
+        write_file_contents(filename, wrapped, mode)
 
 
 def initialize_base(user):
@@ -164,11 +167,11 @@
         subprocess.call(['addgroup', '--gid', str(pwd_database.pw_gid), user])
 
     # Set up container hosts file.
-    lines = [get_file_header()]
-    lines.extend(['{0}\t{1}\n'.format(ip, names)
-                  for ip, names in HOSTS_CONTENT])
     make_backup(HOSTS_FILE)
-    for line in lines:
+    lines = ['{0}\t{1}\n'.format(ip, names)
+             for ip, names in HOSTS_CONTENT]
+    contents = wrap_contents(NEWLINE.join(lines))
+    for line in contents.split(NEWLINE):
         file_append(HOSTS_FILE, line)
 
 initialize.description = initialize_base.description + """ Create Apache \

=== modified file 'lpsetup/subcommands/initlxc.py'
--- lpsetup/subcommands/initlxc.py	2012-08-06 09:37:04 +0000
+++ lpsetup/subcommands/initlxc.py	2012-08-09 12:21:19 +0000
@@ -48,12 +48,12 @@
 from lpsetup.utils import (
     call,
     get_container_path,
-    get_file_header,
     get_lxc_gateway,
     lxc_stopped,
     retry,
     sshlxc as ssh,
     this_command,
+    wrap_contents,
     )
 
 
@@ -98,10 +98,9 @@
     if lxc_gateway is None:
         raise exceptions.ExecutionError(
             'Error: LXC bridge interface not found.')
-    content = LXC_OPTIONS.format(interface=lxc_gateway)
+    contents = wrap_contents(LXC_OPTIONS.format(interface=lxc_gateway))
     with open(LXC_CONFIG_TEMPLATE, 'w') as f:
-        f.write(get_file_header() + '\n')
-        f.write(content)
+        f.write(contents)
     # Creating container.
     call(
         'lxc-create',

=== modified file 'lpsetup/subcommands/initrepo.py'
--- lpsetup/subcommands/initrepo.py	2012-07-30 10:05:19 +0000
+++ lpsetup/subcommands/initrepo.py	2012-08-09 12:21:19 +0000
@@ -19,6 +19,7 @@
     ]
 
 import os
+from StringIO import StringIO
 import subprocess
 
 from shelltoolbox import mkdirs
@@ -37,7 +38,7 @@
 from lpsetup.utils import (
     call,
     ConfigParser,
-    get_file_header,
+    wrap_contents,
     )
 
 
@@ -113,8 +114,10 @@
         for option, value in options.items():
             parser.set(section, option, value.format(**context))
         with open(path, 'w') as f:
-            f.write(get_file_header() + '\n')
-            parser.write(f)
+            contents = StringIO()
+            parser.write(contents)
+            f.write(wrap_contents(contents.getvalue()))
+            contents.close()
 
 setup_bzr_locations.description = """If bzr+ssh is used, update bazaar \
     locations ($home_dir/.bazaar/locations.conf) to include repository \

=== modified file 'lpsetup/subcommands/install_lxc.py'
--- lpsetup/subcommands/install_lxc.py	2012-08-01 20:37:15 +0000
+++ lpsetup/subcommands/install_lxc.py	2012-08-09 12:21:19 +0000
@@ -33,6 +33,7 @@
     render_to_file,
     sshlxc as ssh,
     this_command,
+    wrap_contents,
     )
 
 
@@ -58,8 +59,7 @@
     sudoers_contents = '{user} ALL = (ALL) NOPASSWD: {scripts}\n'.format(
         user=user, scripts=', '. join(scripts))
     with open(sudoers_file, 'w') as sudoers:
-        sudoers.write(get_file_header() + '\n')
-        sudoers.write(sudoers_contents)
+        sudoers.write(wrap_contents(sudoers_contents))
     # The sudoers must have this mode or it will be ignored.
     os.chmod(sudoers_file, 0440)
     # XXX 2012-03-13 frankban bug=944386:
@@ -70,7 +70,7 @@
         f.write('0\n')
 
 create_scripts.description = """If requested, create helper script \
-    /usr/locl/bin/lp-setup-*: they can be used to build Launchpad and \
+    /usr/local/bin/lp-setup-*: they can be used to build Launchpad and \
     start a parallel test run.
 """
 

=== modified file 'lpsetup/utils.py'
--- lpsetup/utils.py	2012-07-31 08:50:37 +0000
+++ lpsetup/utils.py	2012-08-09 12:21:19 +0000
@@ -24,6 +24,7 @@
     'Scrubber',
     'sshlxc',
     'this_command',
+    'wrap_contents',
     ]
 
 from ConfigParser import RawConfigParser
@@ -42,6 +43,7 @@
 import sys
 import textwrap
 import time
+from uuid import uuid1
 
 from shelltoolbox import (
     command,
@@ -116,15 +118,18 @@
 
 
 def get_file_header(program=sys.argv[0], now=None,
-                    initial_indent='# ', subsequent_indent='# '):
+                    initial_indent='# ', subsequent_indent='# ',
+                    version=None):
     if now is None:
         now = datetime.utcnow()
+    if version is None:
+        version = get_version()
     header = (
-        'This file created at {date}UTC by {program}, '
+        'This file modified at {date}UTC by {program}, '
         'version {version}.'.format(
             date=datetime.isoformat(now),
             program=program,
-            version=get_version(),
+            version=version,
             )
         )
     return textwrap.fill(
@@ -132,6 +137,49 @@
         subsequent_indent=subsequent_indent)
 
 
+def wrap_contents(content, program=sys.argv[0], version=None, now=None,
+                  uuid=None, initial_indent='# ', subsequent_indent='# '):
+    """Given some content, wrap the content with a fence.
+
+    The fence will consist of opening and closing markers and a header
+    specifying the program name and time the content was made.
+
+        >>> now = datetime(1969, 7, 20, 20, 18)
+        >>> content = 'how now\\nbrown cow'
+        >>> print wrap_contents(content, '/usr/bin/tester', '1.2.3',
+        ...                     now=now, uuid='DEAD-BEEF')
+        # --------------------/usr/bin/tester_0.2--------------------DEAD-BEEF
+        # This file modified at 1969-07-20T20:18:00UTC by /usr/bin/tester,
+        # version 1.2.3.
+        how now
+        brown cow
+        # --------------------/usr/bin/tester_0.2--------------------DEAD-BEEF
+        <BLANKLINE>
+    """
+    if now is None:
+        now = datetime.utcnow()
+    if uuid is None:
+        uuid = str(uuid1())
+    if version is None:
+        version = get_version()
+    prog_version = "{0}_{1}".format(program, version)
+    open_marker = initial_indent + '-' * 20 + prog_version + '-' * 20 + uuid
+    close_marker = initial_indent + '-' * 20 + prog_version + '-' * 20 + uuid
+
+    header = get_file_header(
+        program, now, subsequent_indent, subsequent_indent, version)
+    template = textwrap.dedent("""\
+    {open_marker}
+    {header}
+    {content}
+    {close_marker}
+    """)
+    return template.format(open_marker=open_marker,
+                           header=header,
+                           content=content,
+                           close_marker=close_marker)
+
+
 def get_lxc_gateway(candidates=('lxcbr0', 'virbr0'), interface_lookup=None):
     """Return the gateway bridge name to be used by LXC containers.
 
@@ -153,8 +201,7 @@
     return [
         i for i in os.listdir(path)
         if i not in exclude and
-        os.path.isdir(os.path.join(path, i))
-        ]
+        os.path.isdir(os.path.join(path, i))]
 
 
 def get_running_containers(containers=None):


Follow ups