sc-frank-ios 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/Gemfile +4 -0
  4. data/Rakefile +38 -0
  5. data/bin/frank +6 -0
  6. data/bin/frank-skeleton +33 -0
  7. data/frank-skeleton/features/my_first.feature +12 -0
  8. data/frank-skeleton/features/step_definitions/launch_steps.rb +20 -0
  9. data/frank-skeleton/features/support/env.rb +8 -0
  10. data/frank-skeleton/frank_static_resources.bundle/ViewAttributeMapping.plist +63 -0
  11. data/frank-skeleton/frank_static_resources.bundle/ViewAttributeMappingMac.plist +99 -0
  12. data/frank-skeleton/frank_static_resources.bundle/images/ajax-loader.gif +0 -0
  13. data/frank-skeleton/frank_static_resources.bundle/images/file.gif +0 -0
  14. data/frank-skeleton/frank_static_resources.bundle/images/folder-closed.gif +0 -0
  15. data/frank-skeleton/frank_static_resources.bundle/images/folder.gif +0 -0
  16. data/frank-skeleton/frank_static_resources.bundle/images/loader.gif +0 -0
  17. data/frank-skeleton/frank_static_resources.bundle/images/loader.png +0 -0
  18. data/frank-skeleton/frank_static_resources.bundle/images/minus.gif +0 -0
  19. data/frank-skeleton/frank_static_resources.bundle/images/plus.gif +0 -0
  20. data/frank-skeleton/frank_static_resources.bundle/images/treeview-black-line.gif +0 -0
  21. data/frank-skeleton/frank_static_resources.bundle/images/treeview-black.gif +0 -0
  22. data/frank-skeleton/frank_static_resources.bundle/images/treeview-default-line.gif +0 -0
  23. data/frank-skeleton/frank_static_resources.bundle/images/treeview-default.gif +0 -0
  24. data/frank-skeleton/frank_static_resources.bundle/images/treeview-famfamfam-line.gif +0 -0
  25. data/frank-skeleton/frank_static_resources.bundle/images/treeview-famfamfam.gif +0 -0
  26. data/frank-skeleton/frank_static_resources.bundle/images/treeview-gray-line.gif +0 -0
  27. data/frank-skeleton/frank_static_resources.bundle/images/treeview-gray.gif +0 -0
  28. data/frank-skeleton/frank_static_resources.bundle/images/treeview-red-line.gif +0 -0
  29. data/frank-skeleton/frank_static_resources.bundle/images/treeview-red.gif +0 -0
  30. data/frank-skeleton/frank_static_resources.bundle/index.html +86 -0
  31. data/frank-skeleton/frank_static_resources.bundle/index.html.haml +76 -0
  32. data/frank-skeleton/frank_static_resources.bundle/js/accessible_views_view.coffee +41 -0
  33. data/frank-skeleton/frank_static_resources.bundle/js/accessible_views_view.js +46 -0
  34. data/frank-skeleton/frank_static_resources.bundle/js/controller.coffee +134 -0
  35. data/frank-skeleton/frank_static_resources.bundle/js/controller.js +139 -0
  36. data/frank-skeleton/frank_static_resources.bundle/js/details_view.coffee +42 -0
  37. data/frank-skeleton/frank_static_resources.bundle/js/details_view.js +51 -0
  38. data/frank-skeleton/frank_static_resources.bundle/js/dropdown_control.coffee +64 -0
  39. data/frank-skeleton/frank_static_resources.bundle/js/dropdown_control.js +73 -0
  40. data/frank-skeleton/frank_static_resources.bundle/js/ersatz_model.coffee +46 -0
  41. data/frank-skeleton/frank_static_resources.bundle/js/ersatz_model.js +60 -0
  42. data/frank-skeleton/frank_static_resources.bundle/js/ersatz_view.coffee +167 -0
  43. data/frank-skeleton/frank_static_resources.bundle/js/ersatz_view.js +205 -0
  44. data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_model.coffee +10 -0
  45. data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_model.js +17 -0
  46. data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_view.coffee +44 -0
  47. data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_view.js +63 -0
  48. data/frank-skeleton/frank_static_resources.bundle/js/frank.coffee +96 -0
  49. data/frank-skeleton/frank_static_resources.bundle/js/frank.js +146 -0
  50. data/frank-skeleton/frank_static_resources.bundle/js/lib/backbone.js +1431 -0
  51. data/frank-skeleton/frank_static_resources.bundle/js/lib/coffee-script.js +8 -0
  52. data/frank-skeleton/frank_static_resources.bundle/js/lib/jquery-ui.min.js +405 -0
  53. data/frank-skeleton/frank_static_resources.bundle/js/lib/jquery.min.js +4 -0
  54. data/frank-skeleton/frank_static_resources.bundle/js/lib/jquery.treeview.js +251 -0
  55. data/frank-skeleton/frank_static_resources.bundle/js/lib/json2.js +481 -0
  56. data/frank-skeleton/frank_static_resources.bundle/js/lib/raphael.js +5815 -0
  57. data/frank-skeleton/frank_static_resources.bundle/js/lib/require.js +2053 -0
  58. data/frank-skeleton/frank_static_resources.bundle/js/lib/underscore.js +1059 -0
  59. data/frank-skeleton/frank_static_resources.bundle/js/main.coffee +27 -0
  60. data/frank-skeleton/frank_static_resources.bundle/js/main.js +29 -0
  61. data/frank-skeleton/frank_static_resources.bundle/js/tabs_controller.coffee +13 -0
  62. data/frank-skeleton/frank_static_resources.bundle/js/tabs_controller.js +22 -0
  63. data/frank-skeleton/frank_static_resources.bundle/js/toast_controller.coffee +15 -0
  64. data/frank-skeleton/frank_static_resources.bundle/js/toast_controller.js +28 -0
  65. data/frank-skeleton/frank_static_resources.bundle/js/transform_stack.coffee +59 -0
  66. data/frank-skeleton/frank_static_resources.bundle/js/transform_stack.js +78 -0
  67. data/frank-skeleton/frank_static_resources.bundle/js/tree_view.coffee +53 -0
  68. data/frank-skeleton/frank_static_resources.bundle/js/tree_view.js +64 -0
  69. data/frank-skeleton/frank_static_resources.bundle/js/view_hier_model.coffee +37 -0
  70. data/frank-skeleton/frank_static_resources.bundle/js/view_hier_model.js +48 -0
  71. data/frank-skeleton/frank_static_resources.bundle/js/view_model.coffee +39 -0
  72. data/frank-skeleton/frank_static_resources.bundle/js/view_model.js +62 -0
  73. data/frank-skeleton/frank_static_resources.bundle/pictos/index.html +329 -0
  74. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.eot +0 -0
  75. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.svg +114 -0
  76. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.ttf +0 -0
  77. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.woff +0 -0
  78. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos.css +20 -0
  79. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos_base64.css +18 -0
  80. data/frank-skeleton/frank_static_resources.bundle/stylesheets/css/symbiote.css +1 -0
  81. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_elements.scss +28 -0
  82. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_header.scss +61 -0
  83. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_inspect_tabs_list_tabs.scss +194 -0
  84. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_jquery.treeview.scss +68 -0
  85. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_jqui.scss +2 -0
  86. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_layout.scss +13 -0
  87. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_mixins.sass +137 -0
  88. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_reset.scss +32 -0
  89. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_selector_test_toolbar.scss +81 -0
  90. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_solarized.scss +16 -0
  91. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_typography.scss +11 -0
  92. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_unicode.scss +3 -0
  93. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_z_index.scss +2 -0
  94. data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/symbiote.scss +26 -0
  95. data/frank-skeleton/frankify.xcconfig.tt +6 -0
  96. data/frank-skeleton/libCocoaAsyncSocket.a +0 -0
  97. data/frank-skeleton/libCocoaAsyncSocketMac.a +0 -0
  98. data/frank-skeleton/libCocoaHTTPServer.a +0 -0
  99. data/frank-skeleton/libCocoaHTTPServerMac.a +0 -0
  100. data/frank-skeleton/libCocoaLumberjack.a +0 -0
  101. data/frank-skeleton/libCocoaLumberjackMac.a +0 -0
  102. data/frank-skeleton/libFrank.a +0 -0
  103. data/frank-skeleton/libFrankMac.a +0 -0
  104. data/frank-skeleton/libShelley.a +0 -0
  105. data/frank-skeleton/libShelleyMac.a +0 -0
  106. data/frank-skeleton/plugins/.empty_directory +0 -0
  107. data/lib/frank-cucumber.rb +15 -0
  108. data/lib/frank-cucumber/app_bundle_locator.rb +58 -0
  109. data/lib/frank-cucumber/bonjour.rb +73 -0
  110. data/lib/frank-cucumber/cli.rb +299 -0
  111. data/lib/frank-cucumber/color_helper.rb +13 -0
  112. data/lib/frank-cucumber/console.rb +28 -0
  113. data/lib/frank-cucumber/core_frank_steps.rb +260 -0
  114. data/lib/frank-cucumber/frank.xcconfig.erb +17 -0
  115. data/lib/frank-cucumber/frank_helper.rb +486 -0
  116. data/lib/frank-cucumber/frank_localize.rb +43 -0
  117. data/lib/frank-cucumber/frank_mac_helper.rb +120 -0
  118. data/lib/frank-cucumber/frankifier.rb +153 -0
  119. data/lib/frank-cucumber/gateway.rb +135 -0
  120. data/lib/frank-cucumber/gesture_helper.rb +99 -0
  121. data/lib/frank-cucumber/host_scripting.rb +96 -0
  122. data/lib/frank-cucumber/keyboard_helper.rb +69 -0
  123. data/lib/frank-cucumber/launcher.rb +70 -0
  124. data/lib/frank-cucumber/localize.yml +104 -0
  125. data/lib/frank-cucumber/location_helper.rb +20 -0
  126. data/lib/frank-cucumber/mac_launcher.rb +35 -0
  127. data/lib/frank-cucumber/plugins/plugin.rb +57 -0
  128. data/lib/frank-cucumber/rect.rb +26 -0
  129. data/lib/frank-cucumber/scroll_helper.rb +24 -0
  130. data/lib/frank-cucumber/version.rb +5 -0
  131. data/lib/frank-cucumber/wait_helper.rb +57 -0
  132. data/sc-frank-cucumber.gemspec +37 -0
  133. data/test/keyboard_helper_test.rb +84 -0
  134. data/test/launcher_test.rb +57 -0
  135. data/test/rect_test.rb +25 -0
  136. data/test/test_helper.rb +16 -0
  137. metadata +367 -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 = $(inherited) FRANKIFIED=1
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
+