diff -r 289c7150ec4b -r f5ffdf0164ab src/eric7/MicroPython/Devices/DeviceBase.py --- a/src/eric7/MicroPython/Devices/DeviceBase.py Mon Mar 24 14:16:32 2025 +0100 +++ b/src/eric7/MicroPython/Devices/DeviceBase.py Wed Mar 26 19:46:41 2025 +0100 @@ -11,6 +11,7 @@ import ast import contextlib import copy +import hashlib import os import time @@ -924,7 +925,6 @@ @rtype bool @exception OSError raised to indicate an issue with the device """ - # TODO: micro:bit with old MPy does not support leading '/' if not deviceFileName: raise OSError("Missing device file name") @@ -987,7 +987,6 @@ @rtype bytes @exception OSError raised to indicate an issue with the device """ - # TODO: micro:bit with old MPy does not support leading '/' if not deviceFileName: raise OSError("Missing device file name") @@ -1029,6 +1028,118 @@ return out + def touch(self, deviceFileName): + """ + Public method to touch a file on the connected device. + + @param deviceFileName name of the file to be touched + @type str + @exception OSError raised to indicate an issue with the device + """ + if not deviceFileName: + raise OSError("Missing device file name") + + command = """ +def touch(): + f = open('{0}', 'a') + f.close() + +touch() +del touch +""".format( + deviceFileName + ) + out, err = self.executeCommands(command, mode=self._submitMode) + if err: + raise OSError(self._shortError(err)) + + def __supportsHash(self, algorithm): + """ + Private method to sheck, if the connected device supports hashing with + the hashlib module and the given algorithm. + + @param algorithm hashing algorithm to be used + @type str + @return flag indicating hashing support + @rtype bool + """ + command = """ +def supportsHash(): + try: + import hashlib + except ImportError: + return 'False - hashlib not available' + try: + h = hashlib.{0}() + except AttributeError: + return 'False - hashlib.{0} not supported' + + return 'True' + +print(supportsHash()) +del supportsHash +""".format( + algorithm + ) + + out, err = self.executeCommands(command, mode=self._submitMode) + if err: + return False + + return out.decode("utf-8").strip() == "True" + + def hash(self, deviceFileName, algorithm="sha256", chunkSize=256): + """ + Public method to calculate the hash value of a file on the connected device. + + @param deviceFileName name of the file to be touched + @type str + @param algorithm hashing algorithm to be used (defaults to "sha256") + @type str (optional) + @param chunkSize size of data chunks to be sent to the algorithm + (defaults to 256) + @type int (optional) + @return calculate hash digest + @rtype bytes + @exception OSError raised to indicate an issue with the device + """ + if not deviceFileName: + raise OSError("Missing device file name") + + command = """ +def hash(): + import hashlib + + h = hashlib.{1}() + buf = memoryview(bytearray({2})) + with open('{0}', 'rb') as f: + while True: + n = f.readinto(buf) + if n == 0: + break + h.update(buf if n == {2} else buf[:n]) + + return h.digest() + +print(hash()) +del hash +""".format( + deviceFileName, algorithm, chunkSize + ) + + if self.__supportsHash(algorithm=algorithm): + out, err = self.executeCommands(command, mode=self._submitMode) + if err: + raise OSError(self._shortError(err)) + digest = ast.literal_eval(out.decode("utf-8")) + else: + # The board does not support hash calculation. Get the data and do + # the calculation locally. + data = self.getData(deviceFileName=deviceFileName) + digest = getattr(hashlib, algorithm)(data).digest() + + return digest + def fileSystemInfo(self): """ Public method to obtain information about the currently mounted file