diff --git a/tools/mpremote/mpremote/transport_serial.py b/tools/mpremote/mpremote/transport_serial.py index 3b4cd00078..15863bf5c0 100644 --- a/tools/mpremote/mpremote/transport_serial.py +++ b/tools/mpremote/mpremote/transport_serial.py @@ -35,7 +35,7 @@ # Once the API is stabilised, the idea is that mpremote can be used both # as a command line tool and a library for interacting with devices. -import ast, io, errno, os, re, struct, sys, time +import ast, io, errno, os, re, struct, sys, time, contextlib, urllib from collections import namedtuple from errno import EPERM from .console import VT_ENABLED @@ -58,6 +58,24 @@ def reraise_filesystem_error(e, info): raise +@contextlib.contextmanager +def open_file(src : str): + """Open a file. Can be either on local disk or a HTTP(S) URL""" + is_http = src.startswith('https://') or src.startswith('http://') + if is_http: + conn = urllib.request.urlopen(src, timeout=60.0) + size = int(conn.headers['content-length']) + file_like = conn + else: + size = os.path.getsize(src) + file_like = open(src, "rb") + + # attach a size() method, so consumers can know the file size + file_like.size = lambda : size + yield file_like + file_like.close() + + class SerialTransport(Transport): def __init__(self, device, baudrate=115200, wait=0, exclusive=True): self.in_raw_repl = False @@ -405,11 +423,12 @@ class SerialTransport(Transport): self.exec("f.close()") def fs_put(self, src, dest, chunk_size=256, progress_callback=None): - if progress_callback: - src_size = os.path.getsize(src) - written = 0 + self.exec("f=open('%s','wb')\nw=f.write" % dest) - with open(src, "rb") as f: + with open_file(src) as f: + if progress_callback: + src_size = f.size() + written = 0 while True: data = f.read(chunk_size) if not data: