Example #1
0
 def test_last_line_precedence(self):
     base = make_tree([], [
         'garbage.md', 'thrash.md', 'README.md', 'README-bis.md',
         'README-secret.md'
     ])
     assert exclude_paths(base, ['*.md', '!README*.md', 'README-secret.md'
                                 ]) == set(['README.md', 'README-bis.md'])
Example #2
0
 def test_parent_directory(self):
     base = make_tree([], ['a.py', 'b.py', 'c.py'])
     # Dockerignore reference stipulates that absolute paths are
     # equivalent to relative paths, hence /../foo should be
     # equivalent to ../foo. It also stipulates that paths are run
     # through Go's filepath.Clean, which explicitely "replace
     # "/.."  by "/" at the beginning of a path".
     assert exclude_paths(base, ['../a.py', '/../b.py']) == set(['c.py'])
Example #3
0
 def test_include_wildcard(self):
     # This may be surprising but it matches the CLI's behavior
     # (tested with 18.05.0-ce on linux)
     base = make_tree(['a'], ['a/b.py'])
     assert exclude_paths(
         base,
         ['*', '!*/b.py']
     ) == set()
 def test_include_wildcard(self):
     # This may be surprising but it matches the CLI's behavior
     # (tested with 18.05.0-ce on linux)
     base = make_tree(['a'], ['a/b.py'])
     assert exclude_paths(
         base,
         ['*', '!*/b.py']
     ) == set()
Example #5
0
 def test_last_line_precedence(self):
     base = make_tree(
         [],
         ['garbage.md',
          'thrash.md',
          'README.md',
          'README-bis.md',
          'README-secret.md'])
     assert exclude_paths(
         base,
         ['*.md', '!README*.md', 'README-secret.md']
     ) == set(['README.md', 'README-bis.md'])
Example #6
0
 def test_parent_directory(self):
     base = make_tree(
         [],
         ['a.py',
          'b.py',
          'c.py'])
     # Dockerignore reference stipulates that absolute paths are
     # equivalent to relative paths, hence /../foo should be
     # equivalent to ../foo. It also stipulates that paths are run
     # through Go's filepath.Clean, which explicitely "replace
     # "/.."  by "/" at the beginning of a path".
     assert exclude_paths(
         base,
         ['../a.py', '/../b.py']
     ) == set(['c.py'])
Example #7
0
def docker_context(dockerfile_content, base_path, options):
    context = tempfile.NamedTemporaryFile()

    archive = tarfile.open(mode='w', fileobj=context)

    archive.addfile(*prepare_string_for_tar('Dockerfile', dockerfile_content))

    root = base_path

    # Process dockerignore
    dockerignore = join(root, '.dockerignore')
    exclude = None
    if exists(dockerignore):
        with open(dockerignore, 'r') as f:
            exclude = list(filter(bool, f.read().splitlines()))

    # Clean patterns
    exclude = clean_dockerignore(exclude)

    # Add root directory
    for path in sorted(exclude_paths(root, exclude)):
        archive.add(join(root, path), arcname=path, recursive=False)

    # Process options to check if we should includes a file outside the root directory
    for option in options.values():
        if option['value']:
            include_file = option['def'].get('include_file', False)
            if include_file:
                archive.add(option['def']['local_path'],
                            arcname=option['value'],
                            recursive=False)

    archive.close()
    context.seek(0)

    return context
Example #8
0
 def test_no_dupes(self):
     paths = exclude_paths(self.base, ['!a.py'])
     assert sorted(paths) == sorted(set(paths))
Example #9
0
 def exclude(self, patterns, dockerfile=None):
     return set(exclude_paths(self.base, patterns, dockerfile=dockerfile))
