utils.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. from __future__ import absolute_import
  2. from __future__ import division
  3. from __future__ import unicode_literals
  4. import math
  5. import os
  6. import platform
  7. import ssl
  8. import subprocess
  9. import sys
  10. import docker
  11. import compose
  12. from ..const import IS_WINDOWS_PLATFORM
  13. # WindowsError is not defined on non-win32 platforms. Avoid runtime errors by
  14. # defining it as OSError (its parent class) if missing.
  15. try:
  16. WindowsError
  17. except NameError:
  18. WindowsError = OSError
  19. def yesno(prompt, default=None):
  20. """
  21. Prompt the user for a yes or no.
  22. Can optionally specify a default value, which will only be
  23. used if they enter a blank line.
  24. Unrecognised input (anything other than "y", "n", "yes",
  25. "no" or "") will return None.
  26. """
  27. answer = input(prompt).strip().lower()
  28. if answer == "y" or answer == "yes":
  29. return True
  30. elif answer == "n" or answer == "no":
  31. return False
  32. elif answer == "":
  33. return default
  34. else:
  35. return None
  36. def input(prompt):
  37. """
  38. Version of input (raw_input in Python 2) which forces a flush of sys.stdout
  39. to avoid problems where the prompt fails to appear due to line buffering
  40. """
  41. sys.stdout.write(prompt)
  42. sys.stdout.flush()
  43. return sys.stdin.readline().rstrip('\n')
  44. def call_silently(*args, **kwargs):
  45. """
  46. Like subprocess.call(), but redirects stdout and stderr to /dev/null.
  47. """
  48. with open(os.devnull, 'w') as shutup:
  49. try:
  50. return subprocess.call(*args, stdout=shutup, stderr=shutup, **kwargs)
  51. except WindowsError:
  52. # On Windows, subprocess.call() can still raise exceptions. Normalize
  53. # to POSIXy behaviour by returning a nonzero exit code.
  54. return 1
  55. def is_mac():
  56. return platform.system() == 'Darwin'
  57. def is_ubuntu():
  58. return platform.system() == 'Linux' and platform.linux_distribution()[0] == 'Ubuntu'
  59. def is_windows():
  60. return IS_WINDOWS_PLATFORM
  61. def get_version_info(scope):
  62. versioninfo = 'docker-compose version {}, build {}'.format(
  63. compose.__version__,
  64. get_build_version())
  65. if scope == 'compose':
  66. return versioninfo
  67. if scope == 'full':
  68. return (
  69. "{}\n"
  70. "docker-py version: {}\n"
  71. "{} version: {}\n"
  72. "OpenSSL version: {}"
  73. ).format(
  74. versioninfo,
  75. docker.version,
  76. platform.python_implementation(),
  77. platform.python_version(),
  78. ssl.OPENSSL_VERSION)
  79. raise ValueError("{} is not a valid version scope".format(scope))
  80. def get_build_version():
  81. filename = os.path.join(os.path.dirname(compose.__file__), 'GITSHA')
  82. if not os.path.exists(filename):
  83. return 'unknown'
  84. with open(filename) as fh:
  85. return fh.read().strip()
  86. def is_docker_for_mac_installed():
  87. return is_mac() and os.path.isdir('/Applications/Docker.app')
  88. def generate_user_agent():
  89. parts = [
  90. "docker-compose/{}".format(compose.__version__),
  91. "docker-py/{}".format(docker.__version__),
  92. ]
  93. try:
  94. p_system = platform.system()
  95. p_release = platform.release()
  96. except IOError:
  97. pass
  98. else:
  99. parts.append("{}/{}".format(p_system, p_release))
  100. return " ".join(parts)
  101. def unquote_path(s):
  102. if not s:
  103. return s
  104. if s[0] == '"' and s[-1] == '"':
  105. return s[1:-1]
  106. return s
  107. def human_readable_file_size(size):
  108. suffixes = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', ]
  109. order = int(math.log(size, 2) / 10) if size else 0
  110. if order >= len(suffixes):
  111. order = len(suffixes) - 1
  112. return '{0:.3g} {1}'.format(
  113. size / float(1 << (order * 10)),
  114. suffixes[order]
  115. )