fir-cli 0.0.1 → 0.0.3

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 (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/fir-cli.rb +268 -0
  3. data/lib/lagunitas.ext.rb +26 -0
  4. metadata +3 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6a2a40586779623fdcb4e00c9e33ee646fb3e601
4
- data.tar.gz: d13c1b240b0846bb9a79812930053da22ab39f9d
3
+ metadata.gz: 83254124e7786b02524d0f9e71959d485fa2c0d5
4
+ data.tar.gz: ab7e4fb4fff850ecdd9e77c11cda079b9d9c21f8
5
5
  SHA512:
6
- metadata.gz: 467a11d0e61dac2781637a8036cfe9ce2f850313996e176b2cd1f1112860b9f3b5879f84a204d5ce1230ed94db76670f7c6812daf7e8063dc0ecd14da81bcdd5
7
- data.tar.gz: 660f8b5539ba9480e81fd1ca99e3013bb422ad6e196e5a17f92201a79c03c7f9d0b68dd31b4a32390d93557b431d576b31a266899512048fbdd959d45aec2307
6
+ metadata.gz: 66cc17ddaaa3c2a40b558d6d345d310e1eed7752a61c18d9078963dc37a8f46e82c09951c44b4619bf52718c9f2dc15c54bcc9a2c2176ef1fa355b6133b16400
7
+ data.tar.gz: e902ebef6f9858250f0e51612134684c8bb8982a3bb348c9667dcd8da07e119454555bf2c151c06367ff9bfbebed17d187ce626e274e9bbd4915448d53319faa
data/lib/fir-cli.rb ADDED
@@ -0,0 +1,268 @@
1
+ require 'uri'
2
+ require 'json'
3
+ require 'pathname'
4
+ require 'tempfile'
5
+ require 'securerandom'
6
+
7
+ require 'thor'
8
+ require 'paint'
9
+ require 'pngdefry'
10
+ require 'user_config'
11
+ require 'rest_client'
12
+ require 'lagunitas'
13
+ require 'lagunitas.ext'
14
+
15
+ # p Lagunitas::App.new('').respond_to? :mobileprovision
16
+
17
+ class FirCli < Thor
18
+ def initialize(*args)
19
+ super
20
+ @uconfig = UserConfig.new '.fir'
21
+ @ipa_config = @uconfig['ipa.yaml']
22
+ if @ipa_config['resign'] == nil then @ipa_config['resign'] = false end
23
+ end
24
+
25
+ desc 'login USER_TOKEN', '以 USER_TOKEN 身份登陆'
26
+ def login(token)
27
+ ot = @ipa_config['token']
28
+ if ot && ot != token
29
+ puts "> 替换用户 #{ot} => #{token}"
30
+ end
31
+ @ipa_config['token'] = token
32
+ @ipa_config.save
33
+ puts "> 当前用户:#{token}"
34
+ end
35
+
36
+ desc 'config', '配置全局设置'
37
+ option :resign, :aliases => '-r', :desc => '是否以企业签名发布,默认为否', :type => :boolean, :default => false
38
+ option :token, :aliases => '-t', :desc => '用户令牌'
39
+ option :email, :aliases => '-e', :desc => '邮件地址'
40
+ option :verbose, :aliases => '-v', :desc => '输出配置项', :type => :boolean
41
+ def config
42
+ if !options[:verbose]
43
+ options.each do |conf|
44
+ puts "> #{ Paint[conf[0].to_s.rjust(10), :blue] } : #{ @ipa_config[conf[0].to_s] } => #{ conf[1] }"
45
+ @ipa_config[conf[0]] = conf[1]
46
+ end
47
+ @ipa_config.save
48
+ end
49
+ puts "> 当前设置:"
50
+ @ipa_config.each {|conf| puts "> #{ Paint[conf[0].to_s.rjust(10), :blue] } => #{conf[1]}"}
51
+ end
52
+
53
+ desc 'update IPA_FILE_PATH', '更新 fir.im 的应用信息'
54
+ option :short, :aliases => '-s', :desc => '自定义短地址'
55
+ option :token, :aliases => '-t', :desc => '用户令牌,不写则使用已经登陆信息'
56
+ def update(path)
57
+ app = info path, false, true
58
+ fir_app = fir_info app[:identifier]
59
+ opt_short = options[:short]
60
+ post = {}
61
+ post[:public] = options[:public] != nil ? options[:public] : @ipa_config['public']
62
+ if opt_short then post[:short] = opt_short end
63
+
64
+ post.each { |i| if i[1] == fir_app[i[0]] then post.delete i[0] end }
65
+
66
+ if post.length == 0 then puts '> 没有可以更新的项目'; return end
67
+ fir_put fir_app[:id], post
68
+
69
+ fir_app = fir_info app[:identifier]
70
+ if opt_short && opt_short != fir_app[:short]
71
+ puts "> 短地址 #{ opt_short } 被占用,FIR.im 自动更新短地址为 #{ fir_app[:short] }"
72
+ end
73
+ puts "> http://fir.im/#{fir_app[:short]}"
74
+ end
75
+
76
+ desc 'publish IPA_FILE_PATH', '将 .ipa 文件发布至 FIR.im'
77
+ option :resign, :aliases => '-r', :desc => '进行企业签名', :type => :boolean
78
+ option :short, :aliases => '-s', :desc => '自定义短地址'
79
+ option :token, :aliases => '-t', :desc => '用户令牌,不写则使用已经登陆信息'
80
+ option :changelog, :aliases => '-c', :desc => '修改纪录,默认为空字符串', :default => ''
81
+ def publish(path)
82
+ if opt_resign
83
+ tfile = Tempfile.new SecureRandom.hex
84
+ resign path, tfile.path
85
+ path = tfile.path
86
+ end
87
+ app = info path
88
+ fir_app = fir_info app[:identifier]
89
+
90
+ id = fir_app[:id]
91
+ short = fir_app[:short]
92
+ bundle_app = fir_app[:bundle][:pkg]
93
+ bundle_icon = fir_app[:bundle][:icon]
94
+
95
+ puts '> 上传应用...'
96
+ res = RestClient.post bundle_app[:url],
97
+ :key => bundle_app[:key],
98
+ :token => bundle_app[:token],
99
+ :file => File.new(path, 'rb')
100
+ puts '> 上传应用成功'
101
+ upload_res = JSON.parse res.body, :symbolize_names => true
102
+
103
+ if app[:icons] != nil
104
+ icon_path = app[:icons][0][:path]
105
+
106
+ puts '> 转换图标...'
107
+ Pngdefry.defry icon_path, icon_path
108
+
109
+ puts "> 上传图标..."
110
+ RestClient.post bundle_icon[:url],
111
+ :key => bundle_icon[:key],
112
+ :token => bundle_icon[:token],
113
+ :file => File.new(icon_path, 'rb')
114
+
115
+ puts '上传图标成功'
116
+ end
117
+
118
+ fir_put fir_app[:id],
119
+ :name => app[:display_name] || app[:name],
120
+ :short => options[:short] || fir_app[:short],
121
+ :version => app[:version],
122
+ :versionShort => app[:short_version]
123
+
124
+ fir_vput upload_res[:versionOid],
125
+ :version => app[:version],
126
+ :versionShort => app[:short_version],
127
+ :devices => app[:devices],
128
+ :release_type => app[:release_type],
129
+ :changelog => options[:changelog]
130
+
131
+
132
+ puts "> http://fir.im/#{short}"
133
+ end
134
+
135
+ desc 'digg IPA_FILE_PATH', '获取 .ipa 文件的信息'
136
+ option 'verbose', :aliases => '-v', :desc => '显示更多信息', :type => :boolean
137
+ option 'fir', :aliases => '-f', :desc => '显示托管在 fir.im 的信息', :type => :boolean
138
+ def digg(path)
139
+ app = info path, false, options['verbose']
140
+ app.each { |i| puts "#{ Paint[i[0].to_s.rjust(15), :blue] } #{ i[1] }" }
141
+ if options[:fir]
142
+ fir_app = fir_info app[:identifier]
143
+ fir_app.each { |i| puts "#{ Paint[i[0].to_s.rjust(15), :blue] } #{ i[1] }" }
144
+ end
145
+ end
146
+
147
+ desc 'resign IPA_FILE_PATH OUTPUT_PATH', '使用 resign.tapbeta.com 进行企业签名'
148
+ option 'email', :aliases => '-e', :desc => '邮件地址'
149
+ def resign(ipath, opath)
150
+ puts '! resign.tapbeta.com 签名服务风险提示'
151
+ puts '! 无法保证签名证书的长期有效性,当某种条件满足后'
152
+ puts '! 苹果会禁止该企业账号,所有由该企业账号所签发的'
153
+ puts '! 证书都会失效。您如果使用该网站提供的服务进行应'
154
+ puts "! 用分发,请注意:#{ Paint['当证书失效后,所有安装以失效证', :red ] }"
155
+ puts "! #{ Paint['书签名的的用户都会无法正常运行应用;同时托管在', :red ] }"
156
+ puts "! #{ Paint['fir.im 的应用将无法正常安装。', :red ] }"
157
+ if opt_email == nil
158
+ puts Paint['! 您需要提供邮件地址才能使用 resign.tapbeta.com 的签名服务', :red]
159
+ puts Paint['! 使用 fir config --email=EMAIL 进行设置', :green]
160
+ exit
161
+ end
162
+ if !/\.ipa$/.match ipath
163
+ puts Paint['! 只能给以 ipa 为扩展名的文件签名', :red]
164
+ exit
165
+ end
166
+ puts '> 正在申请上传令牌...'
167
+ upload_res = RestClient.post 'http://api.resign.tapbeta.com/public/upload',
168
+ :email => @email,
169
+ :file => File.basename(ipath)
170
+ form = JSON.parse upload_res.body, :symbolize_names => true
171
+ tapbeta = {}
172
+ form.each do |f|
173
+ if /^tb_/.match f[0]
174
+ tapbeta[f[0]] = f[1]
175
+ form.delete f[0]
176
+ end
177
+ end
178
+ form[:file] = File.new Pathname.new(Dir.pwd).join(ipath).cleanpath, 'rb'
179
+ puts '> 正在上传...'
180
+ RestClient.post tapbeta[:tb_upload_url], form
181
+ puts '> 正在排队...'
182
+ nped = true
183
+ info = {}
184
+ loop do
185
+ res = RestClient.get "http://api.resign.tapbeta.com/public/#{ tapbeta[:tb_upload_key] }",
186
+ :params => { :__mr => 'eyJ1cmwiOiIkKHVybCkiLCAicmVzaWduU3RhdHVzIjogIiQocmVzaWduU3RhdHVzKSJ9' }
187
+ info = JSON.parse res.body, :symbolize_names => true
188
+ if nped && info[:resignStatus] == 'doing'
189
+ puts '> 正在签名...'
190
+ nped = false
191
+ end
192
+ if info[:url] != '' then break end
193
+ sleep 5
194
+ end
195
+ opath = Pathname.new(Dir.pwd).join(opath).cleanpath
196
+ puts "> 正在下载到 #{ opath }..."
197
+ `curl #{info[:url]} -o #{opath} -s`
198
+ end
199
+
200
+ private
201
+ def info(path, quiet = false, more = false)
202
+ path = Pathname.new(Dir.pwd).join(path).cleanpath
203
+ ipa = Lagunitas::IPA.new path
204
+ if !quiet then puts '> 正在解析 ipa 文件...' end
205
+ app = ipa.app
206
+ info = {
207
+ :identifier => app.identifier,
208
+ :name => app.name,
209
+ :display_name => app.display_name,
210
+ :version => app.version,
211
+ :short_version => app.short_version,
212
+ :devices => app.devices,
213
+ :release_type => app.release_type
214
+ # :distribution_name => app.distribution_name
215
+ }
216
+ if more
217
+ begin
218
+ info[:icons] = app.icons
219
+ rescue
220
+ end
221
+ info[:plist] = app.info
222
+ end
223
+ ipa.cleanup
224
+ info
225
+ end
226
+ def fir_info(identifier, quiet = false)
227
+ if !opt_token
228
+ puts Paint['! 您还没有登录', :red]
229
+ puts Paint['! 请 fir login USER_TOKEN 登录', :green]
230
+ exit
231
+ end
232
+ body = { :token => @token }
233
+ if !quiet then puts '> 正在获取 fir 的应用信息...' end
234
+ res = RestClient.get "http://fir.im/api/v2/app/info/#{identifier}?#{URI.encode_www_form body}"
235
+ JSON.parse res.body, :symbolize_names => true
236
+ end
237
+ def fir_put(id, body, quiet = false)
238
+ if !opt_token
239
+ puts Paint['! 您还没有登录', :red]
240
+ puts Paint['! 请 fir login USER_TOKEN 登录', :green]
241
+ exit
242
+ end
243
+ body[:token] = @token
244
+ if !quiet then puts '> 正在更新 fir 的应用信息...' end
245
+ RestClient.put "http://fir.im/api/v2/app/#{id}?#{URI.encode_www_form body}", body
246
+ puts '> 更新成功'
247
+ end
248
+ def fir_vput(id, body, quiet = false)
249
+ if !opt_token
250
+ puts Paint['! 您还没有登录', :red]
251
+ puts Paint['! 请 fir login USER_TOKEN 登录', :green]
252
+ exit
253
+ end
254
+ body[:token] = @token
255
+ if !quiet then puts '> 正在更新 fir 的应用版本信息...' end
256
+ RestClient.put "http://fir.im/api/v2/appVersion/#{id}/complete?#{URI.encode_www_form body}", body
257
+ puts '> 更新成功'
258
+ end
259
+ def opt_token
260
+ @token = options[:token] || @ipa_config['token'] || nil
261
+ end
262
+ def opt_email
263
+ @email = options[:email] || @ipa_config['email'] || nil
264
+ end
265
+ def opt_resign
266
+ @resign = options[:resign] || @ipa_config['resign'] || nil
267
+ end
268
+ end
@@ -0,0 +1,26 @@
1
+ require 'cfpropertylist'
2
+ require 'lagunitas'
3
+ module Lagunitas
4
+ class App
5
+ def name
6
+ @info['CFBundleName']
7
+ end
8
+ def mobileprovision
9
+ @mobileprovision = CFPropertyList.native_types CFPropertyList::List.new(:data => `security cms -D -i #{File.join @path, 'embedded.mobileprovision'}`).value
10
+ end
11
+ def devices
12
+ mobileprovision['ProvisionedDevices']
13
+ end
14
+ def distribution_name
15
+ mobileprovision['DeveloperCertificates']
16
+ end
17
+ def release_type
18
+ if devices == nil
19
+ 'inhouse'
20
+ else
21
+ 'adhoc'
22
+ end
23
+ end
24
+
25
+ end
26
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fir-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yan
@@ -101,6 +101,8 @@ executables:
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
+ - lib/fir-cli.rb
105
+ - lib/lagunitas.ext.rb
104
106
  - bin/fir
105
107
  homepage: https://github.com/idy/fir-cli
106
108
  licenses: