branch_io_cli 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/assets/patches/ContinueUserActivity.m +4 -0
  3. data/lib/assets/patches/ContinueUserActivity.swift +4 -0
  4. data/lib/assets/patches/ContinueUserActivityNew.m +6 -0
  5. data/lib/assets/patches/ContinueUserActivityNew.swift +5 -0
  6. data/lib/assets/patches/DidFinishLaunching.m +4 -0
  7. data/lib/assets/patches/DidFinishLaunching.swift +5 -0
  8. data/lib/assets/patches/DidFinishLaunchingNew.m +9 -0
  9. data/lib/assets/patches/DidFinishLaunchingNew.swift +9 -0
  10. data/lib/assets/patches/DidFinishLaunchingNewTest.m +13 -0
  11. data/lib/assets/patches/DidFinishLaunchingNewTest.swift +13 -0
  12. data/lib/assets/patches/DidFinishLaunchingTest.m +8 -0
  13. data/lib/assets/patches/DidFinishLaunchingTest.swift +9 -0
  14. data/lib/assets/patches/OpenUrl.m +4 -0
  15. data/lib/assets/patches/OpenUrl.swift +4 -0
  16. data/lib/assets/patches/OpenUrlNew.m +6 -0
  17. data/lib/assets/patches/OpenUrlNew.swift +5 -0
  18. data/lib/assets/patches/OpenUrlSourceApplication.m +4 -0
  19. data/lib/assets/patches/OpenUrlSourceApplication.swift +4 -0
  20. data/lib/assets/patches/cartfile.yml +3 -0
  21. data/lib/assets/patches/continue_user_activity_new_objc.yml +2 -0
  22. data/lib/assets/patches/continue_user_activity_new_swift.yml +2 -0
  23. data/lib/assets/patches/continue_user_activity_objc.yml +2 -0
  24. data/lib/assets/patches/continue_user_activity_swift.yml +2 -0
  25. data/lib/assets/patches/did_finish_launching_new_objc.yml +2 -0
  26. data/lib/assets/patches/did_finish_launching_new_swift.yml +2 -0
  27. data/lib/assets/patches/did_finish_launching_new_test_objc.yml +2 -0
  28. data/lib/assets/patches/did_finish_launching_new_test_swift.yml +2 -0
  29. data/lib/assets/patches/did_finish_launching_objc.yml +2 -0
  30. data/lib/assets/patches/did_finish_launching_swift.yml +2 -0
  31. data/lib/assets/patches/did_finish_launching_test_objc.yml +2 -0
  32. data/lib/assets/patches/did_finish_launching_test_swift.yml +2 -0
  33. data/lib/assets/patches/objc_import.yml +3 -0
  34. data/lib/assets/patches/open_url_new_objc.yml +2 -0
  35. data/lib/assets/patches/open_url_new_swift.yml +2 -0
  36. data/lib/assets/patches/open_url_objc.yml +2 -0
  37. data/lib/assets/patches/open_url_source_application_objc.yml +2 -0
  38. data/lib/assets/patches/open_url_source_application_swift.yml +2 -0
  39. data/lib/assets/patches/open_url_swift.yml +2 -0
  40. data/lib/assets/patches/swift_import.yml +3 -0
  41. data/lib/branch_io_cli.rb +2 -1
  42. data/lib/branch_io_cli/cli.rb +3 -3
  43. data/lib/branch_io_cli/command.rb +4 -0
  44. data/lib/branch_io_cli/{commands → command}/command.rb +4 -3
  45. data/lib/branch_io_cli/{commands → command}/report_command.rb +57 -54
  46. data/lib/branch_io_cli/{commands → command}/setup_command.rb +29 -26
  47. data/lib/branch_io_cli/{commands → command}/validate_command.rb +4 -2
  48. data/lib/branch_io_cli/configuration.rb +4 -0
  49. data/lib/branch_io_cli/configuration/configuration.rb +211 -0
  50. data/lib/branch_io_cli/configuration/report_configuration.rb +164 -0
  51. data/lib/branch_io_cli/configuration/setup_configuration.rb +215 -0
  52. data/lib/branch_io_cli/configuration/validate_configuration.rb +26 -0
  53. data/lib/branch_io_cli/core_ext/io.rb +2 -2
  54. data/lib/branch_io_cli/helper.rb +1 -1
  55. data/lib/branch_io_cli/helper/branch_helper.rb +0 -16
  56. data/lib/branch_io_cli/helper/ios_helper.rb +87 -468
  57. data/lib/branch_io_cli/helper/methods.rb +1 -1
  58. data/lib/branch_io_cli/helper/patch_helper.rb +267 -0
  59. data/lib/branch_io_cli/version.rb +1 -1
  60. metadata +55 -11
  61. data/lib/branch_io_cli/commands.rb +0 -4
  62. data/lib/branch_io_cli/helper/configuration_helper.rb +0 -529
