Esempio n. 1
0
def pull(cli):
    ch.dependencies_check()
    # Where does it go?
    dlcache = cli.storage + "/dlcache"
    if (cli.image_dir is not None):
        unpack_dir = cli.image_dir
        image_subdir = ""
    else:
        unpack_dir = cli.storage + "/img"
        image_subdir = None  # infer from image ref
    # Set things up.
    ref = ch.Image_Ref(cli.image_ref)
    if (cli.parse_only):
        print(ref.as_verbose_str)
        sys.exit(0)
    image = ch.Image(ref, dlcache, unpack_dir, image_subdir)
    ch.INFO("pulling image:   %s" % image.ref)
    if (cli.image_dir is not None):
        ch.INFO("destination:     %s" % image.unpack_path)
    else:
        ch.DEBUG("destination:     %s" % image.unpack_path)
    ch.DEBUG("use cache:       %s" % (not cli.no_cache))
    ch.DEBUG("download cache:  %s" % image.download_cache)
    ch.DEBUG("manifest:        %s" % image.manifest_path)
    # Pull!
    image.pull_to_unpacked(use_cache=(not cli.no_cache),
                           last_layer=cli.last_layer)
    # Done.
    ch.INFO("done")
Esempio n. 2
0
def list_(cli):
    ch.dependencies_check()
    imgdir = ch.storage.unpack_base
    if (cli.image_ref is None):
        # list all images
        if (not os.path.isdir(ch.storage.root)):
            ch.INFO("does not exist: %s" % ch.storage.root)
            return
        if (not ch.storage.valid_p()):
            ch.INFO("not a storage directory: %s" % ch.storage.root)
            return
        imgs = ch.ossafe(os.listdir,
                         "can't list directory: %s" % ch.storage.root, imgdir)
        for img in sorted(imgs):
            print(ch.Image_Ref(img))
    else:
        # list specified image
        img = ch.Image(ch.Image_Ref(cli.image_ref))
        print("details of image:    %s" % img.ref)
        # present locally?
        if (not img.unpack_exist_p):
            stored = "no"
        else:
            img.metadata_load()
            stored = "yes (%s)" % img.metadata["arch"]
        print("in local storage:    %s" % stored)
        # present remotely?
        print("full remote ref:     %s" % img.ref.canonical)
        pullet = pull.Image_Puller(img, not cli.no_cache)
        pullet.fatman_load()
        if (pullet.architectures is not None):
            remote = "yes"
            arch_aware = "yes"
            arch_avail = " ".join(sorted(pullet.architectures.keys()))
        else:
            pullet.manifest_load(True)
            if (pullet.layer_hashes is not None):
                remote = "yes"
                arch_aware = "no"
                arch_avail = "unknown"
            else:
                remote = "no"
                arch_aware = "n/a"
                arch_avail = "n/a"
        pullet.done()
        print("available remotely:  %s" % remote)
        print("remote arch-aware:   %s" % arch_aware)
        print("host architecture:   %s" % ch.arch_host)
        print("archs available:     %s" % arch_avail)
Esempio n. 3
0
def import_(cli):
    ch.dependencies_check()
    if (not os.path.exists(cli.path)):
        ch.FATAL("can't copy: not found: %s" % cli.path)
    dst = ch.Image(ch.Image_Ref(cli.image_ref))
    ch.INFO("importing:    %s" % cli.path)
    ch.INFO("destination:  %s" % dst)
    if (os.path.isdir(cli.path)):
        dst.copy_unpacked(cli.path)
    else:  # tarball, hopefully
        dst.unpack([cli.path])
    # initialize metadata if needed
    dst.metadata_load()
    dst.metadata_save()
    ch.done_notify()
Esempio n. 4
0
def main(cli):
    ch.dependencies_check()
    # Set things up.
    ref = ch.Image_Ref(cli.image_ref)
    if (cli.parse_only):
        print(ref.as_verbose_str)
        sys.exit(0)
    image = ch.Image(ref, cli.image_dir)
    ch.INFO("pulling image:    %s" % ref)
    ch.INFO("requesting arch:  %s" % ch.arch)
    if (cli.image_dir is not None):
        ch.INFO("destination:      %s" % image.unpack_path)
    else:
        ch.VERBOSE("destination:      %s" % image.unpack_path)
    pullet = Image_Puller(image, not cli.no_cache)
    pullet.pull_to_unpacked(cli.last_layer)
    pullet.done()
    ch.done_notify()
