reuse_xcode_plugins 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e75195c8ee6a35fd9d64e0be344fe7e4c61f737
4
- data.tar.gz: f21de8a4ff1d826f9fc5f41e13ce04cc06dd2a91
3
+ metadata.gz: ee46e89f4b99a95715daaa6e93cb5822ee2ab5c1
4
+ data.tar.gz: 937e2172ded713da5b7765fa25ed4e99965aa1af
5
5
  SHA512:
6
- metadata.gz: 0cbd93594f982beb718bf8f6ec6d917b082f7c18c2ae41d49ce81a5770604e1fd769c0dc549d5b66d37f17db1f000780c524b1e6e952d1e28cb802bb33e67450
7
- data.tar.gz: 670537e822e9436ad411655d7e71f6a1b77e7beeb7c5cbad8e672465655c8fc20444f4c43d00b993ee3705935a314375c7ea4609896982da2c0120b159203d99
6
+ metadata.gz: f51efdf60f5b86ac0592f191812b4e8b82f39a3bd7d7d507715758abb72f58e6d4489daa9a58030704a5714fba2250e0551fb4bfcfb85a2c5b8243bd11a19450
7
+ data.tar.gz: bab0870aa549e8ba3fdd37f34c29f139f36c763e3cdab12f198b71bab9d670bf3d42668cd4b8042c9fa694fdf659843f52ed69a9032eb0713cbe6a27e684419e
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/reuse_xcode_plugins'
4
+
5
+ begin
6
+ if CLI.unsign_xcode?
7
+ XcodeUnsigner.unsign_xcode
8
+ elsif CLI.restore_xcode?
9
+ XcodeUnsigner.restore_xcode
10
+ elsif CLI.update_plugins?
11
+ PluginsUpdater.update_plugins
12
+ else
13
+ puts "请输入参数--unsign(取消签名),--restore(恢复签名),--update_plugins(更新所有插件UUID)"
14
+ end
15
+ rescue Interrupt
16
+ end
Binary file
Binary file
data/lib/bin/unsign ADDED
Binary file
data/lib/bundle.rb ADDED
@@ -0,0 +1,41 @@
1
+ require_relative 'cli'
2
+
3
+ class Bundle
4
+ attr_accessor :path
5
+
6
+ def initialize(path)
7
+ self.path = path.strip
8
+ end
9
+
10
+ def valid?
11
+ false
12
+ end
13
+
14
+ def info_path
15
+ "#{path}/Contents/Info.plist"
16
+ end
17
+
18
+ def bundle_identifier
19
+ defaults_read("CFBundleIdentifier")
20
+ end
21
+
22
+ def version
23
+ defaults_read('CFBundleShortVersionString')
24
+ end
25
+
26
+ def defaults_read(key)
27
+ plist_path = "#{path}/Contents/Info"
28
+ `defaults read "#{plist_path}" #{key}`.strip
29
+ end
30
+
31
+ def defaults_write(*args)
32
+ plist_path = "#{path}/Contents/Info"
33
+ command = "defaults write \"#{plist_path}\" #{args.join(' ')}"
34
+
35
+ if CLI.dry_run?
36
+ puts command
37
+ else
38
+ `#{command}`.strip
39
+ end
40
+ end
41
+ end
data/lib/cli.rb ADDED
@@ -0,0 +1,65 @@
1
+ module CLI
2
+ def self.dry_run?
3
+ ARGV.include?('-d') || ARGV.include?('--dry-run')
4
+ end
5
+
6
+ def self.unsign_xcode?
7
+ ARGV.include?('--unsign')
8
+ end
9
+
10
+ def self.restore_xcode?
11
+ ARGV.include?('--restore')
12
+ end
13
+
14
+ def self.update_plugins?
15
+ ARGV.include?('--update_plugins')
16
+ end
17
+
18
+ def self.no_colors?
19
+ ARGV.include?('--no-colors')
20
+ end
21
+
22
+ def self.non_interactive?
23
+ ARGV.include?('--non-interactive')
24
+ end
25
+
26
+ def self.codesign_exists?
27
+ `which codesign` && $CHILD_STATUS.exitstatus == 0
28
+ end
29
+
30
+ def self.chown_if_required(path)
31
+ return yield if File.owned?(path)
32
+
33
+ puts
34
+ puts "* 正在修改 #{path} 的所有者,之后会恢复".colorize(:light_blue)
35
+
36
+ previous_owner = File.stat(path).uid
37
+ system("sudo chown $(whoami) \"#{path}\"")
38
+
39
+ raise "不能修改 #{path} 的所有者" unless File.owned?(path)
40
+
41
+ result = yield
42
+ system("sudo chown #{previous_owner} \"#{path}\"")
43
+ puts "* 恢复 #{path} 的所有者".colorize(:light_blue)
44
+
45
+ result
46
+ end
47
+
48
+ {
49
+ title: :blue,
50
+ process: :light_blue,
51
+ warning: :yellow,
52
+ error: :red,
53
+ success: :green
54
+ }.each do |type, color|
55
+ if CLI.no_colors?
56
+ define_method type.to_sym do |str| puts str end
57
+ else
58
+ define_method type.to_sym do |str| puts str.colorize(color) end
59
+ end
60
+ end
61
+
62
+ def separator
63
+ puts
64
+ end
65
+ end
@@ -0,0 +1,57 @@
1
+ require_relative 'xcode'
2
+ require_relative 'xcode_plugin'
3
+
4
+ class PluginsUpdater
5
+ extend CLI
6
+
7
+ def self.update_plugins
8
+ xcodes = Xcode.find_xcodes
9
+
10
+ if xcodes.empty?
11
+ error "没有发现任何安装的 Xcode"
12
+ return
13
+ else
14
+ title '已找到'
15
+ puts xcodes.map { |xcode| "- #{xcode.detailed_description}" }
16
+ end
17
+
18
+ separator
19
+
20
+ plugins = XcodePlugin.find_plugins
21
+
22
+ if plugins.empty?
23
+ error "Didn't find any Xcode Plug-in installed on your system."
24
+ return
25
+ else
26
+ title '插件:'
27
+ puts plugins.map { |s| "- #{s}" }
28
+ end
29
+
30
+ separator
31
+ process '更新UUID...'
32
+
33
+ uuids = xcodes.collect(&:uuid)
34
+ uuids.each do |uuid|
35
+ plugins.each do |plugin|
36
+ if plugin.add_uuid(uuid) && !CLI.dry_run?
37
+ success "添加 #{uuid} 到 #{plugin}"
38
+ end
39
+ end
40
+ end
41
+
42
+ separator
43
+ success '完成! 🎉'
44
+
45
+ return if CLI.no_colors?
46
+
47
+ # if xcodes.any? { |xcode| xcode.version.to_f >= 8 }
48
+ # separator
49
+ # warning 'It seems that you have Xcode 8+ installed!'
50
+ # puts 'Some plugins might not work on recent versions of Xcode because of library validation.',
51
+ # "See #{'https://github.com/alcatraz/Alcatraz/issues/475'.underline}"
52
+
53
+ # separator
54
+ # puts "Run `#{'update_xcode_plugins --unsign'.bold}` to fix this."
55
+ # end
56
+ end
57
+ end
@@ -1,3 +1,3 @@
1
1
  module ReuseXcodePlugins
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,7 +1,8 @@
1
- require "reuse_xcode_plugins/version"
2
-
3
- module ReuseXcodePlugins
4
- def self.hello
5
- p "Hello 夜禹!"
6
- end
7
- end
1
+ require 'English'
2
+ require 'fileutils'
3
+ require_relative 'cli'
4
+ require 'colorize' unless CLI.no_colors?
5
+ require 'inquirer' unless CLI.non_interactive?
6
+ # require_relative 'version'
7
+ require_relative 'plugins_updater'
8
+ require_relative 'xcode_unsigner'
data/lib/xcode.rb ADDED
@@ -0,0 +1,127 @@
1
+ require_relative 'bundle'
2
+
3
+ class Xcode < Bundle
4
+ attr_accessor :signed
5
+
6
+ # Hardcoded paths in case mdfind is not working because Spotlight is disabled
7
+ DEFAULT_XCODE_PATHS = [
8
+ "/Applications/Xcode.app"
9
+ ]
10
+
11
+ XCODE_BUNDLE_IDENTIFIER = "com.apple.dt.Xcode"
12
+
13
+ def self.find_xcodes
14
+ output = `mdfind kMDItemCFBundleIdentifier = "#{XCODE_BUNDLE_IDENTIFIER}"`
15
+ paths = output.lines + DEFAULT_XCODE_PATHS
16
+
17
+ paths.map(&:strip).uniq.collect do |xcode_path|
18
+ Xcode.from_bundle(xcode_path)
19
+ end.compact.keep_if(&:valid?)
20
+ end
21
+
22
+ def self.from_bundle(path)
23
+ xcode = new(path)
24
+ xcode.valid? ? xcode : nil
25
+ end
26
+
27
+ def valid?
28
+ is_app = path.end_with?('.app')
29
+ has_info = File.exist?(info_path)
30
+ return false unless is_app && has_info
31
+
32
+ bundle_identifier == XCODE_BUNDLE_IDENTIFIER
33
+ end
34
+
35
+ def signed?
36
+ if signed.nil?
37
+ self.signed = `codesign -dv "#{path}" 2>/dev/null` &&
38
+ $CHILD_STATUS.exitstatus == 0
39
+ end
40
+
41
+ signed
42
+ end
43
+
44
+ def restorable?
45
+ binary_restorable? || xcodebuild_restorable?
46
+ end
47
+
48
+ def binary_restorable?
49
+ File.exist?("#{binary_path}.signed")
50
+ end
51
+
52
+ def xcodebuild_restorable?
53
+ File.exist?("#{xcodebuild_path}.signed")
54
+ end
55
+
56
+ def unsign_binary!
57
+ unsign!(binary_path)
58
+ end
59
+
60
+ def unsign_xcodebuild!
61
+ unsign!(xcodebuild_path)
62
+ end
63
+
64
+ def restore_binary!
65
+ restore!(binary_path)
66
+ end
67
+
68
+ def restore_xcodebuild!
69
+ restore!(xcodebuild_path)
70
+ end
71
+
72
+ def uuid
73
+ defaults_read('DVTPlugInCompatibilityUUID')
74
+ end
75
+
76
+ def to_s
77
+ unless signed.nil?
78
+ codesign_status = signed ? ' [Signed]' : ' [Unsigned]'
79
+ end
80
+
81
+ "Xcode (#{version})#{codesign_status}: #{path}"
82
+ end
83
+
84
+ def detailed_description
85
+ "Xcode (#{version}) [#{uuid}]: #{path}"
86
+ end
87
+
88
+ private
89
+
90
+ def binary_path
91
+ "#{path}/Contents/MacOS/Xcode"
92
+ end
93
+
94
+ def xcodebuild_path
95
+ "#{path}/Contents/Developer/usr/bin/xcodebuild"
96
+ end
97
+
98
+ def unsign_path
99
+ lib_path = File.expand_path(File.dirname(__FILE__))
100
+
101
+ "#{lib_path}/bin/unsign"
102
+ end
103
+
104
+ def unsign!(target)
105
+ unsigned_target = "#{target}.unsigned"
106
+ signed_target = "#{target}.signed"
107
+
108
+ CLI.chown_if_required(File.dirname(target)) do
109
+ `#{unsign_path} "#{target}"` &&
110
+ $CHILD_STATUS.exitstatus == 0
111
+ File.exist?(unsigned_target) &&
112
+ FileUtils.mv(target, signed_target) &&
113
+ File.exist?(signed_target) &&
114
+ FileUtils.mv(unsigned_target, target)
115
+ end
116
+ end
117
+
118
+ def restore!(target)
119
+ signed_target = "#{target}.signed"
120
+
121
+ CLI.chown_if_required(File.dirname(target)) do
122
+ File.exist?(signed_target) &&
123
+ File.exist?(target) &&
124
+ FileUtils.mv(signed_target, target)
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,44 @@
1
+ require_relative 'bundle'
2
+
3
+ class XcodePlugin < Bundle
4
+ def self.find_plugins
5
+ plugins_path = "#{Dir.home}/Library/Application Support/Developer/Shared/Xcode/Plug-ins/"
6
+
7
+ unless Dir.exist?(plugins_path)
8
+ puts "未找到 Plug-ins 目录"
9
+ return []
10
+ end
11
+
12
+ Dir.entries(plugins_path).collect do |plugin_path|
13
+ XcodePlugin.from_bundle("#{plugins_path}#{plugin_path}")
14
+ end.compact.keep_if(&:valid?)
15
+ end
16
+
17
+ def self.from_bundle(path)
18
+ plugin = new(path)
19
+ plugin.valid? ? plugin : nil
20
+ end
21
+
22
+ def valid?
23
+ not_hidden = !path.split('/').last.start_with?('.')
24
+ is_plugin = path.end_with?('.xcplugin')
25
+ has_info = File.exist?(info_path)
26
+
27
+ not_hidden && is_plugin && has_info
28
+ end
29
+
30
+ def has_uuid?(uuid)
31
+ defaults_read('DVTPlugInCompatibilityUUIDs').include?(uuid)
32
+ end
33
+
34
+ def add_uuid(uuid)
35
+ return false if has_uuid?(uuid)
36
+
37
+ defaults_write('DVTPlugInCompatibilityUUIDs', '-array-add', uuid)
38
+ true
39
+ end
40
+
41
+ def to_s
42
+ "#{path.split('/').last.sub(/\.xcplugin$/, '')} (#{version})"
43
+ end
44
+ end
@@ -0,0 +1,94 @@
1
+ require_relative 'xcode'
2
+
3
+ class XcodeUnsigner
4
+ extend CLI
5
+
6
+ def self.unsign_xcode
7
+ process '正在查找安装的 Xcode...'
8
+ xcodes = Xcode.find_xcodes
9
+ .select { |xcode| xcode.version.to_f >= 8 }
10
+ .select(&:signed?)
11
+
12
+ separator
13
+
14
+ if xcodes.empty?
15
+ error "没有发现任何有签名的 Xcode 8+."
16
+ return
17
+ end
18
+
19
+ notice
20
+ separator
21
+
22
+ selection = Ask.list "选择你想要去掉签名的 Xcode(按上下键改变箭头)", xcodes
23
+ return unless selection
24
+
25
+ xcode = xcodes[selection]
26
+
27
+ # unsign_xcodebuild = Ask.confirm "Unsign xcodebuild too?"
28
+ unsign_xcodebuild = true
29
+
30
+ separator
31
+
32
+ process '正在去除签名...'
33
+ if xcode.unsign_binary! &&
34
+ (!unsign_xcodebuild || (unsign_xcodebuild && xcode.unsign_xcodebuild!))
35
+ success '完成! 🎉'
36
+ else
37
+ error "未能取消 #{xcode.path} 的签名\n"\
38
+ '请联系mPaaS开发者'
39
+ end
40
+ end
41
+
42
+ def self.restore_xcode
43
+ process '正在查找安装的 Xcode...'
44
+ xcodes = Xcode.find_xcodes
45
+ .select { |xcode| xcode.version.to_f >= 8 }
46
+ .select(&:restorable?)
47
+
48
+ separator
49
+
50
+ if xcodes.empty?
51
+ error "没有发现任何可恢复签名的 Xcode 8+."
52
+ return
53
+ end
54
+
55
+ selection = Ask.list "选择你想要恢复签名的 Xcode(按上下键改变箭头)", xcodes
56
+ return unless selection
57
+
58
+ xcode = xcodes[selection]
59
+
60
+ separator
61
+
62
+ process '正在恢复签名...'
63
+
64
+ success = true
65
+
66
+ if xcode.binary_restorable? && !xcode.restore_binary!
67
+ error "未能恢复 #{xcode.path} 的签名\n"\
68
+ '请联系mPaaS开发者'
69
+ success = false
70
+ end
71
+
72
+ if xcode.xcodebuild_restorable? && !xcode.restore_xcodebuild!
73
+ error "未能恢复 xcodebuild 的签名\n"\
74
+ '请联系mPaaS开发者'
75
+ success = false
76
+ end
77
+
78
+ success '完成! 🎉' if success
79
+ end
80
+
81
+ def self.update_plugins
82
+
83
+ end
84
+
85
+ def self.notice
86
+ puts [
87
+ '取消Xcode的签名将会跳过插件的签名验证,从而允许加载插件'.colorize(:yellow),
88
+ '然而,未签名的Xcode会产生一定的安全风险,Apple和你的系统都会不信任未签名的Xcode'\
89
+ '请不要使用未签名的Xcode进行打包操作,正常开发没有问题'.colorize(:red),
90
+ "这个工具会产生签名文件的备份,以便于之后你可以用下面这个命令恢复\n",
91
+ '$ mpaas --restoresign'.colorize(:light_blue)
92
+ ]
93
+ end
94
+ end
@@ -7,11 +7,12 @@ Gem::Specification.new do |spec|
7
7
  spec.name = "reuse_xcode_plugins"
