Release v1

This commit is contained in:
Gino D
2023-01-04 15:40:22 +01:00
parent 448771f972
commit 967b5b0f93
2 changed files with 152 additions and 116 deletions

View File

@@ -1,3 +0,0 @@
#!/bin/bash
python "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)/picowatch_d/picowatch.py"

View File

@@ -33,11 +33,10 @@ import textwrap
import subprocess import subprocess
from serial import Serial from serial import Serial
from typing import Dict, List, Optional, Tuple, Union from typing import List, Optional, Tuple, Union
BUFFER_SIZE: int = 126 BUFFER_SIZE: int = 126
CURRENT_DIRECTORY: str = os.getcwd().replace('\\', '/')
class Tab(): class Tab():
@@ -51,6 +50,8 @@ class Tab():
def print(self, *texts: str): def print(self, *texts: str):
def coltext(text: str, length: int = 20) -> str: def coltext(text: str, length: int = 20) -> str:
text = str(text)
if len(text) >= length: if len(text) >= length:
text = text[:(length - 4) if length > 5 else length] + '...' text = text[:(length - 4) if length > 5 else length] + '...'
@@ -67,6 +68,7 @@ class Tab():
print(line) print(line)
def labels(self, *texts: str, blank_text: str = '-'): def labels(self, *texts: str, blank_text: str = '-'):
self.blank(blank_text)
self.print(*texts) self.print(*texts)
self.blank(blank_text) self.blank(blank_text)
@@ -294,7 +296,7 @@ class Pyboard(object):
return data.strip() return data.strip()
class PyboardTerminal(object): class FileSystem(object):
pyboard: Pyboard pyboard: Pyboard
def __init__(self, pyboard: Pyboard): def __init__(self, pyboard: Pyboard):
@@ -544,131 +546,126 @@ class PyboardTerminal(object):
class Picowatch(object): class Picowatch(object):
terminal: PyboardTerminal
def __init__(self, pyboard: Pyboard): def __init__(self, pyboard: Pyboard, project_name: str = 'src'):
self.terminal = PyboardTerminal(pyboard) self.filesystem = FileSystem(pyboard)
project_name = project_name.strip('./').strip('/')
if project_name == '/':
raise Exception('Project name is incorrect!')
self.project_name = project_name.replace(os.sep, '/')
self.project_dirname = os.path.join(os.getcwd(), self.project_name).replace(os.sep, '/')
signal.signal(signal.SIGINT, lambda a, b: self.interupt()) signal.signal(signal.SIGINT, lambda a, b: self.interupt())
def interupt(self): def interupt(self):
self.terminal.pyboard.send_ctrl_c() self.filesystem.pyboard.send_ctrl_c()
def terminal(self, command: str): def terminal(self, command: str):
self.terminal.terminal(command, stream_output=True) self.filesystem.terminal(command, stream_output=True)
def listing(self, remote: str = '/'): def listing(self, filepath: str = '/'):
status, output, exception = self.terminal.ls(remote) filepath = filepath.strip('./')
tab = Tab(4, 30, 15, 30)
tab.labels('[ ]', 'Filename', 'Size (kb)', 'Exception')
status, output, exception = self.filesystem.ls(filepath)
if status: if status:
tab = Tab(4, 30, 15, 30) for filename, size in output:
tab.labels('[ ]', 'Filename', 'Size (kb)', 'Exception')
for name, size in output:
if size == -1: if size == -1:
tab.print('[*]', name[1:], '-') tab.print('[*]', filename, '-')
else: else:
tab.print('[*]', name[1:], f'{size}b') tab.print('[*]', filename, f'{size}b')
else: else:
tab.print('[?]', remote, '', str(exception)) tab.print('[?]', filepath, '', str(exception))
def contents(self, remote: str): def contents(self, filename: str):
try: filename = filename.strip('./').strip('/')
content, _ = self.terminal.get(remote) content, _ = self.filesystem.get(filename)
print('-' * 50)
for ln in content.decode('utf-8').split('\n'): for ln in content.decode('utf-8').split('\n'):
print(ln) print(ln)
except Exception as e:
print('[?]', remote, f'\n{str(e)}')
def upload(self, filepath: str): def upload(self, filepath: str):
local = filepath filepath = filepath.strip('./').strip('/')
if local.startswith('/'):
local = '.' + local
if not local.startswith('./'):
local = './' + local
queue = [] queue = []
source = os.path.join(self.project_dirname, filepath).replace(os.sep, '/')
if os.path.isdir(local): if os.path.isdir(source):
for root, _, files in os.walk(local, followlinks=True): for root, _, files in os.walk(source, followlinks=True):
for filename in files: for filename in files:
filename = os.path.join(root, filename).replace('\\', '/') filename = os.path.join(root, filename).replace(os.sep, '/')
queue.append((filename, filename[1:])) queue.append((filename, filename.replace(self.project_dirname, '')))
elif os.path.exists(source):
elif os.path.exists(local): queue.append((source, filepath))
queue.append((local, filepath))
tab = Tab(4, 30, 15, 30) tab = Tab(4, 30, 15, 30)
tab.labels('[ ]', 'Filename', 'Checksum', 'Exception') tab.labels('[ ]', 'Filename', 'Checksum', 'Exception')
for filename, remote in queue: for source, destination in queue:
destination = destination.strip('/')
try: try:
tab.print('[↑]', filename, self.terminal.upload(filename, remote)) tab.print('[↑]', destination, self.filesystem.upload(source, destination))
except Exception as e: except Exception as e:
tab.print('[?]', filename, '-', str(e)) tab.print('[?]', destination, '', str(e))
def download(self, filepath: str): def download(self, filepath: str):
if filepath.startswith('.'): filepath = filepath.strip('./').strip('/')
filepath = filepath[1:] tab = Tab(4, 30, 15, 30)
tab.labels('', 'Filename', 'Checksum', 'Exception')
status, output, exception = self.terminal.ls(filepath) status, output, exception = self.filesystem.ls(filepath)
if status: if status:
tab = Tab(4, 30, 15, 30)
tab.labels('', 'Filename', 'Checksum', 'Exception')
for remote, size in output: for remote, size in output:
if size == -1: if size == -1:
os.makedirs(f'.{remote}', 777, exist_ok=True) os.makedirs(os.path.join(self.project_dirname, remote), 777, exist_ok=True)
for remote, size in output: for remote, size in output:
local = f'.{remote}'
if not size == -1: if not size == -1:
try: try:
tab.print('[↓]', local, self.terminal.download(remote, local)) tab.print('[↓]', remote, self.filesystem.download(remote, os.path.join(self.project_dirname, remote)))
except Exception as e: except Exception as e:
tab.print('[?]', local, '', str(e)) tab.print('[?]', remote, '', str(e))
else: else:
tab.print('[?]', filepath, '', exception) tab.print('[?]', filepath, '', exception)
def delete(self, filepath: str): def delete(self, filepath: str):
status, output, exception = self.terminal.rm(filepath) filepath = filepath.strip('./')
tab = Tab(4, 30, 30)
tab.labels('[ ]', 'Filename', 'Exception')
status, output, exception = self.filesystem.rm(filepath)
if status: if status:
tab = Tab(4, 30, 30) for filename, checked, exception in output:
tab.labels('[ ]', 'Filename', 'Exception')
for remote, checked, message in output:
local = f'.{remote}'
if checked: if checked:
tab.print('[-]', local) tab.print('[-]', filename)
else: else:
tab.print('[?]', local, message) tab.print('[?]', filename, exception)
else: else:
tab.print('[?]', filepath, exception) tab.print('[?]', filepath, exception)
def compare(self, source: str): def compare(self, filepath: str):
content, _ = self.terminal.get(source) filepath = filepath.strip('./').strip('/')
fh, filename = tempfile.mkstemp() content, _ = self.filesystem.get(filepath)
fh, tempname = tempfile.mkstemp()
try: try:
with os.fdopen(fh, 'wb') as tmp: with os.fdopen(fh, 'wb') as tmp:
tmp.write(content) tmp.write(content)
subprocess.Popen(f'code --diff "{filename}" "./src/{source}"', stdout=subprocess.PIPE, shell=True).communicate() subprocess.Popen(f'code --diff "{tempname}" "{os.path.join(self.project_dirname, filepath)}"', stdout=subprocess.PIPE, shell=True).communicate()
finally: finally:
input('Press Enter to delete temp file.') input('Press Enter to delete temp file.')
os.remove(filename) os.remove(tempname)
def status(self): def status(self, return_output: bool = False):
changes = [] changes = []
try: try:
output = subprocess.check_output(['git', 'status', '-s']) output = subprocess.check_output(['git', 'status', '-s'], stderr=subprocess.STDOUT)
for filename in [f.strip() for f in output.decode('utf-8').split('\n')]: for filename in [f.strip() for f in output.decode('utf-8').split('\n')]:
if not filename: if not filename:
@@ -676,51 +673,89 @@ class Picowatch(object):
status, filename = filename.split(' ') status, filename = filename.split(' ')
if filename.startswith('src/'): if filename.startswith(self.project_name):
if status in ['A', 'M', '??']: if status in ['A', 'M', '??']:
changes.append((1, filename)) changes.append((1, filename.replace(self.project_name + '/', '')))
elif status == 'D': elif status == 'D':
changes.append((0, filename)) changes.append((-1, filename.replace(self.project_name + '/', '')))
except: except Exception as e:
pass print(e.output.decode('utf-8').strip())
finally:
if return_output:
return changes
tab = Tab(4, 40) tab = Tab(4, 40)
tab.labels('[ ]', 'Filename') tab.labels('[ ]', 'Filename')
for status, filename in changes: for status, filename in changes:
tab.print('[+]' if status == 1 else '[-]', filename) tab.print('[+]' if status == 1 else '[-]', filename)
def push(self):
tab = Tab(4, 30, 15, 30)
tab.labels('[ ]', 'Filename', 'Checksum', 'Exception')
changes = self.status(return_output=True)
for filepath in [filename for status, filename in changes if status == -1]:
filepath = filepath.strip('/')
status, output, exception = self.filesystem.rm(filepath)
if status:
for filename, checked, exception in output:
if checked:
tab.print('[-]', filename)
else:
tab.print('[?]', filename, '', exception)
else:
tab.print('[?]', filepath, '', exception)
queue = []
for filepath in [filename for status, filename in changes if status == 1]:
filepath = filepath.strip('/')
source = os.path.join(self.project_dirname, filepath).replace(os.sep, '/')
if os.path.isdir(source):
for root, _, files in os.walk(source, followlinks=True):
for file in files:
file = os.path.join(root, file).replace(os.sep, '/')
queue.append((file, file.replace(self.project_dirname, '')))
elif os.path.exists(source):
queue.append((source, filepath))
for source, destination in queue:
destination = destination.strip('/')
try:
tab.print('[↑]', destination, self.filesystem.upload(source, destination))
except Exception as e:
tab.print('[?]', destination, '', str(e))
print('Pico board up to date.')
def test(self, filename: str):
with open(os.path.join(self.project_dirname, filename), 'r') as fh:
self.filesystem.terminal(fh.read(), stream_output=True)
def launch(self, filepath: str): def launch(self, filepath: str):
self.terminal.launch(filepath) self.filesystem.launch(filepath)
def watch(self, filename: str):
if filename.startswith('/'):
filename = '.' + filename
if not filename.startswith('./'):
filename = './' + filename
with open(filename, 'r') as fh:
self.terminal.terminal(fh.read(), stream_output=True)
print('Welcome to Picowatch Terminal') print('Welcome to Picowatch Terminal')
# picowatch = False picowatch = False
# while not picowatch: while not picowatch:
# print('-' * 30) print('-' * 30)
# device = input('Port: ').strip() device = input('Port: ').strip()
# baudrate = input('Baudrate (115200): ').strip() or 115200 baudrate = input('Baudrate (115200): ').strip() or 115200
project_name = input('Project name (src): ').strip() or 'src'
# try: try:
# picowatch = Picowatch(Pyboard(device=device, baudrate=baudrate)) picowatch = Picowatch(Pyboard(device, baudrate), project_name)
# print(f'Connected to device: {device} at a baudrate of: {baudrate}') print(f'Connected to device: {device} at a baudrate of: {baudrate}. Listening to project: {project_name}')
# print('-' * 30) print('-' * 30)
# except Exception as e: except Exception as e:
# print(str(e)) print(str(e))
picowatch = Picowatch(Pyboard('COM5'))
picowatch.interupt() picowatch.interupt()
while True: while True:
@@ -733,26 +768,30 @@ while True:
sys.exit() sys.exit()
case ['reboot']: case ['reboot']:
picowatch.terminal('help()') picowatch.terminal('help()')
case ['ls', *source]: case ['ls' | 'list', *source]:
picowatch.listing(source[0] if source else '/') picowatch.listing(source[0] if source else '/')
case ['cat', source]: case ['cat' | 'code', source]:
picowatch.contents(source) picowatch.contents(source)
case ['rm', source]: case ['rm' | 'delete', source]:
picowatch.delete(source) picowatch.delete(source)
case ['put', source]: case ['put' | 'upload', source]:
picowatch.upload(source) picowatch.upload(source)
case ['get', source]: case ['get' | 'download', source]:
picowatch.download(source) picowatch.download(source)
case ['diff', filename]: case ['diff' | 'compare', filename]:
picowatch.compare(filename) picowatch.compare(filename)
case ['status']: case ['status']:
picowatch.status() picowatch.status(return_output=False)
case ['push']: case ['push']:
picowatch.push()
case ['compile', filename]:
pass
case ['install', package_name]:
pass pass
case ['test', filename]: case ['test', filename]:
picowatch.watch(filename) picowatch.test(filename)
case ['!']: case ['!']:
picowatch.watch('main.py') picowatch.test('main.py')
case ['!!']: case ['!!']:
picowatch.launch('main.py') picowatch.launch('main.py')
case _: case _: