sc-frank-cucumber 1.2.1.00af28c

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 (136) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/Rakefile +38 -0
  4. data/bin/frank +6 -0
  5. data/bin/frank-skeleton +33 -0
  6. data/frank-skeleton/features/my_first.feature +12 -0
  7. data/frank-skeleton/features/step_definitions/launch_steps.rb +20 -0
  8. data/frank-skeleton/features/support/env.rb +8 -0
  9. data/frank-skeleton/frank_static_resources.bundle/ViewAttributeMapping.plist +63 -0
  10. data/frank-skeleton/frank_static_resources.bundle/ViewAttributeMappingMac.plist +99 -0
  11. data/frank-skeleton/frank_static_resources.bundle/images/ajax-loader.gif +0 -0
  12. data/frank-skeleton/frank_static_resources.bundle/images/file.gif +0 -0
  13. data/frank-skeleton/frank_static_resources.bundle/images/folder-closed.gif +0 -0
  14. data/frank-skeleton/frank_static_resources.bundle/images/folder.gif +0 -0
  15. data/frank-skeleton/frank_static_resources.bundle/images/loader.gif +0 -0
  16. data/frank-skeleton/frank_static_resources.bundle/images/loader.png +0 -0
  17. data/frank-skeleton/frank_static_resources.bundle/images/minus.gif +0 -0
  18. data/frank-skeleton/frank_static_resources.bundle/images/plus.gif +0 -0
  19. data/frank-skeleton/frank_static_resources.bundle/images/treeview-black-line.gif +0 -0
  20. data/frank-skeleton/frank_static_resources.bundle/images/treeview-black.gif +0 -0
  21. data/frank-skeleton/frank_static_resources.bundle/images/treeview-default-line.gif +0 -0
  22. data/frank-skeleton/frank_static_resources.bundle/images/treeview-default.gif +0 -0
  23. data/frank-skeleton/frank_static_resources.bundle/images/treeview-famfamfam-line.gif +0 -0
  24. data/frank-skeleton/frank_static_resources.bundle/images/treeview-famfamfam.gif +0 -0
  25. data/frank-skeleton/frank_static_resources.bundle/images/treeview-gray-line.gif +0 -0
  26. data/frank-skeleton/frank_static_resources.bundle/images/treeview-gray.gif +0 -0
  27. data/frank-skeleton/frank_static_resources.bundle/images/treeview-red-line.gif +0 -0
  28. data/frank-skeleton/frank_static_resources.bundle/images/treeview-red.gif +0 -0
  29. data/frank-skeleton/frank_static_resources.bundle/index.html +86 -0
  30. data/frank-skeleton/frank_static_resources.bundle/index.html.haml +76 -0
  31. data/frank-skeleton/frank_static_resources.bundle/js/accessible_views_view.coffee +41 -0
  32. data/frank-skeleton/frank_static_resources.bundle/js/accessible_views_view.js +46 -0
  33. data/frank-skeleton/frank_static_resources.bundle/js/controller.coffee +134 -0
  34. data/frank-skeleton/frank_static_resources.bundle/js/controller.js +139 -0
  35. data/frank-skeleton/frank_static_resources.bundle/js/details_view.coffee +42 -0
  36. data/frank-skeleton/frank_static_resources.bundle/js/details_view.js +51 -0
  37. data/frank-skeleton/frank_static_resources.bundle/js/dropdown_control.coffee +64 -0
  38. data/frank-skeleton/frank_static_resources.bundle/js/dropdown_control.js +73 -0
  39. data/frank-skeleton/frank_static_resources.bundle/js/ersatz_model.coffee +46 -0
  40. data/frank-skeleton/frank_static_resources.bundle/js/ersatz_model.js +60 -0
  41. data/frank-skeleton/frank_static_resources.bundle/js/ersatz_view.coffee +167 -0
  42. data/frank-skeleton/frank_static_resources.bundle/js/ersatz_view.js +205 -0
  43. data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_model.coffee +10 -0
  44. data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_model.js +17 -0
  45. data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_view.coffee +44 -0
  46. data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_view.js +63 -0
  47. data/frank-skeleton/frank_static_resources.bundle/js/frank.coffee +96 -0
  48. data/frank-skeleton/frank_static_resources.bundle/js/frank.js +146 -0
  49. data/frank-skeleton/frank_static_resources.bundle/js/lib/backbone.js +1431 -0
  50. data/frank-skeleton/frank_static_resources.bundle/js/lib/coffee-script.js +8 -0
  51. data/frank-skeleton/frank_static_resources.bundle/js/lib/jquery-ui.min.js +405 -0
  52. data/frank-skeleton/frank_static_resources.bundle/js/lib/jquery.min.js +4 -0
  53. data/frank-skeleton/frank_static_resources.bundle/js/lib/jquery.treeview.js +251 -0
  54. data/frank-skeleton/frank_static_resources.bundle/js/lib/json2.js +481 -0
  55. data/frank-skeleton/frank_static_resources.bundle/js/lib/raphael.js +5815 -0
  56. data/frank-skeleton/frank_static_resources.bundle/js/lib/require.js +2053 -0
  57. data/frank-skeleton/frank_static_resources.bundle/js/lib/underscore.js +1059 -0
  58. data/frank-skeleton/frank_static_resources.bundle/js/main.coffee +27 -0
  59. data/frank-skeleton/frank_static_resources.bundle/js/main.js +29 -0
  60. data/frank-skeleton/frank_static_resources.bundle/js/tabs_controller.coffee +13 -0
  61. data/frank-skeleton/frank_static_resources.bundle/js/tabs_controller.js +22 -0
  62. data/frank-skeleton/frank_static_resources.bundle/js/toast_controller.coffee +15 -0
  63. data/frank-skeleton/frank_static_resources.bundle/js/toast_controller.js +28 -0
  64. data/frank-skeleton/frank_static_resources.bundle/js/transform_stack.coffee +59 -0
  65. data/frank-skeleton/frank_static_resources.bundle/js/transform_stack.js +78 -0
  66. data/frank-skeleton/frank_static_resources.bundle/js/tree_view.coffee +53 -0
  67. data/frank-skeleton/frank_static_resources.bundle/js/tree_view.js +64 -0
  68. data/frank-skeleton/frank_static_resources.bundle/js/view_hier_model.coffee +37 -0
  69. data/frank-skeleton/frank_static_resources.bundle/js/view_hier_model.js +48 -0
  70. data/frank-skeleton/frank_static_resources.bundle/js/view_model.coffee +39 -0
  71. data/frank-skeleton/frank_static_resources.bundle/js/view_model.js +62 -0
  72. data/frank-skeleton/frank_static_resources.bundle/pictos/index.html +329 -0
  73. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.eot +0 -0
  74. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.svg +114 -0
  75. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.ttf +0 -0
  76. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.woff +0 -0
  77. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos.css +20 -0
  78. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos_base64.css +18 -0
  79. data/frank-skeleton/frank_static_resources.bundle/stylesheets/css/symbiote.css +1 -0
  80. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_elements.scss +28 -0
  81. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_header.scss +61 -0
  82. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_inspect_tabs_list_tabs.scss +194 -0
  83. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_jquery.treeview.scss +68 -0
  84. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_jqui.scss +2 -0
  85. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_layout.scss +13 -0
  86. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_mixins.sass +137 -0
  87. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_reset.scss +32 -0
  88. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_selector_test_toolbar.scss +81 -0
  89. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_solarized.scss +16 -0
  90. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_typography.scss +11 -0
  91. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_unicode.scss +3 -0
  92. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_z_index.scss +2 -0
  93. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/symbiote.scss +26 -0
  94. data/frank-skeleton/frankify.xcconfig.tt +6 -0
  95. data/frank-skeleton/libCocoaAsyncSocket.a +0 -0
  96. data/frank-skeleton/libCocoaAsyncSocketMac.a +0 -0
  97. data/frank-skeleton/libCocoaHTTPServer.a +0 -0
  98. data/frank-skeleton/libCocoaHTTPServerMac.a +0 -0
  99. data/frank-skeleton/libCocoaLumberjack.a +0 -0
  100. data/frank-skeleton/libCocoaLumberjackMac.a +0 -0
  101. data/frank-skeleton/libFrank.a +0 -0
  102. data/frank-skeleton/libFrankMac.a +0 -0
  103. data/frank-skeleton/libShelley.a +0 -0
  104. data/frank-skeleton/libShelleyMac.a +0 -0
  105. data/frank-skeleton/plugins/.empty_directory +0 -0
  106. data/lib/frank-cucumber.rb +15 -0
  107. data/lib/frank-cucumber/app_bundle_locator.rb +58 -0
  108. data/lib/frank-cucumber/bonjour.rb +73 -0
  109. data/lib/frank-cucumber/cli.rb +299 -0
  110. data/lib/frank-cucumber/color_helper.rb +13 -0
  111. data/lib/frank-cucumber/console.rb +28 -0
  112. data/lib/frank-cucumber/core_frank_steps.rb +260 -0
  113. data/lib/frank-cucumber/frank.xcconfig.erb +17 -0
  114. data/lib/frank-cucumber/frank_helper.rb +459 -0
  115. data/lib/frank-cucumber/frank_localize.rb +43 -0
  116. data/lib/frank-cucumber/frank_mac_helper.rb +120 -0
  117. data/lib/frank-cucumber/frankifier.rb +150 -0
  118. data/lib/frank-cucumber/gateway.rb +135 -0
  119. data/lib/frank-cucumber/gesture_helper.rb +99 -0
  120. data/lib/frank-cucumber/host_scripting.rb +96 -0
  121. data/lib/frank-cucumber/keyboard_helper.rb +69 -0
  122. data/lib/frank-cucumber/launcher.rb +70 -0
  123. data/lib/frank-cucumber/localize.yml +104 -0
  124. data/lib/frank-cucumber/location_helper.rb +20 -0
  125. data/lib/frank-cucumber/mac_launcher.rb +35 -0
  126. data/lib/frank-cucumber/plugins/plugin.rb +57 -0
  127. data/lib/frank-cucumber/rect.rb +26 -0
  128. data/lib/frank-cucumber/scroll_helper.rb +24 -0
  129. data/lib/frank-cucumber/version.rb +5 -0
  130. data/lib/frank-cucumber/wait_helper.rb +57 -0
  131. data/sc-frank-cucumber.gemspec +37 -0
  132. data/test/keyboard_helper_test.rb +84 -0
  133. data/test/launcher_test.rb +57 -0
  134. data/test/rect_test.rb +25 -0
  135. data/test/test_helper.rb +16 -0
  136. metadata +395 -0
