roku_builder 3.13.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG +12 -0
  4. data/Gemfile.lock +22 -7
  5. data/Guardfile +3 -3
  6. data/README.md +22 -398
  7. data/bin/roku +1 -194
  8. data/config.json.example +1 -1
  9. data/intergration/roku_builder/test_core.rb +52 -0
  10. data/intergration/roku_builder/test_files/core_intergration_test/manifest_template +7 -0
  11. data/intergration/roku_builder/test_files/core_intergration_test/test.pkg +0 -0
  12. data/intergration/roku_builder/test_files/inspector_intergration_test/components/rectanglescene.xml +28 -0
  13. data/intergration/roku_builder/test_files/inspector_intergration_test/images/rde_mm_focus_hd.jpg +0 -0
  14. data/intergration/roku_builder/test_files/inspector_intergration_test/images/rde_mm_focus_sd.jpg +0 -0
  15. data/intergration/roku_builder/test_files/inspector_intergration_test/images/rde_splash_fhd.jpg +0 -0
  16. data/intergration/roku_builder/test_files/inspector_intergration_test/images/rde_splash_hd.jpg +0 -0
  17. data/intergration/roku_builder/test_files/inspector_intergration_test/images/rde_splash_sd.jpg +0 -0
  18. data/intergration/roku_builder/test_files/inspector_intergration_test/images/rsgde_bg_hd.jpg +0 -0
  19. data/intergration/roku_builder/test_files/inspector_intergration_test/images/rsgde_mm_focus_hd.jpg +0 -0
  20. data/intergration/roku_builder/test_files/inspector_intergration_test/images/rsgde_splash_hd.jpg +0 -0
  21. data/intergration/roku_builder/test_files/inspector_intergration_test/manifest +21 -0
  22. data/intergration/roku_builder/test_files/inspector_intergration_test/source/main.brs +23 -0
  23. data/intergration/roku_builder/test_files/inspector_intergration_test/test.pkg +0 -0
  24. data/intergration/roku_builder/test_files/linker_intergration_test/components/rectanglescene.xml +29 -0
  25. data/intergration/roku_builder/test_files/linker_intergration_test/images/rde_mm_focus_hd.jpg +0 -0
  26. data/intergration/roku_builder/test_files/linker_intergration_test/images/rde_mm_focus_sd.jpg +0 -0
  27. data/intergration/roku_builder/test_files/linker_intergration_test/images/rde_splash_fhd.jpg +0 -0
  28. data/intergration/roku_builder/test_files/linker_intergration_test/images/rde_splash_hd.jpg +0 -0
  29. data/intergration/roku_builder/test_files/linker_intergration_test/images/rde_splash_sd.jpg +0 -0
  30. data/intergration/roku_builder/test_files/linker_intergration_test/images/rsgde_bg_hd.jpg +0 -0
  31. data/intergration/roku_builder/test_files/linker_intergration_test/images/rsgde_mm_focus_hd.jpg +0 -0
  32. data/intergration/roku_builder/test_files/linker_intergration_test/images/rsgde_splash_hd.jpg +0 -0
  33. data/intergration/roku_builder/test_files/linker_intergration_test/manifest +21 -0
  34. data/intergration/roku_builder/test_files/linker_intergration_test/source/main.brs +21 -0
  35. data/intergration/roku_builder/test_files/linker_intergration_test/test.pkg +0 -0
  36. data/intergration/roku_builder/test_files/loader_intergration_test/components/rectanglescene.xml +29 -0
  37. data/intergration/roku_builder/test_files/loader_intergration_test/images/rde_mm_focus_hd.jpg +0 -0
  38. data/intergration/roku_builder/test_files/loader_intergration_test/images/rde_mm_focus_sd.jpg +0 -0
  39. data/intergration/roku_builder/test_files/loader_intergration_test/images/rde_splash_fhd.jpg +0 -0
  40. data/intergration/roku_builder/test_files/loader_intergration_test/images/rde_splash_hd.jpg +0 -0
  41. data/intergration/roku_builder/test_files/loader_intergration_test/images/rde_splash_sd.jpg +0 -0
  42. data/intergration/roku_builder/test_files/loader_intergration_test/images/rsgde_bg_hd.jpg +0 -0
  43. data/intergration/roku_builder/test_files/loader_intergration_test/images/rsgde_mm_focus_hd.jpg +0 -0
  44. data/intergration/roku_builder/test_files/loader_intergration_test/images/rsgde_splash_hd.jpg +0 -0
  45. data/intergration/roku_builder/test_files/loader_intergration_test/manifest +21 -0
  46. data/intergration/roku_builder/test_files/loader_intergration_test/source/main.brs +21 -0
  47. data/intergration/roku_builder/test_files/loader_intergration_test/test.pkg +0 -0
  48. data/intergration/roku_builder/test_files/monitor_intergration_test/components/rectanglescene.xml +29 -0
  49. data/intergration/roku_builder/test_files/monitor_intergration_test/images/rde_mm_focus_hd.jpg +0 -0
  50. data/intergration/roku_builder/test_files/monitor_intergration_test/images/rde_mm_focus_sd.jpg +0 -0
  51. data/intergration/roku_builder/test_files/monitor_intergration_test/images/rde_splash_fhd.jpg +0 -0
  52. data/intergration/roku_builder/test_files/monitor_intergration_test/images/rde_splash_hd.jpg +0 -0
  53. data/intergration/roku_builder/test_files/monitor_intergration_test/images/rde_splash_sd.jpg +0 -0
  54. data/intergration/roku_builder/test_files/monitor_intergration_test/images/rsgde_bg_hd.jpg +0 -0
  55. data/intergration/roku_builder/test_files/monitor_intergration_test/images/rsgde_mm_focus_hd.jpg +0 -0
  56. data/intergration/roku_builder/test_files/monitor_intergration_test/images/rsgde_splash_hd.jpg +0 -0
  57. data/intergration/roku_builder/test_files/monitor_intergration_test/manifest +21 -0
  58. data/intergration/roku_builder/test_files/monitor_intergration_test/source/main.brs +21 -0
  59. data/intergration/roku_builder/test_files/monitor_intergration_test/test.pkg +0 -0
  60. data/intergration/roku_builder/test_files/navigator_intergration_test/components/rectanglescene.xml +29 -0
  61. data/intergration/roku_builder/test_files/navigator_intergration_test/images/rde_mm_focus_hd.jpg +0 -0
  62. data/intergration/roku_builder/test_files/navigator_intergration_test/images/rde_mm_focus_sd.jpg +0 -0
  63. data/intergration/roku_builder/test_files/navigator_intergration_test/images/rde_splash_fhd.jpg +0 -0
  64. data/intergration/roku_builder/test_files/navigator_intergration_test/images/rde_splash_hd.jpg +0 -0
  65. data/intergration/roku_builder/test_files/navigator_intergration_test/images/rde_splash_sd.jpg +0 -0
  66. data/intergration/roku_builder/test_files/navigator_intergration_test/images/rsgde_bg_hd.jpg +0 -0
  67. data/intergration/roku_builder/test_files/navigator_intergration_test/images/rsgde_mm_focus_hd.jpg +0 -0
  68. data/intergration/roku_builder/test_files/navigator_intergration_test/images/rsgde_splash_hd.jpg +0 -0
  69. data/intergration/roku_builder/test_files/navigator_intergration_test/manifest +21 -0
  70. data/intergration/roku_builder/test_files/navigator_intergration_test/source/main.brs +21 -0
  71. data/intergration/roku_builder/test_files/navigator_intergration_test/test.pkg +0 -0
  72. data/intergration/roku_builder/test_files/packager_intergration_test/components/rectanglescene.xml +29 -0
  73. data/intergration/roku_builder/test_files/packager_intergration_test/images/rde_mm_focus_hd.jpg +0 -0
  74. data/intergration/roku_builder/test_files/packager_intergration_test/images/rde_mm_focus_sd.jpg +0 -0
  75. data/intergration/roku_builder/test_files/packager_intergration_test/images/rde_splash_fhd.jpg +0 -0
  76. data/intergration/roku_builder/test_files/packager_intergration_test/images/rde_splash_hd.jpg +0 -0
  77. data/intergration/roku_builder/test_files/packager_intergration_test/images/rde_splash_sd.jpg +0 -0
  78. data/intergration/roku_builder/test_files/packager_intergration_test/images/rsgde_bg_hd.jpg +0 -0
  79. data/intergration/roku_builder/test_files/packager_intergration_test/images/rsgde_mm_focus_hd.jpg +0 -0
  80. data/intergration/roku_builder/test_files/packager_intergration_test/images/rsgde_splash_hd.jpg +0 -0
  81. data/intergration/roku_builder/test_files/packager_intergration_test/manifest +21 -0
  82. data/intergration/roku_builder/test_files/packager_intergration_test/source/main.brs +21 -0
  83. data/intergration/roku_builder/test_files/packager_intergration_test/test.pkg +0 -0
  84. data/intergration/roku_builder/test_files/profiler_intergration_test/components/rectanglescene.xml +29 -0
  85. data/intergration/roku_builder/test_files/profiler_intergration_test/images/rde_mm_focus_hd.jpg +0 -0
  86. data/intergration/roku_builder/test_files/profiler_intergration_test/images/rde_mm_focus_sd.jpg +0 -0
  87. data/intergration/roku_builder/test_files/profiler_intergration_test/images/rde_splash_fhd.jpg +0 -0
  88. data/intergration/roku_builder/test_files/profiler_intergration_test/images/rde_splash_hd.jpg +0 -0
  89. data/intergration/roku_builder/test_files/profiler_intergration_test/images/rde_splash_sd.jpg +0 -0
  90. data/intergration/roku_builder/test_files/profiler_intergration_test/images/rsgde_bg_hd.jpg +0 -0
  91. data/intergration/roku_builder/test_files/profiler_intergration_test/images/rsgde_mm_focus_hd.jpg +0 -0
  92. data/intergration/roku_builder/test_files/profiler_intergration_test/images/rsgde_splash_hd.jpg +0 -0
  93. data/intergration/roku_builder/test_files/profiler_intergration_test/manifest +21 -0
  94. data/intergration/roku_builder/test_files/profiler_intergration_test/source/main.brs +21 -0
  95. data/intergration/roku_builder/test_files/profiler_intergration_test/test.pkg +0 -0
  96. data/intergration/roku_builder/test_files/scripter_intergration_test/components/rectanglescene.xml +29 -0
  97. data/intergration/roku_builder/test_files/scripter_intergration_test/images/rde_mm_focus_hd.jpg +0 -0
  98. data/intergration/roku_builder/test_files/scripter_intergration_test/images/rde_mm_focus_sd.jpg +0 -0
  99. data/intergration/roku_builder/test_files/scripter_intergration_test/images/rde_splash_fhd.jpg +0 -0
  100. data/intergration/roku_builder/test_files/scripter_intergration_test/images/rde_splash_hd.jpg +0 -0
  101. data/intergration/roku_builder/test_files/scripter_intergration_test/images/rde_splash_sd.jpg +0 -0
  102. data/intergration/roku_builder/test_files/scripter_intergration_test/images/rsgde_bg_hd.jpg +0 -0
  103. data/intergration/roku_builder/test_files/scripter_intergration_test/images/rsgde_mm_focus_hd.jpg +0 -0
  104. data/intergration/roku_builder/test_files/scripter_intergration_test/images/rsgde_splash_hd.jpg +0 -0
  105. data/intergration/roku_builder/test_files/scripter_intergration_test/manifest +21 -0
  106. data/intergration/roku_builder/test_files/scripter_intergration_test/source/main.brs +21 -0
  107. data/intergration/roku_builder/test_files/scripter_intergration_test/test.pkg +0 -0
  108. data/intergration/roku_builder/test_files/tester_intergration_test/components/rectanglescene.xml +29 -0
  109. data/intergration/roku_builder/test_files/tester_intergration_test/images/rde_mm_focus_hd.jpg +0 -0
  110. data/intergration/roku_builder/test_files/tester_intergration_test/images/rde_mm_focus_sd.jpg +0 -0
  111. data/intergration/roku_builder/test_files/tester_intergration_test/images/rde_splash_fhd.jpg +0 -0
  112. data/intergration/roku_builder/test_files/tester_intergration_test/images/rde_splash_hd.jpg +0 -0
  113. data/intergration/roku_builder/test_files/tester_intergration_test/images/rde_splash_sd.jpg +0 -0
  114. data/intergration/roku_builder/test_files/tester_intergration_test/images/rsgde_bg_hd.jpg +0 -0
  115. data/intergration/roku_builder/test_files/tester_intergration_test/images/rsgde_mm_focus_hd.jpg +0 -0
  116. data/intergration/roku_builder/test_files/tester_intergration_test/images/rsgde_splash_hd.jpg +0 -0
  117. data/intergration/roku_builder/test_files/tester_intergration_test/manifest +21 -0
  118. data/intergration/roku_builder/test_files/tester_intergration_test/source/main.brs +21 -0
  119. data/intergration/roku_builder/test_files/tester_intergration_test/test.pkg +0 -0
  120. data/intergration/roku_builder/test_helper.rb +138 -0
  121. data/intergration/roku_builder/test_inspector.rb +35 -0
  122. data/intergration/roku_builder/test_linker.rb +32 -0
  123. data/intergration/roku_builder/test_loader.rb +38 -0
  124. data/intergration/roku_builder/test_monitor.rb +21 -0
  125. data/intergration/roku_builder/test_navigator.rb +34 -0
  126. data/intergration/roku_builder/test_packager.rb +41 -0
  127. data/intergration/roku_builder/test_profiler.rb +48 -0
  128. data/intergration/roku_builder/test_scripter.rb +38 -0
  129. data/intergration/roku_builder/test_tester.rb +21 -0
  130. data/lib/roku_builder.rb +143 -154
  131. data/lib/roku_builder/config.rb +17 -40
  132. data/lib/roku_builder/config_parser.rb +49 -200
  133. data/lib/roku_builder/config_validator.rb +1 -1
  134. data/lib/roku_builder/errors.rb +12 -0
  135. data/lib/roku_builder/git.rb +28 -0
  136. data/lib/roku_builder/hash.rb +8 -0
  137. data/lib/roku_builder/manifest.rb +121 -0
  138. data/lib/roku_builder/options.rb +68 -29
  139. data/lib/roku_builder/plugin.rb +30 -0
  140. data/lib/roku_builder/plugins/core.rb +117 -0
  141. data/lib/roku_builder/plugins/inspector.rb +104 -0
  142. data/lib/roku_builder/{linker.rb → plugins/linker.rb} +38 -12
  143. data/lib/roku_builder/plugins/loader.rb +152 -0
  144. data/lib/roku_builder/{monitor.rb → plugins/monitor.rb} +20 -9
  145. data/lib/roku_builder/{navigator.rb → plugins/navigator.rb} +136 -88
  146. data/lib/roku_builder/plugins/packager.rb +194 -0
  147. data/lib/roku_builder/plugins/profiler.rb +135 -0
  148. data/lib/roku_builder/plugins/scripter.rb +53 -0
  149. data/lib/roku_builder/{tester.rb → plugins/tester.rb} +28 -19
  150. data/lib/roku_builder/stager.rb +48 -12
  151. data/lib/roku_builder/string.rb +20 -0
  152. data/lib/roku_builder/util.rb +10 -34
  153. data/lib/roku_builder/version.rb +1 -1
  154. data/rakefile +5 -1
  155. data/roku_builder.gemspec +2 -0
  156. data/test/roku_builder/plugins/test_core.rb +112 -0
  157. data/test/roku_builder/plugins/test_inspector.rb +165 -0
  158. data/test/roku_builder/plugins/test_linker.rb +123 -0
  159. data/test/roku_builder/plugins/test_loader.rb +115 -0
  160. data/test/roku_builder/plugins/test_monitor.rb +141 -0
  161. data/test/roku_builder/plugins/test_navigator.rb +274 -0
  162. data/test/roku_builder/plugins/test_packager.rb +202 -0
  163. data/test/roku_builder/plugins/test_profiler.rb +127 -0
  164. data/test/roku_builder/plugins/test_scripter.rb +110 -0
  165. data/test/roku_builder/plugins/test_tester.rb +109 -0
  166. data/test/roku_builder/test_config.rb +51 -35
  167. data/test/roku_builder/test_config_parser.rb +76 -154
  168. data/test/roku_builder/test_config_validator.rb +18 -1
  169. data/test/roku_builder/test_files/{loader_test/manifest → config_parser_test/test.pkg} +0 -0
  170. data/test/roku_builder/test_files/config_test/config.json +3 -0
  171. data/test/roku_builder/test_files/controller_commands_test/manifest_template +7 -0
  172. data/test/roku_builder/test_files/core_test/manifest_template +7 -0
  173. data/test/roku_builder/test_files/core_test/test.pkg +0 -0
  174. data/test/roku_builder/test_files/inspector_test/manifest +6 -0
  175. data/test/roku_builder/test_files/inspector_test/test.pkg +0 -0
  176. data/test/roku_builder/test_files/linker_test/manifest +6 -0
  177. data/test/roku_builder/test_files/linker_test/test.pkg +0 -0
  178. data/test/roku_builder/test_files/loader_test/manifest_template +6 -0
  179. data/test/roku_builder/test_files/loader_test/test.pkg +0 -0
  180. data/test/roku_builder/test_files/loader_test/test.zip +0 -0
  181. data/test/roku_builder/test_files/manifest_test/manifest_comments +6 -0
  182. data/test/roku_builder/test_files/manifest_test/manifest_template +7 -0
  183. data/test/roku_builder/test_files/manifest_test/test.zip +0 -0
  184. data/test/roku_builder/test_files/packager_test/manifest +6 -0
  185. data/test/roku_builder/test_files/packager_test/scripter_test/manifest +6 -0
  186. data/test/roku_builder/test_files/packager_test/test.pkg +0 -0
  187. data/test/roku_builder/test_files/roku_builder_test/config.json +32 -0
  188. data/test/roku_builder/test_files/scripter_test/manifest +6 -0
  189. data/test/roku_builder/test_files/scripter_test/test.pkg +0 -0
  190. data/test/roku_builder/test_files/stager_test/test.pkg +0 -0
  191. data/test/roku_builder/test_files/tester_test/manifest +6 -0
  192. data/test/roku_builder/test_files/tester_test/test.pkg +0 -0
  193. data/test/roku_builder/test_helper.rb +44 -11
  194. data/test/roku_builder/test_logger.rb +1 -0
  195. data/test/roku_builder/test_manifest.rb +99 -0
  196. data/test/roku_builder/test_options.rb +106 -77
  197. data/test/roku_builder/test_options_plugins.rb +111 -0
  198. data/test/roku_builder/test_plugin.rb +48 -0
  199. data/test/roku_builder/test_roku_builder.rb +239 -0
  200. data/test/roku_builder/test_stager.rb +49 -101
  201. data/test/roku_builder/test_util.rb +19 -4
  202. metadata +241 -47
  203. data/lib/roku_builder/controller.rb +0 -98
  204. data/lib/roku_builder/controller_commands.rb +0 -224
  205. data/lib/roku_builder/error_handler.rb +0 -142
  206. data/lib/roku_builder/inspector.rb +0 -82
  207. data/lib/roku_builder/keyer.rb +0 -106
  208. data/lib/roku_builder/loader.rb +0 -131
  209. data/lib/roku_builder/manifest_manager.rb +0 -126
  210. data/lib/roku_builder/packager.rb +0 -43
  211. data/lib/roku_builder/profiler.rb +0 -96
  212. data/lib/roku_builder/scripter.rb +0 -39
  213. data/test/roku_builder/test_controller.rb +0 -70
  214. data/test/roku_builder/test_controller_commands.rb +0 -465
  215. data/test/roku_builder/test_error_handler.rb +0 -90
  216. data/test/roku_builder/test_inspector.rb +0 -298
  217. data/test/roku_builder/test_keyer.rb +0 -176
  218. data/test/roku_builder/test_linker.rb +0 -110
  219. data/test/roku_builder/test_loader.rb +0 -337
  220. data/test/roku_builder/test_manifest_manager.rb +0 -103
  221. data/test/roku_builder/test_monitor.rb +0 -137
  222. data/test/roku_builder/test_navigator.rb +0 -280
  223. data/test/roku_builder/test_packager.rb +0 -127
  224. data/test/roku_builder/test_profiler.rb +0 -35
  225. data/test/roku_builder/test_scripter.rb +0 -102
  226. data/test/roku_builder/test_tester.rb +0 -130
