-
Notifications
You must be signed in to change notification settings - Fork 114
Support image tar, without accessing Docker daemon #256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,3 +10,7 @@ target | |
| docker-squash.iml | ||
| **/image.tar | ||
| **/tox.tar | ||
|
|
||
| .cursor/* | ||
|
|
||
| *.tar | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,7 +70,11 @@ def run(self): | |
| "--version", action="version", help="Show version and exit", version=version | ||
| ) | ||
|
|
||
| parser.add_argument("image", help="Image to be squashed") | ||
| parser.add_argument( | ||
| "image", | ||
| help="Image name or tar file path to be squashed. If a .tar file is provided, it will be processed without requiring Docker daemon.", | ||
| ) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should investigate using exclusive groups for argparse - as that has built in support for having either the
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also - I think its valid for output-path to be the same as input-tar (?) , should, in tar mode, this be the default?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great ! I have the code changes. |
||
|
|
||
| parser.add_argument( | ||
| "-f", | ||
| "--from-layer", | ||
|
|
@@ -79,7 +83,7 @@ def run(self): | |
| parser.add_argument( | ||
| "-t", | ||
| "--tag", | ||
| help="Specify the tag to be used for the new image. If not specified no tag will be applied", | ||
| help="Specify the tag to be used for the squashed image (recommended). Without this, the squashed image will have no repository tags to avoid overwriting the original image.", | ||
| ) | ||
| parser.add_argument( | ||
| "-m", | ||
|
|
@@ -118,18 +122,16 @@ def run(self): | |
| self.log.setLevel(logging.INFO) | ||
|
|
||
| self.log.debug("Running version %s", version) | ||
|
|
||
| try: | ||
| squash.Squash( | ||
| log=self.log, | ||
| image=args.image, | ||
| from_layer=args.from_layer, | ||
| tag=args.tag, | ||
| comment=args.message, | ||
| output_path=args.output_path, | ||
| load_image=args.load_image, | ||
| tmp_dir=args.tmp_dir, | ||
| cleanup=args.cleanup, | ||
| ).run() | ||
| # Auto-detect if input is tar file or image name | ||
| if self._is_tar_file(args.image): | ||
| self.log.debug(f"Detected tar file: {args.image}") | ||
| self._run_tar_mode(args) | ||
| else: | ||
| self.log.debug(f"Detected image name: {args.image}") | ||
| self._run_image_mode(args) | ||
|
|
||
| except KeyboardInterrupt: | ||
| self.log.error("Program interrupted by user, exiting...") | ||
| sys.exit(1) | ||
|
|
@@ -150,6 +152,91 @@ def run(self): | |
|
|
||
| sys.exit(1) | ||
|
|
||
| def _run_tar_mode(self, args): | ||
| from docker_squash.tar_image import TarImage | ||
|
|
||
| # Provide helpful guidance about --tag parameter | ||
| if not args.tag: | ||
| self.log.info( | ||
| "💡 Tip: Consider using --tag to specify a name for your squashed image" | ||
| ) | ||
| self.log.info(" Example: --tag myimage:squashed") | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does a tag make sense for an output tar? It is probably of only relevance if
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| tar_image = TarImage( | ||
| log=self.log, | ||
| tar_path=args.image, # 这里改为 args.image | ||
| from_layer=args.from_layer, | ||
| tmp_dir=args.tmp_dir, | ||
| tag=args.tag, | ||
| comment=args.message, | ||
| ) | ||
|
|
||
| try: | ||
| new_image_id = tar_image.squash() | ||
| self.log.info("New squashed image ID is %s" % new_image_id) | ||
|
|
||
| if not args.output_path: | ||
| import os | ||
|
|
||
| self.output_path = os.path.join( | ||
| os.path.dirname(args.image), f"squashed-{new_image_id[:12]}.tar" | ||
| ) | ||
|
|
||
| if args.output_path: | ||
| tar_image.export_tar_archive(args.output_path) | ||
|
|
||
| if args.load_image: | ||
| tar_image.load_squashed_image() | ||
|
|
||
| self.log.info("Done") | ||
|
|
||
| finally: | ||
| if not args.tmp_dir: | ||
| tar_image.cleanup() | ||
|
|
||
| def _run_image_mode(self, args): | ||
| squash.Squash( | ||
| log=self.log, | ||
| image=args.image, | ||
| from_layer=args.from_layer, | ||
| tag=args.tag, | ||
| comment=args.message, | ||
| output_path=args.output_path, | ||
| load_image=args.load_image, | ||
| tmp_dir=args.tmp_dir, | ||
| cleanup=args.cleanup, | ||
| ).run() | ||
|
|
||
| def _is_tar_file(self, input_path): | ||
| """Detect if input is a tar file or image name""" | ||
| import os | ||
| import tarfile | ||
|
|
||
| # Check if it's a file path that exists | ||
| if os.path.isfile(input_path): | ||
| # Check if it's a valid tar file | ||
| try: | ||
| with tarfile.open(input_path, "r"): | ||
| return True | ||
| except (tarfile.TarError, OSError): | ||
| return False | ||
|
|
||
| # Check if it ends with .tar extension | ||
| if input_path.endswith((".tar", ".tar.gz", ".tgz")): | ||
| return True | ||
|
|
||
| # Check for obvious file path patterns | ||
| if ( | ||
| input_path.startswith(("/")) # Absolute path | ||
| or input_path.startswith(("./")) # Current dir | ||
| or input_path.startswith(("../")) # Parent dir | ||
| or input_path.startswith(("~/")) | ||
| ): # Home dir | ||
| return True | ||
|
|
||
| # Otherwise assume it's an image name (even if it contains '/') | ||
| return False | ||
|
|
||
|
|
||
| def run(): | ||
| cli = CLI() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would imagine that its helpful when working with podman as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.