utils.py 3.7 KB

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