@@ -4,15 +4,42 @@ module RokuBuilder
4
4
 
5
5
  # Launch application, sending parameters
6
6
  class Linker < Util
7
+ extend Plugin
8
+
9
+ def self.commands
10
+ {
11
+ deeplink: {device: true, stage: true},
12
+ applist: {device: true}
13
+ }
14
+ end
15
+
16
+ def self.parse_options(parser:, options:)
17
+ parser.separator "Commands:"
18
+ parser.on("-o", "--deeplink OPTIONS", "Deeplink into app. Define options as keypairs. (eg. a:b, c:d,e:f)") do |o|
19
+ options[:deeplink] = o
20
+ end
21
+ parser.on("-A", "--app-list", "List currently installed apps") do
22
+ options[:applist] = true
23
+ end
24
+ parser.separator "Options:"
25
+ parser.on("-a", "--app ID", "Send App id for deeplinking") do |a|
26
+ options[:app_id] = a
27
+ end
28
+ end
29
+
30
+ def self.dependencies
31
+ [Loader]
32
+ end
33
+
7
34
  # Deeplink to an app
8
- # @param options [String] Options string
9
- # @param app_id [String] Id of the app to launch (defaults to dev)
10
- # @param logger [Logger] System Logger
11
- # @note Options string should be formated like the following: "<key>:<value>[, <key>:<value>]*"
12
- # @note Any options will be accepted and sent to the app
13
- def launch(options: nil, app_id: "dev")
35
+ def deeplink(options:)
36
+ if options.has_source?
37
+ Loader.new(config: @config).sideload(options: options)
38
+ end
39
+ app_id = options[:app_id]
40
+ app_id ||= "dev"
14
41
  path = "/launch/#{app_id}"