Esempio n. 5
0
def main(cli):
   ch.dependencies_check()
   # Set things up.
   ref = ch.Image_Ref(cli.image_ref)
   if (cli.parse_only):
      ch.INFO(ref.as_verbose_str)
      sys.exit(0)
   image = ch.Image(ref, cli.image_dir)
   ch.INFO("pulling image:   %s" % ref)
   if (cli.image_dir is not None):
      ch.INFO( "destination:     %s" % image.unpack_path)
   else:
      ch.VERBOSE("destination:     %s" % image.unpack_path)
   ch.VERBOSE("use cache:       %s" % (not cli.no_cache))
   ch.VERBOSE("download cache:  %s" % ch.storage.download_cache)
   pullet = Image_Puller(image)
   ch.VERBOSE("manifest:        %s" % pullet.manifest_path)
   pullet.pull_to_unpacked(use_cache=(not cli.no_cache),
                           last_layer=cli.last_layer)
   ch.done_notify()
Esempio n. 6
0
def main(cli):
    ch.dependencies_check()
    src_ref = ch.Image_Ref(cli.source_ref)
    ch.INFO("pushing image:   %s" % src_ref)
    image = ch.Image(src_ref, cli.image)
    # FIXME: validate it's an image using Megan's new function (PR #908)
    if (not os.path.isdir(image.unpack_path)):
        if (cli.image is not None):
            ch.FATAL("can't push: %s does not appear to be an image" %
                     cli.image)
        else:
            ch.FATAL("can't push: no image %s" % src_ref)
    if (cli.image is not None):
        ch.INFO("image path:      %s" % image.unpack_path)
    else:
        ch.VERBOSE("image path:      %s" % image.unpack_path)
    if (cli.dest_ref is not None):
        dst_ref = ch.Image_Ref(cli.dest_ref)
        ch.INFO("destination:     %s" % dst_ref)
    else:
        dst_ref = ch.Image_Ref(cli.source_ref)
    up = Image_Pusher(image, dst_ref)
    up.push()
    ch.done_notify()
