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.
- 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
|
+
|