8
8
  spec.version = ReuseXcodePlugins::VERSION
9
9
  spec.authors = ["夜禹"]
10
- spec.email = ["mingyu.ymy@alipay.com"]
10
+ spec.email = ["me@yemingyu.com"]
11
11
 
12
12
  spec.summary = %q{Write a short summary, because Rubygems requires one.}
13
13
  spec.description = %q{Write a longer description or delete this line.}
14
14
  spec.homepage = "https://yemingyu.com"
15
+ spec.license = "MIT"
15
16
 
16
17
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
18
  # to allow pushing to a single host or delete this section to allow pushing to any host.
@@ -26,9 +27,13 @@ Gem::Specification.new do |spec|
26
27
  f.match(%r{^(test|spec|features)/})
27
28
  end
28
29
  spec.bindir = "exe"
29
- spec.executables = %w(ymyTest)
30
+ spec.executables = ['reuse_xcode_plugins']
31
+ # spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
32
  spec.require_paths = ["lib"]
31
33
 
32
34
  spec.add_development_dependency "bundler", "~> 1.13"
33
35
  spec.add_development_dependency "rake", "~> 10.0"
36
+
37
+ spec.add_runtime_dependency 'colorize', '~> 0.8.1'
38
+ spec.add_runtime_dependency 'inquirer', '~> 0.2.1'
34
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reuse_xcode_plugins
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - "夜禹"
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-23 00:00:00.000000000 Z
11
+ date: 2017-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,11 +38,39 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: colorize
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.8.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.8.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: inquirer
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.2.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.2.1
41
69
  description: Write a longer description or delete this line.
