fir-cli 0.0.7 → 0.1.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 +4 -4
- data/.gitignore +85 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +37 -0
- data/LICENSE.txt +22 -0
- data/README.md +69 -0
- data/bin/fir +9 -1
- data/fir-cli.gemspec +26 -0
- data/fir-cli.rb +8 -0
- data/lib/fir-cli-commands/config.rb +21 -0
- data/lib/fir-cli-commands/info.rb +17 -0
- data/lib/fir-cli-commands/login.rb +16 -0
- data/lib/fir-cli-commands/publish.rb +66 -0
- data/lib/fir-cli-commands/resign.rb +67 -0
- data/lib/fir-cli-commands/update.rb +28 -0
- data/lib/fir-cli.ext.rb +172 -0
- data/lib/lagunitas.ext.rb +2 -1
- metadata +21 -8
- data/lib/fir-cli.rb +0 -321
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3954cf53014a8df835ab179b86ab8d2db19f88ac
|
|
4
|
+
data.tar.gz: eb30457b5e3eae90ad3ec155aedebe7b5735c9f6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e21a7166998730abcd305a041c379a0f9749756b8d8f4dae21a7b7ac01628bbe39576f6712c3eb008b7a6fa78657bdc34c3be0e217e1e55831db1d0ef3133a0a
|
|
7
|
+
data.tar.gz: 4120ab1cecace7ed4f098399302589ff7cb1938dcf4a9430a89cee112ba66321d7935f477fe23d73f376b5153969c796661161225c15dd9d0f8c7f9cd1a5ae66
|
data/.gitignore
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Created by https://www.gitignore.io
|
|
2
|
+
|
|
3
|
+
### Ruby ###
|
|
4
|
+
*.gem
|
|
5
|
+
*.rbc
|
|
6
|
+
/.config
|
|
7
|
+
/coverage/
|
|
8
|
+
/InstalledFiles
|
|
9
|
+
/pkg/
|
|
10
|
+
/spec/reports/
|
|
11
|
+
/test/tmp/
|
|
12
|
+
/test/version_tmp/
|
|
13
|
+
/tmp/
|
|
14
|
+
|
|
15
|
+
## Specific to RubyMotion:
|
|
16
|
+
.dat*
|
|
17
|
+
.repl_history
|
|
18
|
+
build/
|
|
19
|
+
|
|
20
|
+
## Documentation cache and generated files:
|
|
21
|
+
/.yardoc/
|
|
22
|
+
/_yardoc/
|
|
23
|
+
/doc/
|
|
24
|
+
/rdoc/
|
|
25
|
+
|
|
26
|
+
## Environment normalisation:
|
|
27
|
+
/.bundle/
|
|
28
|
+
/lib/bundler/man/
|
|
29
|
+
|
|
30
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
31
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
32
|
+
# Gemfile.lock
|
|
33
|
+
# .ruby-version
|
|
34
|
+
# .ruby-gemset
|
|
35
|
+
|
|
36
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
37
|
+
.rvmrc
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### Linux ###
|
|
41
|
+
*~
|
|
42
|
+
|
|
43
|
+
# KDE directory preferences
|
|
44
|
+
.directory
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
### OSX ###
|
|
48
|
+
.DS_Store
|
|
49
|
+
.AppleDouble
|
|
50
|
+
.LSOverride
|
|
51
|
+
|
|
52
|
+
# Icon must end with two \r
|
|
53
|
+
Icon
|
|
54
|
+
|
|
55
|
+
# Thumbnails
|
|
56
|
+
._*
|
|
57
|
+
|
|
58
|
+
# Files that might appear on external disk
|
|
59
|
+
.Spotlight-V100
|
|
60
|
+
.Trashes
|
|
61
|
+
|
|
62
|
+
# Directories potentially created on remote AFP share
|
|
63
|
+
.AppleDB
|
|
64
|
+
.AppleDesktop
|
|
65
|
+
Network Trash Folder
|
|
66
|
+
Temporary Items
|
|
67
|
+
.apdisk
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### SublimeText ###
|
|
71
|
+
# cache files for sublime text
|
|
72
|
+
*.tmlanguage.cache
|
|
73
|
+
*.tmPreferences.cache
|
|
74
|
+
*.stTheme.cache
|
|
75
|
+
|
|
76
|
+
# workspace files are user-specific
|
|
77
|
+
*.sublime-workspace
|
|
78
|
+
|
|
79
|
+
# project files should be checked into the repository, unless a significant
|
|
80
|
+
# proportion of contributors will probably not be using SublimeText
|
|
81
|
+
# *.sublime-project
|
|
82
|
+
|
|
83
|
+
# sftp configuration file
|
|
84
|
+
sftp-config.json
|
|
85
|
+
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
fir-cli (0.1.0)
|
|
5
|
+
lagunitas (= 0.0.1)
|
|
6
|
+
paint (~> 0.9.0)
|
|
7
|
+
pngdefry (= 0.1.1)
|
|
8
|
+
rest_client (~> 1.8.2)
|
|
9
|
+
ruby_apk (~> 0.7.1)
|
|
10
|
+
thor (~> 0.19.1)
|
|
11
|
+
user_config (= 0.0.4)
|
|
12
|
+
|
|
13
|
+
GEM
|
|
14
|
+
remote: https://ruby.taobao.org/
|
|
15
|
+
specs:
|
|
16
|
+
CFPropertyList (2.2.8)
|
|
17
|
+
lagunitas (0.0.1)
|
|
18
|
+
CFPropertyList
|
|
19
|
+
pngdefry (>= 0.1.0)
|
|
20
|
+
zip
|
|
21
|
+
netrc (0.7.9)
|
|
22
|
+
paint (0.9.0)
|
|
23
|
+
pngdefry (0.1.1)
|
|
24
|
+
rest_client (1.8.2)
|
|
25
|
+
netrc (~> 0.7.7)
|
|
26
|
+
ruby_apk (0.7.1)
|
|
27
|
+
rubyzip (< 1.0.0)
|
|
28
|
+
rubyzip (0.9.9)
|
|
29
|
+
thor (0.19.1)
|
|
30
|
+
user_config (0.0.4)
|
|
31
|
+
zip (2.0.2)
|
|
32
|
+
|
|
33
|
+
PLATFORMS
|
|
34
|
+
ruby
|
|
35
|
+
|
|
36
|
+
DEPENDENCIES
|
|
37
|
+
fir-cli!
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 idy0013@gmail.com
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
FIR.im 命令行工具
|
|
2
|
+
---
|
|
3
|
+
###安装
|
|
4
|
+
```shell
|
|
5
|
+
gem install fir-cli
|
|
6
|
+
```
|
|
7
|
+
###指令文档
|
|
8
|
+
####帮助
|
|
9
|
+
> 以下指令可以获取帮助
|
|
10
|
+
|
|
11
|
+
```shell
|
|
12
|
+
fir help
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
> 以下指令获取具体指令的帮助
|
|
16
|
+
|
|
17
|
+
- `COMMAND`:具体的一个指令,如`publish`,`update`
|
|
18
|
+
```shell
|
|
19
|
+
fir help COMMAND
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
####登录
|
|
23
|
+
> 以下指令通过用户`USER_TOKEN`登录,已登录用户可以在[这里](http://fir.im/user/info)上可以查看自己的令牌。
|
|
24
|
+
|
|
25
|
+
```shell
|
|
26
|
+
fir login USER_TOKEN
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
####获取应用文件的信息
|
|
30
|
+
> 以下指令可以显示应用文件的信息,支持 ipa 和 apk 文件。
|
|
31
|
+
|
|
32
|
+
- `-v`:可选,显示更多信息
|
|
33
|
+
- `-f`:可选,显示托管在 [FIR.im](http://fir.im) 的信息
|
|
34
|
+
```shell
|
|
35
|
+
fir info APP_FILE_PATH [-f] [-v]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
####设置全局信息
|
|
39
|
+
> 以下指令可以设置全局信息.
|
|
40
|
+
|
|
41
|
+
- `-r`:可选,默认发布都会使用企业证书签名
|
|
42
|
+
- `-t TOKEN`:可选,设置登录用户的令牌(作用和`fir loging USER_TOKEN`一样)
|
|
43
|
+
- `-e EMAIL`:可选,设置用户使用企业签名服务的默认邮件地址
|
|
44
|
+
```shell
|
|
45
|
+
fir config [-r] [-t TOKEN] [-e EMAIL]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
####企业证书签名
|
|
49
|
+
> 以下指令使用 [resign.tapbeta.com](http://resign.tapbeta.com) 进行企业证书签名
|
|
50
|
+
|
|
51
|
+
- `INPUT_IPA_FILE`:待签名的 ipa 文件
|
|
52
|
+
- `OUTPUT_IPA_FILE`:签名后的输出文件
|
|
53
|
+
- `-e EMAIL`:可选,设置使用签名服务的邮件地址,不填则使用全局设置
|
|
54
|
+
```shell
|
|
55
|
+
fir resign INTPUT_IPA_FILE OUTPUT_IPA_FILE [-e EMAIL]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
####发布应用至 [FIR.im](http://fir.im)
|
|
59
|
+
> 以下指令将指定应用文件发布到 [FIR.im](http://fir.im),支持 ipa 和 apk 文件。
|
|
60
|
+
|
|
61
|
+
- `-r`:可选,设置此开关将首先企业签名,之后发布到 [FIR.im](http://fir.im)
|
|
62
|
+
- `-s SHORT`:可选,指定发布应用的短地址
|
|
63
|
+
- `-t USER_TOKEN`:可选,设定发布应用的帐号,未设置则使用全局设置
|
|
64
|
+
- `-c CHANGE_LOG`:可选,设置发布的发布日志
|
|
65
|
+
```shell
|
|
66
|
+
fir publish APP_FILE_PATH [-r] [-s SHORT] [-t USER_TOKEN] [-c CHANGE_LOG]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
|
data/bin/fir
CHANGED
data/fir-cli.gemspec
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'fir-cli'
|
|
7
|
+
s.version = '0.1.0'
|
|
8
|
+
s.date = '2014-11-20'
|
|
9
|
+
s.summary = 'FIR.im 命令行工具'
|
|
10
|
+
s.description = 'FIR.im 命令行工具,支持 ios 和 android'
|
|
11
|
+
s.homepage = 'http://blog.fir.im/2014/fir-cli'
|
|
12
|
+
s.author = 'FIR.im'
|
|
13
|
+
s.email = 'fir-cli@fir.im'
|
|
14
|
+
s.license = 'GPL'
|
|
15
|
+
s.executables << 'fir'
|
|
16
|
+
s.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
s.require_paths = ['./']
|
|
18
|
+
|
|
19
|
+
s.add_dependency 'lagunitas', '0.0.1'
|
|
20
|
+
s.add_dependency 'user_config', '0.0.4'
|
|
21
|
+
s.add_dependency 'pngdefry', '0.1.1'
|
|
22
|
+
s.add_dependency 'rest_client', '~> 1.8.2'
|
|
23
|
+
s.add_dependency 'paint', '~> 0.9.0'
|
|
24
|
+
s.add_dependency 'thor', '~> 0.19.1'
|
|
25
|
+
s.add_dependency 'ruby_apk', '~> 0.7.1'
|
|
26
|
+
end
|
data/fir-cli.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Fir
|
|
2
|
+
class Cli < Thor
|
|
3
|
+
desc 'config', '配置全局设置'
|
|
4
|
+
option :token, :aliases => '-t', :desc => '用户令牌'
|
|
5
|
+
option :email, :aliases => '-e', :desc => '邮件地址'
|
|
6
|
+
option :resign, :aliases => '-r', :desc => '是否以企业签名发布 ios 应用', :type => :boolean
|
|
7
|
+
option :verbose, :aliases => '-v', :desc => '输出级别项 v, vv, vvv', :type => :string, :enum => ['v', 'vv', 'vvv']
|
|
8
|
+
option :quiet, :aliases => '-q', :desc => '安静模式', :type => :boolean
|
|
9
|
+
def config
|
|
10
|
+
if options.length > 0
|
|
11
|
+
options.each do |conf|
|
|
12
|
+
puts "> #{ Paint[conf[0].to_s.rjust(10), :blue] } : #{ @config[conf[0].to_s] } => #{ conf[1] }"
|
|
13
|
+
@config[conf[0]] = conf[1]
|
|
14
|
+
end
|
|
15
|
+
@config.save
|
|
16
|
+
end
|
|
17
|
+
puts '> 当前设置:'
|
|
18
|
+
@config.each {|conf| puts "> #{ Paint[conf[0].to_s.rjust(10), :blue] } => #{ conf[1] }"}
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Fir
|
|
2
|
+
class Cli < Thor
|
|
3
|
+
desc 'info APP_FILE_PATH', '获取应用文件的信息(支持 ipa 文件和 apk 文件)'
|
|
4
|
+
option :all, :aliases => '-a', :desc => '显示全部应用信息', :type => :boolean
|
|
5
|
+
option :fir, :aliases => '-f', :desc => '显示托管在 fir.im 的应用信息', :type => :boolean
|
|
6
|
+
option :verbose, :aliases => '-v', :desc => '设置输出级别 v, vv, vvv'
|
|
7
|
+
option :quiet, :aliases => '-q', :desc => '安静模式,不输出任何选项'
|
|
8
|
+
def info(path)
|
|
9
|
+
app = _info path, options[:all]
|
|
10
|
+
app.each { |i| puts "#{ Paint[i[0].to_s.rjust(18), :blue] } #{ i[1] }" }
|
|
11
|
+
if options[:fir]
|
|
12
|
+
fir_app = _fir_info app[:identifier], app[:type]
|
|
13
|
+
fir_app.each { |i| puts "#{ Paint[i[0].to_s.rjust(18), :blue] } #{ i[1] }" }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Fir
|
|
2
|
+
class Cli < Thor
|
|
3
|
+
desc 'login USER_TOKEN', '以 USER_TOKEN 身份登陆'
|
|
4
|
+
option :verbose, :aliases => '-v', :desc => '设置输出级别 v, vv, vvv'
|
|
5
|
+
option :quite, :aliases => '-q', :desc => '安静模式,不输出任何选项'
|
|
6
|
+
def login(token)
|
|
7
|
+
if _opt_token && _opt_token != token
|
|
8
|
+
_puts "> 已登陆用户: #{ _opt_token }"
|
|
9
|
+
_puts "> 替换为用户: #{ token }"
|
|
10
|
+
end
|
|
11
|
+
@config['token'] = token
|
|
12
|
+
@config.save
|
|
13
|
+
_puts "> 当前登陆用户为:#{ token }"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Fir
|
|
2
|
+
class Cli < Thor
|
|
3
|
+
desc 'publish APP_FILE_PATH', '将应用文件发布至 FIR.im(支持 ipa 文件和 apk 文件)'
|
|
4
|
+
option :resign, :aliases => '-r', :desc => '进行企业签名', :type => :boolean
|
|
5
|
+
option :short, :aliases => '-s', :desc => '自定义短地址'
|
|
6
|
+
option :token, :aliases => '-t', :desc => '用户令牌,不写则使用已经登陆信息'
|
|
7
|
+
option :changelog, :aliases => '-c', :desc => '修改纪录,默认为空字符串', :default => ''
|
|
8
|
+
option :verbose, :aliases => '-v', :desc => '设置输出级别 v, vv, vvv'
|
|
9
|
+
option :quiet, :aliases => '-q', :desc => '安静模式,不输出任何选项'
|
|
10
|
+
def publish(path)
|
|
11
|
+
if _opt_resign && _is_ipa(path)
|
|
12
|
+
tfile = Tempfile.new ["resign-#{ SecureRandom.hex }", '.ipa']
|
|
13
|
+
resign path, tfile.path
|
|
14
|
+
path = tfile.path
|
|
15
|
+
end
|
|
16
|
+
app = _info path, true
|
|
17
|
+
fir_app = _fir_info app[:identifier], app[:type]
|
|
18
|
+
|
|
19
|
+
id = fir_app[:id]
|
|
20
|
+
short = fir_app[:short]
|
|
21
|
+
bundle_app = fir_app[:bundle][:pkg]
|
|
22
|
+
bundle_icon = fir_app[:bundle][:icon]
|
|
23
|
+
|
|
24
|
+
if app[:icons] != nil && app[:icons].length > 0
|
|
25
|
+
icon_path = app[:icons][0][:path]
|
|
26
|
+
|
|
27
|
+
if _is_ipa path
|
|
28
|
+
_puts '> 转换图标...'
|
|
29
|
+
Pngdefry.defry icon_path, icon_path
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
_puts "> 上传图标..."
|
|
33
|
+
RestClient.post bundle_icon[:url],
|
|
34
|
+
:key => bundle_icon[:key],
|
|
35
|
+
:token => bundle_icon[:token],
|
|
36
|
+
:file => File.new(icon_path, 'rb')
|
|
37
|
+
|
|
38
|
+
_puts '> 上传图标成功'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
_puts '> 上传应用...'
|
|
42
|
+
res = RestClient.post bundle_app[:url],
|
|
43
|
+
:key => bundle_app[:key],
|
|
44
|
+
:token => bundle_app[:token],
|
|
45
|
+
:file => File.new(path, 'rb')
|
|
46
|
+
_puts '> 上传应用成功'
|
|
47
|
+
upload_res = JSON.parse res.body, :symbolize_names => true
|
|
48
|
+
|
|
49
|
+
_fir_put fir_app[:id],
|
|
50
|
+
:name => app[:display_name] || app[:name],
|
|
51
|
+
:short => options[:short] || fir_app[:short],
|
|
52
|
+
:version => app[:version],
|
|
53
|
+
:versionShort => app[:short_version]
|
|
54
|
+
|
|
55
|
+
_fir_vput upload_res[:versionOid],
|
|
56
|
+
:version => app[:version],
|
|
57
|
+
:versionShort => app[:short_version],
|
|
58
|
+
:devices => app[:devices],
|
|
59
|
+
:release_type => app[:release_type],
|
|
60
|
+
:changelog => options[:changelog]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
_puts "> http://fir.im/#{short}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Fir
|
|
2
|
+
class Cli < Thor
|
|
3
|
+
desc 'resign IPA_FILE_PATH OUTPUT_PATH', '使用 resign.tapbeta.com 进行企业签名'
|
|
4
|
+
option :email, :aliases => '-e', :desc => '邮件地址'
|
|
5
|
+
option :verbose, :aliases => '-v', :desc => '设置输出级别 v, vv, vvv'
|
|
6
|
+
option :quiet, :aliases => '-q', :desc => '安静模式,不输出任何选项'
|
|
7
|
+
def resign(ipath, opath)
|
|
8
|
+
_puts "! #{ Paint['resign.tapbeta.com 签名服务风险提示', :red] }"
|
|
9
|
+
_puts '! 无法保证签名证书的长期有效性,当某种条件满足后'
|
|
10
|
+
_puts '! 苹果会禁止该企业账号,所有由该企业账号所签发的'
|
|
11
|
+
_puts '! 证书都会失效。您如果使用该网站提供的服务进行应'
|
|
12
|
+
_puts "! 用分发,请注意:#{ Paint['当证书失效后,所有安装了已失效', :red ] }"
|
|
13
|
+
_puts "! #{ Paint['证书签名的用户都会无法正常运行应用;同时托管在', :red ] }"
|
|
14
|
+
_puts "! #{ Paint['fir.im 的应用将无法正常安装。', :red ] }"
|
|
15
|
+
if _opt_email == nil
|
|
16
|
+
_puts "! #{ Paint['您需要提供邮件地址才能使用 resign.tapbeta.com', :red] }"
|
|
17
|
+
_puts "! #{ Paint['的签名服务, 请输入:', :red] } fir config --email=EMAIL"
|
|
18
|
+
_puts "! #{ Paint['进行设置', :red] }"
|
|
19
|
+
exit 1
|
|
20
|
+
end
|
|
21
|
+
if !/\.ipa$/.match ipath
|
|
22
|
+
_puts Paint['! 只能给以 ipa 为扩展名的文件签名', :red]
|
|
23
|
+
exit 1
|
|
24
|
+
end
|
|
25
|
+
_puts '> 正在申请上传令牌...'
|
|
26
|
+
upload_res = RestClient.post 'http://api.resign.tapbeta.com/public/upload',
|
|
27
|
+
:email => @email,
|
|
28
|
+
:file => File.basename(ipath)
|
|
29
|
+
form = JSON.parse upload_res.body, :symbolize_names => true
|
|
30
|
+
tapbeta = {}
|
|
31
|
+
form.each do |f|
|
|
32
|
+
if /^tb_/.match f[0]
|
|
33
|
+
tapbeta[f[0]] = f[1]
|
|
34
|
+
form.delete f[0]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
form[:file] = File.new Pathname.new(Dir.pwd).join(ipath).cleanpath, 'rb'
|
|
38
|
+
_puts '> 正在上传...'
|
|
39
|
+
res = RestClient.post tapbeta[:tb_upload_url], form
|
|
40
|
+
|
|
41
|
+
# Upyun's notify is fucking, handle it specific
|
|
42
|
+
# if tapbeta[:tb_upload_url].include? 'upyun'
|
|
43
|
+
# RestClient.get "#{ form[:'notify-url'] }?#{ URI.encode_www_form JSON.parse res.body }"
|
|
44
|
+
# end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
_puts '> 正在排队...'
|
|
48
|
+
nped = true
|
|
49
|
+
info = {}
|
|
50
|
+
loop do
|
|
51
|
+
res = RestClient.get "http://api.resign.tapbeta.com/public/#{ tapbeta[:tb_upload_key] }",
|
|
52
|
+
:params => { :__mr => 'eyJ1cmwiOiIkKHVybCkiLCAicmVzaWduU3RhdHVzIjogIiQocmVzaWduU3RhdHVzKSJ9' }
|
|
53
|
+
info = JSON.parse res.body, :symbolize_names => true
|
|
54
|
+
if nped && info[:resignStatus] == 'doing'
|
|
55
|
+
_puts '> 正在签名...'
|
|
56
|
+
nped = false
|
|
57
|
+
end
|
|
58
|
+
break if info[:url] != ''
|
|
59
|
+
sleep 5
|
|
60
|
+
end
|
|
61
|
+
opath = Pathname.new(Dir.pwd).join(opath).cleanpath
|
|
62
|
+
_puts "> 正在下载到 #{ opath }..."
|
|
63
|
+
`curl #{ info[:url] } -o #{ opath } -s`
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Fir
|
|
2
|
+
class Cli < Thor
|
|
3
|
+
desc 'update APP_FILE_PATH|BUNDLE_ID', '更新 FIR.im 的应用信息'
|
|
4
|
+
option :short, :aliases => '-s', :desc => '自定义短地址'
|
|
5
|
+
option :token, :aliases => '-t', :desc => '用户令牌,不写则使用已经登陆信息'
|
|
6
|
+
option :verbose, :aliases => '-v', :desc => '设置输出级别 v, vv, vvv'
|
|
7
|
+
option :quiet, :aliases => '-q', :desc => '安静模式,不输出任何选项'
|
|
8
|
+
def update(path)
|
|
9
|
+
identifier = path
|
|
10
|
+
identifier = _info(path)[:identifier] if File.exist? _path path
|
|
11
|
+
fir_app = _fir_info identifier
|
|
12
|
+
opt_short = options[:short]
|
|
13
|
+
post = {}
|
|
14
|
+
post[:short] = opt_short if opt_short
|
|
15
|
+
|
|
16
|
+
post.each { |i| post.delete i[0] if i[1] == fir_app[i[0]] }
|
|
17
|
+
|
|
18
|
+
if post.length == 0 then _puts '> 没有什么可以更新的'; return end
|
|
19
|
+
_fir_put fir_app[:id], post
|
|
20
|
+
|
|
21
|
+
fir_app = _fir_info identifier
|
|
22
|
+
if opt_short && opt_short != fir_app[:short]
|
|
23
|
+
_puts "> 短地址 #{ opt_short } 被占用,FIR.im 自动更新短地址为 #{ fir_app[:short] }"
|
|
24
|
+
end
|
|
25
|
+
_puts "> http://fir.im/#{ fir_app[:short] }"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/fir-cli.ext.rb
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
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 'ruby_apk'
|
|
14
|
+
|
|
15
|
+
module Fir
|
|
16
|
+
class Cli < Thor
|
|
17
|
+
def initialize(*args)
|
|
18
|
+
super
|
|
19
|
+
_init_config
|
|
20
|
+
_puts_welcome
|
|
21
|
+
end
|
|
22
|
+
def self.load_extends
|
|
23
|
+
`gem list --local`.each_line("\n") do |gem|
|
|
24
|
+
gem_name = /^[^\s]+/.match(gem)[0]
|
|
25
|
+
require gem_name if gem_name.start_with? 'fir-cli-'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
private
|
|
29
|
+
def _init_config
|
|
30
|
+
@uconfig = UserConfig.new '.fir'
|
|
31
|
+
@config = @uconfig['default.yaml']
|
|
32
|
+
@tmpfiles = []
|
|
33
|
+
end
|
|
34
|
+
def _path(path)
|
|
35
|
+
path = Pathname.new(Dir.pwd).join(path).cleanpath
|
|
36
|
+
end
|
|
37
|
+
def _opt_token
|
|
38
|
+
@token ||= options[:token] || @config['token']
|
|
39
|
+
end
|
|
40
|
+
def _opt_email
|
|
41
|
+
@email ||= options[:email] || @config['email']
|
|
42
|
+
end
|
|
43
|
+
def _opt_verbose
|
|
44
|
+
@verbose ||= options[:verbose] || @config['verbose']
|
|
45
|
+
end
|
|
46
|
+
def _opt_resign
|
|
47
|
+
return options[:resign] if defined? options[:resign]
|
|
48
|
+
@resign ||= options[:resign] || @config['resign']
|
|
49
|
+
end
|
|
50
|
+
def _opt_quiet
|
|
51
|
+
return options[:quiet] if defined? options[:quiet]
|
|
52
|
+
@quiet ||= options[:quiet] || @config['quiet']
|
|
53
|
+
end
|
|
54
|
+
def _is_ipa(path)
|
|
55
|
+
path.end_with? '.ipa'
|
|
56
|
+
end
|
|
57
|
+
def _is_apk(path)
|
|
58
|
+
path.end_with? '.apk'
|
|
59
|
+
end
|
|
60
|
+
def _is_identifier(str)
|
|
61
|
+
/^(?:(?:[a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*(?:[A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$/.match str
|
|
62
|
+
end
|
|
63
|
+
def _chk_login
|
|
64
|
+
if !_opt_token
|
|
65
|
+
_puts "! #{ Paint['您还没有登录, 请输入:', :red] } fir login USER_TOKEN #{ Paint['进行登录', :red] }"
|
|
66
|
+
exit 1
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
def _puts_welcome
|
|
70
|
+
_puts "> #{ Paint['欢迎使用 FIR.im 命令行工具,如需帮助请输入:', :green] } fir help"
|
|
71
|
+
end
|
|
72
|
+
def _puts(text)
|
|
73
|
+
return if _opt_quiet
|
|
74
|
+
case _opt_verbose || 'vv' # If nothing about log is set, use the default option - vv
|
|
75
|
+
when 'v'
|
|
76
|
+
puts text if text.start_with?('!')
|
|
77
|
+
when 'vv'
|
|
78
|
+
puts text if text.start_with?('!') || text.start_with?('>')
|
|
79
|
+
when 'vvv'
|
|
80
|
+
puts text if text.start_with?('!') || text.start_with?('>') || text.start_with?('-')
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
def _info(path, more = false)
|
|
84
|
+
if _is_ipa path
|
|
85
|
+
_ipa_info path, more
|
|
86
|
+
elsif _is_apk path
|
|
87
|
+
_apk_info path, more
|
|
88
|
+
else
|
|
89
|
+
_puts "! #{ Paint['只能支持后缀为 ipa 和 apk 地文件', :red] }"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
def _apk_info(path, more = false)
|
|
93
|
+
path = _path path
|
|
94
|
+
apk = Android::Apk.new path
|
|
95
|
+
info = {
|
|
96
|
+
:type => 'android',
|
|
97
|
+
:identifier => apk.manifest.package_name,
|
|
98
|
+
:name => apk.label,
|
|
99
|
+
:version => apk.manifest.version_code,
|
|
100
|
+
:short_version => apk.manifest.version_name
|
|
101
|
+
}
|
|
102
|
+
if more
|
|
103
|
+
info[:icons] = apk.icon.map do |name, data|
|
|
104
|
+
tfile = Tempfile.new ["icon-#{ SecureRandom.hex }", '.png']
|
|
105
|
+
tfile.write data
|
|
106
|
+
@tmpfiles.push tfile
|
|
107
|
+
{
|
|
108
|
+
:name => File.basename(name),
|
|
109
|
+
:path => tfile.path
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
info
|
|
114
|
+
end
|
|
115
|
+
def _ipa_info(path, more = false)
|
|
116
|
+
path = _path path
|
|
117
|
+
ipa = Lagunitas::IPA.new path
|
|
118
|
+
_puts '> 正在解析 ipa 文件...'
|
|
119
|
+
app = ipa.app
|
|
120
|
+
info = {
|
|
121
|
+
:type => 'ios',
|
|
122
|
+
:identifier => app.identifier,
|
|
123
|
+
:name => app.name,
|
|
124
|
+
:display_name => app.display_name,
|
|
125
|
+
:version => app.version,
|
|
126
|
+
:short_version => app.short_version,
|
|
127
|
+
:devices => app.devices,
|
|
128
|
+
:release_type => app.release_type,
|
|
129
|
+
:distribution_name => app.distribution_name
|
|
130
|
+
}
|
|
131
|
+
if more
|
|
132
|
+
if app.icons
|
|
133
|
+
info[:icons] = app.icons.map do |icon|
|
|
134
|
+
tfile = Tempfile.new ["icon-#{ SecureRandom.hex }", '.png']
|
|
135
|
+
@tmpfiles.push tfile
|
|
136
|
+
FileUtils.cp icon[:path], tfile.path
|
|
137
|
+
{
|
|
138
|
+
:name => File.basename(icon[:path]),
|
|
139
|
+
:path => tfile.path
|
|
140
|
+
}
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
info[:plist] = app.info
|
|
144
|
+
app.mobileprovision.delete 'DeveloperCertificates' if app.mobileprovision
|
|
145
|
+
info[:mobileprovision] = app.mobileprovision
|
|
146
|
+
end
|
|
147
|
+
ipa.cleanup
|
|
148
|
+
info
|
|
149
|
+
end
|
|
150
|
+
def _fir_info(identifier, type = 'ios')
|
|
151
|
+
_puts "> 正在获取 #{ identifier }@FIR.im 的应用信息..."
|
|
152
|
+
_chk_login
|
|
153
|
+
body = { :token => @token, :type => type }
|
|
154
|
+
res = RestClient.get "http://fir.im/api/v2/app/info/#{ identifier }?#{ URI.encode_www_form body }"
|
|
155
|
+
JSON.parse res.body, :symbolize_names => true
|
|
156
|
+
end
|
|
157
|
+
def _fir_put(id, body)
|
|
158
|
+
_chk_login
|
|
159
|
+
body[:token] = @token
|
|
160
|
+
_puts '> 正在更新 fir 的应用信息...'
|
|
161
|
+
RestClient.put "http://fir.im/api/v2/app/#{ id }?#{ URI.encode_www_form body }", body
|
|
162
|
+
_puts '> 更新成功'
|
|
163
|
+
end
|
|
164
|
+
def _fir_vput(id, body)
|
|
165
|
+
_chk_login
|
|
166
|
+
body[:token] = @token
|
|
167
|
+
_puts '> 正在更新 fir 的应用版本信息...'
|
|
168
|
+
RestClient.put "http://fir.im/api/v2/appVersion/#{ id }/complete?#{ URI.encode_www_form body }", body
|
|
169
|
+
_puts '> 更新成功'
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
data/lib/lagunitas.ext.rb
CHANGED
|
@@ -21,7 +21,8 @@ module Lagunitas
|
|
|
21
21
|
mobileprovision['ProvisionedDevices'] if mobileprovision
|
|
22
22
|
end
|
|
23
23
|
def distribution_name
|
|
24
|
-
mobileprovision['DeveloperCertificates'] if mobileprovision
|
|
24
|
+
# mobileprovision['DeveloperCertificates'] if mobileprovision
|
|
25
|
+
"#{ mobileprovision['Name'] }: #{ mobileprovision['TeamName'] }" if mobileprovision
|
|
25
26
|
end
|
|
26
27
|
def metadata
|
|
27
28
|
return if !metadata?
|
metadata
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fir-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- FIR.im
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
@@ -109,24 +109,37 @@ dependencies:
|
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: 0.7.1
|
|
111
111
|
description: FIR.im 命令行工具,支持 ios 和 android
|
|
112
|
-
email:
|
|
112
|
+
email: fir-cli@fir.im
|
|
113
113
|
executables:
|
|
114
114
|
- fir
|
|
115
115
|
extensions: []
|
|
116
116
|
extra_rdoc_files: []
|
|
117
117
|
files:
|
|
118
|
-
-
|
|
118
|
+
- .gitignore
|
|
119
|
+
- Gemfile
|
|
120
|
+
- Gemfile.lock
|
|
121
|
+
- LICENSE.txt
|
|
122
|
+
- README.md
|
|
123
|
+
- bin/fir
|
|
124
|
+
- fir-cli.gemspec
|
|
125
|
+
- fir-cli.rb
|
|
126
|
+
- lib/fir-cli-commands/config.rb
|
|
127
|
+
- lib/fir-cli-commands/info.rb
|
|
128
|
+
- lib/fir-cli-commands/login.rb
|
|
129
|
+
- lib/fir-cli-commands/publish.rb
|
|
130
|
+
- lib/fir-cli-commands/resign.rb
|
|
131
|
+
- lib/fir-cli-commands/update.rb
|
|
132
|
+
- lib/fir-cli.ext.rb
|
|
119
133
|
- lib/lagunitas.ext.rb
|
|
120
134
|
- lib/lagunitas.patch.rb
|
|
121
|
-
|
|
122
|
-
homepage: https://github.com/idy/fir-cli
|
|
135
|
+
homepage: http://blog.fir.im/2014/fir-cli
|
|
123
136
|
licenses:
|
|
124
|
-
-
|
|
137
|
+
- GPL
|
|
125
138
|
metadata: {}
|
|
126
139
|
post_install_message:
|
|
127
140
|
rdoc_options: []
|
|
128
141
|
require_paths:
|
|
129
|
-
-
|
|
142
|
+
- ./
|
|
130
143
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
144
|
requirements:
|
|
132
145
|
- - '>='
|
data/lib/fir-cli.rb
DELETED
|
@@ -1,321 +0,0 @@
|
|
|
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.patch'
|
|
14
|
-
require 'lagunitas.ext'
|
|
15
|
-
require 'ruby_apk'
|
|
16
|
-
|
|
17
|
-
# p Lagunitas::App.new('').respond_to? :mobileprovision
|
|
18
|
-
|
|
19
|
-
class FirCli < Thor
|
|
20
|
-
def initialize(*args)
|
|
21
|
-
super
|
|
22
|
-
@uconfig = UserConfig.new '.fir'
|
|
23
|
-
@ipa_config = @uconfig['ipa.yaml']
|
|
24
|
-
@ipa_config['resign'] = false if @ipa_config['resign'] == nil
|
|
25
|
-
@tmpfiles = []
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
desc 'login USER_TOKEN', '以 USER_TOKEN 身份登陆'
|
|
29
|
-
def login(token)
|
|
30
|
-
ot = @ipa_config['token']
|
|
31
|
-
if ot && ot != token
|
|
32
|
-
puts "> 替换用户 #{ot} => #{token}"
|
|
33
|
-
end
|
|
34
|
-
@ipa_config['token'] = token
|
|
35
|
-
@ipa_config.save
|
|
36
|
-
puts "> 当前用户:#{token}"
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
desc 'config', '配置全局设置'
|
|
40
|
-
option :resign, :aliases => '-r', :desc => '是否以企业签名发布', :type => :boolean
|
|
41
|
-
option :token, :aliases => '-t', :desc => '用户令牌'
|
|
42
|
-
option :email, :aliases => '-e', :desc => '邮件地址'
|
|
43
|
-
option :verbose, :aliases => '-v', :desc => '输出配置项', :type => :boolean
|
|
44
|
-
def config
|
|
45
|
-
if !options[:verbose]
|
|
46
|
-
options.each do |conf|
|
|
47
|
-
puts "> #{ Paint[conf[0].to_s.rjust(10), :blue] } : #{ @ipa_config[conf[0].to_s] } => #{ conf[1] }"
|
|
48
|
-
@ipa_config[conf[0]] = conf[1]
|
|
49
|
-
end
|
|
50
|
-
@ipa_config.save
|
|
51
|
-
end
|
|
52
|
-
puts "> 当前设置:"
|
|
53
|
-
@ipa_config.each {|conf| puts "> #{ Paint[conf[0].to_s.rjust(10), :blue] } => #{conf[1]}"}
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
desc 'update IPA_FILE_PATH', '更新 fir.im 的应用信息'
|
|
57
|
-
option :short, :aliases => '-s', :desc => '自定义短地址'
|
|
58
|
-
option :token, :aliases => '-t', :desc => '用户令牌,不写则使用已经登陆信息'
|
|
59
|
-
def update(path)
|
|
60
|
-
app = _info path
|
|
61
|
-
fir_app = _fir_info app[:identifier], app[:type]
|
|
62
|
-
opt_short = options[:short]
|
|
63
|
-
post = {}
|
|
64
|
-
post[:short] = opt_short if opt_short
|
|
65
|
-
|
|
66
|
-
post.each { |i| post.delete i[0] if i[1] == fir_app[i[0]] }
|
|
67
|
-
|
|
68
|
-
if post.length == 0 then puts '> 没有可以更新的项目'; return end
|
|
69
|
-
_fir_put fir_app[:id], post
|
|
70
|
-
|
|
71
|
-
fir_app = _fir_info app[:identifier], app[:type]
|
|
72
|
-
if opt_short && opt_short != fir_app[:short]
|
|
73
|
-
puts "> 短地址 #{ opt_short } 被占用,FIR.im 自动更新短地址为 #{ fir_app[:short] }"
|
|
74
|
-
end
|
|
75
|
-
puts "> http://fir.im/#{fir_app[:short]}"
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
desc 'publish IPA_FILE_PATH', '将 .ipa 文件发布至 FIR.im'
|
|
79
|
-
option :resign, :aliases => '-r', :desc => '进行企业签名', :type => :boolean
|
|
80
|
-
option :short, :aliases => '-s', :desc => '自定义短地址'
|
|
81
|
-
option :token, :aliases => '-t', :desc => '用户令牌,不写则使用已经登陆信息'
|
|
82
|
-
option :changelog, :aliases => '-c', :desc => '修改纪录,默认为空字符串', :default => ''
|
|
83
|
-
def publish(path)
|
|
84
|
-
if _opt_resign && _is_ipa(path)
|
|
85
|
-
tfile = Tempfile.new SecureRandom.hex
|
|
86
|
-
resign path, tfile.path
|
|
87
|
-
path = tfile.path
|
|
88
|
-
end
|
|
89
|
-
app = _info path, false, true
|
|
90
|
-
fir_app = _fir_info app[:identifier], app[:type]
|
|
91
|
-
|
|
92
|
-
id = fir_app[:id]
|
|
93
|
-
short = fir_app[:short]
|
|
94
|
-
bundle_app = fir_app[:bundle][:pkg]
|
|
95
|
-
bundle_icon = fir_app[:bundle][:icon]
|
|
96
|
-
|
|
97
|
-
puts '> 上传应用...'
|
|
98
|
-
res = RestClient.post bundle_app[:url],
|
|
99
|
-
:key => bundle_app[:key],
|
|
100
|
-
:token => bundle_app[:token],
|
|
101
|
-
:file => File.new(path, 'rb')
|
|
102
|
-
puts '> 上传应用成功'
|
|
103
|
-
upload_res = JSON.parse res.body, :symbolize_names => true
|
|
104
|
-
|
|
105
|
-
if app[:icons] != nil
|
|
106
|
-
icon_path = app[:icons][0][:path]
|
|
107
|
-
|
|
108
|
-
if _is_ipa path
|
|
109
|
-
puts '> 转换图标...'
|
|
110
|
-
Pngdefry.defry icon_path, icon_path
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
puts "> 上传图标..."
|
|
114
|
-
RestClient.post bundle_icon[:url],
|
|
115
|
-
:key => bundle_icon[:key],
|
|
116
|
-
:token => bundle_icon[:token],
|
|
117
|
-
:file => File.new(icon_path, 'rb')
|
|
118
|
-
|
|
119
|
-
puts '> 上传图标成功'
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
_fir_put fir_app[:id],
|
|
123
|
-
:name => app[:display_name] || app[:name],
|
|
124
|
-
:short => options[:short] || fir_app[:short],
|
|
125
|
-
:version => app[:version],
|
|
126
|
-
:versionShort => app[:short_version]
|
|
127
|
-
|
|
128
|
-
_fir_vput upload_res[:versionOid],
|
|
129
|
-
:version => app[:version],
|
|
130
|
-
:versionShort => app[:short_version],
|
|
131
|
-
:devices => app[:devices],
|
|
132
|
-
:release_type => app[:release_type],
|
|
133
|
-
:changelog => options[:changelog]
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
puts "> http://fir.im/#{short}"
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
desc 'info IPA_FILE_PATH', '获取 .ipa 文件的信息'
|
|
140
|
-
option 'verbose', :aliases => '-v', :desc => '显示更多信息', :type => :boolean
|
|
141
|
-
option 'fir', :aliases => '-f', :desc => '显示托管在 fir.im 的信息', :type => :boolean
|
|
142
|
-
def info(path)
|
|
143
|
-
app = _info path, false, options['verbose']
|
|
144
|
-
app.each { |i| puts "#{ Paint[i[0].to_s.rjust(15), :blue] } #{ i[1] }" }
|
|
145
|
-
if options[:fir]
|
|
146
|
-
fir_app = _fir_info app[:identifier], app[:type]
|
|
147
|
-
fir_app.each { |i| puts "#{ Paint[i[0].to_s.rjust(15), :blue] } #{ i[1] }" }
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
desc 'resign IPA_FILE_PATH OUTPUT_PATH', '使用 resign.tapbeta.com 进行企业签名'
|
|
152
|
-
option 'email', :aliases => '-e', :desc => '邮件地址'
|
|
153
|
-
def resign(ipath, opath)
|
|
154
|
-
puts '! resign.tapbeta.com 签名服务风险提示'
|
|
155
|
-
puts '! 无法保证签名证书的长期有效性,当某种条件满足后'
|
|
156
|
-
puts '! 苹果会禁止该企业账号,所有由该企业账号所签发的'
|
|
157
|
-
puts '! 证书都会失效。您如果使用该网站提供的服务进行应'
|
|
158
|
-
puts "! 用分发,请注意:#{ Paint['当证书失效后,所有安装以失效证', :red ] }"
|
|
159
|
-
puts "! #{ Paint['书签名的的用户都会无法正常运行应用;同时托管在', :red ] }"
|
|
160
|
-
puts "! #{ Paint['fir.im 的应用将无法正常安装。', :red ] }"
|
|
161
|
-
if _opt_email == nil
|
|
162
|
-
puts Paint['! 您需要提供邮件地址才能使用 resign.tapbeta.com 的签名服务', :red]
|
|
163
|
-
puts Paint['! 使用 fir config --email=EMAIL 进行设置', :green]
|
|
164
|
-
exit
|
|
165
|
-
end
|
|
166
|
-
if !/\.ipa$/.match ipath
|
|
167
|
-
puts Paint['! 只能给以 ipa 为扩展名的文件签名', :red]
|
|
168
|
-
exit
|
|
169
|
-
end
|
|
170
|
-
puts '> 正在申请上传令牌...'
|
|
171
|
-
upload_res = RestClient.post 'http://api.resign.tapbeta.com/public/upload',
|
|
172
|
-
:email => @email,
|
|
173
|
-
:file => File.basename(ipath)
|
|
174
|
-
form = JSON.parse upload_res.body, :symbolize_names => true
|
|
175
|
-
tapbeta = {}
|
|
176
|
-
form.each do |f|
|
|
177
|
-
if /^tb_/.match f[0]
|
|
178
|
-
tapbeta[f[0]] = f[1]
|
|
179
|
-
form.delete f[0]
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
form[:file] = File.new Pathname.new(Dir.pwd).join(ipath).cleanpath, 'rb'
|
|
183
|
-
puts '> 正在上传...'
|
|
184
|
-
RestClient.post tapbeta[:tb_upload_url], form
|
|
185
|
-
puts '> 正在排队...'
|
|
186
|
-
nped = true
|
|
187
|
-
info = {}
|
|
188
|
-
loop do
|
|
189
|
-
res = RestClient.get "http://api.resign.tapbeta.com/public/#{ tapbeta[:tb_upload_key] }",
|
|
190
|
-
:params => { :__mr => 'eyJ1cmwiOiIkKHVybCkiLCAicmVzaWduU3RhdHVzIjogIiQocmVzaWduU3RhdHVzKSJ9' }
|
|
191
|
-
info = JSON.parse res.body, :symbolize_names => true
|
|
192
|
-
if nped && info[:resignStatus] == 'doing'
|
|
193
|
-
puts '> 正在签名...'
|
|
194
|
-
nped = false
|
|
195
|
-
end
|
|
196
|
-
break if info[:url] != ''
|
|
197
|
-
sleep 5
|
|
198
|
-
end
|
|
199
|
-
opath = Pathname.new(Dir.pwd).join(opath).cleanpath
|
|
200
|
-
puts "> 正在下载到 #{ opath }..."
|
|
201
|
-
`curl #{info[:url]} -o #{opath} -s`
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
private
|
|
205
|
-
def _path(path)
|
|
206
|
-
path = Pathname.new(Dir.pwd).join(path).cleanpath
|
|
207
|
-
end
|
|
208
|
-
def _info(path, quiet = false, more = false, bin = false)
|
|
209
|
-
if _is_ipa path
|
|
210
|
-
_ipa_info path, quiet, more
|
|
211
|
-
elsif _is_apk path
|
|
212
|
-
_apk_info path, quiet, more
|
|
213
|
-
else
|
|
214
|
-
puts Paint['! 只能支持后缀为 ipa 和 apk 地文件', :red]
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
def _apk_info(path, quiet = false, more = false)
|
|
218
|
-
path = _path path
|
|
219
|
-
apk = Android::Apk.new path
|
|
220
|
-
info = {
|
|
221
|
-
:type => 'android',
|
|
222
|
-
:identifier => apk.manifest.package_name,
|
|
223
|
-
:name => apk.label,
|
|
224
|
-
:version => apk.manifest.version_code,
|
|
225
|
-
:short_version => apk.manifest.version_name
|
|
226
|
-
}
|
|
227
|
-
if more
|
|
228
|
-
info[:icons] = apk.icon.map do |name, data|
|
|
229
|
-
tfile = Tempfile.new SecureRandom.hex
|
|
230
|
-
tfile.write data
|
|
231
|
-
@tmpfiles.push tfile
|
|
232
|
-
{
|
|
233
|
-
:name => File.basename(name),
|
|
234
|
-
:path => tfile.path
|
|
235
|
-
}
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
info
|
|
239
|
-
end
|
|
240
|
-
def _ipa_info(path, quiet = false, more = false, bin = false)
|
|
241
|
-
path = _path path
|
|
242
|
-
ipa = Lagunitas::IPA.new path
|
|
243
|
-
puts '> 正在解析 ipa 文件...' if !quiet
|
|
244
|
-
app = ipa.app
|
|
245
|
-
info = {
|
|
246
|
-
:type => 'ios',
|
|
247
|
-
:identifier => app.identifier,
|
|
248
|
-
:name => app.name,
|
|
249
|
-
:display_name => app.display_name,
|
|
250
|
-
:version => app.version,
|
|
251
|
-
:short_version => app.short_version,
|
|
252
|
-
:devices => app.devices,
|
|
253
|
-
:release_type => app.release_type
|
|
254
|
-
# :distribution_name => app.distribution_name
|
|
255
|
-
}
|
|
256
|
-
if more
|
|
257
|
-
info[:icons] = app.icons.map do |icon|
|
|
258
|
-
tfile = Tempfile.new SecureRandom.hex
|
|
259
|
-
@tmpfiles.push tfile
|
|
260
|
-
File.copy icon[:path], tfile.path
|
|
261
|
-
{
|
|
262
|
-
:name => File.basename(icon[:path]),
|
|
263
|
-
:path => tfile.path
|
|
264
|
-
}
|
|
265
|
-
end
|
|
266
|
-
info[:plist] = app.info
|
|
267
|
-
end
|
|
268
|
-
ipa.cleanup
|
|
269
|
-
info
|
|
270
|
-
end
|
|
271
|
-
def _fir_info(identifier, type = 'ios', quiet = false)
|
|
272
|
-
if !_opt_token
|
|
273
|
-
puts Paint['! 您还没有登录', :red]
|
|
274
|
-
puts Paint['! 请 fir login USER_TOKEN 登录', :green]
|
|
275
|
-
exit
|
|
276
|
-
end
|
|
277
|
-
body = { :token => @token }
|
|
278
|
-
body[:type] = type
|
|
279
|
-
puts '> 正在获取 fir 的应用信息...' if !quiet
|
|
280
|
-
res = RestClient.get "http://fir.im/api/v2/app/info/#{identifier}?#{URI.encode_www_form body}"
|
|
281
|
-
JSON.parse res.body, :symbolize_names => true
|
|
282
|
-
end
|
|
283
|
-
def _fir_put(id, body, quiet = false)
|
|
284
|
-
if !_opt_token
|
|
285
|
-
puts Paint['! 您还没有登录', :red]
|
|
286
|
-
puts Paint['! 请 fir login USER_TOKEN 登录', :green]
|
|
287
|
-
exit
|
|
288
|
-
end
|
|
289
|
-
body[:token] = @token
|
|
290
|
-
puts '> 正在更新 fir 的应用信息...' if !quiet
|
|
291
|
-
RestClient.put "http://fir.im/api/v2/app/#{id}?#{URI.encode_www_form body}", body
|
|
292
|
-
puts '> 更新成功'
|
|
293
|
-
end
|
|
294
|
-
def _fir_vput(id, body, quiet = false)
|
|
295
|
-
if !_opt_token
|
|
296
|
-
puts Paint['! 您还没有登录', :red]
|
|
297
|
-
puts Paint['! 请 fir login USER_TOKEN 登录', :green]
|
|
298
|
-
exit
|
|
299
|
-
end
|
|
300
|
-
body[:token] = @token
|
|
301
|
-
puts '> 正在更新 fir 的应用版本信息...' if !quiet
|
|
302
|
-
RestClient.put "http://fir.im/api/v2/appVersion/#{id}/complete?#{URI.encode_www_form body}", body
|
|
303
|
-
puts '> 更新成功'
|
|
304
|
-
end
|
|
305
|
-
def _opt_token
|
|
306
|
-
@token = options[:token] || @ipa_config['token'] || nil
|
|
307
|
-
end
|
|
308
|
-
def _opt_email
|
|
309
|
-
@email = options[:email] || @ipa_config['email'] || nil
|
|
310
|
-
end
|
|
311
|
-
def _opt_resign
|
|
312
|
-
return options[:resign] if defined? options[:resign]
|
|
313
|
-
@resign = options[:resign] || @ipa_config['resign'] || nil
|
|
314
|
-
end
|
|
315
|
-
def _is_ipa(path)
|
|
316
|
-
/\.ipa$/.match path
|
|
317
|
-
end
|
|
318
|
-
def _is_apk(path)
|
|
319
|
-
/\.apk$/.match path
|
|
320
|
-
end
|
|
321
|
-
end
|