Compare commits
3 Commits
eee9327e15
...
2f3db9272b
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f3db9272b | |||
| 713cd6e9a1 | |||
| 9e72c62481 |
2
Pipfile
2
Pipfile
@@ -16,5 +16,5 @@ python_version = "3"
|
|||||||
[scripts]
|
[scripts]
|
||||||
web = "python web.py"
|
web = "python web.py"
|
||||||
cli = "python cli.py"
|
cli = "python cli.py"
|
||||||
build = "pyinstaller --clean led-cli.spec"
|
build = "pyinstaller --clean --onefile --name led-cli --paths lib cli.py"
|
||||||
install = "pipenv install"
|
install = "pipenv install"
|
||||||
|
|||||||
117
cli.py
117
cli.py
@@ -11,6 +11,7 @@ import argparse
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import shutil
|
||||||
from typing import Dict, Any, List, Optional
|
from typing import Dict, Any, List, Optional
|
||||||
|
|
||||||
import tempfile
|
import tempfile
|
||||||
@@ -147,14 +148,14 @@ _FLAGS_WITH_VALUE = frozenset({
|
|||||||
'-p', '--port', '-n', '--name', '--pin', '-b', '--brightness',
|
'-p', '--port', '-n', '--name', '--pin', '-b', '--brightness',
|
||||||
'-l', '--leds', '-d', '-debug', '--debug', '-o', '--order',
|
'-l', '--leds', '-d', '-debug', '--debug', '-o', '--order',
|
||||||
'--preset', '--pattern', '--default', '--transport', '--ssid',
|
'--preset', '--pattern', '--default', '--transport', '--ssid',
|
||||||
'--wifi-password', '--wifi-channel',
|
'--wifi-password', '--wifi-channel', '--src', '--lib', '--patterns', '--paterns',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def _get_ordered_actions(argv: List[str]) -> List[tuple]:
|
def _get_ordered_actions(argv: List[str]) -> List[tuple]:
|
||||||
"""
|
"""
|
||||||
Scan argv and return list of (action_name, value) in order of appearance.
|
Scan argv and return list of (action_name, value) in order of appearance.
|
||||||
Actions: flash, pause, reset, upload, erase_all, rm, follow.
|
Actions: flash, pause, reset, upload, ls, erase_all, rm, follow.
|
||||||
"""
|
"""
|
||||||
actions = []
|
actions = []
|
||||||
i = 1
|
i = 1
|
||||||
@@ -201,22 +202,47 @@ def _get_ordered_actions(argv: List[str]) -> List[tuple]:
|
|||||||
i += 2
|
i += 2
|
||||||
else:
|
else:
|
||||||
i += 1
|
i += 1
|
||||||
# Use empty string as remote_dir to map to root on device
|
# Upload source tree excluding patterns/ (handled by --patterns).
|
||||||
actions.append(('upload', [local_dir, ""]))
|
actions.append(('upload_src_no_patterns', local_dir))
|
||||||
continue
|
continue
|
||||||
if arg == '--lib':
|
if arg in ('--patterns', '--paterns'):
|
||||||
# Upload local DIR to /lib on device
|
# Upload local patterns DIR (default: ./src/patterns) to /patterns.
|
||||||
if i + 1 < len(argv):
|
local_dir = os.path.join("src", "patterns")
|
||||||
|
if i + 1 < len(argv) and not argv[i + 1].startswith('-'):
|
||||||
local_dir = argv[i + 1]
|
local_dir = argv[i + 1]
|
||||||
actions.append(('upload', [local_dir, "lib"]))
|
|
||||||
i += 2
|
i += 2
|
||||||
else:
|
else:
|
||||||
raise ValueError("--lib requires a directory argument")
|
i += 1
|
||||||
|
actions.append(('upload', [local_dir, "patterns"]))
|
||||||
|
continue
|
||||||
|
if arg == '--all':
|
||||||
|
actions.append(('upload_src_no_patterns', "src"))
|
||||||
|
actions.append(('upload', [os.path.join("src", "patterns"), "patterns"]))
|
||||||
|
actions.append(('upload', ["lib", "lib"]))
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
if arg == '--lib':
|
||||||
|
# Upload local DIR (default: ./lib) to /lib on device
|
||||||
|
local_dir = "lib"
|
||||||
|
if i + 1 < len(argv) and not argv[i + 1].startswith('-'):
|
||||||
|
local_dir = argv[i + 1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
actions.append(('upload', [local_dir, "lib"]))
|
||||||
|
continue
|
||||||
|
if arg == '--ls':
|
||||||
|
actions.append(('ls', None))
|
||||||
|
i += 1
|
||||||
continue
|
continue
|
||||||
if arg == '-e':
|
if arg == '-e':
|
||||||
actions.append(('erase_all', None))
|
actions.append(('erase_all', None))
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
if arg == '--erase':
|
||||||
|
actions.append(('erase_all', None))
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
if arg == '--rm':
|
if arg == '--rm':
|
||||||
if i + 1 < len(argv):
|
if i + 1 < len(argv):
|
||||||
actions.append(('rm', argv[i + 1]))
|
actions.append(('rm', argv[i + 1]))
|
||||||
@@ -429,17 +455,40 @@ Examples:
|
|||||||
nargs="?",
|
nargs="?",
|
||||||
const="src",
|
const="src",
|
||||||
metavar="DIR",
|
metavar="DIR",
|
||||||
help="Upload DIR recursively to device root (:/, no leading directory). If DIR is omitted, uses local ./src."
|
help="Upload DIR recursively to device root (:/, no leading directory), excluding patterns/. If DIR is omitted, uses local ./src."
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--lib",
|
"--lib",
|
||||||
|
nargs="?",
|
||||||
|
const="lib",
|
||||||
metavar="DIR",
|
metavar="DIR",
|
||||||
help="Upload DIR recursively to /lib on device"
|
help="Upload DIR recursively to /lib on device. If DIR is omitted, uses local ./lib."
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-e",
|
"--all",
|
||||||
|
action="store_true",
|
||||||
|
help="Upload ./src (excluding patterns), ./src/patterns, and ./lib."
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--patterns", "--paterns",
|
||||||
|
dest="patterns_dir",
|
||||||
|
nargs="?",
|
||||||
|
const=os.path.join("src", "patterns"),
|
||||||
|
metavar="DIR",
|
||||||
|
help="Upload DIR recursively to /patterns on device. If DIR is omitted, uses local ./src/patterns."
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--ls",
|
||||||
|
action="store_true",
|
||||||
|
help="List files on the device root (:/)"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"-e", "--erase",
|
||||||
dest="erase_all",
|
dest="erase_all",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Erase all code on the device (delete all files except settings.json)"
|
help="Erase all code on the device (delete all files except settings.json)"
|
||||||
@@ -526,6 +575,50 @@ Examples:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error uploading directory: {e}", file=sys.stderr)
|
print(f"Error uploading directory: {e}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
elif action_name == 'upload_src_no_patterns':
|
||||||
|
src_dir = value
|
||||||
|
if not os.path.exists(src_dir):
|
||||||
|
print(f"Error: Directory does not exist: {src_dir}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
if not os.path.isdir(src_dir):
|
||||||
|
print(f"Error: Not a directory: {src_dir}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
try:
|
||||||
|
with tempfile.TemporaryDirectory() as temp_src:
|
||||||
|
for entry in sorted(os.listdir(src_dir)):
|
||||||
|
if entry == "patterns":
|
||||||
|
continue
|
||||||
|
src_entry = os.path.join(src_dir, entry)
|
||||||
|
dst_entry = os.path.join(temp_src, entry)
|
||||||
|
if os.path.isdir(src_entry):
|
||||||
|
shutil.copytree(src_entry, dst_entry)
|
||||||
|
else:
|
||||||
|
shutil.copy2(src_entry, dst_entry)
|
||||||
|
print(
|
||||||
|
f"Uploading {src_dir} (excluding patterns/) to device root on {port}...",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
conn = DeviceConnection(port)
|
||||||
|
files_copied, dirs_created = conn.upload_directory(temp_src, "")
|
||||||
|
print(
|
||||||
|
f"Upload complete: {files_copied} files, {dirs_created} directories created.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error uploading src (excluding patterns): {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
elif action_name == 'ls':
|
||||||
|
try:
|
||||||
|
print(f"Listing files on device {port}...", file=sys.stderr)
|
||||||
|
conn = DeviceConnection(port)
|
||||||
|
items = conn.list_files('')
|
||||||
|
for name, is_dir, size in items:
|
||||||
|
marker = "d" if is_dir else "-"
|
||||||
|
print(f"{marker} {size:>8} {name}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error listing files: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
elif action_name == 'erase_all':
|
elif action_name == 'erase_all':
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ pipenv install "$@"
|
|||||||
if [ ! -f "dist/led-cli" ] || [ "cli.py" -nt "dist/led-cli" ] || [ "device.py" -nt "dist/led-cli" ]; then
|
if [ ! -f "dist/led-cli" ] || [ "cli.py" -nt "dist/led-cli" ] || [ "device.py" -nt "dist/led-cli" ]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "Building binary..."
|
echo "Building binary..."
|
||||||
pipenv run pyinstaller --clean led-cli.spec
|
pipenv run pyinstaller --clean --onefile --name led-cli --paths lib cli.py
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Ensure ~/.local/bin exists
|
# Ensure ~/.local/bin exists
|
||||||
|
|||||||
Reference in New Issue
Block a user