download_utils.py raw

   1  #!/usr/bin/env python3
   2  #
   3  # Copyright (c) The Bitcoin Core developers
   4  # Distributed under the MIT software license, see the accompanying
   5  # file COPYING or https://opensource.org/license/mit/.
   6  
   7  import sys
   8  import time
   9  import urllib.request
  10  
  11  
  12  def download_from_url(url, archive):
  13      print(f"Fetching: {url}")
  14      last_print_time = time.time()
  15  
  16      def progress_hook(progress_bytes, total_size):
  17          nonlocal last_print_time
  18          now = time.time()
  19          percent = min(100, (progress_bytes * 100) / total_size)
  20          bar_length = 40
  21          filled_length = int(bar_length * percent / 100)
  22          bar = '#' * filled_length + '-' * (bar_length - filled_length)
  23          if now - last_print_time >= 1 or percent >= 100:
  24              print(f'\rDownloading: [{bar}] {percent:.1f}%', flush=True, end="")
  25              last_print_time = now
  26  
  27      with urllib.request.urlopen(url) as response:
  28          if response.status != 200:
  29              raise RuntimeError(f"HTTP request failed with status code: {response.status}")
  30  
  31          sock_info = response.fp.raw._sock.getpeername()
  32          print(f"Connected to {sock_info[0]}")
  33  
  34          total_size = int(response.getheader("Content-Length"))
  35          progress_bytes = 0
  36  
  37          with open(archive, 'wb') as file:
  38              while True:
  39                  chunk = response.read(8192)
  40                  if not chunk:
  41                      break
  42                  file.write(chunk)
  43                  progress_bytes += len(chunk)
  44                  progress_hook(progress_bytes, total_size)
  45  
  46          if progress_bytes < total_size:
  47              raise RuntimeError(f"Download incomplete: expected {total_size} bytes, got {progress_bytes} bytes")
  48  
  49      print('\n', flush=True, end="") # Flush to avoid error output on the same line.
  50  
  51  
  52  def download_script_assets(script_assets_dir):
  53      script_assets_dir.mkdir(parents=True, exist_ok=True)
  54      script_assets = script_assets_dir / "script_assets_test.json"
  55      url = "https://github.com/bitcoin-core/qa-assets/raw/main/unit_test_data/script_assets_test.json"
  56      try:
  57          download_from_url(url, script_assets)
  58      except Exception as e:
  59          print(f"\nDownload failed: {e}", file=sys.stderr)
  60          print("Retrying download after failure ...", file=sys.stderr)
  61          time.sleep(12)
  62          try:
  63              download_from_url(url, script_assets)
  64          except Exception as e2:
  65              sys.exit(e2)
  66