Ejemplo n.º 1
0
 def copy_src_file(self, src, dst):
     """Copy file src, named by COPY either explicitly or with wildcards, to
      dst. src might be a symlink, but dst is a canonical path. Both must
      be at the top level of the COPY instruction; i.e., this function must
      not be called recursively. If dst is a directory, file should go in
      that directory named src (i.e., the directory creation magic has
      already happened)."""
     assert (os.path.isfile(src))
     assert (not os.path.exists(dst)
             or (os.path.isdir(dst) and not os.path.islink(dst))
             or (os.path.isfile(dst) and not os.path.islink(dst)))
     ch.DEBUG("copying named file: %s -> %s" % (src, dst))
     ch.copy2(src, dst, follow_symlinks=True)
Ejemplo n.º 2
0
 def execute_(self):
    # Complain about unsupported stuff.
    if (self.options.pop("chown", False)):
       self.unsupported_forever_warn("--chown")
    # Any remaining options are invalid.
    self.options_assert_empty()
    # Find the source directory.
    if (self.from_ is None):
       context = cli.context
    else:
       if (self.from_ == image_i or self.from_ == image_alias):
          ch.FATAL("COPY --from: stage %s is the current stage" % self.from_)
       if (not self.from_ in images):
          # FIXME: Would be nice to also report if a named stage is below.
          if (isinstance(self.from_, int) and self.from_ < image_ct):
             if (self.from_ < 0):
                ch.FATAL("COPY --from: invalid negative stage index %d"
                         % self.from_)
             else:
                ch.FATAL("COPY --from: stage %d does not exist yet"
                         % self.from_)
          else:
             ch.FATAL("COPY --from: stage %s does not exist" % self.from_)
       context = images[self.from_].unpack_path
    ch.DEBUG("context: " + context)
    # Do the copy.
    srcs = list()
    for src in self.srcs:
       if (os.path.normpath(src).startswith("..")):
          ch.FATAL("can't COPY: %s climbs outside context" % src)
       for i in glob.glob(context + "/" + src):
          srcs.append(i)
    if (len(srcs) == 0):
       ch.FATAL("can't COPY: no sources exist")
    dst = images[image_i].unpack_path + "/"
    if (not self.dst.startswith("/")):
       dst += env.workdir + "/"
    dst += self.dst
    if (dst.endswith("/") or len(srcs) > 1 or os.path.isdir(srcs[0])):
       # Create destination directory.
       if (dst.endswith("/")):
          dst = dst[:-1]
       if (os.path.exists(dst) and not os.path.isdir(dst)):
          ch.FATAL("can't COPY: %s exists but is not a directory" % dst)
       ch.mkdirs(dst)
    for src in srcs:
       # Check for symlinks to outside context.
       src_real = os.path.realpath(src)
       context_real = os.path.realpath(context)
       if (not os.path.commonpath([src_real, context_real]) \
               .startswith(context_real)):
          ch.FATAL("can't COPY: %s climbs outside context via symlink" % src)
       # Do the copy.
       if (os.path.isfile(src)):   # or symlink to file
          ch.DEBUG("COPY via copy2 file %s to %s" % (src, dst))
          ch.copy2(src, dst, follow_symlinks=True)
       elif (os.path.isdir(src)):  # or symlink to directory
          # Copy *contents* of src, not src itself. Note: shutil.copytree()
          # has a parameter dirs_exist_ok that I think will make this easier
          # in Python 3.8.
          ch.DEBUG("COPY dir %s to %s" % (src, dst))
          if (not os.path.isdir(dst)):
             ch.FATAL("can't COPY: destination not a directory: %s to %s"
                      % (src, dst))
          for src2_basename in ch.ossafe(
                os.listdir, "can't list directory: %s" % src, src):
             src2 = src + "/" + src2_basename
             if (os.path.islink(src2)):
                # Symlinks within directories do not get dereferenced.
                ch.DEBUG("symlink via copy2: %s to %s" % (src2, dst))
                ch.copy2(src2, dst, follow_symlinks=False)
             elif (os.path.isfile(src2)):  # not symlink to file
                ch.DEBUG("file via copy2: %s to %s" % (src2, dst))
                ch.copy2(src2, dst)
             elif (os.path.isdir(src2)):   # not symlink to directory
                dst2 = dst + "/" + src2_basename
                ch.DEBUG("directory via copytree: %s to %s" % (src2, dst2))
                ch.copytree(src2, dst2, symlinks=True,
                            ignore_dangling_symlinks=True)
             else:
                ch.FATAL("can't COPY unknown file type: %s" % src2)
       else:
          ch.FATAL("can't COPY unknown file type: %s" % src)