15
- payload = Util.options_parse(options: options)
42
+ payload = RokuBuilder.options_parse(options: options[:deeplink])
16
43
 
17
44
  unless payload.keys.count > 0
18
45
  @logger.warn "No options sent to launched app"
@@ -25,15 +52,13 @@ module RokuBuilder
25
52
  @logger.info "curl -d '' '#{@url}:8060#{path}'"
26
53
  end
27
54
 
28
- conn = multipart_connection(port: 8060)
29
-
30
- response = conn.post path
31
- return response.success?
55
+ response = multipart_connection(port: 8060).post path
56
+ @logger.fatal("Failed Deeplinking") unless response.success?
32
57
  end
33
58
 
34
59
  # List currently installed apps
35
60
  # @param logger [Logger] System Logger
36
- def list()
61
+ def applist(options:)
37
62
  path = "/query/apps"
38
63
  conn = multipart_connection(port: 8060)
39
64
  response = conn.get path
@@ -58,4 +83,5 @@ module RokuBuilder
58
83
  params.collect{|k,v| "#{k}=#{CGI.escape(v)}"}.join('&')
59
84
  end
60
85
  end
86
+ RokuBuilder.register_plugin(Linker)
61
87
  end
@@ -0,0 +1,152 @@
1
+ # ********** Copyright Viacom, Inc. Apache 2.0 **********
2
+
3
+ module RokuBuilder
4
+
5
+ # Load/Unload/Build roku applications
6
+ class Loader < Util
7
+ extend Plugin
8
+
9
+ def self.commands
10
+ {
11
+ sideload: {source: true, device: true, stage: true},
12
+ build: {source: true, stage: true, exclude: true},
13
+ delete: {device: true}
14
+ }
15
+ end
16
+
17
+ def self.parse_options(parser:, options:)
18
+ parser.separator "Commands:"
19
+ parser.on("-l", "--sideload", "Sideload an app") do
20
+ options[:sideload] = true
21
+ end
22
+ parser.on("-d", "--delete", "Delete the currently sideloaded app") do
23
+ options[:delete] = true
24
+ end
25
+ parser.on("-b", "--build", "Build a zip to be sideloaded") do
26
+ options[:build] = true
27
+ end
28
+ parser.separator "Options:"
29
+ parser.on("-x", "--exclude", "Apply exclude config to sideload") do
30
+ options[:exclude] = true
31
+ end
32
+ end
33
+
34
+ def self.dependencies
35
+ [Navigator]
36
+ end
37
+
38
+ # Sideload an app onto a roku device
39
+ def sideload(options:)
40
+ Navigator.new(config: @config).nav(options:{nav: "home"})
41
+ did_build = false
42
+ unless options[:in]
43
+ did_build = true
44
+ build(options: options)
45
+ end
46
+ upload
47
+ # Cleanup
48
+ File.delete(file_path(:in)) if did_build and not options[:out]
49
+ end
50
+
51
+
52
+ # Build an app to sideload later
53
+ def build(options:)
54
+ @options = options
55
+ build_zip(setup_build_content)
56
+ @config.in = @config.out #setting in path for possible sideload
57
+ end
58
+
59
+ # Remove the currently sideloaded app
60
+ def delete(options:)
61
+ payload = {mysubmit: "Delete", archive: ""}
62
+ response = multipart_connection.post "/plugin_install", payload
63
+ unless response.status == 200 and response.body =~ /Delete Succeeded/
64
+ raise ExecutionError, "Failed Unloading"
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def upload
71
+ payload = {
72
+ mysubmit: "Replace",
73
+ archive: Faraday::UploadIO.new(file_path(:in), 'application/zip')
74
+ }
75
+ response = multipart_connection.post "/plugin_install", payload
76
+ if response.status==200 and response.body=~/Identical to previous version/
77
+ @logger.warn("Sideload identival to previous version")
78
+ elsif not (response.status==200 and response.body=~/Install Success/)
79
+ @logger.debug("Status: #{response.status}, Body: #{response.body}")
80
+ raise ExecutionError, "Failed Sideloading"
81
+ end
82
+ end
83
+
84
+ def file_path(type)
85
+ file = @config.send(type)[:file]
86
+ file ||= Manifest.new(config: @config).build_version
87
+ file = file+".zip" unless file.end_with?(".zip")
88
+ File.join(@config.send(type)[:folder], file)
89
+ end
90
+
91
+ def setup_build_content()
92
+ content = {}
93
+ content[:excludes] = []
94
+ if @options[:current]
95
+ content[:folders] = Dir.entries(@config.root_dir).select {|entry| File.directory? File.join(@config.root_dir, entry) and !(entry =='.' || entry == '..') }
96
+ content[:files] = Dir.entries(@config.root_dir).select {|entry| File.file? File.join(@config.root_dir, entry)}
97
+ else
98
+ content[:folders] = @config.project[:folders]
99
+ content[:files] = @config.project[:files]
100
+ content[:exclude] if @options[:exclude] or @options.exclude_command?
101
+ end
102
+ content
103
+ end
104
+
105
+ def build_zip(content)
106
+ path = file_path(:out)
107
+ File.delete(path) if File.exist?(path)
108
+ io = Zip::File.open(path, Zip::File::CREATE)
109
+ # Add folders to zip
110
+ content[:folders].each do |folder|
111
+ base_folder = File.join(@config.root_dir, folder)
112
+ if File.exist?(base_folder)
113
+ entries = Dir.entries(base_folder)
114
+ entries.delete(".")
115
+ entries.delete("..")
116
+ writeEntries(@config.root_dir, entries, folder, content[:excludes], io)
117
+ else
118
+ @logger.warn "Missing Folder: #{base_folder}"
119
+ end
120
+ end
121
+ # Add file to zip
122
+ writeEntries(@config.parsed[:root_dir], content[:files], "", content[:excludes], io)
123
+ io.close()
124
+ end
125
+
126
+ # Recursively write directory contents to a zip archive
127
+ # @param root_dir [String] Path of the root directory
128
+ # @param entries [Array<String>] Array of file paths of files/directories to store in the zip archive
129
+ # @param path [String] The path of the current directory starting at the root directory
130
+ # @param io [IO] zip IO object
131
+ def writeEntries(root_dir, entries, path, excludes, io)
132
+ entries.each { |e|
133
+ zipFilePath = path == "" ? e : File.join(path, e)
134
+ diskFilePath = File.join(root_dir, zipFilePath)
135
+ if File.directory?(diskFilePath)
136
+ io.mkdir(zipFilePath)
137
+ subdir =Dir.entries(diskFilePath); subdir.delete("."); subdir.delete("..")
138
+ writeEntries(root_dir, subdir, zipFilePath, excludes, io)
139
+ else
140
+ unless excludes.include?(zipFilePath)
141
+ if File.exist?(diskFilePath)
142
+ io.get_output_stream(zipFilePath) { |f| f.puts(File.open(diskFilePath, "rb").read()) }
143
+ else
144
+ @logger.warn "Missing File: #{diskFilePath}"
145
+ end
146
+ end
147
+ end
148
+ }
149
+ end
150
+ end
151
+ RokuBuilder.register_plugin(Loader)
152
+ end
@@ -4,25 +4,35 @@ module RokuBuilder
4
4
 
