diff --git a/Atomic/Export.py b/Atomic/Export.py index 60908e8..5691331 100644 --- a/Atomic/Export.py +++ b/Atomic/Export.py @@ -2,7 +2,6 @@ export docker images, containers and volumes into a filesystem directory. """ import os -import sys from .client import AtomicDocker from . import util @@ -21,10 +20,11 @@ def export_docker(graph, export_location, force): dangling_images = AtomicDocker().images(filters={"dangling":True}, quiet=True) if any(dangling_images): if not force: - util.write_out("There are dangling images in your system. Would you like atomic to prune them [y/N]") - choice = sys.stdin.read(1) - if choice.lower() == 'n': + choice = util.input("There are dangling images in your system. Would you like atomic to prune them [y/N]") + choice = choice.strip().lower() + if not choice in ['y', 'yes']: raise ValueError("Please delete dangling images before running atomic storage export") + util.write_out("Deleting dangling images") util.check_call([util.default_docker(), "rmi", "-f"]+dangling_images) diff --git a/Atomic/Import.py b/Atomic/Import.py index 9d9a3eb..c22b1af 100644 --- a/Atomic/Import.py +++ b/Atomic/Import.py @@ -25,10 +25,10 @@ def import_docker(graph, import_location): import_volumes(graph, import_location) util.write_out("atomic import completed successfully") - util.write_out("Would you like to cleanup (rm -rf {0}) the temporary directory [y/N]" + confirm = util.input("Would you like to cleanup (rm -rf {0}) the temporary directory [y/N]" .format(import_location)) - choice = sys.stdin.read(1) - if choice.lower() == 'y': + confirm = confirm.strip().lower() + if confirm in ['y', 'yes']: util.write_out("Deleting {0}".format(import_location)) util.check_call(['/usr/bin/rm', '-rf', import_location]) util.write_out("Please restart docker daemon for the changes to take effect") diff --git a/Atomic/atomic.py b/Atomic/atomic.py index 07c4efd..83a59e9 100644 --- a/Atomic/atomic.py +++ b/Atomic/atomic.py @@ -401,7 +401,7 @@ class Atomic(object): def _check_latest(self): inspect = self._inspect_image() if inspect and inspect["Id"] != self.inspect["Image"]: - sys.stdout.write( + util.write_out( "The '%(name)s' container is using an older version of the " "installed\n'%(image)s' container image. If you wish to use " "the newer image,\nyou must either create a new container " diff --git a/Atomic/delete.py b/Atomic/delete.py index e6cb00a..27cc2b4 100644 --- a/Atomic/delete.py +++ b/Atomic/delete.py @@ -19,7 +19,7 @@ class Delete(Atomic): confirm = util.input("Do you wish to delete {}? (y/N) ".format(self.args.delete_targets)) confirm = confirm.strip().lower() if not confirm in ['y', 'yes']: - sys.stderr.write("User aborted delete operation for {}\n".format(self.args.delete_targets)) + util.write_err("User aborted delete operation for {}".format(self.args.delete_targets)) sys.exit(2) if self.args.remote_delete: @@ -65,7 +65,7 @@ class Delete(Atomic): util.skopeo_delete(img, args) util.write_out("Image {} marked for deletion".format(img)) except ValueError as e: - sys.stderr.write("Failed to mark Image {} for deletion: {}\n".format(img, e)) + util.write_err("Failed to mark Image {} for deletion: {}".format(img, e)) results = 2 return results @@ -75,9 +75,9 @@ class Delete(Atomic): try: self.d.remove_image(target) except NotFound as e: - sys.stderr.write("Failed to delete Image {}: {}\n".format(target, e)) + util.write_err("Failed to delete Image {}: {}".format(target, e)) results = 2 except APIError as e: - sys.stderr.write("Failed operation for delete Image {}: {}\n".format(target, e)) + util.write_err("Failed operation for delete Image {}: {}".format(target, e)) results = 2 return results diff --git a/Atomic/diff.py b/Atomic/diff.py index 2e43b0b..651c68a 100644 --- a/Atomic/diff.py +++ b/Atomic/diff.py @@ -88,7 +88,7 @@ class DiffHelpers(object): except mount.SelectionMatchError as e: if len(image_list) > 0: DiffHelpers.cleanup(image_list) - sys.stderr.write("{}\n".format(e)) + util.write_err("{}".format(e)) sys.exit(1) return image_list diff --git a/Atomic/mount.py b/Atomic/mount.py index 5efc9c5..df1411c 100644 --- a/Atomic/mount.py +++ b/Atomic/mount.py @@ -219,7 +219,7 @@ class Mount(Atomic): rc, result_stdout, result_stderr = util.subp(['umount', path]) if rc == 0: return rc, result_stdout, result_stderr - sys.stderr.write("Warning: {}\nRetrying {}/{} to unmount {}\n" + util.write_err("Warning: {}\nRetrying {}/{} to unmount {}" .format(result_stderr, x+1, timeout, path)) time.sleep(1) raise ValueError("Unable to unmount {0} due to {1}".format(path, result_stderr)) @@ -641,7 +641,7 @@ def getxattrfuncs(): else: try: import xattr #pylint: disable=import-error - module = xattr + module = xattr except ImportError: pass diff --git a/Atomic/pulp.py b/Atomic/pulp.py index 95fba16..f484488 100644 --- a/Atomic/pulp.py +++ b/Atomic/pulp.py @@ -1,5 +1,4 @@ import os -import sys import json try: import ConfigParser as configparser @@ -97,7 +96,7 @@ class PulpServer(object): return r_json if 'error_message' in r_json: - sys.stderr.write('Error messages from Pulp response:\n{0}' + util.write_err('Error messages from Pulp response:\n{0}' ''.format(r_json['error_message'])) if 'spawned_tasks' in r_json: @@ -188,8 +187,7 @@ class PulpServer(object): break url = '{0}/pulp/api/v2/content/uploads/{1}/{2}/' \ ''.format(self._server_url, upload_id, offset) - sys.stdout.flush() - sys.stdout.write(".") + util.write_out(".", "") self._call_pulp(url, "put", data) offset += self._chunk_size image_stream.close() diff --git a/Atomic/satellite.py b/Atomic/satellite.py index 83b7d38..8a41000 100644 --- a/Atomic/satellite.py +++ b/Atomic/satellite.py @@ -1,5 +1,4 @@ import os -import sys import json try: import ConfigParser as configparser @@ -135,7 +134,7 @@ class SatelliteServer(object): return None if ('errors' in r_json): - sys.stderr.write('Error message from Satellite response:\n{0}\n' + util.write_err('Error message from Satellite response:\n{0}' .format(r_json['errors'])) if 'spawned_tasks' in r_json: for task in r_json['spawned_tasks']: @@ -219,8 +218,7 @@ class SatelliteServer(object): if not content: break url = "{0}/katello/api/repositories/{1}/content_uploads/{2}".format(self._server_url, repo_id, upload_id) - sys.stdout.flush() - sys.stdout.write(".") + util.write_out(".", "") payload = { 'offset': offset, 'content': content diff --git a/Atomic/util.py b/Atomic/util.py index 088c162..9421c08 100644 --- a/Atomic/util.py +++ b/Atomic/util.py @@ -131,13 +131,22 @@ def default_ro_container_context(): return selinux.getfilecon("/usr")[1] return "" -def write_out(output, lf="\n"): - sys.stdout.flush() - if is_python2: - sys.stdout.write(output.encode('utf-8') + lf) - else: - sys.stdout.write(output + str(lf)) +def write_out(output, lf="\n"): + _output(sys.stdout, output, lf) + + +def write_err(output, lf="\n"): + _output(sys.stderr, output, lf) + + +def _output(fd, output, lf): + fd.flush() + + if is_python2: + fd.write(output.encode('utf-8') + lf) + else: + fd.write(output + str(lf)) def output_json(json_data): ''' Pretty print json data ''' diff --git a/atomic b/atomic index eee3345..b5b6e4e 100755 --- a/atomic +++ b/atomic @@ -39,7 +39,7 @@ from Atomic.help import AtomicHelp from Atomic.run import Run from Atomic.ps import Ps from Atomic.storage import Storage -from Atomic.util import get_scanners, default_docker_lib, NoDockerDaemon +from Atomic.util import get_scanners, default_docker_lib, write_err, NoDockerDaemon import traceback from Atomic.mount import MountError @@ -60,8 +60,8 @@ except IOError: class HelpByDefaultArgumentParser(argparse.ArgumentParser): def error(self, message): - sys.stderr.write('%s: %s\n' % (sys.argv[0], message)) - sys.stderr.write("Try '%s --help' for more information.\n" % self.prog) + write_err('%s: %s' % (sys.argv[0], message)) + write_err("Try '%s --help' for more information." % self.prog) sys.exit(2) @@ -678,12 +678,12 @@ if __name__ == '__main__': except KeyboardInterrupt: sys.exit(0) except (ValueError, IOError, docker.errors.DockerException, NoDockerDaemon) as e: - sys.stderr.write("%s\n" % str(e)) + write_err("%s" % str(e)) if os.geteuid() != 0: need_root() sys.exit(1) except subprocess.CalledProcessError as e: - sys.stderr.write("\n") + write_err("") sys.exit(e.returncode) except AttributeError: # python3 throws exception on no args to atomic @@ -693,10 +693,10 @@ if __name__ == '__main__': if str(e).find("Permission denied") > 0: need_root() else: - sys.stderr.write("%s\n" % str(e)) + write_err("%s" % str(e)) sys.exit(1) except Exception as e: # pylint: disable=broad-except - sys.stderr.write("%s\n" % str(e)) + write_err("%s" % str(e)) sys.exit(1) except SystemExit as e: # Overriding debug args to avoid a traceback from sys.exit()