utils.py 3.7 KB

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