5
5
  # Monitor development Logs
6
6
  class Monitor < Util
7
+ extend Plugin
8
+
9
+ def self.commands
10
+ { monitor: {device: true}}
11
+ end
12
+
13
+ def self.parse_options(parser:, options:)
14
+ parser.separator "Commands:"
15
+ parser.on("-m", "--monitor [TYPE]", "Run telnet to monitor roku log") do |m|
16
+ options[:monitor] = m || "main"
17
+ end
18
+ parser.separator "Options:"
19
+ parser.on("-R", "--regexp REGEXP", "A regular expression used to filter monitor logs") do |r|
20
+ options[:regexp] = r
21
+ end
22
+ end
7
23
 
8
24
  # Initialize port config
9
25
  def init()
10
26
  @ports = {
11
27
  main: 8085,
12
- sg: 8089,
13
- task1: 8090,
14
- task2: 8091,
15
- task3: 8092,
16
- taskX: 8093,
17
28
  profiler: 8080,
18
29
  }
19
30
  @show_prompt = false
20
31
  end
21
32
 
22
33
  # Monitor a development log on the Roku device
23
- # @param type [Symbol] The log type to monitor
24
- # @param regexp [Regexp] regular expression to filter text on
25
- def monitor(type:, regexp: nil)
34
+ def monitor(options:)
35
+ type = options[:monitor].to_sym
26
36
  telnet_config = { 'Host' => @roku_ip_address, 'Port' => @ports[type] }
