utils.py 3.5 KB

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