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")
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)
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()
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()
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()
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()
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]))
def delete(cli): ch.dependencies_check() img_ref = ch.Image_Ref(cli.image_ref) img = ch.Image(img_ref) img.unpack_delete()
def __call__(self, *args, **kwargs): ch.dependencies_check() sys.exit(0)
def reset(cli): ch.dependencies_check() ch.storage.reset()
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))
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)