27
37
  waitfor_config = { 'Match' => /./, 'Timeout' => false }
28
38
 
@@ -33,7 +43,7 @@ module RokuBuilder
33
43
  all_text = ""
34
44
  while true
35
45
  connection.waitfor(waitfor) do |txt|
36
- all_text = manage_text(all_text: all_text, txt: txt, regexp: regexp)
46
+ all_text = manage_text(all_text: all_text, txt: txt, regexp: options[:regexp])
37
47
  end
38
48
  end
39
49
  }
@@ -118,4 +128,5 @@ module RokuBuilder
118
128
  all_text
119
129
  end
120
130
  end
131
+ RokuBuilder.register_plugin(Monitor)
121
132
  end
@@ -4,9 +4,39 @@ module RokuBuilder
4
4
 
5
5
  # Navigation methods
6
6
  class Navigator < Util
7
+ extend Plugin
8
+
9
+ def self.commands
10
+ {
11
+ nav: {device: true},
12
+ navigate: {device: true},
13
+ type: {device: true},
14
+ screen: {device: true},
15
+ screens: {}
16
+ }
17
+ end
18
+
19
+ def self.parse_options(parser:, options:)
20
+ parser.separator("Commands:")
21
+ parser.on("-N", "--nav CMD", "Send the given command to the roku") do |n|
22
+ options[:nav] = n
23
+ end
24
+ parser.on("--navigate", "Run interactive navigator") do
25
+ options[:navigate] = true
26
+ end
27
+ parser.on("-y", "--type TEXT", "Type the given text on the roku device") do |t|
28
+ options[:type] = t
29
+ end
30
+ parser.on("--screen SCREEN", "Show a screen") do |s|
31
+ options[:screen] = s
32
+ end
33
+ parser.on("--screens", "Show possible screens") do
34
+ options[:screens] = true
35
+ end
36
+ end
7
37
 