@@ -1,13 +1,16 @@
1
1
  require "branch_io_cli/helper/methods"
2
+ require "shellwords"
2
3
 
3
4
  module BranchIOCLI
4
- module Commands
5
+ module Command
5
6
  class SetupCommand < Command
7
+ attr_reader :config
8
+
6
9
  def initialize(options)
7
10
  super
8
- config_helper.validate_setup_options options
9
- @keys = config_helper.keys
10
- @domains = config_helper.all_domains
11
+ @config = Configuration::SetupConfiguration.new options
12
+ @keys = config.keys
13
+ @domains = config.all_domains
11
14
  end
12
15
 
13
16
  # rubocop: disable Metrics/PerceivedComplexity
@@ -15,26 +18,9 @@ module BranchIOCLI
15
18
  # Make sure the user stashes or commits before continuing.
16
19
  check_repo_status
17
20
 
18
- xcodeproj = config_helper.xcodeproj
19
-
20
- case config_helper.sdk_integration_mode
21
- when :cocoapods
22
- if File.exist? config_helper.podfile_path
23
- helper.update_podfile options
24
- else
25
- helper.add_cocoapods options
26
- end
27
- when :carthage
28
- if File.exist? config_helper.cartfile_path
29
- helper.update_cartfile options, xcodeproj
30
- else
31
- helper.add_carthage options
32
- end
33
- when :direct
34
- helper.add_direct options
35
- end
21
+ xcodeproj = config.xcodeproj
36
22
 
37
- is_app_target = !config_helper.target.extension_target_type?
23
+ is_app_target = !config.target.extension_target_type?
38
24
 
39
25
  if is_app_target && options.validate &&
40
26
  !helper.validate_team_and_bundle_ids_from_aasa_files(@domains)
@@ -51,13 +37,30 @@ module BranchIOCLI
51
37
  helper.ensure_uri_scheme_in_info_plist if is_app_target # does nothing if already present
52
38
 
53
39
  new_path = helper.add_universal_links_to_project @domains, false if is_app_target
54
- sh "git add #{new_path}" if options.commit && new_path
40
+ sh "git add #{Shellwords.escape(new_path)}" if options.commit && new_path
55
41
 
56
42
  config_helper.target.add_system_frameworks options.frameworks unless options.frameworks.nil? || options.frameworks.empty?
57
43
 
58
44
  xcodeproj.save
59
45
 
60
- helper.patch_source xcodeproj if options.patch_source
46
+ case config.sdk_integration_mode
47
+ when :cocoapods
48
+ if File.exist? config.podfile_path
49
+ helper.update_podfile options
50
+ else
51
+ helper.add_cocoapods options
52
+ end
53
+ when :carthage
54
+ if File.exist? config.cartfile_path
55
+ helper.update_cartfile options, xcodeproj
56
+ else
57
+ helper.add_carthage options
58
+ end
59
+ when :direct
60
+ helper.add_direct options
61
+ end
62
+
63
+ patch_helper.patch_source xcodeproj if options.patch_source
61
64
 
