omt-cli 1.6.3 → 1.6.4
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +8 -0
- data/.gitignore +24 -0
- data/.travis.yml +31 -0
- data/CHANGELOG +188 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +35 -0
- data/Rakefile +10 -0
- data/bin/console +11 -0
- data/bin/fir +14 -0
- data/bin/setup +7 -0
- data/doc/build_apk.md +42 -0
- data/doc/build_ipa.md +66 -0
- data/doc/help.md +34 -0
- data/doc/info.md +44 -0
- data/doc/install.md +65 -0
- data/doc/login.md +19 -0
- data/doc/mapping.md +22 -0
- data/doc/publish.md +35 -0
- data/doc/upgrade.md +7 -0
- data/lib/fir.rb +28 -0
- data/lib/fir/api.yml +13 -0
- data/lib/fir/api.yml.bak +13 -0
- data/lib/fir/cli.rb +195 -0
- data/lib/fir/patches.rb +10 -0
- data/lib/fir/patches/blank.rb +131 -0
- data/lib/fir/patches/concern.rb +146 -0
- data/lib/fir/patches/default_headers.rb +9 -0
- data/lib/fir/patches/hash.rb +79 -0
- data/lib/fir/patches/instance_variables.rb +30 -0
- data/lib/fir/patches/native_patch.rb +28 -0
- data/lib/fir/patches/os_patch.rb +28 -0
- data/lib/fir/patches/try.rb +102 -0
- data/lib/fir/util.rb +87 -0
- data/lib/fir/util/build_apk.rb +76 -0
- data/lib/fir/util/build_common.rb +93 -0
- data/lib/fir/util/build_ipa.rb +240 -0
- data/lib/fir/util/config.rb +42 -0
- data/lib/fir/util/http.rb +30 -0
- data/lib/fir/util/info.rb +39 -0
- data/lib/fir/util/login.rb +18 -0
- data/lib/fir/util/mapping.rb +98 -0
- data/lib/fir/util/me.rb +19 -0
- data/lib/fir/util/parser/apk.rb +43 -0
- data/lib/fir/util/parser/bin/pngcrush +0 -0
- data/lib/fir/util/parser/common.rb +24 -0
- data/lib/fir/util/parser/ipa.rb +188 -0
- data/lib/fir/util/parser/pngcrush.rb +23 -0
- data/lib/fir/util/publish.rb +106 -0
- data/lib/fir/util/publish.rb.bak +185 -0
- data/lib/fir/version.rb +5 -0
- data/lib/fir/xcode_wrapper.sh +29 -0
- data/lib/omt-cli.rb +3 -0
- data/lib/omt_cli.rb +3 -0
- data/omt-cli.gemspec +48 -0
- data/test/build_ipa_test.rb +17 -0
- data/test/cases/test_apk.apk +0 -0
- data/test/cases/test_apk_txt +1 -0
- data/test/cases/test_ipa.ipa +0 -0
- data/test/cases/test_ipa_dsym +0 -0
- data/test/info_test.rb +36 -0
- data/test/login_test.rb +12 -0
- data/test/mapping_test.rb +18 -0
- data/test/me_test.rb +17 -0
- data/test/publish_test.rb +44 -0
- data/test/test_helper.rb +98 -0
- metadata +84 -4
@@ -0,0 +1,102 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Object
|
4
|
+
# Invokes the public method whose name goes as first argument just like
|
5
|
+
# +public_send+ does, except that if the receiver does not respond to it the
|
6
|
+
# call returns +nil+ rather than raising an exception.
|
7
|
+
#
|
8
|
+
# This method is defined to be able to write
|
9
|
+
#
|
10
|
+
# @person.try(:name)
|
11
|
+
#
|
12
|
+
# instead of
|
13
|
+
#
|
14
|
+
# @person.name if @person
|
15
|
+
#
|
16
|
+
# +try+ calls can be chained:
|
17
|
+
#
|
18
|
+
# @person.try(:spouse).try(:name)
|
19
|
+
#
|
20
|
+
# instead of
|
21
|
+
#
|
22
|
+
# @person.spouse.name if @person && @person.spouse
|
23
|
+
#
|
24
|
+
# +try+ will also return +nil+ if the receiver does not respond to the method:
|
25
|
+
#
|
26
|
+
# @person.try(:non_existing_method) #=> nil
|
27
|
+
#
|
28
|
+
# instead of
|
29
|
+
#
|
30
|
+
# @person.non_existing_method if @person.respond_to?(:non_existing_method) #=> nil
|
31
|
+
#
|
32
|
+
# +try+ returns +nil+ when called on +nil+ regardless of whether it responds
|
33
|
+
# to the method:
|
34
|
+
#
|
35
|
+
# nil.try(:to_i) # => nil, rather than 0
|
36
|
+
#
|
37
|
+
# Arguments and blocks are forwarded to the method if invoked:
|
38
|
+
#
|
39
|
+
# @posts.try(:each_slice, 2) do |a, b|
|
40
|
+
# ...
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# The number of arguments in the signature must match. If the object responds
|
44
|
+
# to the method the call is attempted and +ArgumentError+ is still raised
|
45
|
+
# in case of argument mismatch.
|
46
|
+
#
|
47
|
+
# If +try+ is called without arguments it yields the receiver to a given
|
48
|
+
# block unless it is +nil+:
|
49
|
+
#
|
50
|
+
# @person.try do |p|
|
51
|
+
# ...
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# You can also call try with a block without accepting an argument, and the block
|
55
|
+
# will be instance_eval'ed instead:
|
56
|
+
#
|
57
|
+
# @person.try { upcase.truncate(50) }
|
58
|
+
#
|
59
|
+
# Please also note that +try+ is defined on +Object+. Therefore, it won't work
|
60
|
+
# with instances of classes that do not have +Object+ among their ancestors,
|
61
|
+
# like direct subclasses of +BasicObject+. For example, using +try+ with
|
62
|
+
# +SimpleDelegator+ will delegate +try+ to the target instead of calling it on
|
63
|
+
# the delegator itself.
|
64
|
+
def try(*a, &b)
|
65
|
+
try!(*a, &b) if a.empty? || respond_to?(a.first)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Same as #try, but will raise a NoMethodError exception if the receiver is not +nil+ and
|
69
|
+
# does not implement the tried method.
|
70
|
+
|
71
|
+
def try!(*a, &b)
|
72
|
+
if a.empty? && block_given?
|
73
|
+
if b.arity.zero?
|
74
|
+
instance_eval(&b)
|
75
|
+
else
|
76
|
+
yield self
|
77
|
+
end
|
78
|
+
else
|
79
|
+
public_send(*a, &b)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class NilClass
|
85
|
+
# Calling +try+ on +nil+ always returns +nil+.
|
86
|
+
# It becomes especially helpful when navigating through associations that may return +nil+.
|
87
|
+
#
|
88
|
+
# nil.try(:name) # => nil
|
89
|
+
#
|
90
|
+
# Without +try+
|
91
|
+
# @person && @person.children.any? && @person.children.first.name
|
92
|
+
#
|
93
|
+
# With +try+
|
94
|
+
# @person.try(:children).try(:first).try(:name)
|
95
|
+
def try(*args)
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
def try!(*args)
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
end
|
data/lib/fir/util.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative './util/http'
|
4
|
+
require_relative './util/config'
|
5
|
+
require_relative './util/parser/apk'
|
6
|
+
require_relative './util/parser/ipa'
|
7
|
+
require_relative './util/parser/pngcrush'
|
8
|
+
require_relative './util/login'
|
9
|
+
require_relative './util/me'
|
10
|
+
require_relative './util/info'
|
11
|
+
require_relative './util/build_common'
|
12
|
+
require_relative './util/build_ipa'
|
13
|
+
require_relative './util/build_apk'
|
14
|
+
require_relative './util/publish'
|
15
|
+
require_relative './util/mapping'
|
16
|
+
|
17
|
+
module FIR
|
18
|
+
module Util
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
include FIR::Http
|
23
|
+
include FIR::Config
|
24
|
+
include FIR::Login
|
25
|
+
include FIR::Me
|
26
|
+
include FIR::Info
|
27
|
+
include FIR::BuildCommon
|
28
|
+
include FIR::BuildIpa
|
29
|
+
include FIR::BuildApk
|
30
|
+
include FIR::Publish
|
31
|
+
include FIR::Mapping
|
32
|
+
|
33
|
+
attr_accessor :logger
|
34
|
+
|
35
|
+
def fetch_user_info(token)
|
36
|
+
get fir_api[:user_url], api_token: token
|
37
|
+
end
|
38
|
+
|
39
|
+
def fetch_user_uuid(token)
|
40
|
+
user_info = fetch_user_info(token)
|
41
|
+
user_info[:uuid]
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_file_exist(path)
|
45
|
+
return if File.file?(path)
|
46
|
+
|
47
|
+
logger.error 'File does not exist'
|
48
|
+
exit 1
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_supported_file(path)
|
52
|
+
return if APP_FILE_TYPE.include?(File.extname(path))
|
53
|
+
|
54
|
+
logger.error 'Unsupported file type'
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_token_cannot_be_blank(token)
|
59
|
+
return unless token.blank?
|
60
|
+
|
61
|
+
logger.error 'Token can not be blank'
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_logined
|
66
|
+
return unless current_token.blank?
|
67
|
+
|
68
|
+
logger.error 'Please use `fir login` first'
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def logger_info_blank_line
|
73
|
+
logger.info ''
|
74
|
+
end
|
75
|
+
|
76
|
+
def logger_info_dividing_line
|
77
|
+
logger.info '✈ -------------------------------------------- ✈'
|
78
|
+
end
|
79
|
+
|
80
|
+
def generate_rqrcode(string, png_file_path)
|
81
|
+
qrcode = ::RQRCode::QRCode.new(string.to_s)
|
82
|
+
qrcode.as_png(size: 500, border_modules: 2, file: png_file_path)
|
83
|
+
png_file_path
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FIR
|
4
|
+
module BuildApk
|
5
|
+
|
6
|
+
def build_apk(*args, options)
|
7
|
+
initialize_build_common_options(args, options)
|
8
|
+
set_flavor(options)
|
9
|
+
|
10
|
+
Dir.chdir(@build_dir)
|
11
|
+
@build_cmd = initialize_apk_build_cmd
|
12
|
+
|
13
|
+
logger_info_and_run_build_command
|
14
|
+
|
15
|
+
output_apk
|
16
|
+
publish_build_app(options) if options.publish?
|
17
|
+
|
18
|
+
logger_info_blank_line
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def set_flavor(options)
|
24
|
+
unless options.flavor.blank?
|
25
|
+
@flavor = options.flavor
|
26
|
+
unless @flavor =~ /^assemble(.+)/
|
27
|
+
@flavor = "assemble#{@flavor}Release"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize_apk_build_cmd
|
33
|
+
check_build_gradle_exist
|
34
|
+
|
35
|
+
cmd = "./gradlew build"
|
36
|
+
cmd = "./gradlew #{@flavor}" unless @flavor.blank?
|
37
|
+
cmd
|
38
|
+
end
|
39
|
+
|
40
|
+
def gradle_build_path
|
41
|
+
"#{@build_dir}/build/outputs/apk"
|
42
|
+
end
|
43
|
+
|
44
|
+
def prefix_gradle_build_path
|
45
|
+
"#{@build_dir}/app/build/outputs/apk"
|
46
|
+
end
|
47
|
+
|
48
|
+
def output_apk
|
49
|
+
@builded_apk ||= Dir["#{gradle_build_path}/*.apk"].find { |i| i =~ /release/ }
|
50
|
+
@builded_apk ||= Dir["#{prefix_gradle_build_path}/*.apk"].find { |i| i =~ /release/ }
|
51
|
+
@builded_apk ||= Dir["#{@build_dir}/*.apk"].find { |i| i =~ /release/ }
|
52
|
+
|
53
|
+
check_no_output_apk
|
54
|
+
|
55
|
+
apk_info = FIR.apk_info(@builded_apk)
|
56
|
+
@apk_name = @name.blank? ? "#{apk_info[:name]}-#{apk_info[:version]}-Build-#{apk_info[:build]}" : @name
|
57
|
+
|
58
|
+
@builded_app_path = "#{@output_path}/#{@apk_name}.apk"
|
59
|
+
FileUtils.cp(@builded_apk, @builded_app_path)
|
60
|
+
end
|
61
|
+
|
62
|
+
def check_no_output_apk
|
63
|
+
unless @builded_apk
|
64
|
+
logger.error 'Builded has no output apk'
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def check_build_gradle_exist
|
70
|
+
return if File.exist?("#{@build_dir}/build.gradle")
|
71
|
+
|
72
|
+
logger.error "The build.gradle isn't exit, please use gradle and edit"
|
73
|
+
exit 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FIR
|
4
|
+
module BuildCommon
|
5
|
+
|
6
|
+
def initialize_build_common_options(args, options)
|
7
|
+
@build_dir = initialize_build_dir(args, options)
|
8
|
+
@output_path = initialize_output_path(options)
|
9
|
+
@token = options[:token] || current_token
|
10
|
+
@changelog = options[:changelog].to_s
|
11
|
+
@short = options[:short].to_s
|
12
|
+
@name = options[:name].to_s
|
13
|
+
@proj = options[:proj].to_s
|
14
|
+
@export_qrcode = options[:qrcode]
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize_build_dir(args, options)
|
18
|
+
build_dir = args.first.to_s
|
19
|
+
if File.extname(build_dir) == '.git'
|
20
|
+
args.shift && git_clone_build_dir(build_dir, options)
|
21
|
+
elsif build_dir.blank? || !File.exist?(build_dir)
|
22
|
+
Dir.pwd
|
23
|
+
else
|
24
|
+
args.shift && File.absolute_path(build_dir)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def git_clone_build_dir(ssh_url, options)
|
29
|
+
repo_name = File.basename(ssh_url, '.git') + "_#{Time.now.strftime('%Y%m%dT%H%M%S')}"
|
30
|
+
branch = options[:branch].blank? ? 'master' : options[:branch]
|
31
|
+
git_cmd = "git clone --depth=50 --branch=#{branch} #{ssh_url} #{repo_name}"
|
32
|
+
|
33
|
+
logger.info git_cmd
|
34
|
+
logger_info_dividing_line
|
35
|
+
|
36
|
+
if system(git_cmd)
|
37
|
+
File.absolute_path(repo_name)
|
38
|
+
else
|
39
|
+
logger.error 'Git clone failed'
|
40
|
+
exit 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize_output_path(options)
|
45
|
+
if options[:output].blank?
|
46
|
+
output_path = "#{@build_dir}/fir_build"
|
47
|
+
FileUtils.mkdir_p(output_path) unless File.exist?(output_path)
|
48
|
+
output_path
|
49
|
+
else
|
50
|
+
output_path = options[:output].to_s
|
51
|
+
unless File.exist?(output_path)
|
52
|
+
logger.warn "The output path not exist and fir-cli will autocreate it..."
|
53
|
+
end
|
54
|
+
File.absolute_path(output_path)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def publish_build_app(options)
|
59
|
+
logger_info_blank_line
|
60
|
+
publish @builded_app_path, options
|
61
|
+
end
|
62
|
+
|
63
|
+
def logger_info_and_run_build_command
|
64
|
+
puts @build_cmd if $DEBUG
|
65
|
+
|
66
|
+
logger.info 'Building......'
|
67
|
+
logger_info_dividing_line
|
68
|
+
|
69
|
+
logger.info `#{@build_cmd}`
|
70
|
+
|
71
|
+
if $?.to_i != 0
|
72
|
+
logger.error 'Build failed'
|
73
|
+
exit 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# split ['a=1', 'b=2'] => { 'a' => '1', 'b' => '2' }
|
78
|
+
def split_assignment_array_to_hash(arr)
|
79
|
+
hash = {}
|
80
|
+
arr.each do |assignment|
|
81
|
+
k, v = assignment.split('=', 2).map(&:strip)
|
82
|
+
hash[k] = v
|
83
|
+
end
|
84
|
+
|
85
|
+
hash
|
86
|
+
end
|
87
|
+
|
88
|
+
# convert { "a" => "1", "b" => "2" } => "a='1' b='2'"
|
89
|
+
def convert_hash_to_assignment_string(hash)
|
90
|
+
hash.collect { |k, v| "#{k}='#{v}'" }.join(' ')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'xcodeproj'
|
3
|
+
|
4
|
+
module FIR
|
5
|
+
module BuildIpa
|
6
|
+
|
7
|
+
def build_ipa(*args, options)
|
8
|
+
initialize_build_common_options(args, options)
|
9
|
+
|
10
|
+
@build_tmp_dir = Dir.mktmpdir
|
11
|
+
@build_cmd = initialize_ipa_build_cmd(args, options)
|
12
|
+
|
13
|
+
logger_info_and_run_build_command
|
14
|
+
|
15
|
+
output_ipa_and_dsym
|
16
|
+
publish_build_app(options) if options.publish?
|
17
|
+
upload_build_dsym_mapping_file if options.mapping?
|
18
|
+
|
19
|
+
logger_info_blank_line
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def initialize_ipa_build_cmd(args, options)
|
25
|
+
@configuration = options[:configuration] || 'Release'
|
26
|
+
@target_name = options[:target]
|
27
|
+
@scheme_name = options[:scheme]
|
28
|
+
@profile_name = options[:profile]
|
29
|
+
@destination = options[:destination]
|
30
|
+
@export_method = options[:export_method] || 'ad-hoc'
|
31
|
+
@optionPlistPath = options[:optionPlistPath]
|
32
|
+
|
33
|
+
build_cmd = 'xcodebuild archive -sdk iphoneos'
|
34
|
+
build_cmd += initialize_xcode_build_path(options)
|
35
|
+
|
36
|
+
build_settings = find_build_setting
|
37
|
+
@team_id = build_settings['DEVELOPMENT_TEAM']
|
38
|
+
provisioning_profile_id = build_settings['PROVISIONING_PROFILE']
|
39
|
+
|
40
|
+
check_ios_scheme(@scheme_name)
|
41
|
+
build_cmd += " -scheme '#{@scheme_name}'" unless @scheme_name.blank?
|
42
|
+
build_cmd += " -configuration '#{@configuration}'" unless @configuration.blank?
|
43
|
+
|
44
|
+
# build_cmd += " -target '#{@target_name}'" unless @target_name.blank?
|
45
|
+
|
46
|
+
# xcarchive name for build -exportArchive
|
47
|
+
@xcarchive_name = @scheme_name.nil? ? @target_name : @scheme_name + '.xcarchive'
|
48
|
+
@xcarchive_path = "#{@build_dir}/fir_build/#{@xcarchive_name}"
|
49
|
+
|
50
|
+
build_cmd += " -archivePath #{@xcarchive_path}"
|
51
|
+
build_cmd += " PROVISIONING_PROFILE='#{provisioning_profile_id}'"
|
52
|
+
build_cmd += " #{ipa_custom_settings(args)} 2>&1"
|
53
|
+
build_cmd
|
54
|
+
end
|
55
|
+
|
56
|
+
def ipa_custom_settings(args)
|
57
|
+
custom_settings = split_assignment_array_to_hash(args)
|
58
|
+
|
59
|
+
setting_str = convert_hash_to_assignment_string(custom_settings)
|
60
|
+
setting_str += " TARGET_BUILD_DIR='#{@build_tmp_dir}'" unless custom_settings['TARGET_BUILD_DIR']
|
61
|
+
setting_str += " CONFIGURATION_BUILD_DIR='#{@build_tmp_dir}'" unless custom_settings['CONFIGURATION_BUILD_DIR']
|
62
|
+
setting_str += " DWARF_DSYM_FOLDER_PATH='#{@output_path}'" unless custom_settings['DWARF_DSYM_FOLDER_PATH']
|
63
|
+
setting_str
|
64
|
+
end
|
65
|
+
|
66
|
+
def output_ipa_and_dsym
|
67
|
+
apps = Dir["#{@build_tmp_dir}/*.app"].sort_by(&:size)
|
68
|
+
# check_no_output_app(apps)
|
69
|
+
|
70
|
+
@temp_ipa = "#{@build_tmp_dir}/#{Time.now.to_i}.ipa"
|
71
|
+
archive_ipa(apps)
|
72
|
+
|
73
|
+
# check_archived_ipa_is_exist
|
74
|
+
rename_ipa_and_dsym
|
75
|
+
|
76
|
+
FileUtils.rm_rf(@build_tmp_dir) unless $DEBUG
|
77
|
+
logger.info 'Build Success'
|
78
|
+
end
|
79
|
+
|
80
|
+
def archive_ipa(apps)
|
81
|
+
logger.info 'Archiving......'
|
82
|
+
logger_info_dividing_line
|
83
|
+
|
84
|
+
option_plist_path = @optionPlistPath || gen_option_plist
|
85
|
+
|
86
|
+
@xcrun_cmd = "#{FIR::Config::XCODE_WRAPPER_PATH} -exportArchive"
|
87
|
+
@xcrun_cmd += " -archivePath #{@xcarchive_path}"
|
88
|
+
@xcrun_cmd += " -exportOptionsPlist #{option_plist_path}"
|
89
|
+
@xcrun_cmd += " -exportPath #{@build_dir}/fir_build"
|
90
|
+
|
91
|
+
puts @xcrun_cmd if $DEBUG
|
92
|
+
logger.info `#{@xcrun_cmd}`
|
93
|
+
end
|
94
|
+
|
95
|
+
def check_archived_ipa_is_exist
|
96
|
+
unless File.exist?(@temp_ipa)
|
97
|
+
logger.error 'Archive failed'
|
98
|
+
exit 1
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def gen_option_plist
|
103
|
+
plist = "
|
104
|
+
<plist version=\"1.0\">
|
105
|
+
<dict>
|
106
|
+
<key>teamID</key>
|
107
|
+
<string>#{@team_id}</string>
|
108
|
+
<key>method</key>
|
109
|
+
<string>#{@export_method}</string>
|
110
|
+
<key>uploadSymbols</key>
|
111
|
+
<true/>
|
112
|
+
<key>compileBitcode</key>
|
113
|
+
<false/>
|
114
|
+
<key>uploadBitcode</key>
|
115
|
+
<false/>
|
116
|
+
</dict>
|
117
|
+
</plist>"
|
118
|
+
|
119
|
+
logger.info 'Generated plist file for exportOptionsPlist argument'
|
120
|
+
logger.info "{"
|
121
|
+
logger.info " teamID:#{@team_id}" unless @team_id.nil?
|
122
|
+
logger.info " method:#{@export_method}"
|
123
|
+
logger.info " uploadSymbols:true"
|
124
|
+
logger.info " uploadBitcode:false"
|
125
|
+
logger.info "}"
|
126
|
+
|
127
|
+
begin
|
128
|
+
plist_path = "#{@build_dir}/fir_build/exportOptions.plist"
|
129
|
+
file = File.open(plist_path, "w")
|
130
|
+
file.write(plist)
|
131
|
+
plist_path
|
132
|
+
rescue IOError => e
|
133
|
+
raise e
|
134
|
+
ensure
|
135
|
+
file.close unless file.nil?
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Find build setting from xcode project by target and configuration
|
140
|
+
def find_build_setting
|
141
|
+
project = Xcodeproj::Project.open(@xc_project)
|
142
|
+
|
143
|
+
# find target
|
144
|
+
used_target = project.targets[0]
|
145
|
+
if @target_name
|
146
|
+
project.targets.each do |target|
|
147
|
+
if target.name == @target_name
|
148
|
+
used_target = target
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# find configuration settings
|
154
|
+
used_target.build_configurations.each do |config|
|
155
|
+
if config.name == @configuration
|
156
|
+
return config.build_settings
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
logger.info "configuration '#{@configuration}' not found"
|
161
|
+
end
|
162
|
+
|
163
|
+
def rename_ipa_and_dsym
|
164
|
+
@temp_ipa = "#{@build_dir}/fir_build/#{@scheme_name}.ipa"
|
165
|
+
ipa_info = FIR.ipa_info(@temp_ipa)
|
166
|
+
|
167
|
+
if @name.blank?
|
168
|
+
@ipa_name = "#{ipa_info[:name]}-#{ipa_info[:version]}-build-#{ipa_info[:build]}"
|
169
|
+
else
|
170
|
+
@ipa_name = @name
|
171
|
+
end
|
172
|
+
|
173
|
+
@builded_app_path = "#{@output_path}/#{@ipa_name}.ipa"
|
174
|
+
dsym_name = " #{@output_path}/#{ipa_info[:name]}.app.dSYM"
|
175
|
+
|
176
|
+
FileUtils.mv(@temp_ipa, @builded_app_path, force: true)
|
177
|
+
if File.exist?(dsym_name)
|
178
|
+
FileUtils.mv(dsym_name, "#{@output_path}/#{@ipa_name}.app.dSYM", force: true)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def upload_build_dsym_mapping_file
|
183
|
+
logger_info_blank_line
|
184
|
+
|
185
|
+
@app_info = ipa_info(@builded_app_path)
|
186
|
+
@mapping_file = Dir["#{@output_path}/#{@ipa_name}.app.dSYM/Contents/Resources/DWARF/*"].first
|
187
|
+
|
188
|
+
mapping @mapping_file, proj: @proj,
|
189
|
+
build: @app_info[:build],
|
190
|
+
version: @app_info[:version],
|
191
|
+
token: @token
|
192
|
+
end
|
193
|
+
|
194
|
+
def initialize_xcode_build_path(options)
|
195
|
+
@xc_workspace = check_and_find_ios_xcworkspace(@build_dir)
|
196
|
+
@xc_project = check_and_find_ios_xcodeproj(@build_dir)
|
197
|
+
|
198
|
+
if options.workspace?
|
199
|
+
" -workspace '#{@xc_workspace}'"
|
200
|
+
else
|
201
|
+
" -project '#{@xc_project}'"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
%w(xcodeproj xcworkspace).each do |workplace|
|
206
|
+
define_method "check_and_find_ios_#{workplace}" do |path|
|
207
|
+
unless File.exist?(path)
|
208
|
+
logger.error "The first param BUILD_DIR must be a #{workplace} directory"
|
209
|
+
exit 1
|
210
|
+
end
|
211
|
+
|
212
|
+
if File.extname(path) == ".#{workplace}"
|
213
|
+
build_dir = path
|
214
|
+
else
|
215
|
+
build_dir = Dir["#{path}/*.#{workplace}"].first
|
216
|
+
if build_dir.blank?
|
217
|
+
logger.error "The #{workplace} file is missing, check the BUILD_DIR"
|
218
|
+
exit 1
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
build_dir
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def check_ios_scheme(scheme_name)
|
227
|
+
if scheme_name.blank?
|
228
|
+
logger.error 'Must provide a scheme by `-S` option when build a workspace'
|
229
|
+
exit 1
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def check_no_output_app(apps)
|
234
|
+
if apps.length == 0
|
235
|
+
logger.error 'Builded has no output app, Can not be packaged'
|
236
|
+
exit 1
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|