sc-frank-cucumber 1.2.1.00af28c
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +38 -0
- data/bin/frank +6 -0
- data/bin/frank-skeleton +33 -0
- data/frank-skeleton/features/my_first.feature +12 -0
- data/frank-skeleton/features/step_definitions/launch_steps.rb +20 -0
- data/frank-skeleton/features/support/env.rb +8 -0
- data/frank-skeleton/frank_static_resources.bundle/ViewAttributeMapping.plist +63 -0
- data/frank-skeleton/frank_static_resources.bundle/ViewAttributeMappingMac.plist +99 -0
- data/frank-skeleton/frank_static_resources.bundle/images/ajax-loader.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/file.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/folder-closed.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/folder.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/loader.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/loader.png +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/minus.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/plus.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-black-line.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-black.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-default-line.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-default.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-famfamfam-line.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-famfamfam.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-gray-line.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-gray.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-red-line.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/images/treeview-red.gif +0 -0
- data/frank-skeleton/frank_static_resources.bundle/index.html +86 -0
- data/frank-skeleton/frank_static_resources.bundle/index.html.haml +76 -0
- data/frank-skeleton/frank_static_resources.bundle/js/accessible_views_view.coffee +41 -0
- data/frank-skeleton/frank_static_resources.bundle/js/accessible_views_view.js +46 -0
- data/frank-skeleton/frank_static_resources.bundle/js/controller.coffee +134 -0
- data/frank-skeleton/frank_static_resources.bundle/js/controller.js +139 -0
- data/frank-skeleton/frank_static_resources.bundle/js/details_view.coffee +42 -0
- data/frank-skeleton/frank_static_resources.bundle/js/details_view.js +51 -0
- data/frank-skeleton/frank_static_resources.bundle/js/dropdown_control.coffee +64 -0
- data/frank-skeleton/frank_static_resources.bundle/js/dropdown_control.js +73 -0
- data/frank-skeleton/frank_static_resources.bundle/js/ersatz_model.coffee +46 -0
- data/frank-skeleton/frank_static_resources.bundle/js/ersatz_model.js +60 -0
- data/frank-skeleton/frank_static_resources.bundle/js/ersatz_view.coffee +167 -0
- data/frank-skeleton/frank_static_resources.bundle/js/ersatz_view.js +205 -0
- data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_model.coffee +10 -0
- data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_model.js +17 -0
- data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_view.coffee +44 -0
- data/frank-skeleton/frank_static_resources.bundle/js/experiment_bar_view.js +63 -0
- data/frank-skeleton/frank_static_resources.bundle/js/frank.coffee +96 -0
- data/frank-skeleton/frank_static_resources.bundle/js/frank.js +146 -0
- data/frank-skeleton/frank_static_resources.bundle/js/lib/backbone.js +1431 -0
- data/frank-skeleton/frank_static_resources.bundle/js/lib/coffee-script.js +8 -0
- data/frank-skeleton/frank_static_resources.bundle/js/lib/jquery-ui.min.js +405 -0
- data/frank-skeleton/frank_static_resources.bundle/js/lib/jquery.min.js +4 -0
- data/frank-skeleton/frank_static_resources.bundle/js/lib/jquery.treeview.js +251 -0
- data/frank-skeleton/frank_static_resources.bundle/js/lib/json2.js +481 -0
- data/frank-skeleton/frank_static_resources.bundle/js/lib/raphael.js +5815 -0
- data/frank-skeleton/frank_static_resources.bundle/js/lib/require.js +2053 -0
- data/frank-skeleton/frank_static_resources.bundle/js/lib/underscore.js +1059 -0
- data/frank-skeleton/frank_static_resources.bundle/js/main.coffee +27 -0
- data/frank-skeleton/frank_static_resources.bundle/js/main.js +29 -0
- data/frank-skeleton/frank_static_resources.bundle/js/tabs_controller.coffee +13 -0
- data/frank-skeleton/frank_static_resources.bundle/js/tabs_controller.js +22 -0
- data/frank-skeleton/frank_static_resources.bundle/js/toast_controller.coffee +15 -0
- data/frank-skeleton/frank_static_resources.bundle/js/toast_controller.js +28 -0
- data/frank-skeleton/frank_static_resources.bundle/js/transform_stack.coffee +59 -0
- data/frank-skeleton/frank_static_resources.bundle/js/transform_stack.js +78 -0
- data/frank-skeleton/frank_static_resources.bundle/js/tree_view.coffee +53 -0
- data/frank-skeleton/frank_static_resources.bundle/js/tree_view.js +64 -0
- data/frank-skeleton/frank_static_resources.bundle/js/view_hier_model.coffee +37 -0
- data/frank-skeleton/frank_static_resources.bundle/js/view_hier_model.js +48 -0
- data/frank-skeleton/frank_static_resources.bundle/js/view_model.coffee +39 -0
- data/frank-skeleton/frank_static_resources.bundle/js/view_model.js +62 -0
- data/frank-skeleton/frank_static_resources.bundle/pictos/index.html +329 -0
- data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.eot +0 -0
- data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.svg +114 -0
- data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.ttf +0 -0
- data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.woff +0 -0
- data/frank-skeleton/frank_static_resources.bundle/pictos/pictos.css +20 -0
- data/frank-skeleton/frank_static_resources.bundle/pictos/pictos_base64.css +18 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/css/symbiote.css +1 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_elements.scss +28 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_header.scss +61 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_inspect_tabs_list_tabs.scss +194 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_jquery.treeview.scss +68 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_jqui.scss +2 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_layout.scss +13 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_mixins.sass +137 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_reset.scss +32 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_selector_test_toolbar.scss +81 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_solarized.scss +16 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_typography.scss +11 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_unicode.scss +3 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_z_index.scss +2 -0
- data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/symbiote.scss +26 -0
- data/frank-skeleton/frankify.xcconfig.tt +6 -0
- data/frank-skeleton/libCocoaAsyncSocket.a +0 -0
- data/frank-skeleton/libCocoaAsyncSocketMac.a +0 -0
- data/frank-skeleton/libCocoaHTTPServer.a +0 -0
- data/frank-skeleton/libCocoaHTTPServerMac.a +0 -0
- data/frank-skeleton/libCocoaLumberjack.a +0 -0
- data/frank-skeleton/libCocoaLumberjackMac.a +0 -0
- data/frank-skeleton/libFrank.a +0 -0
- data/frank-skeleton/libFrankMac.a +0 -0
- data/frank-skeleton/libShelley.a +0 -0
- data/frank-skeleton/libShelleyMac.a +0 -0
- data/frank-skeleton/plugins/.empty_directory +0 -0
- data/lib/frank-cucumber.rb +15 -0
- data/lib/frank-cucumber/app_bundle_locator.rb +58 -0
- data/lib/frank-cucumber/bonjour.rb +73 -0
- data/lib/frank-cucumber/cli.rb +299 -0
- data/lib/frank-cucumber/color_helper.rb +13 -0
- data/lib/frank-cucumber/console.rb +28 -0
- data/lib/frank-cucumber/core_frank_steps.rb +260 -0
- data/lib/frank-cucumber/frank.xcconfig.erb +17 -0
- data/lib/frank-cucumber/frank_helper.rb +459 -0
- data/lib/frank-cucumber/frank_localize.rb +43 -0
- data/lib/frank-cucumber/frank_mac_helper.rb +120 -0
- data/lib/frank-cucumber/frankifier.rb +150 -0
- data/lib/frank-cucumber/gateway.rb +135 -0
- data/lib/frank-cucumber/gesture_helper.rb +99 -0
- data/lib/frank-cucumber/host_scripting.rb +96 -0
- data/lib/frank-cucumber/keyboard_helper.rb +69 -0
- data/lib/frank-cucumber/launcher.rb +70 -0
- data/lib/frank-cucumber/localize.yml +104 -0
- data/lib/frank-cucumber/location_helper.rb +20 -0
- data/lib/frank-cucumber/mac_launcher.rb +35 -0
- data/lib/frank-cucumber/plugins/plugin.rb +57 -0
- data/lib/frank-cucumber/rect.rb +26 -0
- data/lib/frank-cucumber/scroll_helper.rb +24 -0
- data/lib/frank-cucumber/version.rb +5 -0
- data/lib/frank-cucumber/wait_helper.rb +57 -0
- data/sc-frank-cucumber.gemspec +37 -0
- data/test/keyboard_helper_test.rb +84 -0
- data/test/launcher_test.rb +57 -0
- data/test/rect_test.rb +25 -0
- data/test/test_helper.rb +16 -0
- 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
|
+
}
|
data/frank-skeleton/frank_static_resources.bundle/stylesheets/sass/_selector_test_toolbar.scss
ADDED
@@ -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,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
|
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
|
+
|