62
65
  return unless options.commit
63
66
 
@@ -98,7 +101,7 @@ module BranchIOCLI
98
101
  sh "git stash -q"
99
102
  when /^Commit/
100
103
  message = ask "Please enter a commit message: "
101
- sh "git commit -aqm'#{message}'"
104
+ sh "git commit -aqm #{Shellwords.escape(message)}"
102
105
  else
103
106
  say "Please stash or commit your changes before continuing."
104
107
  exit(-1)
@@ -1,9 +1,11 @@
1
1
  module BranchIOCLI
2
- module Commands
2
+ module Command
3
3
  class ValidateCommand < Command
4
+ attr_reader :config
5
+
4
6
  def initialize(options)
5
7
  super
6
- config_helper.validate_validation_options options
8
+ @config = Configuration::ValidateConfiguration.new options
7
9
  end
8
10
 
9
11
  def run!
@@ -0,0 +1,4 @@
1
+ require "branch_io_cli/configuration/configuration"
2
+ require "branch_io_cli/configuration/report_configuration"
3
+ require "branch_io_cli/configuration/setup_configuration"
4
+ require "branch_io_cli/configuration/validate_configuration"
@@ -0,0 +1,211 @@
1
+ require "cocoapods-core"
2
+ require "pathname"
3
+ require "xcodeproj"
4
+
5
+ module BranchIOCLI
6
+ module Configuration
7
+ class Configuration
8
+ class << self
9
+ attr_accessor :current
10
+ end
11
+
12
+ attr_reader :options
13
+ attr_reader :xcodeproj
14
+ attr_reader :xcodeproj_path
15
+ attr_reader :target
16
+ attr_reader :podfile
17
+ attr_reader :podfile_path
18
+ attr_reader :cartfile_path
19
+ attr_reader :sdk_integration_mode
20
+ attr_reader :workspace
21
+ attr_reader :workspace_path
22
+ attr_reader :pod_repo_update
23
+
24
+ def initialize(options)
25
+ @options = options
26
+ @pod_repo_update = options.pod_repo_update
27
+ Configuration.current = self
28
+
29
+ print_identification self.class.name.sub(/^.*::(.*?)Configuration$/, '\1').downcase
30
+ validate_options
31
+ log
32
+ end
33
+
34
+ def validate_options
35
+ # implemented in subclasses
36
+ end
37
+
38
+ def log
39
+ say <<EOF
40
+ <%= color('Configuration:', [CYAN, BOLD, UNDERLINE]) %>
41
+
42
+ EOF
43
+ # subclass implementation follows
44
+ end
45
+
46
+ def print_identification(command)
47
+ say <<EOF
48
+
49
+ <%= color("branch_io #{command} v. #{VERSION}", BOLD) %>
50
+
51
+ EOF
52
+ end
53
+
54
+ def helper
55
+ Helper::BranchHelper
56
+ end
57
+
58
+ # 1. Look for options.xcodeproj.
59
+ # 2. If not specified, look for projects under . (excluding anything in Pods or Carthage folder).
60
+ # 3. If none or more than one found, prompt the user.
61
+ def validate_xcodeproj_path
62
+ if options.xcodeproj
63
+ path = options.xcodeproj
64
+ else
65
+ all_xcodeproj_paths = Dir[File.expand_path(File.join(".", "**/*.xcodeproj"))]
66
+ # find an xcodeproj (ignoring the Pods and Carthage folders)
67
+ # TODO: Improve this filter
68
+ xcodeproj_paths = all_xcodeproj_paths.select do |p|
69
+ valid = true
70
+ Pathname.new(p).each_filename do |f|
71
+ valid = false && break if f == "Carthage" || f == "Pods"
72
+ end
73
+ valid
74
+ end
75
+
76
+ path = xcodeproj_paths.first if xcodeproj_paths.count == 1
77
+ end
78
+
79
+ loop do
80
+ path = ask "Please enter the path to your Xcode project or use --xcodeproj: " if path.nil?
81
+ # TODO: Allow the user to choose if xcodeproj_paths.count > 0
82
+ begin
83
+ @xcodeproj = Xcodeproj::Project.open path
84
+ @xcodeproj_path = path
85
+ return
86
+ rescue StandardError => e
87
+ say e.message
88
+ path = nil
89
+ end
90
+ end
91
+ end
92
+
93
+ def validate_target(allow_extensions = true)
94
+ non_test_targets = xcodeproj.targets.reject(&:test_target_type?)
95
+ raise "No non-test target found in project" if non_test_targets.empty?
96
+
97
+ valid_targets = non_test_targets.reject { |t| !allow_extensions && t.extension_target_type? }
98
+
99
+ begin
100
+ target = helper.target_from_project xcodeproj, options.target
101
+
102
+ # If a test target was explicitly specified.
103
+ raise "Cannot use test targets" if target.test_target_type?
104
+
105
+ # If an extension target was explicitly specified for validation.
106
+ raise "Extension targets not allowed for this command" if !allow_extensions && target.extension_target_type?
107
+
108
+ @target = target
109
+ rescue StandardError => e
110
+ say e.message
111
+
112
+ choice = choose do |menu|
113
+ valid_targets.each { |t| menu.choice t.name }
114
+ menu.prompt = "Which target do you wish to use? "
115
+ end
116
+
117
+ @target = xcodeproj.targets.find { |t| t.name = choice }
118
+ end
119
+ end
120
+
121
+ def validate_buildfile_path(buildfile_path, filename)
122
+ # Disable Podfile/Cartfile update if --no-add-sdk is present
123
+ return unless sdk_integration_mode.nil?
124
+
125
+ # No --podfile or --cartfile option
126
+ if buildfile_path.nil?
127
+ # Check for Podfile/Cartfile next to workspace or project
128
+ buildfile_path = File.expand_path "../#{filename}", (workspace_path || xcodeproj_path)
129
+ return unless File.exist? buildfile_path
130
+ end
131
+
132
+ # Validate. Prompt if not valid.
133
+ while !buildfile_path || !validate_buildfile_at_path(buildfile_path, filename)
134
+ buildfile_path = ask "Please enter the path to your #{filename}: "
135
+ end
136
+
137
+ @sdk_integration_mode = filename == "Podfile" ? :cocoapods : :carthage
138
+ end
139
+
140
+ def open_podfile(path)
141
+ @podfile = Pod::Podfile.from_file path
142
+ @podfile_path = path
143
+ true
144
+ rescue RuntimeError => e
145
+ say e.message
146
+ false
147
+ end
148
+
149
+ def validate_buildfile_at_path(buildfile_path, filename)
150
+ valid = buildfile_path =~ %r{/?#{filename}$}
151
+ say "#{filename} path must end in /#{filename}." unless valid
152
+
153
+ if valid
154
+ valid = File.exist? buildfile_path
155
+ say "#{buildfile_path} not found." unless valid
156
+ end
157
+
158
+ if filename == "Podfile" && open_podfile(buildfile_path)
159
+ true
160
+ elsif filename == "Cartfile"
161
+ @cartfile_path = buildfile_path
162
+ true
163
+ else
164
+ false
165
+ end
166
+ end
167
+
168
+ def uses_frameworks?
169
+ return nil unless podfile
170
+ target_definition = podfile.target_definition_list.find { |t| t.name == target.name }
171
+ return nil unless target_definition
172
+ target_definition.uses_frameworks?
173
+ end
174
+
175
+ def bridging_header_required?
176
+ return false unless swift_version
177
+ # If there is a Podfile and use_frameworks! is not present for this
178
+ # target, we need a bridging header.
179
+ podfile && !uses_frameworks?
180
+ end
181
+
182
+ # TODO: How many of these can vary by configuration?
183
+
184
+ def modules_enabled?
185
+ return nil unless target
186
+ setting = target.resolved_build_setting("CLANG_ENABLE_MODULES")["Release"]
187
+ return nil unless setting
188
+ setting == "YES"
189
+ end
190
+
191
+ def bridging_header_path
192
+ return @bridging_header_path if @bridging_header_path
193
+
194
+ return nil unless target
195
+ path = helper.expanded_build_setting target, "SWIFT_OBJC_BRIDGING_HEADER", "Release"
196
+ return nil unless path
197
+
198
+ @bridging_header_path = File.expand_path path, File.dirname(xcodeproj_path)
199
+ @bridging_header_path
200
+ end
201
+
202
+ def swift_version
203
+ return @swift_version if @swift_version
204
+
205
+ return nil unless target
206
+ @swift_version = target.resolved_build_setting("SWIFT_VERSION")["Release"]
207
+ @swift_version
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,164 @@
1
+ module BranchIOCLI
2
+ module Configuration
3
+ class ReportConfiguration < Configuration
4
+ attr_reader :clean
5
+ attr_reader :header_only
6
+ attr_reader :scheme
7
+ attr_reader :configuration
8
+ attr_reader :report_path
9
+ attr_reader :sdk
10
+
11
+ def validate_options
12
+ @clean = options.clean
13
+ @header_only = options.header_only
14
+ @scheme = options.scheme
15
+ @target = options.target
16
+ @configuration = options.configuration
17
+ @report_path = options.out
18
+ @sdk = options.sdk
19
+ @pod_repo_update = options.pod_repo_update
20
+
21
+ validate_xcodeproj_and_workspace options
22
+ validate_target options
23
+ validate_scheme options
24
+
25
+ # If neither --podfile nor --cartfile is present, arbitrarily look for a Podfile
26
+ # first.
27
+
28
+ # If --cartfile is present, don't look for a Podfile. Just validate that
29
+ # Cartfile.
30
+ validate_buildfile_path(options.podfile, "Podfile") if options.cartfile.nil?
31
+
32
+ # If --podfile is present or a Podfile was found, don't look for a Cartfile.
33
+ validate_buildfile_path(options.cartfile, "Cartfile") if sdk_integration_mode.nil?
34
+ end
35
+
36
+ def log
37
+ super
38
+ say <<EOF
39
+ <%= color('Xcode workspace:', BOLD) %> #{workspace_path || '(none)'}
40
+ <%= color('Xcode project:', BOLD) %> #{xcodeproj_path || '(none)'}
41
+ <%= color('Scheme:', BOLD) %> #{scheme || '(none)'}
42
+ <%= color('Target:', BOLD) %> #{target || '(none)'}
43
+ <%= color('Configuration:', BOLD) %> #{configuration}
44
+ <%= color('SDK:', BOLD) %> #{sdk}
45
+ <%= color('Podfile:', BOLD) %> #{podfile_path || '(none)'}
46
+ <%= color('Cartfile:', BOLD) %> #{cartfile_path || '(none)'}
47
+ <%= color('Pod repo update:', BOLD) %> #{pod_repo_update.inspect}
48
+ <%= color('Clean:', BOLD) %> #{clean.inspect}
49
+ <%= color('Report path:', BOLD) %> #{report_path}
50
+ EOF
51
+ end
52
+
53
+ # rubocop: disable Metrics/PerceivedComplexity
54
+ def validate_xcodeproj_and_workspace(options)
55
+ # 1. What was passed in?
56
+ begin
57
+ if options.workspace
58
+ path = options.workspace
59
+ @workspace = Xcodeproj::Workspace.new_from_xcworkspace options.workspace
60
+ @workspace_path = options.workspace
61
+ end
62
+ if options.xcodeproj
63
+ path = options.xcodeproj
64
+ @xcodeproj = Xcodeproj::Project.open options.xcodeproj
65
+ @xcodeproj_path = options.xcodeproj
66
+ else
67
+ # Pass --workspace and --xcodeproj to override this inference.
68
+ if workspace && workspace.file_references.count > 0 && workspace.file_references.first.path =~ /\.xcodeproj$/
69
+ @xcodeproj_path = File.expand_path "../#{@workspace.file_references.first.path}", workspace_path
70
+ @xcodeproj = Xcodeproj::Project.open xcodeproj_path
71
+ end
72
+ end
73
+ return if @workspace || @xcodeproj
74
+ rescue StandardError => e
75
+ say e.message
76
+ end
77
+
78
+ # Try to find first a workspace, then a project
79
+ all_workspace_paths = Dir[File.expand_path(File.join(".", "**/*.xcworkspace"))]
80
+ .reject { |w| w =~ %r{/project.xcworkspace$} }
81
+ .select do |p|
82
+ valid = true
83
+ Pathname.new(p).each_filename do |f|
84
+ valid = false && break if f == "Carthage" || f == "Pods"
85
+ end
86
+ valid
87
+ end
88
+
89
+ if all_workspace_paths.count == 1
90
+ path = all_workspace_paths.first
91
+ elsif all_workspace_paths.count == 0
92
+ all_xcodeproj_paths = Dir[File.expand_path(File.join(".", "**/*.xcodeproj"))]
93
+ xcodeproj_paths = all_xcodeproj_paths.select do |p|
94
+ valid = true
95
+ Pathname.new(p).each_filename do |f|
96
+ valid = false && break if f == "Carthage" || f == "Pods"
97
+ end
98
+ valid
99
+ end
100
+
101
+ path = xcodeproj_paths.first if xcodeproj_paths.count == 1
102
+ end
103
+ # If more than one workspace. Don't try to find a project. Just prompt.
104
+
105
+ loop do
106
+ path = ask "Please enter a path to your Xcode project or workspace: " if path.nil?
107
+ begin
108
+ if path =~ /\.xcworkspace$/
109
+ @workspace = Xcodeproj::Workspace.new_from_xcworkspace path
110
+ @workspace_path = path
111
+
112
+ # Pass --workspace and --xcodeproj to override this inference.
113
+ if workspace.file_references.count > 0 && workspace.file_references.first.path =~ /\.xcodeproj$/
114
+ @xcodeproj_path = File.expand_path "../#{workspace.file_references.first.path}", workspace_path
115
+ @xcodeproj = Xcodeproj::Project.open xcodeproj_path
116
+ end
117
+
118
+ return
119
+ elsif path =~ /\.xcodeproj$/
120
+ @xcodeproj = Xcodeproj::Project.open path
121
+ @xcodeproj_path = path
122
+ return
123
+ else
124
+ say "Path must end with .xcworkspace or .xcodeproj"
125
+ end
126
+ rescue StandardError => e
127
+ say e.message
128
+ end
129
+ end
130
+ end
131
+ # rubocop: enable Metrics/PerceivedComplexity
132
+
133
+ def validate_scheme(options)
134
+ schemes = all_schemes
135
+ # TODO: Prompt if --scheme specified but not found.
136
+ if options.scheme && schemes.include?(options.scheme)
137
+ @scheme = options.scheme
138
+ elsif schemes.count == 1
139
+ @scheme = schemes.first
140
+ elsif !schemes.empty?
141
+ # By default, take a scheme with the same name as the target name.
142
+ return if (@scheme = schemes.find { |s| s == target.name })
143
+
144
+ say "Please specify one of the following for the --scheme argument:"
145
+ schemes.each do |scheme|
146
+ say " #{scheme}"
147
+ end
148
+ exit 1
149
+ else
150
+ say "No scheme defined in project."
151
+ exit(-1)
152
+ end
153
+ end
154
+
155
+ def all_schemes
156
+ if workspace_path
157
+ workspace.schemes.keys.reject { |scheme| scheme == "Pods" }
158
+ else
159
+ Xcodeproj::Project.schemes xcodeproj_path
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end