Esempio n. 7
0
def main(cli_):

   # CLI namespace. :P
   global cli
   cli = cli_

   # Infer input file if needed.
   if (cli.file is None):
      cli.file = cli.context + "/Dockerfile"

   # Infer image name if needed.
   if (cli.tag is None):
      m = re.search(r"(([^/]+)/)?Dockerfile(\.(.+))?$",
                    os.path.abspath(cli.file))
      if (m is not None):
         if m.group(4):    # extension
            cli.tag = m.group(4)
         elif m.group(2):  # containing directory
            cli.tag = m.group(2)

   # Deal with build arguments.
   def build_arg_get(arg):
      kv = arg.split("=")
      if (len(kv) == 2):
         return kv
      else:
         v = os.getenv(kv[0])
         if (v is None):
            ch.FATAL("--build-arg: %s: no value and not in environment" % kv[0])
         return (kv[0], v)
   if (cli.build_arg is None):
      cli.build_arg = list()
   cli.build_arg = dict( build_arg_get(i) for i in cli.build_arg )

   # Finish CLI initialization.
   ch.DEBUG(cli)
   ch.dependencies_check()

   # Guess whether the context is a URL, and error out if so. This can be a
   # typical looking URL e.g. "https://..." or also something like
   # "[email protected]:...". The line noise in the second line of the regex is
   # to match this second form. Username and host characters from
   # https://tools.ietf.org/html/rfc3986.
   if (re.search(r"""  ^((git|git+ssh|http|https|ssh)://
                     | ^[\w.~%!$&'\(\)\*\+,;=-]+@[\w.~%!$&'\(\)\*\+,;=-]+:)""",
                 cli.context, re.VERBOSE) is not None):
      ch.FATAL("not yet supported: issue #773: URL context: %s" % cli.context)
   if (os.path.exists(cli.context + "/.dockerignore")):
      ch.WARNING("not yet supported, ignored: issue #777: .dockerignore file")

   # Set up build environment.
   global env
   env = Environment()

   # Read input file.
   if (cli.file == "-"):
      text = ch.ossafe(sys.stdin.read, "can't read stdin")
   else:
      fp = ch.open_(cli.file, "rt")
      text = ch.ossafe(fp.read, "can't read: %s" % cli.file)
      fp.close()

   # Parse it.
   parser = lark.Lark("?start: dockerfile\n" + ch.GRAMMAR,
                      parser="earley", propagate_positions=True)
   # Avoid Lark issue #237: lark.exceptions.UnexpectedEOF if the file does not
   # end in newline.
   text += "\n"
   try:
      tree = parser.parse(text)
   except lark.exceptions.UnexpectedInput as x:
      ch.DEBUG(x)  # noise about what was expected in the grammar
      ch.FATAL("can't parse: %s:%d,%d\n\n%s" % (cli.file, x.line, x.column, x.get_context(text, 39)))
   ch.DEBUG(tree.pretty())

   # Sometimes we exit after parsing.
   if (cli.parse_only):
      sys.exit(0)

   # Count the number of stages (i.e., FROM instructions)
   global image_ct
   image_ct = sum(1 for i in ch.tree_children(tree, "from_"))

   # Traverse the tree and do what it says.
   #
   # We don't actually care whether the tree is traversed breadth-first or
   # depth-first, but we *do* care that instruction nodes are visited in
   # order. Neither visit() nor visit_topdown() are documented as of
   # 2020-06-11 [1], but examining source code [2] shows that visit_topdown()
   # uses Tree.iter_trees_topdown(), which *is* documented to be in-order [3].
   #
   # This change seems to have been made in 0.8.6 (see PR #761); before then,
   # visit() was in order. Therefore, we call that instead, if visit_topdown()
   # is not present, to improve compatibility (see issue #792).
   #
   # [1]: https://lark-parser.readthedocs.io/en/latest/visitors/#visitors
   # [2]: https://github.com/lark-parser/lark/blob/445c8d4/lark/visitors.py#L211
   # [3]: https://lark-parser.readthedocs.io/en/latest/classes/#tree
   ml = Main_Loop()
   if (hasattr(ml, 'visit_topdown')):
      ml.visit_topdown(tree)
   else:
      ml.visit(tree)

   # Check that all build arguments were consumed.
   if (len(cli.build_arg) != 0):
      ch.FATAL("--build-arg: not consumed: " + " ".join(cli.build_arg.keys()))

   # Print summary & we're done.
   if (ml.instruction_ct == 0):
      ch.FATAL("no instructions found: %s" % cli.file)
   assert (image_i + 1 == image_ct)  # should have errored already if not
   ch.INFO("grown in %d instructions: %s"
           % (ml.instruction_ct, images[image_i]))
Esempio n. 8
0
def delete(cli):
    ch.dependencies_check()
    img_ref = ch.Image_Ref(cli.image_ref)
    img = ch.Image(img_ref)
    img.unpack_delete()
Esempio n. 9
0
 def __call__(self, *args, **kwargs):
     ch.dependencies_check()
     sys.exit(0)
Esempio n. 10
0
def reset(cli):
    ch.dependencies_check()
    ch.storage.reset()
Esempio n. 11
0
def list_(cli):
    ch.dependencies_check()
    imgdir = ch.storage.unpack_base
    imgs = ch.ossafe(os.listdir, "can't list directory: %s" % imgdir, imgdir)
    for img in sorted(imgs):
        print(ch.Image_Ref(img))
Esempio n. 12
0
 def __call__(self, ap, cli, *args, **kwargs):
     # ch.init() not yet called, so must get verbosity from arguments.
     ch.dependencies_check()
     if (cli.verbose >= 1):
         print("lark path: %s" % os.path.normpath(inspect.getfile(ch.lark)))
     sys.exit(0)