yjcocoa 18.11.22 → 19.01.05
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/lib/yjcocoa/command.rb +1 -0
- data/lib/yjcocoa/git/git_pull.rb +6 -7
- data/lib/yjcocoa/git/git_tag_add.rb +1 -1
- data/lib/yjcocoa/pod/pod_release.rb +2 -10
- data/lib/yjcocoa/test.rb +7 -2
- data/lib/yjcocoa/unused/unused.rb +63 -0
- data/lib/yjcocoa/unused/unused_class.rb +107 -0
- data/lib/yjcocoa/unused/unused_image.rb +98 -0
- data/lib/yjcocoa/unused/unused_method.rb +91 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d266e13f581e8b1e706cfae22758563cde9ccf80
|
4
|
+
data.tar.gz: a3ceb39237847ad6873865e63beb5c3aa6dfb20c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2c1e1b68c4098051235349c7e49b9c6b64705210b5e9ed1fe53e9640bc66496e415383c3939896e1e5b717b57e9c181279f9517564e3cd44cf4d0538962c89c
|
7
|
+
data.tar.gz: c1b7f1068d3f60e22ea160a99fed19b22f795f12c07d4559047f9a964890b5b33bc2ed2e578cdc05fe5f118cd6fe5f2c6ebb6bd9b6cd3136c3d0d1ce122f766c
|
data/README.md
CHANGED
data/lib/yjcocoa/command.rb
CHANGED
data/lib/yjcocoa/git/git_pull.rb
CHANGED
@@ -15,20 +15,20 @@ module YJCocoa
|
|
15
15
|
|
16
16
|
self.command = 'pull'
|
17
17
|
self.summary = 'git pull'
|
18
|
-
self.description = 'git pull 当前文件夹下所有 gits
|
18
|
+
self.description = 'git pull 当前文件夹下所有 gits'
|
19
19
|
|
20
20
|
def self.options
|
21
|
-
[['--
|
21
|
+
[['--all', 'pull all branch'],]
|
22
22
|
end
|
23
23
|
|
24
24
|
# property
|
25
|
-
attr_accessor :
|
25
|
+
attr_accessor :all #是否拉取所有分支
|
26
26
|
attr_accessor :gits # git array
|
27
27
|
|
28
28
|
# 初始化
|
29
29
|
def initialize(argv)
|
30
30
|
super
|
31
|
-
self.
|
31
|
+
self.all = argv.flag?('all', false)
|
32
32
|
end
|
33
33
|
|
34
34
|
# businrss
|
@@ -57,9 +57,8 @@ module YJCocoa
|
|
57
57
|
Dir.chdir(path) {
|
58
58
|
puts "YJCocoa git pull #{path}/.git".green
|
59
59
|
localChanges = !(`git stash` =~ /No local changes to save/)
|
60
|
-
|
61
|
-
|
62
|
-
unless self.currentBranch
|
60
|
+
system("git pull -p")
|
61
|
+
if self.all
|
63
62
|
list = (`git branch`).split("\n")
|
64
63
|
if list.size >= 2
|
65
64
|
headBranch = "master"
|
@@ -23,7 +23,7 @@ module YJCocoa
|
|
23
23
|
if File.exist?(".git")
|
24
24
|
current_branch = self.current_branch
|
25
25
|
tag = File.basename(Dir.pwd)
|
26
|
-
tag << "-#{current_branch}" unless current_branch
|
26
|
+
tag << "-#{current_branch}" unless current_branch == "master"
|
27
27
|
tag << "-#{Time.now.strftime('%Y%m%d%H%M')}"
|
28
28
|
puts "YJCocoa build tag #{tag}".green
|
29
29
|
system("yjcocoa git tag --add=#{tag}")
|
@@ -52,7 +52,6 @@ module YJCocoa
|
|
52
52
|
|
53
53
|
# businrss
|
54
54
|
def run
|
55
|
-
self.gitPull
|
56
55
|
content = []
|
57
56
|
File.open(self.podfile, "r") { |file|
|
58
57
|
while line = file.gets #标准输入流
|
@@ -63,20 +62,13 @@ module YJCocoa
|
|
63
62
|
puts "YJCocoa Pod Release".green
|
64
63
|
puts content.sort * "\n"
|
65
64
|
end
|
66
|
-
|
67
|
-
def gitPull
|
68
|
-
puts "#{self.podfile} git pull".green
|
69
|
-
Dir.chdir(File.dirname(self.podfile)) {| path |
|
70
|
-
system("yjcocoa git pull")
|
71
|
-
}
|
72
|
-
end
|
73
|
-
|
65
|
+
|
74
66
|
private def check (pods, line)
|
75
67
|
pods.each { |pod|
|
76
68
|
if line.include?(pod)
|
77
|
-
pods.delete(pod)
|
78
69
|
line.split(',').each { |item|
|
79
70
|
if item.include?("tag") || item.include?("branch")
|
71
|
+
pods.delete(pod)
|
80
72
|
return "#{pod}, #{item.chomp}"
|
81
73
|
end
|
82
74
|
}
|
data/lib/yjcocoa/test.rb
CHANGED
@@ -1,2 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
gem build yjcocoa.gemspec
|
2
|
+
|
3
|
+
gem install yjcocoa-18.12.13.gem
|
4
|
+
|
5
|
+
yjcocoa unused image --dir=/Users/cisdi/Desktop/QingTui/master --ignore=QTComm,Pods,LaunchImage,Emoji,AppIcon
|
6
|
+
|
7
|
+
otool -oV /Users/cisdi/Desktop/QingTui_Developer
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#
|
2
|
+
# unused.rb
|
3
|
+
# YJCocoaGem
|
4
|
+
#
|
5
|
+
# https://github.com/937447974
|
6
|
+
# YJ技术支持群:557445088
|
7
|
+
#
|
8
|
+
# Created by 阳君 on 2018/12/8.
|
9
|
+
# Copyright © 2018年 YJCocoa. All rights reserved.
|
10
|
+
#
|
11
|
+
|
12
|
+
module YJCocoa
|
13
|
+
|
14
|
+
# Usage
|
15
|
+
class Unused < Command
|
16
|
+
|
17
|
+
self.abstract_command = true
|
18
|
+
self.command = 'unused'
|
19
|
+
self.summary = 'OC 项目未使用资源查找'
|
20
|
+
self.description = 'These are common unused commands used in YJCocoa.'
|
21
|
+
|
22
|
+
# property
|
23
|
+
attr_accessor :matcho
|
24
|
+
attr_accessor :match
|
25
|
+
attr_accessor :ignore
|
26
|
+
attr_accessor :output
|
27
|
+
|
28
|
+
# 初始化
|
29
|
+
def initialize(argv)
|
30
|
+
super
|
31
|
+
self.matcho = argv.option('match-o')
|
32
|
+
self.match = argv.option('match')
|
33
|
+
self.match = self.match.split(",").reject {|i| i.empty? } if self.match
|
34
|
+
self.ignore = argv.option('ignore')
|
35
|
+
self.ignore = self.ignore.split(",").reject {|i| i.empty? } if self.ignore
|
36
|
+
self.output = argv.option('output')
|
37
|
+
self.output = Dir.pwd + "/YJCocoa.h" unless self.output
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_match(item)
|
41
|
+
return true unless self.match
|
42
|
+
self.match.each { |m|
|
43
|
+
return true if item.include?(m)
|
44
|
+
}
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_ignore(item)
|
49
|
+
return false unless self.ignore
|
50
|
+
self.ignore.each { |i|
|
51
|
+
return true if item.include?(i)
|
52
|
+
}
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# Commands
|
59
|
+
require 'yjcocoa/unused/unused_class'
|
60
|
+
require 'yjcocoa/unused/unused_image'
|
61
|
+
require 'yjcocoa/unused/unused_method'
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
#
|
2
|
+
# unused_class.rb
|
3
|
+
# YJCocoaGem
|
4
|
+
#
|
5
|
+
# https://github.com/937447974
|
6
|
+
# YJ技术支持群:557445088
|
7
|
+
#
|
8
|
+
# Created by 阳君 on 2018/12/8.
|
9
|
+
# Copyright © 2018年 YJCocoa. All rights reserved.
|
10
|
+
#
|
11
|
+
|
12
|
+
module YJCocoa
|
13
|
+
|
14
|
+
# Usage
|
15
|
+
class UnusedClass < Unused
|
16
|
+
|
17
|
+
self.command = 'class'
|
18
|
+
self.summary = 'unused class commands'
|
19
|
+
self.description = '查找 OC 项目中未使用的 class'
|
20
|
+
|
21
|
+
def self.options
|
22
|
+
[['--match-o', 'Match O 文件地址'],
|
23
|
+
['--match', '指定的字符串匹配,多字符串用 "," 分隔'],
|
24
|
+
['--ignore', '忽略的字符串匹配, 多字符串用 "," 分隔'],
|
25
|
+
['--output', '日志存放路径,默认当前路径']] + super
|
26
|
+
end
|
27
|
+
|
28
|
+
# businrss
|
29
|
+
def validate!
|
30
|
+
super
|
31
|
+
unless self.matcho && self.matcho.length > 0
|
32
|
+
puts "Match O 文件地址为空".red
|
33
|
+
self.banner!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run
|
38
|
+
unused_class = self.unreferenced_class
|
39
|
+
fetch_class = unused_class.reject {|m| !(check_match(m) && !check_ignore(m))}
|
40
|
+
puts "分析完毕,打开日志:#{self.output}".green
|
41
|
+
File.write(self.output, fetch_class.join("\n"))
|
42
|
+
`open #{self.output}`
|
43
|
+
end
|
44
|
+
|
45
|
+
def unreferenced_class
|
46
|
+
section = match_o_section
|
47
|
+
unless section.count
|
48
|
+
puts "#{self.matcho} can't find classlist".red
|
49
|
+
self.banner!
|
50
|
+
end
|
51
|
+
classlist = section["Contents of (__DATA,__objc_classlist) section"]
|
52
|
+
classrefs = section["Contents of (__DATA,__objc_classrefs) section"]
|
53
|
+
superrefs = section["Contents of (__DATA,__objc_superrefs) section"]
|
54
|
+
all_classlist = objc_classlist(classlist)
|
55
|
+
used_classlist = objc_super_classlist(classlist) + objc_classlist(classrefs) + objc_classlist(superrefs)
|
56
|
+
unused_classlist = []
|
57
|
+
all_classlist.each {|item|
|
58
|
+
unused_classlist << item unless used_classlist.include?(item)
|
59
|
+
}
|
60
|
+
return unused_classlist.sort
|
61
|
+
end
|
62
|
+
|
63
|
+
def match_o_section
|
64
|
+
lines = `otool -oV #{self.matcho}`.split("\n")
|
65
|
+
section = Hash.new
|
66
|
+
key = nil
|
67
|
+
lines.each {|line|
|
68
|
+
line = line#.strip
|
69
|
+
if line.include?("Contents of (__DATA,")
|
70
|
+
key = line
|
71
|
+
elsif (key)
|
72
|
+
if section.include?(key)
|
73
|
+
section[key] << line
|
74
|
+
else
|
75
|
+
section[key] = [line]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
}
|
79
|
+
return section
|
80
|
+
end
|
81
|
+
|
82
|
+
def objc_super_classlist(classlist)
|
83
|
+
result = []
|
84
|
+
classlist.each { |line|
|
85
|
+
line_scan = line.scan(/_OBJC_CLASS_\$_(.+)/)
|
86
|
+
if line_scan.count > 0 && line.include?("superclass")
|
87
|
+
result << line_scan[0][0]
|
88
|
+
end
|
89
|
+
}
|
90
|
+
return result
|
91
|
+
end
|
92
|
+
|
93
|
+
def objc_classlist(classlist)
|
94
|
+
result = []
|
95
|
+
classlist.each { |line|
|
96
|
+
line_scan = line.scan(/_OBJC_CLASS_\$_(.+)/)
|
97
|
+
if line_scan.count > 0 && !line.include?("superclass")
|
98
|
+
result << line_scan[0][0]
|
99
|
+
end
|
100
|
+
}
|
101
|
+
return result
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#
|
2
|
+
# unused_image.rb
|
3
|
+
# YJCocoaGem
|
4
|
+
#
|
5
|
+
# https://github.com/937447974
|
6
|
+
# YJ技术支持群:557445088
|
7
|
+
#
|
8
|
+
# Created by 阳君 on 2018/12/8.
|
9
|
+
# Copyright © 2018年 YJCocoa. All rights reserved.
|
10
|
+
#
|
11
|
+
|
12
|
+
module YJCocoa
|
13
|
+
|
14
|
+
# Usage
|
15
|
+
class UnusedImage < Unused
|
16
|
+
|
17
|
+
self.command = 'image'
|
18
|
+
self.summary = 'unused image commands'
|
19
|
+
self.description = '查找 OC 项目中未使用的 image'
|
20
|
+
|
21
|
+
def self.options
|
22
|
+
[['--dir', '项目文件夹'],
|
23
|
+
['--ignore', '忽略的字符串匹配, 多字符串用 "," 分隔'],
|
24
|
+
['--output', '日志存放路径,默认当前路径']] + super
|
25
|
+
end
|
26
|
+
|
27
|
+
# property
|
28
|
+
attr_accessor :dir
|
29
|
+
attr_accessor :image_hash
|
30
|
+
attr_accessor :class_content
|
31
|
+
|
32
|
+
# 初始化
|
33
|
+
def initialize(argv)
|
34
|
+
super
|
35
|
+
self.dir = argv.option('dir')
|
36
|
+
self.image_hash = Hash.new
|
37
|
+
self.class_content = ""
|
38
|
+
end
|
39
|
+
|
40
|
+
# businrss
|
41
|
+
def validate!
|
42
|
+
super
|
43
|
+
unless self.dir && self.dir.length > 0
|
44
|
+
puts "dir 文件地址为空".red
|
45
|
+
self.banner!
|
46
|
+
end
|
47
|
+
unless Dir.exist?(self.dir)
|
48
|
+
puts "dir 文件路径 #{self.dir} 不是文件夹".red
|
49
|
+
self.banner!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def run
|
54
|
+
unused_image = self.unreferenced_image
|
55
|
+
puts "分析完毕,打开日志:#{self.output}".green
|
56
|
+
File.write(self.output, unused_image.join("\n"))
|
57
|
+
`open #{self.output}`
|
58
|
+
end
|
59
|
+
|
60
|
+
def unreferenced_image
|
61
|
+
self.deal_with_path(self.dir)
|
62
|
+
puts "分析图片资源".green
|
63
|
+
result = []
|
64
|
+
self.image_hash.each {|key, value|
|
65
|
+
puts key
|
66
|
+
result += value unless self.class_content.include?(key)
|
67
|
+
}
|
68
|
+
return result.sort
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def deal_with_path(path)
|
73
|
+
Dir.chdir(path) {
|
74
|
+
Dir["**/*.{png,jpg}"].each {|filename| self.deal_with_image(filename)}
|
75
|
+
Dir["**/*.{h,m,mm,swift,xib,storyboard,plist}"].each {|filename| self.deal_with_file(filename)}
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def deal_with_image(filename)
|
80
|
+
return if self.check_ignore(filename)
|
81
|
+
basename = File.basename(filename)
|
82
|
+
image_gsub = [".png", ".jpg", "@1x", "@2x", "@3x", "@1X", "@2X", "@3X"]
|
83
|
+
image_gsub.each {|gsub| basename.gsub!(gsub, "")}
|
84
|
+
if self.image_hash.include?(basename)
|
85
|
+
self.image_hash[basename] << filename
|
86
|
+
else
|
87
|
+
self.image_hash[basename] = [filename]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def deal_with_file(filename)
|
92
|
+
self.class_content << File.read(filename) unless File.symlink?(filename)
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#
|
2
|
+
# unused_method.rb
|
3
|
+
# YJCocoaGem
|
4
|
+
#
|
5
|
+
# https://github.com/937447974
|
6
|
+
# YJ技术支持群:557445088
|
7
|
+
#
|
8
|
+
# Created by 阳君 on 2018/12/8.
|
9
|
+
# Copyright © 2018年 YJCocoa. All rights reserved.
|
10
|
+
#
|
11
|
+
|
12
|
+
module YJCocoa
|
13
|
+
|
14
|
+
# Usage
|
15
|
+
class UnusedMethod < Unused
|
16
|
+
|
17
|
+
self.command = 'method'
|
18
|
+
self.summary = 'unused method commands'
|
19
|
+
self.description = '查找 OC 项目中未使用的 method'
|
20
|
+
|
21
|
+
def self.options
|
22
|
+
[['--match-o', 'Match O 文件地址'],
|
23
|
+
['--match', '指定的字符串匹配,多字符串用 "," 分隔'],
|
24
|
+
['--ignore', '忽略的字符串匹配, 多字符串用 "," 分隔'],
|
25
|
+
['--output', '日志存放路径,默认当前路径']] + super
|
26
|
+
end
|
27
|
+
|
28
|
+
# businrss
|
29
|
+
def validate!
|
30
|
+
super
|
31
|
+
unless self.matcho && self.matcho.length > 0
|
32
|
+
puts "Match O 文件地址为空".red
|
33
|
+
self.banner!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run
|
38
|
+
unused_methods = self.unreferenced_methods
|
39
|
+
fetch_methods = unused_methods.reject {|m| !(check_match(m) && !check_ignore(m))}
|
40
|
+
puts "分析完毕,打开日志:#{self.output}".green
|
41
|
+
File.write(self.output, fetch_methods.join("\n"))
|
42
|
+
`open #{self.output}`
|
43
|
+
end
|
44
|
+
|
45
|
+
def unreferenced_methods
|
46
|
+
methods = self.implemented_methods
|
47
|
+
unless methods.count
|
48
|
+
puts "#{self.matcho} can't find implemented methods".red
|
49
|
+
self.banner!
|
50
|
+
end
|
51
|
+
sels = self.referenced_selectors
|
52
|
+
sels.each {|sel| methods.delete(sel)}
|
53
|
+
result = []
|
54
|
+
methods.values.each {|value| result += value}
|
55
|
+
return result.sort
|
56
|
+
end
|
57
|
+
|
58
|
+
def implemented_methods
|
59
|
+
lines = `otool -oV #{self.matcho}`.split("\n")
|
60
|
+
methods = Hash.new
|
61
|
+
lines.each {|line|
|
62
|
+
line_scan = line.scan(/\s*imp 0x\w+ ([+|-]\[.+\s(.+)\])/)
|
63
|
+
if line_scan.count > 0
|
64
|
+
imp = line_scan[0][0]
|
65
|
+
sel = line_scan[0][1]
|
66
|
+
if methods.include?(sel)
|
67
|
+
methods[sel] << imp
|
68
|
+
else
|
69
|
+
methods[sel] = [imp]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
}
|
73
|
+
return methods
|
74
|
+
end
|
75
|
+
|
76
|
+
def referenced_selectors
|
77
|
+
lines = `otool -v -s __DATA __objc_selrefs #{self.matcho}`.split("\n")
|
78
|
+
refs = []
|
79
|
+
lines.each { |line|
|
80
|
+
line_scan = line.scan(/__TEXT:__objc_methname:(.+)/)
|
81
|
+
if line_scan.count > 0
|
82
|
+
refs << line_scan[0][0]
|
83
|
+
end
|
84
|
+
}
|
85
|
+
return refs
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yjcocoa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 19.01.05
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 阳君
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: claide
|
@@ -78,6 +78,10 @@ files:
|
|
78
78
|
- lib/yjcocoa/pod/pod_release.rb
|
79
79
|
- lib/yjcocoa/pod/product_class.rb
|
80
80
|
- lib/yjcocoa/test.rb
|
81
|
+
- lib/yjcocoa/unused/unused.rb
|
82
|
+
- lib/yjcocoa/unused/unused_class.rb
|
83
|
+
- lib/yjcocoa/unused/unused_image.rb
|
84
|
+
- lib/yjcocoa/unused/unused_method.rb
|
81
85
|
homepage: https://github.com/937447974/YJCocoaGem
|
82
86
|
licenses:
|
83
87
|
- MIT
|