Ejemplo n.º 3
0
    def copy_src_dir(self, src, dst):
        """Copy the contents of directory src, named by COPY, either explicitly
         or with wildcards, to dst. src might be a symlink, but dst is a
         canonical path. Both must be at the top level of the COPY
         instruction; i.e., this function must not be called recursively. dst
         must exist already and be a directory. Unlike subdirectories, the
         metadata of dst will not be altered to match src."""
        def onerror(x):
            ch.FATAL("can't scan directory: %s: %s" % (x.filename, x.strerror))

        # Use Path objects in this method because the path arithmetic was
        # getting too hard with strings.
        src = ch.Path(os.path.realpath(src))
        dst = ch.Path(dst)
        assert (os.path.isdir(src) and not os.path.islink(src))
        assert (os.path.isdir(dst) and not os.path.islink(dst))
        ch.DEBUG("copying named directory: %s -> %s" % (src, dst))
        for (dirpath, dirnames, filenames) in os.walk(src, onerror=onerror):
            dirpath = ch.Path(dirpath)
            subdir = dirpath.relative_to(src)
            dst_dir = dst // subdir
            # dirnames can contain symlinks, which we handle as files, so we'll
            # rebuild it; the walk will not descend into those "directories".
            dirnames2 = dirnames.copy()  # shallow copy
            dirnames[:] = list()  # clear in place
            for d in dirnames2:
                d = ch.Path(d)
                src_path = dirpath // d
                dst_path = dst_dir // d
                ch.TRACE("dir: %s -> %s" % (src_path, dst_path))
                if (os.path.islink(src_path)):
                    filenames.append(d)  # symlink, handle as file
                    ch.TRACE("symlink to dir, will handle as file")
                    continue
                else:
                    dirnames.append(d)  # directory, descend into later
                # If destination exists, but isn't a directory, remove it.
                if (os.path.exists(dst_path)):
                    if (os.path.isdir(dst_path)
                            and not os.path.islink(dst_path)):
                        ch.TRACE("dst_path exists and is a directory")
                    else:
                        ch.TRACE("dst_path exists, not a directory, removing")
                        ch.unlink(dst_path)
                # If destination directory doesn't exist, create it.
                if (not os.path.exists(dst_path)):
                    ch.TRACE("mkdir dst_path")
                    ch.ossafe(os.mkdir, "can't mkdir: %s" % dst_path, dst_path)
                # Copy metadata, now that we know the destination exists and is a
                # directory.
                ch.ossafe(shutil.copystat,
                          "can't copy metadata: %s -> %s" %
                          (src_path, dst_path),
                          src_path,
                          dst_path,
                          follow_symlinks=False)
            for f in filenames:
                f = ch.Path(f)
                src_path = dirpath // f
                dst_path = dst_dir // f
                ch.TRACE("file or symlink via copy2: %s -> %s" %
                         (src_path, dst_path))
                if (not (os.path.isfile(src_path)
                         or os.path.islink(src_path))):
                    ch.FATAL("can't COPY: unknown file type: %s" % src_path)
                if (os.path.exists(dst_path)):
                    ch.TRACE("destination exists, removing")
                    if (os.path.isdir(dst_path)
                            and not os.path.islink(dst_path)):
                        ch.rmtree(dst_path)
                    else:
                        ch.unlink(dst_path)
                ch.copy2(src_path, dst_path, follow_symlinks=False)