8
38
  # Setup navigation commands
9
- def init(mappings: nil)
39
+ def init()
10
40
  @commands = {
11
41
  home: "Home", rew: "Rev", ff: "Fwd",
12
42
  play: "Play", select: "Select", left: "Left",
@@ -33,67 +63,33 @@ module RokuBuilder
33
63
  @runable = [
34
64
  :secret, :channels
35
65
  ]
36
- mappings_init(mappings: mappings)
66
+ mappings_init
37
67
  end
38
68
 
39
- # Init Mappings
40
- def mappings_init(mappings: nil)
41
- @mappings = {
42
- "\e[1~": [ "home", "Home" ],
43
- "<": [ "rew", "<" ],
44
- ">": [ "ff", ">" ],
45
- "=": [ "play", "=" ],
46
- "\r": [ "select", "Enter" ],
47
- "\e[D": [ "left", "Left Arrow" ],
48
- "\e[C": [ "right", "Right Arrow" ],
49
- "\e[B": [ "down", "Down Arrow" ],
50
- "\e[A": [ "up", "Up Arrow" ],
51
- "\t": [ "back", "Tab" ],
52
- #"": [ "replay", "" ],
53
- "*": [ "info", "*" ],
54
- "\u007f": [ "backspace", "Backspace" ],
55
- "?": [ "search", "?" ],
56
- "\e\r": [ "enter", "Alt + Enter" ],
57
- "\e[5~": [ "volumeup", "Page Up" ],
58
- "\e[6~": [ "volumedown", "Page Down" ],
59
- "\e[4~": [ "mute", "End" ],
60
- #"": [ "channeldown", "" ],
61
- #"": [ "channelup", "" ],
62
- #"": [ "tuner", "" ],
63
- #"": [ "hdmi1", "" ],
64
- #"": [ "hdmi2", "" ],
65
- #"": [ "hdmi3", "" ],
66
- #"": [ "hdmi4", "" ],
67
- #"": [ "avi", "" ]
68
- }
69
- @mappings.merge!(mappings) if mappings
70
- end
71
69
 
72
70
  # Send a navigation command to the roku device
73
71
  # @param command [Symbol] The smbol of the command to send
74
72
  # @return [Boolean] Success
75
- def nav(commands:)
73
+ def nav(options:)
74
+ commands = options[:nav].split(/, */).map{|c| c.to_sym}
76
75
  commands.each do |command|
77
- if @commands.has_key?(command)
78
- conn = multipart_connection(port: 8060)
79
-
80
- path = "/keypress/#{@commands[command]}"
81
- @logger.debug("Send Command: "+path)
82
- response = conn.post path
83
- return false unless response.success?
84
- else
85
- return false
76
+ unless @commands.has_key?(command)
77
+ raise ExecutionError, "Unknown Navigation Command"
86
78
  end
79
+ conn = multipart_connection(port: 8060)
80
+ path = "/keypress/#{@commands[command]}"
81
+ @logger.debug("Send Command: "+path)
82
+ response = conn.post path
83
+ raise ExecutionError, "Navigation Failed" unless response.success?
87
84
  end
88
- return true
89
85
  end
90
86
 
91
87
  # Type text on the roku device
92
88
  # @param text [String] The text to type on the device
93
89
  # @return [Boolean] Success
94
- def type(text:)
90
+ def type(options:)
95
91
  conn = multipart_connection(port: 8060)
96
- text.split(//).each do |c|
92
+ options[:type].split(//).each do |c|
97
93
  path = "/keypress/LIT_#{CGI::escape(c)}"
98
94
  @logger.debug("Send Letter: "+path)
99
95
  response = conn.post path
@@ -102,7 +98,7 @@ module RokuBuilder
102
98
  return true
103
99
  end
104
100
 
105
- def interactive
101
+ def navigate(options:)
106
102
  running = true
107
103
  @logger.info("Key Mappings:")
108
104
  @mappings.each_value {|key|
@@ -115,64 +111,83 @@ module RokuBuilder
115
111
  if char == "\u0003"
116
112
  running = false
117
113
  else
118
- Thread.new(char) {|character|
119
- if @mappings[character.to_sym] != nil
120
- nav(commands:[@mappings[character.to_sym][0].to_sym])
121
- elsif character.inspect.force_encoding("UTF-8").ascii_only?
122
- type(text: character)
123
- end
124
- }
114
+ Thread.new(char) {|character| handle_navigate_input(character)}
125
115
  end
126
116
  end
127
117
  end
128
118
 
119
+
129
120
  # Show the commands for one of the roku secret screens
130
121
  # @param type [Symbol] The type of screen to show
131
122
  # @return [Boolean] Screen found
132
- def screen(type:)
133
- if @screens.has_key?(type)
134
- if @runable.include?(type)
135
- nav(commands: @screens[type])
136
- else
137
- @logger.unknown("Cannot run command automatically")
138
- end
139
- display, count, string = [], [], ""
140
- @screens[type].each do |command|
141
- if display.count > 0 and display[-1] == command
142
- count[-1] = count[-1] + 1
143
- else
144
- display.push(command)
145
- count.push(1)
146
- end
147
- end
148
- display.each_index do |i|
149
- if count[i] > 1
150
- string = string + @commands[display[i]]+" x "+count[i].to_s+", "
151
- else
152
- string = string + @commands[display[i]]+", "
153
- end
154
- end
155
- if @runable.include?(type)
156
- @logger.info(string.strip)
157
- else
158
- @logger.unknown(string.strip)
159
- end
123
+ def screen(options:)
124
+ type = options[:screen].to_sym
125
+ unless @screens.has_key?(type)
126
+ raise ExecutionError, "Unknown Screen"
127
+ end
128
+ if @runable.include?(type)
129
+ nav(options: {nav: @screens[type].join(", ")})
160
130
  else
161
- return false
131
+ @logger.unknown("Cannot run command automatically")
162
132
  end
163
- true
133
+ display_screen_command(type)
164
134
  end
165
135
 
166
136
  # Show avaiable roku secret screens
167
- def screens
137
+ def screens(options:)
168
138
  @screens.keys.each {|screen| @logger.unknown(screen)}
169
139
  end
170
140
 
141
+ private
142
+
143
+ def mappings_init()
144
+ @mappings = {
145
+ "\e[1~": [ "home", "Home" ],
146
+ "<": [ "rew", "<" ],
147
+ ">": [ "ff", ">" ],
148
+ "=": [ "play", "=" ],
149
+ "\r": [ "select", "Enter" ],
150
+ "\e[D": [ "left", "Left Arrow" ],
151
+ "\e[C": [ "right", "Right Arrow" ],
152
+ "\e[B": [ "down", "Down Arrow" ],
153
+ "\e[A": [ "up", "Up Arrow" ],
154
+ "\t": [ "back", "Tab" ],
155
+ #"": [ "replay", "" ],
156
+ "*": [ "info", "*" ],
157
+ "\u007f": [ "backspace", "Backspace" ],
158
+ "?": [ "search", "?" ],
159
+ "\e\r": [ "enter", "Alt + Enter" ],
160
+ "\e[5~": [ "volumeup", "Page Up" ],
161
+ "\e[6~": [ "volumedown", "Page Down" ],
162
+ "\e[4~": [ "mute", "End" ],
163
+ #"": [ "channeldown", "" ],
164
+ #"": [ "channelup", "" ],
165
+ #"": [ "tuner", "" ],
166
+ #"": [ "hdmi1", "" ],
167
+ #"": [ "hdmi2", "" ],
168
+ #"": [ "hdmi3", "" ],
169
+ #"": [ "hdmi4", "" ],
170
+ #"": [ "avi", "" ]
171
+ }
172
+ @mappings.merge!(generate_maggings) if @config.input_mappings
173
+ end
174
+
175
+ def generate_maggings
176
+ mappings = {}
177
+ if @config.input_mappings
178
+ @config.input_mappings.each_pair {|key, value|
179
+ unless "".to_sym == key
180
+ key = key.to_s.sub(/\\e/, "\e").to_sym
181
+ mappings[key] = value
182
+ end
183
+ }
184
+ end
185
+ mappings
186
+ end
187
+
171
188
  def read_char
172
189
  STDIN.echo = false
173
190
  STDIN.raw!
174
-
175
-
176
191
  input = STDIN.getc.chr
177
192
  if input == "\e" then
178
193
  input << STDIN.read_nonblock(3) rescue nil
@@ -183,5 +198,38 @@ module RokuBuilder
183
198
  STDIN.echo = true
184
199
  STDIN.cooked!
185
200
  end
201
+
202
+ def handle_navigate_input(char)
203
+ if @mappings[char.to_sym] != nil
204
+ nav(options: {nav: @mappings[char.to_sym][0]})
205
+ elsif char.inspect.force_encoding("UTF-8").ascii_only?
206
+ type(options: {type: char})
207
+ end
208
+ end
209
+
210
+ def display_screen_command(type)
211
+ display, count, string = [], [], ""
212
+ @screens[type].each do |command|
213
+ if display.count > 0 and display[-1] == command
214
+ count[-1] = count[-1] + 1
215
+ else
216
+ display.push(command)
217
+ count.push(1)
218
+ end
219
+ end
220
+ display.each_index do |i|
221
+ if count[i] > 1
222
+ string = string + @commands[display[i]]+" x "+count[i].to_s+", "
223
+ else
224
+ string = string + @commands[display[i]]+", "
225
+ end
226
+ end
227
+ if @runable.include?(type)
228
+ @logger.info(string.strip)
229
+ else
230
+ @logger.unknown(string.strip)
231
+ end
232
+ end
186
233
  end
234
+ RokuBuilder.register_plugin(Navigator)
187
235
  end