flappy-cli 0.3.0
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 +7 -0
- data/.gitignore +10 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/flappy +14 -0
- data/bin/setup +8 -0
- data/flappy-cli.gemspec +50 -0
- data/lib/flappy/api.yml +7 -0
- data/lib/flappy/cli.rb +145 -0
- data/lib/flappy/patches/blank.rb +131 -0
- data/lib/flappy/patches/concern.rb +146 -0
- data/lib/flappy/patches/default_headers.rb +9 -0
- data/lib/flappy/patches/hash.rb +79 -0
- data/lib/flappy/patches/instance_variables.rb +30 -0
- data/lib/flappy/patches/native_patch.rb +28 -0
- data/lib/flappy/patches/os_patch.rb +28 -0
- data/lib/flappy/patches/try.rb +102 -0
- data/lib/flappy/patches.rb +12 -0
- data/lib/flappy/util/archive_ipa.rb +55 -0
- data/lib/flappy/util/build_apk.rb +104 -0
- data/lib/flappy/util/build_common.rb +90 -0
- data/lib/flappy/util/build_ipa.rb +331 -0
- data/lib/flappy/util/config.rb +41 -0
- data/lib/flappy/util/http.rb +30 -0
- data/lib/flappy/util/iOS_check.rb +29 -0
- data/lib/flappy/util/iOS_env_config.rb +54 -0
- data/lib/flappy/util/iOS_logger.rb +113 -0
- data/lib/flappy/util/info.rb +39 -0
- data/lib/flappy/util/ipa_info.rb +198 -0
- data/lib/flappy/util/mapping.rb +84 -0
- data/lib/flappy/util/multi_io.rb +27 -0
- data/lib/flappy/util/parser/apk.rb +42 -0
- data/lib/flappy/util/parser/bin/pngcrush +0 -0
- data/lib/flappy/util/parser/common.rb +24 -0
- data/lib/flappy/util/parser/pngcrush.rb +23 -0
- data/lib/flappy/util/publish.rb +185 -0
- data/lib/flappy/util/update_pod.rb +264 -0
- data/lib/flappy/util.rb +105 -0
- data/lib/flappy/version.rb +3 -0
- data/lib/flappy-cli.rb +3 -0
- data/lib/flappy.rb +28 -0
- data/output/Flappy-Archives/iOS/WorkspaceForPackageTest/20170103000308/20170103000308_WorkspaceForPackageTest.json +1 -0
- data/output/Flappy-Archives/iOS/WorkspaceForPackageTest/20170103000308/20170103000308_WorkspaceForPackageTest_Podfile +16 -0
- data/output/Flappy-Archives/iOS/WorkspaceForPackageTest/20170103000308/20170103000308_WorkspaceForPackageTest_Podfile_lock +40 -0
- data/output/Flappy-Archives/iOS/WorkspaceForPackageTest/20170103000314/20170103000314_WorkspaceForPackageTest.json +1 -0
- data/output/Flappy-Archives/iOS/WorkspaceForPackageTest/20170103000314/20170103000314_WorkspaceForPackageTest_Podfile +16 -0
- data/output/Flappy-Archives/iOS/WorkspaceForPackageTest/20170103000314/20170103000314_WorkspaceForPackageTest_Podfile_lock +40 -0
- metadata +223 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Flappy
|
|
4
|
+
module IpaInfo
|
|
5
|
+
class Ipa
|
|
6
|
+
# include Parser::Common
|
|
7
|
+
|
|
8
|
+
def initialize(path)
|
|
9
|
+
@path = path # ipa包的路径
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def contents # contents为ipa解压路径
|
|
13
|
+
return @contents if @contents
|
|
14
|
+
|
|
15
|
+
@contents = "#{Dir.tmpdir}/#{Time.now.strftime('%Y%m%d%H%M%S')}_ipa_files"
|
|
16
|
+
Zip::File.open(@path) do |zip_file| # zip_file为待解压的文件路径
|
|
17
|
+
# puts "zipfile: #{zip_file}"
|
|
18
|
+
zip_file.each do |f| # f为解压出来的文件
|
|
19
|
+
# puts "file: #{f}"
|
|
20
|
+
f_path = File.join(@contents, f.name) # f_path为解压出来的文件路径
|
|
21
|
+
# puts "path: #{f_path}"
|
|
22
|
+
# FileUtils.mkdir_p(File.dirname(f_path)) # File.dirname(f_path)为所有的文件夹、资源束文件;这里建立压缩包里面的每个文件夹,这一步可以省略的
|
|
23
|
+
# puts "dir: #{File.dirname(f_path)}"
|
|
24
|
+
zip_file.extract(f, f_path) unless File.exist?(f_path) # 解压文件到相应位置
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
@contents
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def app_path
|
|
31
|
+
@app_path ||= Dir.glob(File.join(contents, 'Payload', '*.app')).first
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def app
|
|
35
|
+
@app ||= App.new(app_path, is_stored)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def cleanup
|
|
39
|
+
return unless @contents
|
|
40
|
+
FileUtils.rm_rf(@contents)
|
|
41
|
+
@contents = nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def metadata
|
|
45
|
+
return unless has_metadata?
|
|
46
|
+
begin
|
|
47
|
+
@metadata ||= CFPropertyList.native_types(CFPropertyList::List.new(file: metadata_path).value)
|
|
48
|
+
rescue CFFormatError
|
|
49
|
+
@metadata = {}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def has_metadata?
|
|
54
|
+
File.file?(metadata_path)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def metadata_path
|
|
58
|
+
@metadata_path ||= File.join(contents, 'iTunesMetadata.plist')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def is_stored # 是否是appstore包
|
|
62
|
+
has_metadata? ? true : false
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class App
|
|
68
|
+
def initialize(path, is_stored = false)
|
|
69
|
+
@path = path # app的路径
|
|
70
|
+
@is_stored = is_stored
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def full_info(options)
|
|
74
|
+
# if options.fetch(:full_info, false)
|
|
75
|
+
# basic_info.merge!(icons: tmp_icons)
|
|
76
|
+
# end
|
|
77
|
+
|
|
78
|
+
basic_info
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def basic_info
|
|
82
|
+
@basic_info ||= {
|
|
83
|
+
type: 'ios',
|
|
84
|
+
identifier: identifier,
|
|
85
|
+
name: name,
|
|
86
|
+
display_name: display_name,
|
|
87
|
+
build: version.to_s,
|
|
88
|
+
version: short_version.to_s,
|
|
89
|
+
devices: devices,
|
|
90
|
+
release_type: release_type,
|
|
91
|
+
distribution_name: distribution_name
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def info
|
|
96
|
+
@info ||= CFPropertyList.native_types(
|
|
97
|
+
CFPropertyList::List.new(file: File.join(@path, 'Info.plist')).value)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def identifier
|
|
101
|
+
info['CFBundleIdentifier']
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def name
|
|
105
|
+
info['CFBundleName']
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def display_name
|
|
109
|
+
info['CFBundleDisplayName']
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def version
|
|
113
|
+
info['CFBundleVersion']
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def short_version
|
|
117
|
+
info['CFBundleShortVersionString']
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def mobileprovision_path
|
|
121
|
+
@mobileprovision_path ||= File.join(@path, 'embedded.mobileprovision')
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def has_mobileprovision?
|
|
125
|
+
File.file? mobileprovision_path
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def mobileprovision
|
|
129
|
+
return unless has_mobileprovision?
|
|
130
|
+
return @mobileprovision if @mobileprovision
|
|
131
|
+
|
|
132
|
+
cmd = "security cms -D -i \"#{mobileprovision_path}\""
|
|
133
|
+
begin
|
|
134
|
+
@mobileprovision = CFPropertyList.native_types(CFPropertyList::List.new(data: `#{cmd}`).value)
|
|
135
|
+
rescue CFFormatError
|
|
136
|
+
@mobileprovision = {}
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def devices
|
|
141
|
+
mobileprovision['ProvisionedDevices'] if has_mobileprovision?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def hide_developer_certificates
|
|
145
|
+
mobileprovision.delete('DeveloperCertificates') if has_mobileprovision?
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def distribution_name
|
|
149
|
+
"#{mobileprovision['Name']} - #{mobileprovision['TeamName']}" if has_mobileprovision?
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def release_type
|
|
153
|
+
if @is_stored
|
|
154
|
+
'Release'
|
|
155
|
+
else
|
|
156
|
+
if has_mobileprovision?
|
|
157
|
+
if devices
|
|
158
|
+
'AdHoc'
|
|
159
|
+
else
|
|
160
|
+
'InHouse'
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def icons
|
|
167
|
+
@icons ||= begin
|
|
168
|
+
icons = []
|
|
169
|
+
info['CFBundleIcons']['CFBundlePrimaryIcon']['CFBundleIconFiles'].each do |name|
|
|
170
|
+
icons << get_image_path(name)
|
|
171
|
+
icons << get_image_path("#{name}@2x")
|
|
172
|
+
icons << get_image_path("#{name}@3x")
|
|
173
|
+
end
|
|
174
|
+
icons.delete_if &:!
|
|
175
|
+
rescue NoMethodError
|
|
176
|
+
[]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
begin
|
|
180
|
+
info['CFBundleIcons~ipad']['CFBundlePrimaryIcon']['CFBundleIconFiles'].each do |name|
|
|
181
|
+
icons << get_image_path("#{name}~ipad")
|
|
182
|
+
icons << get_image_path("#{name}@2x~ipad")
|
|
183
|
+
end
|
|
184
|
+
icons.delete_if &:!
|
|
185
|
+
rescue NoMethodError
|
|
186
|
+
[]
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def get_image_path(name)
|
|
191
|
+
path = File.join(@path, "#{name}.png")
|
|
192
|
+
return nil unless File.exist?(path)
|
|
193
|
+
path
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
end
|
|
198
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Flappy
|
|
4
|
+
module Mapping
|
|
5
|
+
|
|
6
|
+
def mapping(*args, options)
|
|
7
|
+
initialize_and_check_mapping_options(args, options)
|
|
8
|
+
check_file_and_token
|
|
9
|
+
|
|
10
|
+
logger.info "Creating bughd project's version......."
|
|
11
|
+
logger_info_dividing_line
|
|
12
|
+
|
|
13
|
+
logger.info 'Uploading mapping file.......'
|
|
14
|
+
|
|
15
|
+
# upload_mapping_file
|
|
16
|
+
logger_info_dividing_line
|
|
17
|
+
|
|
18
|
+
logger.info "save mapping succeed"
|
|
19
|
+
logger_info_blank_line
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def initialize_and_check_mapping_options(args, options)
|
|
25
|
+
@file_path = File.absolute_path(args.first.to_s)
|
|
26
|
+
@token = options[:token] || current_token
|
|
27
|
+
@proj = options[:proj].to_s
|
|
28
|
+
@version = options[:version].to_s
|
|
29
|
+
@build = options[:build].to_s
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def check_file_and_token
|
|
33
|
+
check_file_exist(@file_path)
|
|
34
|
+
check_token_cannot_be_blank(@token)
|
|
35
|
+
check_project_id_cannot_be_blank
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def check_project_id_cannot_be_blank
|
|
39
|
+
return unless @proj.blank?
|
|
40
|
+
|
|
41
|
+
logger.error "Project id can't be blank"
|
|
42
|
+
exit 1
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def uuid
|
|
46
|
+
@uuid ||= fetch_user_uuid(@token)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def generate_temp_mapping_file
|
|
50
|
+
tmp_file_path = "#{Dir.tmpdir}/flappycli-#{File.basename(@file_path)}"
|
|
51
|
+
FileUtils.cp(@file_path, tmp_file_path)
|
|
52
|
+
|
|
53
|
+
tmp_file_path = zip_mapping_file(tmp_file_path)
|
|
54
|
+
tmp_file_path = dsym_or_txt_file(tmp_file_path)
|
|
55
|
+
|
|
56
|
+
tmp_file_path
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def zip_mapping_file(tmp_file_path)
|
|
60
|
+
if File.size?(tmp_file_path) > 50 * 1000 * 1000
|
|
61
|
+
logger.info 'Zipping mapping file.......'
|
|
62
|
+
|
|
63
|
+
system("zip -qr #{tmp_file_path}.zip #{tmp_file_path}")
|
|
64
|
+
tmp_file_path += '.zip'
|
|
65
|
+
|
|
66
|
+
logger.info "Zipped Mapping file size - #{File.size?(tmp_file_path)}"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
tmp_file_path
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def dsym_or_txt_file(tmp_file_path)
|
|
73
|
+
if File.dsym?(@file_path)
|
|
74
|
+
FileUtils.mv(tmp_file_path, tmp_file_path + '.dSYM')
|
|
75
|
+
tmp_file_path += '.dSYM'
|
|
76
|
+
elsif File.text?(@file_path)
|
|
77
|
+
FileUtils.mv(tmp_file_path, tmp_file_path + '.txt')
|
|
78
|
+
tmp_file_path += '.txt'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
tmp_file_path
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
|
|
3
|
+
module Flappy
|
|
4
|
+
module MultiIO
|
|
5
|
+
|
|
6
|
+
class MultiDelegator
|
|
7
|
+
def initialize(*targets)
|
|
8
|
+
@targets = targets
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.delegate(*methods)
|
|
12
|
+
methods.each do |m|
|
|
13
|
+
define_method(m) do |*args|
|
|
14
|
+
@targets.map { |t| t.send(m, *args) }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
self
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class <<self
|
|
21
|
+
alias to new
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require_relative './common'
|
|
4
|
+
|
|
5
|
+
module Flappy
|
|
6
|
+
module Parser
|
|
7
|
+
class Apk
|
|
8
|
+
include Parser::Common
|
|
9
|
+
|
|
10
|
+
def initialize(path)
|
|
11
|
+
@apk = ::Android::Apk.new(path)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def full_info(options)
|
|
15
|
+
if options.fetch(:full_info, false)
|
|
16
|
+
basic_info.merge!(icons: tmp_icons)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
basic_info
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def basic_info
|
|
23
|
+
@basic_info ||= {
|
|
24
|
+
type: 'android',
|
|
25
|
+
identifier: @apk.manifest.package_name,
|
|
26
|
+
name: @apk.label,
|
|
27
|
+
build: @apk.manifest.version_code.to_s,
|
|
28
|
+
version: @apk.manifest.version_name.to_s
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @apk.icon is a hash, { icon_name: icon_binary_data }
|
|
33
|
+
def tmp_icons
|
|
34
|
+
begin
|
|
35
|
+
@apk.icon.map { |_, data| generate_tmp_icon(data, :apk) }
|
|
36
|
+
rescue
|
|
37
|
+
[]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Flappy
|
|
4
|
+
module Parser
|
|
5
|
+
module Common
|
|
6
|
+
|
|
7
|
+
# when type is ipa, the icon data is a png file.
|
|
8
|
+
# when type is apk, the icon data is a binary data.
|
|
9
|
+
def generate_tmp_icon data, type
|
|
10
|
+
tmp_icon_path = "#{Dir.tmpdir}/icon-#{SecureRandom.hex[4..9]}.png"
|
|
11
|
+
|
|
12
|
+
if type == :ipa
|
|
13
|
+
FileUtils.cp(data, tmp_icon_path)
|
|
14
|
+
elsif type == :apk
|
|
15
|
+
File.open(tmp_icon_path, 'w+') { |f| f << data }
|
|
16
|
+
else
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
tmp_icon_path
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Flappy
|
|
4
|
+
module Parser
|
|
5
|
+
module Pngcrush
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
|
|
9
|
+
def png_bin
|
|
10
|
+
@png_bin ||= File.expand_path('../bin/pngcrush', __FILE__)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def uncrush_icon crushed_icon_path, uncrushed_icon_path
|
|
14
|
+
system("#{png_bin} -revert-iphone-optimizations #{crushed_icon_path} #{uncrushed_icon_path} &> /dev/null")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def crush_icon uncrushed_icon_path, crushed_icon_path
|
|
18
|
+
system("#{png_bin} -iphone #{uncrushed_icon_path} #{crushed_icon_path} &> /dev/null")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Flappy
|
|
4
|
+
module Publish
|
|
5
|
+
|
|
6
|
+
def publish(*args, options)
|
|
7
|
+
initialize_publish_options(args, options)
|
|
8
|
+
check_supported_file_and_token
|
|
9
|
+
|
|
10
|
+
logger_info_publishing_message
|
|
11
|
+
|
|
12
|
+
@app_info = send("#{@file_type}_info", @file_path, full_info: true)
|
|
13
|
+
@uploading_info = fetch_uploading_info
|
|
14
|
+
@app_id = @uploading_info[:id]
|
|
15
|
+
|
|
16
|
+
upload_app
|
|
17
|
+
|
|
18
|
+
logger_info_dividing_line
|
|
19
|
+
logger_info_app_short_and_qrcode
|
|
20
|
+
|
|
21
|
+
upload_mapping_file_with_publish(options)
|
|
22
|
+
logger_info_blank_line
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def logger_info_publishing_message
|
|
26
|
+
user_info = fetch_user_info(@token)
|
|
27
|
+
|
|
28
|
+
email = user_info.fetch(:email, '')
|
|
29
|
+
name = user_info.fetch(:name, '')
|
|
30
|
+
|
|
31
|
+
logger.info "Publishing app via #{name}<#{email}>......."
|
|
32
|
+
logger_info_dividing_line
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def upload_app
|
|
36
|
+
@icon_cert = @uploading_info[:cert][:icon]
|
|
37
|
+
@binary_cert = @uploading_info[:cert][:binary]
|
|
38
|
+
|
|
39
|
+
upload_app_icon unless @app_info[:icons].blank?
|
|
40
|
+
upload_app_binary
|
|
41
|
+
upload_device_info
|
|
42
|
+
update_app_info
|
|
43
|
+
fetch_app_info
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
%w(icon binary).each do |postfix|
|
|
47
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
|
48
|
+
def upload_app_#{postfix}
|
|
49
|
+
logger.info "Uploading app #{postfix}......"
|
|
50
|
+
uploaded_info = post(@#{postfix}_cert[:upload_url], uploading_#{postfix}_info)
|
|
51
|
+
|
|
52
|
+
return if uploaded_info[:is_completed]
|
|
53
|
+
|
|
54
|
+
logger.error "Uploading app #{postfix} failed"
|
|
55
|
+
exit 1
|
|
56
|
+
end
|
|
57
|
+
METHOD
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def uploading_icon_info
|
|
61
|
+
large_icon_path = @app_info[:icons].max_by { |f| File.size(f) }
|
|
62
|
+
uncrushed_icon_path = convert_icon(large_icon_path)
|
|
63
|
+
|
|
64
|
+
{
|
|
65
|
+
key: @icon_cert[:key],
|
|
66
|
+
token: @icon_cert[:token],
|
|
67
|
+
file: File.new(uncrushed_icon_path, 'rb'),
|
|
68
|
+
'x:is_converted' => '1'
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def uploading_binary_info
|
|
73
|
+
{
|
|
74
|
+
key: @binary_cert[:key],
|
|
75
|
+
token: @binary_cert[:token],
|
|
76
|
+
file: File.new(@file_path, 'rb'),
|
|
77
|
+
# Custom variables
|
|
78
|
+
'x:name' => @app_info[:display_name] || @app_info[:name],
|
|
79
|
+
'x:build' => @app_info[:build],
|
|
80
|
+
'x:version' => @app_info[:version],
|
|
81
|
+
'x:changelog' => @changelog,
|
|
82
|
+
'x:release_type' => @app_info[:release_type],
|
|
83
|
+
'x:distribution_name' => @app_info[:distribution_name]
|
|
84
|
+
}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def upload_device_info
|
|
88
|
+
return if @app_info[:devices].blank?
|
|
89
|
+
|
|
90
|
+
logger.info 'Updating devices info......'
|
|
91
|
+
|
|
92
|
+
post fir_api[:udids_url], key: @binary_cert[:key],
|
|
93
|
+
udids: @app_info[:devices].join(','),
|
|
94
|
+
api_token: @token
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def update_app_info
|
|
98
|
+
update_info = { short: @short, passwd: @passwd, is_opened: @is_opened }.compact
|
|
99
|
+
|
|
100
|
+
return if update_info.blank?
|
|
101
|
+
|
|
102
|
+
logger.info "Updating app info......"
|
|
103
|
+
|
|
104
|
+
patch fir_api[:app_url] + "/#{@app_id}", update_info.merge(api_token: @token)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def fetch_uploading_info
|
|
108
|
+
logger.info "Fetching #{@app_info[:identifier]}@fir.im uploading info......"
|
|
109
|
+
logger.info "Uploading app: #{@app_info[:name]}-#{@app_info[:version]}(Build #{@app_info[:build]})"
|
|
110
|
+
|
|
111
|
+
post fir_api[:app_url], type: @app_info[:type],
|
|
112
|
+
bundle_id: @app_info[:identifier],
|
|
113
|
+
api_token: @token
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def fetch_app_info
|
|
117
|
+
logger.info 'Fetch app info from fir.im'
|
|
118
|
+
|
|
119
|
+
@fir_app_info = get(fir_api[:app_url] + "/#{@app_id}", api_token: @token)
|
|
120
|
+
write_app_info(id: @fir_app_info[:id], short: @fir_app_info[:short], name: @fir_app_info[:name])
|
|
121
|
+
@fir_app_info
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def upload_mapping_file_with_publish(options)
|
|
125
|
+
return if !options[:mappingfile] || !options[:proj]
|
|
126
|
+
|
|
127
|
+
logger_info_blank_line
|
|
128
|
+
|
|
129
|
+
mapping options[:mappingfile], proj: options[:proj],
|
|
130
|
+
build: @app_info[:build],
|
|
131
|
+
version: @app_info[:version],
|
|
132
|
+
token: @token
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def logger_info_app_short_and_qrcode
|
|
136
|
+
short = "#{fir_api[:domain]}/#{@fir_app_info[:short]}"
|
|
137
|
+
|
|
138
|
+
logger.info "Published succeed: #{short}"
|
|
139
|
+
|
|
140
|
+
if @export_qrcode
|
|
141
|
+
qrcode_path = "#{File.dirname(@file_path)}/fir-#{@app_info[:name]}.png"
|
|
142
|
+
Flappy.generate_rqrcode(short, qrcode_path)
|
|
143
|
+
|
|
144
|
+
logger.info "Local qrcode file: #{qrcode_path}"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
def initialize_publish_options(args, options)
|
|
151
|
+
@file_path = File.absolute_path(args.first.to_s)
|
|
152
|
+
@file_type = File.extname(@file_path).delete('.')
|
|
153
|
+
@token = options[:firToken] || current_token
|
|
154
|
+
@changelog = read_changelog(options[:changelog]).to_s.to_utf8
|
|
155
|
+
@short = options[:short].to_s
|
|
156
|
+
@passwd = options[:password].to_s
|
|
157
|
+
@is_opened = @passwd.blank? ? options[:open] : false
|
|
158
|
+
@export_qrcode = !!options[:qrcode]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def read_changelog(changelog)
|
|
162
|
+
return if changelog.blank?
|
|
163
|
+
File.exist?(changelog) ? File.read(changelog) : changelog
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def check_supported_file_and_token
|
|
167
|
+
check_file_exist(@file_path)
|
|
168
|
+
check_supported_file(@file_path)
|
|
169
|
+
check_token_cannot_be_blank(@token)
|
|
170
|
+
fetch_user_info(@token)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def convert_icon origin_path
|
|
174
|
+
logger.info "Converting app's icon......"
|
|
175
|
+
|
|
176
|
+
if @app_info[:type] == 'ios'
|
|
177
|
+
output_path = Tempfile.new(['uncrushed_icon', '.png']).path
|
|
178
|
+
FIR::Parser::Pngcrush.uncrush_icon(origin_path, output_path)
|
|
179
|
+
origin_path = output_path if File.size(output_path) != 0
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
origin_path
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|