feat: add android-fs5 CLI toolset
- fs5 entrypoint with status, push, pull, app, shell, logs commands - lib/adb.sh: ADB wrapper functions with idempotency and --force guards - lib/output.sh: human + JSON output formatting via Python - 33 bats tests (6 status, 9 transfer, 7 app, 5 shell, 6 logs) — all passing - Zero shellcheck warnings - .env-based config (device serial, log path) - Spec-Driven Development artifacts in specs/001-android-fs5-management/ Device: exone GmbH FS5 (RD51QE202392, Android 9)
This commit is contained in:
+133
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env bash
|
||||
# lib/adb.sh — ADB wrapper functions for android-fs5
|
||||
# shellcheck shell=bash
|
||||
|
||||
# adb_check_device — validate device is connected; exit 2 if not
|
||||
adb_check_device() {
|
||||
local state
|
||||
state=$(adb -s "${DEVICE_SERIAL}" get-state 2>/dev/null || echo "offline")
|
||||
if [[ "${state}" != "device" ]]; then
|
||||
out_error "Device not found: ${DEVICE_SERIAL}"
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
# adb_cmd ARGS... — run adb with the configured device serial
|
||||
adb_cmd() {
|
||||
adb -s "${DEVICE_SERIAL}" "$@"
|
||||
}
|
||||
|
||||
# adb_get_prop KEY — read a device system property
|
||||
adb_get_prop() {
|
||||
local key="${1}"
|
||||
adb_cmd shell getprop "${key}" 2>/dev/null | tr -d '\r'
|
||||
}
|
||||
|
||||
# adb_shell CMD — execute a shell command on the device
|
||||
adb_shell() {
|
||||
adb_cmd shell "$@" 2>&1
|
||||
}
|
||||
|
||||
# adb_file_exists DEVICE_PATH — return 0 if file exists on device, 1 otherwise
|
||||
adb_file_exists() {
|
||||
local path="${1}"
|
||||
local result
|
||||
result=$(adb_cmd shell "[ -e '${path}' ] && echo yes || echo no" 2>/dev/null | tr -d '\r')
|
||||
[[ "${result}" == "yes" ]]
|
||||
}
|
||||
|
||||
# adb_push SRC DST [--force] — push local file to device
|
||||
# Skips if destination exists unless --force is set
|
||||
adb_push() {
|
||||
local src="${1}"
|
||||
local dst="${2}"
|
||||
local force="${3:-}"
|
||||
|
||||
if [[ ! -e "${src}" ]]; then
|
||||
out_error "Source not found: ${src}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if adb_file_exists "${dst}" && [[ "${force}" != "--force" ]]; then
|
||||
out_warn "File exists on device, use --force to overwrite: ${dst}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
adb_cmd push "${src}" "${dst}"
|
||||
local exit_code=$?
|
||||
if [[ ${exit_code} -eq 0 ]]; then
|
||||
adb_log_op "PUSH" "${src} -> ${dst}"
|
||||
out_success "Pushed: ${src} → ${dst}"
|
||||
else
|
||||
out_error "Push failed: ${src} → ${dst}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# adb_pull SRC DST [--force] — pull file from device to local
|
||||
# Skips if local destination exists unless --force is set
|
||||
adb_pull() {
|
||||
local src="${1}"
|
||||
local dst="${2}"
|
||||
local force="${3:-}"
|
||||
|
||||
if ! adb_file_exists "${src}"; then
|
||||
out_error "Source not found on device: ${src}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -e "${dst}" ]] && [[ "${force}" != "--force" ]]; then
|
||||
out_warn "Local file exists, use --force to overwrite: ${dst}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
adb_cmd pull "${src}" "${dst}"
|
||||
local exit_code=$?
|
||||
if [[ ${exit_code} -eq 0 ]]; then
|
||||
adb_log_op "PULL" "${src} -> ${dst}"
|
||||
out_success "Pulled: ${src} → ${dst}"
|
||||
else
|
||||
out_error "Pull failed: ${src} → ${dst}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# adb_log_op OPERATION DETAIL — append timestamped entry to LOG_FILE
|
||||
adb_log_op() {
|
||||
local op="${1}"
|
||||
local detail="${2}"
|
||||
local ts
|
||||
ts=$(date -Iseconds)
|
||||
echo "${ts} ${op} ${detail} [OK]" >> "${LOG_FILE:-./fs5.log}"
|
||||
}
|
||||
|
||||
# adb_battery_level — return battery percentage as integer
|
||||
adb_battery_level() {
|
||||
adb_cmd shell dumpsys battery 2>/dev/null \
|
||||
| grep -E '^\s+level:' \
|
||||
| awk '{print $2}' \
|
||||
| tr -d '\r'
|
||||
}
|
||||
|
||||
# adb_battery_charging — return true/false string
|
||||
adb_battery_charging() {
|
||||
local status
|
||||
status=$(adb_cmd shell dumpsys battery 2>/dev/null \
|
||||
| grep -E '^\s+status:' \
|
||||
| awk '{print $2}' \
|
||||
| tr -d '\r')
|
||||
# status 2 = charging
|
||||
if [[ "${status}" == "2" ]]; then
|
||||
echo "true"
|
||||
else
|
||||
echo "false"
|
||||
fi
|
||||
}
|
||||
|
||||
# adb_storage_info — echo space-separated: total_kb used_kb free_kb percent_used
|
||||
adb_storage_info() {
|
||||
adb_cmd shell df /sdcard 2>/dev/null \
|
||||
| tail -1 \
|
||||
| awk '{print $2, $3, $4, $5}' \
|
||||
| tr -d '\r%'
|
||||
}
|
||||
Reference in New Issue
Block a user