42
70
  email:
43
- - mingyu.ymy@alipay.com
71
+ - me@yemingyu.com
44
72
  executables:
45
- - ymyTest
73
+ - reuse_xcode_plugins
46
74
  extensions: []
47
75
  extra_rdoc_files: []
48
76
  files:
@@ -52,12 +80,22 @@ files:
52
80
  - Rakefile
53
81
  - bin/console
54
82
  - bin/setup
55
- - exe/ymyTest
83
+ - exe/reuse_xcode_plugins
84
+ - lib/bin/System Preferences
85
+ - lib/bin/System Preferences.unsigned
86
+ - lib/bin/unsign
87
+ - lib/bundle.rb
88
+ - lib/cli.rb
89
+ - lib/plugins_updater.rb
56
90
  - lib/reuse_xcode_plugins.rb
57
91
  - lib/reuse_xcode_plugins/version.rb
92
+ - lib/xcode.rb
93
+ - lib/xcode_plugin.rb
94
+ - lib/xcode_unsigner.rb
58
95
  - reuse_xcode_plugins.gemspec
59
96
  homepage: https://yemingyu.com
60
- licenses: []
97
+ licenses:
98
+ - MIT
61
99
  metadata:
62
100
  allowed_push_host: https://rubygems.org
63
101
  post_install_message:
data/exe/ymyTest DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env bash
2
- p "Hello World!"