runfap.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #!/usr/bin/env python3
  2. import operator
  3. from functools import reduce
  4. from flipper.app import App
  5. from flipper.storage import FlipperStorage, FlipperStorageOperations
  6. from flipper.utils.cdc import resolve_port
  7. class Main(App):
  8. def init(self):
  9. self.parser.add_argument("-p", "--port", help="CDC Port", default="auto")
  10. self.parser.add_argument(
  11. "--sources",
  12. "-s",
  13. nargs="+",
  14. action="append",
  15. default=[],
  16. help="Files to send",
  17. )
  18. self.parser.add_argument(
  19. "--targets",
  20. "-t",
  21. nargs="+",
  22. action="append",
  23. default=[],
  24. help="File destinations (must be same length as -s)",
  25. )
  26. self.parser.add_argument(
  27. "--host-app",
  28. "-a",
  29. help="Host app to launch",
  30. )
  31. self.parser.set_defaults(func=self.install)
  32. @staticmethod
  33. def flatten(item_list):
  34. return reduce(operator.concat, item_list, [])
  35. def install(self):
  36. self.args.sources = self.flatten(self.args.sources)
  37. self.args.targets = self.flatten(self.args.targets)
  38. if len(self.args.sources) != len(self.args.targets):
  39. self.logger.error(
  40. f"Error: sources ({self.args.sources}) and targets ({self.args.targets}) must be same length"
  41. )
  42. return 1
  43. if not (port := resolve_port(self.logger, self.args.port)):
  44. return 2
  45. try:
  46. with FlipperStorage(port) as storage:
  47. storage_ops = FlipperStorageOperations(storage)
  48. for fap_local_path, fap_dst_path in zip(
  49. self.args.sources, self.args.targets
  50. ):
  51. self.logger.info(f'Installing "{fap_local_path}" to {fap_dst_path}')
  52. storage_ops.recursive_send(fap_dst_path, fap_local_path, False)
  53. fap_host_app = self.args.targets[0]
  54. startup_command = f'"Applications" {fap_host_app}'
  55. if self.args.host_app:
  56. startup_command = self.args.host_app
  57. self.logger.info(f"Launching app: {startup_command}")
  58. storage.send_and_wait_eol(f"loader open {startup_command}\r")
  59. if len(result := storage.read.until(storage.CLI_EOL)):
  60. self.logger.error(f"Unexpected response: {result.decode('ascii')}")
  61. return 3
  62. return 0
  63. except Exception as e:
  64. self.logger.error(f"Error: {e}")
  65. # raise
  66. return 4
  67. if __name__ == "__main__":
  68. Main()()