@@ -0,0 +1,32 @@
1
+ /* css reset based on the work by eric meyer */
2
+ html,body {position:relative;margin:0;padding:0;min-height:100%;width:100%;height:100%;}
3
+ div,p,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td, keygen, select, button, button::-moz-focus-inner, isindex, hr {margin:0;padding:0;}
4
+ table {border-collapse:collapse;border-spacing:0;}
5
+ fieldset,img {border:0;}
6
+ input, textarea{border:none;outline:none;padding:none;background-color:#fff;}
7
+ address,caption,cite,code,dfn,th,var {font-style:normal;font-weight:normal;}
8
+ ol,ul {list-style:none;}
9
+ li {list-style-type: none;}
10
+ caption,th {text-align:left;}
11
+ em, strong {font-style: normal; font-weight: normal;}
12
+ h1,h2,h3,h4,h5,h6 {font-size:100%;font-weight:normal;}
13
+ q:before,q:after {content:'';}
14
+ abbr,acronym {border:0;}
15
+ a, a:hover, a:visited, a:active, a:link {text-decoration:none;}
16
+ form {display: block;}
17
+ textarea:focus, input:focus, select:focus {outline: none;}
18
+ input, textarea, keygen, select, button, isindex { font: inherit; color: inherit; letter-spacing: inherit; word-spacing: inherit; line-height: inherit; text-transform: none; text-indent: 0; text-shadow: inherit; display: inline-block; text-align: inherit; border: none; }
19
+ /* html5 block elements for IE. Stop using IE. */
20
+ article, aside, details, figcaption, figure, footer, header, hgroup, nav, section, address {display: block;}
21
+ .clear, .clearfloat {clear:both;}
22
+ h1,h2,h3,h4,h5,h6 {font-size: 1.0em; }
23
+
24
+ /* save your sanity */
25
+ * {
26
+ -webkit-box-sizing: border-box;
27
+ -khtml-box-sizing: border-box;
28
+ -icab-box-sizing: border-box;
29
+ -moz-box-sizing: border-box;
30
+ -o-box-sizing: border-box;
31
+ box-sizing: border-box;
32
+ }
@@ -0,0 +1,81 @@
1
+ //----------------------------------------------
2
+ // horizontal layout
3
+ $wrap-middle-width: 60%;
4
+ $wrap-outter-width: (100% - $wrap-middle-width)/2;
5
+ //----------------------------------------------
6
+
7
+ #selector-test {
8
+ position: relative;
9
+ text-align: center;
10
+ padding: $selector-test-toolbar-vt-padding 0;
11
+ .wrap {
12
+ display: inline-block;
13
+ position: relative;
14
+ vertical-align: middle;
15
+ padding: 0 .5em;
16
+ &.middle { width: $wrap-middle-width; }
17
+ &.outter { width: $wrap-outter-width; }
18
+ }//.wrap
19
+
20
+ #query { width: 100%; }
21
+
22
+ label {
23
+ display: block;
24
+ text-align: left;
25
+ text-transform: capitalize;
26
+ &:after {
27
+ content: "#{$arrow-right-down}";
28
+ font-size: .8em;
29
+ font-weight: bold;
30
+ padding-left: .3em;
31
+ }
32
+ }//label
33
+ }//#selector-test
34
+
35
+ $drop-indicator-width: 2em;
36
+
37
+ .dropdown {
38
+ position: relative;
39
+ display: block;
40
+ width: 100%;
41
+
42
+ * { z-index: $dropdown-child-z; }
43
+
44
+ button {
45
+ position: relative;
46
+ width: 100%;
47
+ padding-left: .8em;
48
+ padding-right: $drop-indicator-width;
49
+ white-space: nowrap;
50
+ overflow: hidden;
51
+ text-overflow: ellipsis;
52
+ }//button
53
+
54
+ ul {
55
+ position: absolute;
56
+ top: 100%;
57
+ width: 100%;
58
+ float: left;
59
+ opacity: 0;
60
+ visibility: hidden;
61
+ @include transition-two( visibility 0s linear 0.2s,opacity 0.2s linear );
62
+ &.shown {
63
+ opacity: 1;
64
+ visibility:visible;
65
+ @include transition-delay( 0s );
66
+ }//&.shown
67
+ }//ul
68
+
69
+ .drop-indicator {
70
+ color: #eee;
71
+ position: absolute;
72
+ width: $drop-indicator-width;
73
+ right: 0;
74
+ top: 6px;
75
+ bottom: 6px;
76
+ border-left: 1px solid white;
77
+ text-align: center;
78
+ cursor: pointer;
79
+ @include user-select( none );
80
+ }//.drop-indicator
81
+ }//.dropdown
@@ -0,0 +1,16 @@
1
+ $base03: #002b36 !default; //darkest blue
2
+ $base02: #073642 !default; //dark blue
3
+ $base01: #586e75 !default; //darkest gray
4
+ $base00: #657b83 !default; //dark gray
5
+ $base0: #839496 !default; //medium gray
6
+ $base1: #93a1a1 !default; //medium light gray
7
+ $base2: #eee8d5 !default; //cream
8
+ $base3: #fdf6e3 !default; //white
9
+ $solar-yellow: #b58900 !default;
10
+ $solar-orange: #cb4b16 !default;
11
+ $solar-red: #dc322f !default;
12
+ $solar-magenta: #d33682 !default;
13
+ $solar-violet: #6c71c4 !default;
14
+ $solar-blue: #268bd2 !default;
15
+ $solar-cyan: #2aa198 !default;
16
+ $solar-green: #859900 !default;
@@ -0,0 +1,11 @@
1
+ $sans: "Helvetica Neue", "HelveticaNeue", Arial;
2
+
3
+ $base-font-size: 16px;
4
+ $base-line-height: 24px;
5
+ $label-line-height: $base-line-height;
6
+
7
+
8
+ @mixin light-text {
9
+ color: #fff;
10
+ text-shadow: 0 -1px rgba(0,0,0, .3);
11
+ }
@@ -0,0 +1,3 @@
1
+ $arrow-right-down: "\21b4";
2
+ $arrow-down-right: "\21b3";
3
+ $arrow-right: "\2192";
@@ -0,0 +1,2 @@
1
+ $ui-locator-view-z: -1;
2
+ $dropdown-child-z: 1;
@@ -0,0 +1,26 @@
1
+ //-------------------------------
2
+ // primary application file
3
+ // all partials should be loaded here.
4
+ //-------------------------------
5
+ // base
6
+ @import "_unicode.scss";
7
+ @import "_mixins.sass";
8
+ @import "_solarized.scss";
9
+ @import "_typography.scss";
10
+ @import "_z_index.scss";
11
+ //----------------------------------
12
+ @import "_reset.scss";
13
+ @import "_elements.scss";
14
+ //----------------------------------
15
+ // global layout affords control
16
+ // over container heights.
17
+ @import "_layout.scss";
18
+ //----------------------------------
19
+ // partials
20
+ @import "_header.scss";
21
+ @import "_selector_test_toolbar.scss";
22
+ @import "_inspect_tabs_list_tabs.scss";
23
+ //-------------------------------
24
+ // vender
25
+ @import "_jquery.treeview.scss";
26
+ @import "_jqui.scss";
@@ -0,0 +1,6 @@
1
+ INSTALL_PATH = /./
2
+
3
+ FRANK_CORE_LDFLAGS = -all_load -ObjC -framework CFNetwork -framework Security <%= @libs.map { |lib| "-l#{lib}" }.join(' ') %>
4
+ FRANK_CORE_MAC_LDFLAGS = -all_load -ObjC -framework CFNetwork -framework Security <%= @libsMac.map { |lib| "-l#{lib}" }.join(' ') %>
5
+
6
+ GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = FRANKIFIED
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
File without changes
@@ -0,0 +1,15 @@
1
+ require 'frank-cucumber/rect'
2
+ require 'frank-cucumber/color_helper'
3
+ require 'frank-cucumber/frank_helper'
4
+ require 'frank-cucumber/frank_mac_helper'
5
+ require 'frank-cucumber/launcher'
6
+ require 'frank-cucumber/mac_launcher'
7
+
8
+ World(Frank::Cucumber::ColorHelper)
9
+ World(Frank::Cucumber::FrankHelper)
10
+ World(Frank::Cucumber::FrankMacHelper)
11
+ World(Frank::Cucumber::Launcher)
12
+
13
+ AfterConfiguration do
14
+ require 'frank-cucumber/core_frank_steps'
15
+ end
@@ -0,0 +1,58 @@
1
+ module Frank module Cucumber
2
+ class XCode4Project
3
+ def initialize( workspace_path, derived_dir )
4
+ @workspace_path, @derived_dir = workspace_path, derived_dir
5
+ end
6
+
7
+ def derived_name
8
+ File.basename( @derived_dir )
9
+ end
10
+
11
+ def project_name
12
+ derived_name.split('-')[0]
13
+ end
14
+
15
+ def workspace_dir
16
+ File.dirname( @workspace_path )
17
+ end
18
+
19
+ def available_app_bundles
20
+ Dir.glob( File.join( @derived_dir, "Build", "Products", "*", "*.app" ) )
21
+ end
22
+
23
+ end
24
+
25
+ # utility class which will find all XCode4 projects which are using DerivedData to store their
26
+ # build output, and present information about those projects
27
+ class AppBundleLocator
28
+ def initialize
29
+ @projects = find_all_known_xcode_projects
30
+ end
31
+
32
+ def find_all_known_xcode_projects
33
+ require 'plist'
34
+
35
+ projects = []
36
+ Dir.glob( File.expand_path( "~/Library/Developer/Xcode/DerivedData/*/info.plist" ) ) do |plist_path|
37
+ workspace_path = Plist::parse_xml(plist_path)['WorkspacePath']
38
+ projects << XCode4Project.new( workspace_path, File.dirname(plist_path) )
39
+ end
40
+ projects
41
+ end
42
+
43
+ def guess_possible_app_bundles_for_dir( dir )
44
+ return [] if dir == '/'
45
+
46
+ project = @projects.find do |project|
47
+ project.workspace_dir == dir
48
+ end
49
+
50
+ if project.nil?
51
+ return guess_possible_app_bundles_for_dir( File.dirname(dir) )
52
+ end
53
+
54
+ return project.available_app_bundles
55
+ end
56
+
57
+ end
58
+ end end
@@ -0,0 +1,73 @@
1
+ require 'timeout'
2
+ require 'uri'
3
+
4
+ module Frank module Cucumber
5
+ class Bonjour
6
+
7
+ FRANK_SERVICE_NAME = 'Frank UISpec server'
8
+ FRANK_PORT = 37265
9
+ LOOKUP_TIMEOUT = 10
10
+
11
+ def debug string
12
+ puts string if $DEBUG
13
+ end
14
+
15
+ def found_a_frank( reply )
16
+ debug reply.inspect
17
+ unless reply.flags.add?
18
+ debug 'got a non-add reply'
19
+ debug "flags: #{reply.flags.to_a.inspect}"
20
+ return nil
21
+ end
22
+
23
+ resolve_service = DNSSD::Service.new
24
+ addr_service = DNSSD::Service.new
25
+ resolve_service.resolve reply do |r|
26
+ debug "#{r.name} on #{r.target}:#{r.port}"
27
+
28
+ address = nil
29
+ addr_service.getaddrinfo r.target do |addrinfo|
30
+ address = addrinfo.address
31
+ break
32
+ end
33
+
34
+ debug "first address for #{r.target} is #{address}"
35
+ return address
36
+ end
37
+ end
38
+
39
+ def browse_for_franks_address
40
+ require 'dnssd'
41
+
42
+ DNSSD.browse! '_http._tcp.' do |reply|
43
+ debug 'got a reply'
44
+ if reply.name == FRANK_SERVICE_NAME
45
+ address = found_a_frank(reply)
46
+ if address
47
+ debug "OK WE HAVE AN ADDRESS: #{address}"
48
+ return address
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def lookup_frank_base_uri
55
+ puts "finding Frank server via Bonjour..."
56
+ address = begin
57
+ Timeout::timeout(LOOKUP_TIMEOUT){ address = browse_for_franks_address }
58
+ rescue Timeout::Error
59
+ puts "could not find Frank within #{LOOKUP_TIMEOUT} seconds"
60
+ end
61
+
62
+ if address
63
+ puts "...found Frank via Bonjour: #{address}"
64
+ return URI::HTTP.new( 'http', nil, address, FRANK_PORT, nil, nil, nil, nil, nil )
65
+ else
66
+ puts '...failed to find Frank server via Bonjour'
67
+ return nil
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ end end
@@ -0,0 +1,299 @@
1
+ begin
2
+ require 'pry'
3
+ rescue LoadError
4
+ end
5
+
6
+ require 'thor'
7
+ require 'frank-cucumber/launcher'
8
+ require 'frank-cucumber/console'
9
+ require 'frank-cucumber/frankifier'
10
+ require 'frank-cucumber/mac_launcher'
11
+ require 'frank-cucumber/plugins/plugin'
12
+
13
+ module Frank
14
+ class CLI < Thor
15
+ include Thor::Actions
16
+
17
+ def self.source_root
18
+ File.join( File.dirname(__FILE__), '..','..','frank-skeleton' )
19
+ end
20
+
21
+ # included just because the old setup script was called frank-skeleton
22
+ desc "skeleton", "an alias for setup"
23
+ def skeleton
24
+ invoke :setup
25
+ end
26
+
27
+ WITHOUT_SERVER = "without-cocoa-http-server"
28
+ WITHOUT_ASYNC_SOCKET = "without-cocoa-async-socket"
29
+ WITHOUT_LUMBERJACK = "without-cocoa-lumberjack"
30
+ desc "setup", "set up your iOS app by adding a Frank subdirectory containing everything Frank needs"
31
+ method_option WITHOUT_SERVER, :type => :boolean
32
+ method_option WITHOUT_ASYNC_SOCKET, :type => :boolean
33
+ method_option WITHOUT_LUMBERJACK, :type => :boolean
34
+ method_option :build_configuration, :aliases=>'--conf', :type=>:string, :default => 'Debug'
35
+ method_option :target, :type=>:string
36
+ method_option :project, :type=>:string
37
+ def setup
38
+ @libs = %w(Shelley CocoaAsyncSocket CocoaLumberjack CocoaHTTPServer Frank)
39
+ @libsMac = %w(ShelleyMac CocoaAsyncSocketMac CocoaLumberjackMac CocoaHTTPServerMac FrankMac)
40
+ @libs -= %w(CocoaHTTPServer) if options[WITHOUT_SERVER]
41
+ @libsMac -= %w(CocoaHTTPServerMac) if options[WITHOUT_SERVER]
42
+ @libs -= %w(CocoaAsyncSocket) if options[WITHOUT_ASYNC_SOCKET]
43
+ @libsMac -= %w(CocoaAsyncSocketMac) if options[WITHOUT_ASYNC_SOCKET]
44
+ @libs -= %w(CocoaLumberjack) if options[WITHOUT_LUMBERJACK]
45
+ @libsMac -= %w(CocoaLumberjackMac) if options[WITHOUT_LUMBERJACK]
46
+ directory ".", "Frank"
47
+
48
+ Frankifier.frankify!( File.expand_path('.'), :build_config => options[:build_configuration], :target => options[:target], :project => options[:project] )
49
+ end
50
+
51
+ desc "update", "updates the frank server components inside your Frank directory"
52
+ long_desc "This updates the parts of Frank that are embedded inside your app (e.g. libFrank.a and frank_static_resources.bundle)"
53
+ def update
54
+ %w{libFrank.a libCocoaAsyncSocket.a libCocoaLumberjack.a libCocoaHTTPServer.a libShelley.a libFrankMac.a libShelleyMac.a libCocoaAsyncSocketMac.a libCocoaLumberjackMac.a libCocoaHTTPServerMac.a}.each do |f|
55
+ copy_file f, File.join( 'Frank', f ), :force => true
56
+ end
57
+ directory( 'frank_static_resources.bundle', 'Frank/frank_static_resources.bundle', :force => true )
58
+
59
+ if yes? "\nOne or more static libraries may have been updated. For these changes to take effect the 'frankified_build' directory must be cleaned. Would you like me to do that now? Type 'y' or 'yes' to delete the contents of frankified_build."
60
+ remove_file('Frank/frankified_build')
61
+ end
62
+ end
63
+
64
+ XCODEBUILD_OPTIONS = %w{workspace project scheme target configuration}
65
+ desc "build [<buildsetting>=<value>]...", "builds a Frankified version of your native app"
66
+ XCODEBUILD_OPTIONS.each do |option|
67
+ method_option option
68
+ end
69
+
70
+ WITHOUT_DEPS = 'without-dependencies'
71
+ method_option 'no-plugins', :type => :boolean, :default => false, :aliases => '--np', :desc => 'Disable plugins'
72
+ method_option 'arch', :type => :string, :default => 'i386'
73
+ method_option 'mac', :type => :string, :default => false
74
+ method_option :noclean, :type => :boolean, :default => false, :aliases => '--nc', :desc => "Don't clean the build directory before building"
75
+ method_option WITHOUT_DEPS, :type => :array, :desc => 'An array (space separated list) of plugin dependencies to exclude'
76
+ def build(*args)
77
+ clean = !options['noclean']
78
+ use_plugins = !options['no-plugins']
79
+ exclude_dependencies = options[WITHOUT_DEPS] || []
80
+
81
+ in_root do
82
+ unless File.directory? 'Frank'
83
+ if yes? "You don't appear to have set up a Frank directory for this project. Would you like me to set that up now? Type 'y' or 'yes' if so."
84
+ invoke :skeleton
85
+ else
86
+ say "OK, in that case there's not much I can do for now. Whenever you change your mind and want to get your project setup with Frank simply run `frank setup` from the root of your project directory."
87
+ say "Bye bye for now!"
88
+ exit 11
89
+ end
90
+ end
91
+ end
92
+
93
+ static_bundle = 'frank_static_resources.bundle'
94
+
95
+ if clean
96
+ remove_dir build_output_dir
97
+ end
98
+
99
+ build_steps = 'build'
100
+ if clean
101
+ build_steps = 'clean ' + build_steps
102
+ end
103
+
104
+ plugins = use_plugins ? gather_plugins : []
105
+
106
+ say "Detected plugins: #{plugins.map {|p| p.name}.join(', ')}" unless plugins.empty?
107
+
108
+ say "Excluding plugin dependencies: #{exclude_dependencies.join(', ')}" unless exclude_dependencies.empty?
109
+
110
+ plugins.each {|plugin| plugin.write_xcconfig(exclude_dependencies)}
111
+
112
+ xcconfig_data = Frank::Plugins::Plugin.generate_core_xcconfig(plugins)
113
+
114
+ xcconfig_file = 'Frank/frank.xcconfig'
115
+ File.open(xcconfig_file,'w') {|f| f.write(xcconfig_data) }
116
+
117
+ extra_opts = XCODEBUILD_OPTIONS.map{ |o| "-#{o} \"#{options[o]}\"" if options[o] and (o != "target" or options['workspace'] == nil)}.compact.join(' ')
118
+
119
+ # If there is a scheme specified we don't want to inject the default configuration
120
+ # If there is a configuration specified, we also do not want to inject the default configuration
121
+ if options['scheme'] || options['configuration']
122
+ separate_configuration_option = ""
123
+ else
124
+ separate_configuration_option = "-configuration Debug"
125
+ end
126
+
127
+ xcodebuild_args = args.join(" ")
128
+
129
+ if options['mac']
130
+ run %Q|xcodebuild -xcconfig #{xcconfig_file} #{build_steps} #{extra_opts} #{separate_configuration_option} DEPLOYMENT_LOCATION=YES DSTROOT="#{build_output_dir}" FRANK_LIBRARY_SEARCH_PATHS="#{frank_lib_search_paths}" #{xcodebuild_args}|
131
+ else
132
+ extra_opts += " -arch #{options['arch']}"
133
+
134
+ run %Q|xcodebuild -xcconfig #{xcconfig_file} #{build_steps} #{extra_opts} #{separate_configuration_option} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO DEPLOYMENT_LOCATION=YES DSTROOT="#{build_output_dir}" FRANK_LIBRARY_SEARCH_PATHS="#{frank_lib_search_paths}" #{xcodebuild_args}|
135
+ end
136
+ exit $?.exitstatus if not $?.success?
137
+
138
+ app = Dir.glob("#{build_output_dir}/*.app").delete_if { |x| x =~ /\/#{app_bundle_name}$/ }
139
+ app = app.first
140
+ FileUtils.cp_r("#{app}/.", frankified_app_dir)
141
+
142
+ if options['mac']
143
+ in_root do
144
+ FileUtils.cp_r(
145
+ File.join( 'Frank',static_bundle),
146
+ File.join( frankified_app_dir, "Contents", "Resources", static_bundle )
147
+ )
148
+ end
149
+ else
150
+ fix_frankified_apps_bundle_identifier
151
+
152
+ in_root do
153
+ FileUtils.cp_r(
154
+ File.join( 'Frank',static_bundle),
155
+ File.join( frankified_app_dir, static_bundle )
156
+ )
157
+ end
158
+ end
159
+ end
160
+
161
+ desc "build_and_launch", "rebuild a Frankfied version of your app then launch"
162
+ def build_and_launch
163
+ invoke :build
164
+ invoke :launch
165
+ end
166
+
167
+ desc "launch", "open the Frankified app in the simulator"
168
+ method_option :debug, :type => :boolean, :default => false
169
+ method_option :idiom, :banner => 'iphone|ipad', :type => :string, :default => (ENV['FRANK_SIM_IDIOM'] || 'iphone')
170
+ def launch
171
+ $DEBUG = options[:debug]
172
+ launcher = case options[:idiom].downcase
173
+ when 'iphone'
174
+ SimLauncher::DirectClient.for_iphone_app( frankified_app_dir )
175
+ when 'ipad'
176
+ SimLauncher::DirectClient.for_ipad_app( frankified_app_dir )
177
+ else
178
+ say "idiom must be either iphone or ipad. You supplied '#{options[:idiom]}'", :red
179
+ exit 10
180
+ end
181
+
182
+ in_root do
183
+ unless File.exists? frankified_app_dir
184
+ say "A Frankified version of the app doesn't appear to have been built. Building one now"
185
+ say "..."
186
+ invoke :build
187
+ end
188
+
189
+ if built_product_is_mac_app( frankified_app_dir )
190
+ launcher = Frank::MacLauncher.new( frankified_app_dir )
191
+ say "LAUNCHING APP..."
192
+ else
193
+ say "LAUNCHING IN THE SIMULATOR..."
194
+ end
195
+
196
+ launcher.relaunch
197
+ end
198
+ end
199
+
200
+ desc "inspect", "launch Symbiote in the browser"
201
+ long_desc "launch Symbiote in the browser so you can inspect the live state of your Frankified app"
202
+ def inspect
203
+ # TODO: check whether app is running (using ps or similar), and launch it if it's not
204
+ run 'open http://localhost:37265'
205
+ end
206
+
207
+ desc 'console', "launch a ruby console connected to your Frankified app"
208
+ method_option :bonjour, :type => :boolean, :default => false, :aliases => :b, :desc => "find Frank via Bonjour."
209
+ method_option :server, :type => :string, :default => false, :aliases => :s, :desc => "server URL for Frank."
210
+ def console
211
+ # TODO: check whether app is running (using ps or similar), and launch it if it's not
212
+
213
+ begin
214
+ require 'pry'
215
+ rescue LoadError
216
+ say 'The Frank console requires the pry gem.'
217
+ say 'Simply run `sudo gem install pry` (the `sudo` bit might be optional), and then try again. Thanks!'
218
+ exit 41
219
+ end
220
+
221
+ Frank::Cucumber::FrankHelper.use_shelley_from_now_on
222
+ console = Frank::Console.new
223
+ Frank::Cucumber::FrankHelper.test_on_physical_device_via_bonjour if options[:bonjour]
224
+ Frank::Cucumber::FrankHelper.server_base_url = options[:server] if options[:server]
225
+ if console.check_for_running_app
226
+ console.pry
227
+ end
228
+ end
229
+
230
+ private
231
+
232
+ def product_name
233
+ "Frankified"
234
+ end
235
+
236
+ def app_bundle_name
237
+ "#{product_name}.app"
238
+ end
239
+
240
+ def frank_lib_directory
241
+ File.expand_path "Frank"
242
+ end
243
+
244
+ def frank_lib_search_paths
245
+ paths = [frank_lib_directory]
246
+ each_plugin_path do |path|
247
+ paths << path
248
+ end
249
+
250
+ paths.map {|path| %Q[\\"#{path}\\"]}.join(' ')
251
+ end
252
+
253
+ def build_output_dir
254
+ File.expand_path "Frank/frankified_build"
255
+ end
256
+
257
+ def frankified_app_dir
258
+ File.join( build_output_dir, app_bundle_name )
259
+ end
260
+
261
+ def plugin_dir
262
+ File.expand_path 'Frank/plugins'
263
+ end
264
+
265
+ def built_product_is_mac_app ( app_dir )
266
+ return File.exists? File.join( app_dir, "Contents", "MacOS" )
267
+ end
268
+
269
+ def fix_frankified_apps_bundle_identifier
270
+ # as of iOS 6 the iOS Simulator locks up with a black screen if you try and launch an app which has the same
271
+ # bundle identifier as a previously installed app but which is in fact a different app. This impacts us because our
272
+ # Frankified app is different but has the same bundle identifier as the standard non-Frankified app which most users
273
+ # will want to have installed in the simulator as well.
274
+ #
275
+ # We work around this by modifying the Frankified app's bundle identifier inside its Info.plist.
276
+ inside frankified_app_dir do
277
+ existing_bundle_identifier = `/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' Info.plist`.chomp
278
+ new_bundle_identifier = existing_bundle_identifier + '.frankified'
279
+ run %Q|/usr/libexec/PlistBuddy -c 'Set :CFBundleIdentifier #{new_bundle_identifier}' Info.plist|
280
+ run %Q|/usr/libexec/PlistBuddy -c 'Set :CFBundleDisplayName Frankified' Info.plist|
281
+ end
282
+ end
283
+
284
+ def each_plugin_path(&block)
285
+ plugin_glob = File.join("#{plugin_dir}",'*')
286
+ Dir[plugin_glob].map do |plugin_path|
287
+ yield plugin_path
288
+ end
289
+ end
290
+
291
+ def gather_plugins
292
+ each_plugin_path do |plugin_path|
293
+ Frank::Plugins::Plugin.from_plugin_directory(plugin_path)
294
+ end
295
+ end
296
+
297
+ end
298
+ end
299
+