roku_builder 3.13.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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