branch_io_cli 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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