Example #10
0
 def make_build_context(self):
     """
     Makes a Docker build context from a local director.
     Normalises all file ownership and times so that the docker hashes align
     better.
     """
     # Start temporary tar file
     fileobj = tempfile.NamedTemporaryFile()
     tfile = tarfile.open(mode='w:gz', fileobj=fileobj)
     # Get list of files/dirs to add to the tar
     paths = exclude_paths(self.container.path, [])
     # For each file, add it to the tar with normalisation
     for path in paths:
         disk_location = os.path.join(self.container.path, path)
         # For Kubernetes images, use original date values for source code
         user_real_time = (
             'FTL_BUILD_SRC_REAL_TIME' in os.environ
             and os.environ['FTL_BUILD_SRC_REAL_TIME'] == 'true'
             and "/src/" in disk_location
         )
         # Directory addition
         if os.path.isdir(disk_location):
             info = tarfile.TarInfo(name=path)
             info.mtime = (0, os.stat(disk_location).st_mtime)[user_real_time]
             info.mode = 0o775
             info.type = tarfile.DIRTYPE
             info.uid = 0
             info.gid = 0
             info.uname = 'root'
             info.gname = 'root'
             tfile.addfile(info)
         # Normal file addition
         elif os.path.isfile(disk_location):
             stat = os.stat(disk_location)
             info = tarfile.TarInfo(name=path)
             info.mtime = (0, stat.st_mtime)[user_real_time]
             info.size = stat.st_size
             info.mode = 0o775
             info.type = tarfile.REGTYPE
             info.uid = 0
             info.gid = 0
             info.uname = 'root'
             info.gname = 'root'
             # Rewrite docker FROM lines with a : in them and raise a warning
             # TODO: Deprecate this!
             if path.lstrip('/') == self.container.dockerfile_name:
                 # Read in dockerfile line by line, replacing the FROM line
                 dockerfile = io.BytesIO()
                 with open(disk_location, 'r') as fh:
                     for line in fh:
                         if line.upper().startswith('FROM') and self.container.build_parent_in_prefix:
                             line = line.replace(':', '-')
                         dockerfile.write(line.encode('utf8'))
                 dockerfile.seek(0)
                 tfile.addfile(info, dockerfile)
             else:
                 with open(disk_location, 'rb') as fh:
                     tfile.addfile(info, fh)
         # Ignore symlinks
         elif os.path.islink(disk_location):
             pass
         # Error for anything else
         else:
             raise ValueError(
                 'Cannot add non-file/dir {} to docker build context'.format(path)
             )
     # Return that tarfile
     tfile.close()
     fileobj.seek(0)
     return fileobj
Example #11
0
 def test_include_wildcard(self):
     base = make_tree(['a'], ['a/b.py'])
     assert exclude_paths(base,
                          ['*', '!*/b.py']) == convert_paths(['a/b.py'])
Example #12
0
 def test_exclude_include_absolute_path(self):
     base = make_tree([], ['a.py', 'b.py'])
     assert exclude_paths(base, ['/*', '!/*.py']) == set(['a.py', 'b.py'])
Example #13
0
 def test_include_wildcard(self):
     base = make_tree(['a'], ['a/b.py'])
     assert exclude_paths(
         base,
         ['*', '!*/b.py']
     ) == convert_paths(['a/b.py'])
Example #14
0
 def test_exclude_include_absolute_path(self):
     base = make_tree([], ['a.py', 'b.py'])
     assert exclude_paths(
         base,
         ['/*', '!/*.py']
     ) == set(['a.py', 'b.py'])
Example #15
0
 def exclude(self, patterns, dockerfile=None):
     return set(exclude_paths(self.base, patterns, dockerfile=dockerfile))
Example #16
0
 def test_no_dupes(self):
     paths = exclude_paths(self.base, ['!a.py'])
     assert sorted(paths) == sorted(set(paths))
Example #17
0
 def make_build_context(self):
     """
     Makes a Docker build context from a local directory.
     Normalises all file ownership and times so that the docker hashes align
     better.
     """
     # Start temporary tar file
     fileobj = tempfile.NamedTemporaryFile()
     tfile = tarfile.open(mode='w:gz', fileobj=fileobj)
     # Get list of files/dirs to add to the tar
     paths = exclude_paths(self.container.path, [])
     # For each file, add it to the tar with normalisation
     for path in paths:
         disk_location = os.path.join(self.container.path, path)
         # Directory addition
         if os.path.isdir(disk_location):
             info = tarfile.TarInfo(name=path)
             info.mtime = 0
             info.mode = 0o775
             info.type = tarfile.DIRTYPE
             info.uid = 0
             info.gid = 0
             info.uname = "root"
             info.gname = "root"
             tfile.addfile(info)
         # Normal file addition
         elif os.path.isfile(disk_location):
             stat = os.stat(disk_location)
             info = tarfile.TarInfo(name=path)
             info.mtime = 0
             info.size = stat.st_size
             info.mode = 0o755
             info.type = tarfile.REGTYPE
             info.uid = 0
             info.gid = 0
             info.uname = "root"
             info.gname = "root"
             # Rewrite docker FROM lines with a : in them and raise a warning
             # TODO: Deprecate this!
             if path.lstrip("/") == self.container.dockerfile_name:
                 # Read in dockerfile line by line, replacing the FROM line
                 dockerfile = io.BytesIO()
                 with open(disk_location, "r") as fh:
                     for line in fh:
                         if line.upper().startswith(
                                 "FROM "
                         ) and self.container.build_parent_in_prefix:
                             line = line.replace(":", "-")
                         dockerfile.write(line.encode("utf8"))
                 dockerfile.seek(0)
                 tfile.addfile(info, dockerfile)
             else:
                 with open(disk_location, "rb") as fh:
                     tfile.addfile(info, fh)
         # Error for anything else
         else:
             raise ValueError(
                 "Cannot add non-file/dir %s to docker build context" %
                 path)
     # Return that tarfile
     tfile.close()
     fileobj.seek(0)
     return fileobj