pprof 0.3.8 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/bin/pprof +41 -40
- data/lib/pprof/entitlements.rb +6 -3
- data/lib/pprof/output_formatter.rb +61 -47
- data/lib/pprof/provisioning_profile.rb +21 -18
- data/lib/pprof/version.rb +3 -1
- data/lib/pprof.rb +2 -0
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d476948086afa6ea5bb7de05378c7e384bf85b14a42f083c2850b5b497ce0f45
|
4
|
+
data.tar.gz: 158efbc09babce572ced4074c231793af16ed2c7db3567bd5b60fb1c8c7a66b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 224f0d480b357a04a6e3dc2e13f1962b337b100ee599fd36a9a937060056cba90f7fcdf49080b87334ad79d62a61a4e80d817737c7680725e6ded84f506580b2
|
7
|
+
data.tar.gz: 04b13e78ae4a7b133d21c5786bb9f4bd4ccb4238bff33b3007bcf11dfe520b26af4157168883a7456766f93ad9efa9ed37087a0b5cb8ad5cf9d64ec4e4b91efb
|
data/bin/pprof
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'pprof'
|
4
5
|
require 'optparse'
|
@@ -7,7 +8,7 @@ require 'optparse'
|
|
7
8
|
# Or a standard match if the string is bare.
|
8
9
|
#
|
9
10
|
def matcher(string)
|
10
|
-
m = string.match(%r
|
11
|
+
m = string.match(%r{^/(.*)/(.*)$})
|
11
12
|
if m.nil?
|
12
13
|
Regexp.new(Regexp.escape(string))
|
13
14
|
else
|
@@ -19,10 +20,11 @@ end
|
|
19
20
|
|
20
21
|
filters = {}
|
21
22
|
options = {}
|
22
|
-
list_options = { :
|
23
|
+
list_options = { mode: :table }
|
23
24
|
|
25
|
+
# rubocop:disable Metrics/BlockLength
|
24
26
|
parser = OptionParser.new do |opts|
|
25
|
-
opts.banner = <<-BANNER.gsub(/^ *\|/,'')
|
27
|
+
opts.banner = <<-BANNER.gsub(/^ *\|/, '')
|
26
28
|
|Usage:
|
27
29
|
| pprof [print_options] (PATH|UUID)
|
28
30
|
| pprof [list_options] [filters]
|
@@ -40,125 +42,124 @@ parser = OptionParser.new do |opts|
|
|
40
42
|
| - To remove all expired certificates, you can use `#{opts.program_name} -e0 | xargs -0 rm`
|
41
43
|
BANNER
|
42
44
|
|
43
|
-
opts.separator
|
44
|
-
opts.separator
|
45
|
+
opts.separator ''
|
46
|
+
opts.separator 'Print options (when file given)'
|
45
47
|
|
46
|
-
opts.on(
|
48
|
+
opts.on('-i', '--info', 'Print general info (default)') do
|
47
49
|
options[:info] = true
|
48
50
|
end
|
49
|
-
opts.on(
|
51
|
+
opts.on('-c', '--certs', 'Print certificates') do
|
50
52
|
options[:certs] = true
|
51
53
|
end
|
52
|
-
opts.on(
|
54
|
+
opts.on('-d', '--devices', 'Print provisioned devices') do
|
53
55
|
options[:devices] = true
|
54
56
|
end
|
55
57
|
|
56
|
-
opts.separator
|
57
|
-
opts.separator
|
58
|
+
opts.separator ''
|
59
|
+
opts.separator 'List options (when no file given)'
|
58
60
|
|
59
|
-
opts.on(
|
61
|
+
opts.on('-l', '--list', 'Print only the UUIDs, one per line (instead of an ASCII table)') do
|
60
62
|
list_options[:mode] = :list
|
61
63
|
end
|
62
|
-
opts.on(
|
64
|
+
opts.on('-p', '--path', 'Print only the paths, one per line (instead of an ASCII table)') do
|
63
65
|
list_options[:mode] = :path
|
64
66
|
end
|
65
|
-
opts.on(
|
67
|
+
opts.on('-0', '--print0', 'Separate each found entry by \\0, to be used by `xargs -0`') do
|
66
68
|
list_options[:zero] = true
|
67
69
|
end
|
68
70
|
|
69
|
-
opts.separator
|
70
|
-
opts.separator
|
71
|
+
opts.separator ''
|
72
|
+
opts.separator 'Filters (when no file given)'
|
71
73
|
|
72
|
-
opts.on(
|
74
|
+
opts.on('--name NAME', 'Filter by name') do |name|
|
73
75
|
filters[:name] = matcher(name)
|
74
76
|
end
|
75
77
|
|
76
|
-
opts.on(
|
78
|
+
opts.on('--appid-name APPID', 'Filter by App ID Name') do |appid_name|
|
77
79
|
filters[:appid_name] = matcher(appid_name)
|
78
80
|
end
|
79
81
|
|
80
|
-
opts.on(
|
82
|
+
opts.on('--appid APPID', 'Filter by App ID') do |appid|
|
81
83
|
filters[:appid] = matcher(appid)
|
82
84
|
end
|
83
85
|
|
84
|
-
opts.on(
|
86
|
+
opts.on('--uuid UUID', 'Filter by UUID') do |uuid|
|
85
87
|
filters[:uuid] = matcher(uuid)
|
86
88
|
end
|
87
89
|
|
88
|
-
opts.on(
|
90
|
+
opts.on('--team TEAM', 'Filter by team name or ID') do |team|
|
89
91
|
filters[:team] = matcher(team)
|
90
92
|
end
|
91
93
|
|
92
|
-
opts.on(
|
94
|
+
opts.on('--[no-]exp', 'Only profiles (not) expired') do |flag|
|
93
95
|
filters[:exp] = flag
|
94
96
|
end
|
95
97
|
|
96
|
-
opts.on(
|
98
|
+
opts.on('--[no-]has-devices', 'Filter by profiles having (no) provisioned devices') do |d|
|
97
99
|
filters[:has_devices] = d
|
98
100
|
end
|
99
101
|
|
100
|
-
opts.on(
|
102
|
+
opts.on('--[no-]all-devices', 'Filter by profiles (not) provisioning all devices') do |d|
|
101
103
|
filters[:all_devices] = d
|
102
104
|
end
|
103
105
|
|
104
|
-
opts.on(
|
106
|
+
opts.on('--aps [ENV]', 'Only profiles having Push entitlements (or a specific aps env)') do |env|
|
105
107
|
filters[:aps_env] = env.nil? ? true : matcher(env)
|
106
108
|
end
|
107
109
|
|
110
|
+
opts.separator ''
|
111
|
+
opts.separator 'Misc'
|
108
112
|
|
109
|
-
opts.
|
110
|
-
opts.separator "Misc"
|
111
|
-
|
112
|
-
opts.on_tail("-h", "--help", "Show this message") do
|
113
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
113
114
|
puts opts
|
114
115
|
exit
|
115
116
|
end
|
116
117
|
|
117
|
-
opts.on_tail(
|
118
|
+
opts.on_tail('-v', '--version', 'Show version') do
|
118
119
|
puts PProf::VERSION
|
119
120
|
exit
|
120
121
|
end
|
121
122
|
end
|
123
|
+
# rubocop:enable Metrics/BlockLength
|
122
124
|
|
123
125
|
# Parse the options, catching parse errors nicely
|
124
126
|
begin
|
125
127
|
parser.parse!
|
126
|
-
rescue OptionParser::InvalidOption =>
|
127
|
-
puts
|
128
|
-
puts parser.help
|
128
|
+
rescue OptionParser::InvalidOption => e
|
129
|
+
puts e
|
130
|
+
puts parser.help
|
129
131
|
exit 1
|
130
132
|
end
|
131
133
|
|
132
134
|
# Don't mix filters and options together, that doesn't make sense
|
133
135
|
|
134
136
|
unless filters.empty? || ARGV.empty?
|
135
|
-
puts
|
137
|
+
puts 'You should use either filter flags to filter the whole list, or an specific path, not both.'
|
136
138
|
puts parser # Usage
|
137
139
|
exit
|
138
140
|
end
|
139
141
|
|
140
142
|
unless options.empty? || !ARGV.empty?
|
141
|
-
puts
|
143
|
+
puts 'You should use option flags only when providing an specific path.'
|
142
144
|
puts parser # Usage
|
143
145
|
exit
|
144
146
|
end
|
145
147
|
|
146
148
|
# Call the appropriate action
|
147
149
|
|
150
|
+
o = PProf::OutputFormatter.new
|
148
151
|
if ARGV.empty?
|
149
152
|
# Print list of matching profiles
|
150
|
-
o = PProf::OutputFormatter.new
|
151
153
|
list_options[:mode] = :path if list_options[:zero] && list_options[:mode] == :table
|
152
154
|
o.print_filtered_list(PProf::ProvisioningProfile::DEFAULT_DIR, filters, list_options)
|
153
155
|
else
|
154
|
-
# Print info about given profile path/UUID
|
155
|
-
o = PProf::OutputFormatter.new
|
156
156
|
begin
|
157
|
+
# Print info about given profile path/UUID
|
157
158
|
p = PProf::ProvisioningProfile.new(ARGV[0])
|
158
|
-
|
159
|
-
options = { :
|
159
|
+
|
160
|
+
options = { info: true } if options.empty?
|
160
161
|
o.print_info(p, options)
|
161
|
-
rescue
|
162
|
+
rescue StandardError => e
|
162
163
|
o.print_error(e, ARGV[0])
|
163
164
|
end
|
164
165
|
end
|
data/lib/pprof/entitlements.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Module for the pprof tool to manipulate Provisioning Profiles
|
2
4
|
module PProf
|
3
5
|
# Represents the list of entitlements in a Provisioning Profile
|
@@ -23,7 +25,7 @@ module PProf
|
|
23
25
|
# True if we can attach a debugger to the executable, false if not.
|
24
26
|
#
|
25
27
|
# @return [Bool]
|
26
|
-
def get_task_allow
|
28
|
+
def get_task_allow # rubocop:disable Naming/AccessorMethodName
|
27
29
|
@dict['get-task-allow']
|
28
30
|
end
|
29
31
|
|
@@ -98,9 +100,10 @@ module PProf
|
|
98
100
|
# @param [#to_s] key
|
99
101
|
# The key to check
|
100
102
|
#
|
101
|
-
def
|
102
|
-
@dict.
|
103
|
+
def key?(key)
|
104
|
+
@dict.key?(key.to_s)
|
103
105
|
end
|
106
|
+
alias has_key? key?
|
104
107
|
|
105
108
|
# The list of all entitlement keys, as String
|
106
109
|
#
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Module for the pprof tool to manipulate Provisioning Profiles
|
2
4
|
module PProf
|
3
5
|
# A helper tool to pretty-print Provisioning Profile informations
|
@@ -27,14 +29,16 @@ module PProf
|
|
27
29
|
# @param [String...] cols
|
28
30
|
# The content of each column of the row to add
|
29
31
|
def row(*cols)
|
30
|
-
|
32
|
+
justified_cols = cols.zip(@widths).map do |c, w|
|
31
33
|
(c || '<nil>').to_s.ljust(w)[0...w]
|
32
|
-
end
|
34
|
+
end
|
35
|
+
"| #{justified_cols.join(' | ')} |"
|
33
36
|
end
|
34
37
|
|
35
38
|
# Add a separator line to the ASCII table
|
36
39
|
def separator
|
37
|
-
|
40
|
+
columns_dashes = @widths.map { |w| '-' * (w + 2) }
|
41
|
+
"+#{columns_dashes.join('+')}+"
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
@@ -57,25 +61,36 @@ module PProf
|
|
57
61
|
# Decide what to print. Valid keys are :info, :certs and :devices
|
58
62
|
#
|
59
63
|
def print_info(profile, options = nil)
|
60
|
-
options ||= { :
|
64
|
+
options ||= { info: true }
|
61
65
|
if options[:info]
|
62
|
-
keys = [
|
66
|
+
keys = %i[name uuid app_id_name app_id_prefix creation_date expiration_date ttl team_ids
|
67
|
+
team_name]
|
63
68
|
keys.each do |key|
|
64
|
-
@output.puts "- #{key
|
69
|
+
@output.puts "- #{key}: #{profile.send(key.to_sym)}"
|
65
70
|
end
|
66
|
-
@output.puts
|
67
|
-
@output.puts
|
71
|
+
@output.puts '- Entitlements:'
|
72
|
+
@output.puts(profile.entitlements.to_s.split("\n").map { |line| " #{line}" })
|
68
73
|
end
|
69
74
|
|
70
|
-
|
75
|
+
# rubocop:disable Style/GuardClause
|
76
|
+
if options[:info] || options[:certs]
|
71
77
|
@output.puts "- #{profile.developer_certificates.count} Developer Certificates"
|
72
|
-
|
78
|
+
if options[:certs]
|
79
|
+
profile.developer_certificates.each do |cert|
|
80
|
+
@output.puts " - #{cert.subject}"
|
81
|
+
@output.puts " issuer: #{cert.issuer}"
|
82
|
+
@output.puts " serial: #{cert.serial}"
|
83
|
+
@output.puts " expires: #{cert.not_after}"
|
84
|
+
end
|
85
|
+
end
|
73
86
|
end
|
87
|
+
|
74
88
|
if options[:info] || options[:devices]
|
75
89
|
@output.puts "- #{(profile.provisioned_devices || []).count} Provisioned Devices"
|
76
90
|
profile.provisioned_devices.each { |udid| @output.puts " - #{udid}" } if options[:devices]
|
77
91
|
@output.puts "- Provision all devices: #{profile.provisions_all_devices.inspect}"
|
78
92
|
end
|
93
|
+
# rubocop:enable Style/GuardClause
|
79
94
|
end
|
80
95
|
|
81
96
|
# Prints the filtered list of Provisioning Profiles
|
@@ -97,18 +112,18 @@ module PProf
|
|
97
112
|
# * Valid values for key `:zero` are `true` or `false` to decide if we print `\0` at the end of each output.
|
98
113
|
# Only used by `:list` and `:path` modes
|
99
114
|
#
|
100
|
-
def print_filtered_list(dir = PProf::ProvisioningProfile::DEFAULT_DIR, filters = {}, list_options = { :
|
115
|
+
def print_filtered_list(dir = PProf::ProvisioningProfile::DEFAULT_DIR, filters = {}, list_options = { mode: :table })
|
101
116
|
filter_func = lambda do |p|
|
102
117
|
(filters[:name].nil? || p.name =~ filters[:name]) &&
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
118
|
+
(filters[:appid_name].nil? || p.app_id_name =~ filters[:appid_name]) &&
|
119
|
+
(filters[:appid].nil? || p.entitlements.app_id =~ filters[:appid]) &&
|
120
|
+
(filters[:uuid].nil? || p.uuid =~ filters[:uuid]) &&
|
121
|
+
(filters[:team].nil? || p.team_name =~ filters[:team] || p.team_ids.any? { |id| id =~ filters[:team] }) &&
|
122
|
+
(filters[:exp].nil? || (p.expiration_date < DateTime.now) == filters[:exp]) &&
|
123
|
+
(filters[:has_devices].nil? || !(p.provisioned_devices || []).empty? == filters[:has_devices]) &&
|
124
|
+
(filters[:all_devices].nil? || p.provisions_all_devices == filters[:all_devices]) &&
|
125
|
+
(filters[:aps_env].nil? || match_aps_env(p.entitlements.aps_environment, filters[:aps_env])) &&
|
126
|
+
true
|
112
127
|
end
|
113
128
|
|
114
129
|
case list_options[:mode]
|
@@ -138,16 +153,17 @@ module PProf
|
|
138
153
|
@output.puts table.row('UUID', 'Name', 'AppID', 'Expiration Date', ' ', 'Team Name')
|
139
154
|
@output.puts table.separator
|
140
155
|
|
141
|
-
Dir[
|
156
|
+
Dir['*.mobileprovision', base: dir].each do |file_name|
|
157
|
+
file = File.join(dir, file_name)
|
142
158
|
begin
|
143
159
|
p = PProf::ProvisioningProfile.new(file)
|
144
|
-
|
160
|
+
|
145
161
|
next if block_given? && !yield(p)
|
146
162
|
|
147
163
|
state = DateTime.now < p.expiration_date ? "\u{2705}" : "\u{274c}" # 2705=checkmark, 274C=red X
|
148
164
|
@output.puts table.row(p.uuid, p.name, p.entitlements.app_id, p.expiration_date.to_time, state, p.team_name)
|
149
|
-
rescue
|
150
|
-
errors << { :
|
165
|
+
rescue StandardError => e
|
166
|
+
errors << { message: e, file: file }
|
151
167
|
end
|
152
168
|
count += 1
|
153
169
|
end
|
@@ -155,9 +171,7 @@ module PProf
|
|
155
171
|
@output.puts table.separator
|
156
172
|
@output.puts "#{count} Provisioning Profiles found."
|
157
173
|
|
158
|
-
unless errors.empty?
|
159
|
-
errors.each { |e| print_error(e[:message], e[:file]) }
|
160
|
-
end
|
174
|
+
errors.each { |e| print_error(e[:message], e[:file]) } unless errors.empty?
|
161
175
|
end
|
162
176
|
|
163
177
|
# Prints the filtered list of UUIDs or Paths only
|
@@ -165,35 +179,35 @@ module PProf
|
|
165
179
|
# @param [String] dir
|
166
180
|
# The directory containing the mobileprovision files to list.
|
167
181
|
# Defaults to '~/Library/MobileDevice/Provisioning Profiles'
|
182
|
+
# @param [Hash] options
|
183
|
+
# The options hash typically filled while parsing the command line arguments.
|
184
|
+
# - :mode: will print the UUIDs if set to `:uuid`, the file path otherwise
|
185
|
+
# - :zero: will concatenate the entries with `\0` instead of `\n` if set
|
168
186
|
#
|
169
|
-
# @yield each provisioning
|
187
|
+
# @yield each provisioning profile for filtering/validation
|
170
188
|
# The block is given ProvisioningProfile object and should
|
171
189
|
# return true to display the row, false to filter it out
|
172
190
|
#
|
173
|
-
def print_list(dir = PProf::ProvisioningProfile::DEFAULT_DIR, options)
|
191
|
+
def print_list(dir = PProf::ProvisioningProfile::DEFAULT_DIR, options) # rubocop:disable Style/OptionalArguments
|
174
192
|
errors = []
|
175
|
-
Dir[
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
end
|
185
|
-
end
|
186
|
-
unless errors.empty?
|
187
|
-
errors.each { |e| print_error(e[:message], e[:file]) }
|
193
|
+
Dir['*.mobileprovision', base: dir].each do |file_name|
|
194
|
+
file = File.join(dir, file_name)
|
195
|
+
p = PProf::ProvisioningProfile.new(file)
|
196
|
+
next if block_given? && !yield(p)
|
197
|
+
|
198
|
+
@output.print options[:mode] == :uuid ? p.uuid.chomp : file.chomp
|
199
|
+
@output.print options[:zero] ? "\0" : "\n"
|
200
|
+
rescue StandardError => e
|
201
|
+
errors << { message: e, file: file }
|
188
202
|
end
|
203
|
+
errors.each { |e| print_error(e[:message], e[:file]) } unless errors.empty?
|
189
204
|
end
|
190
205
|
|
191
|
-
|
192
|
-
private
|
193
206
|
def self.match_aps_env(actual, expected)
|
194
|
-
return false if actual.nil?
|
195
|
-
return true if expected
|
196
|
-
|
207
|
+
return false if actual.nil? # false if no Push entitlements
|
208
|
+
return true if expected == true # true if Push present but we don't filter on specific env
|
209
|
+
|
210
|
+
actual =~ expected # true if Push present and we filter on specific env
|
197
211
|
end
|
198
212
|
end
|
199
213
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'openssl'
|
2
4
|
require 'plist'
|
3
5
|
require 'time'
|
@@ -7,7 +9,7 @@ module PProf
|
|
7
9
|
# Represents the content of a Provisioning Profile file
|
8
10
|
class ProvisioningProfile
|
9
11
|
# The default location where all the Provisioning Profiles are stored on a Mac
|
10
|
-
DEFAULT_DIR="#{ENV['HOME']}/Library/MobileDevice/Provisioning Profiles"
|
12
|
+
DEFAULT_DIR = "#{ENV['HOME']}/Library/MobileDevice/Provisioning Profiles"
|
11
13
|
|
12
14
|
# Create a new ProvisioningProfile object from a file path or UUID
|
13
15
|
#
|
@@ -19,25 +21,26 @@ module PProf
|
|
19
21
|
# File path or UUID of the ProvisioningProfile
|
20
22
|
#
|
21
23
|
def initialize(file)
|
22
|
-
if file =~
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
path = if file =~ /^[0-9A-F-]*$/i
|
25
|
+
"#{PProf::ProvisioningProfile::DEFAULT_DIR}/#{file}.mobileprovision"
|
26
|
+
else
|
27
|
+
file
|
28
|
+
end
|
27
29
|
xml = nil
|
28
30
|
begin
|
29
31
|
pkcs7 = OpenSSL::PKCS7.new(File.read(path))
|
30
32
|
pkcs7.verify([], OpenSSL::X509::Store.new)
|
31
33
|
xml = pkcs7.data
|
32
|
-
|
34
|
+
raise 'Empty PKCS7 payload' if xml.nil? || xml.empty?
|
35
|
+
rescue StandardError
|
33
36
|
# Seems like sometimes OpenSSL fails to parse the PKCS7 payload
|
34
37
|
# Besides, OpenSSL is deprecated on macOS so might not be up-to-date on all machines
|
35
38
|
# So as a fallback, we run the `security` command line.
|
36
|
-
# (We could use `security` everytime, but invoking a command line is generally less
|
39
|
+
# (We could use `security` everytime, but invoking a command line is generally less
|
37
40
|
# efficient than calling the OpenSSL gem if available, so for now it's just used as fallback)
|
38
41
|
xml = `security cms -D -i "#{path}" 2> /dev/null`
|
39
42
|
end
|
40
|
-
@plist = Plist
|
43
|
+
@plist = Plist.parse_xml(xml)
|
41
44
|
raise "Unable to parse file #{file}." if @plist.nil?
|
42
45
|
end
|
43
46
|
|
@@ -100,7 +103,7 @@ module PProf
|
|
100
103
|
def team_ids
|
101
104
|
@plist['TeamIdentifier']
|
102
105
|
end
|
103
|
-
|
106
|
+
|
104
107
|
# The name of the Team associated with this Provisioning Profile
|
105
108
|
#
|
106
109
|
# @return [String]
|
@@ -108,7 +111,7 @@ module PProf
|
|
108
111
|
@plist['TeamName']
|
109
112
|
end
|
110
113
|
|
111
|
-
# The list of X509 Developer
|
114
|
+
# The list of X509 Developer Certificates associated with this profile
|
112
115
|
#
|
113
116
|
# @return [Array<OpenSSL::X509::Certificate>]
|
114
117
|
def developer_certificates
|
@@ -151,14 +154,14 @@ module PProf
|
|
151
154
|
#
|
152
155
|
# @return [String]
|
153
156
|
def to_s
|
154
|
-
lines = [
|
155
|
-
"- #{key
|
157
|
+
lines = %i[name uuid app_id_name app_id_prefix creation_date expiration_date ttl team_ids team_name].map do |key|
|
158
|
+
"- #{key}: #{send(key.to_sym)}"
|
156
159
|
end +
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
160
|
+
[
|
161
|
+
"- #{developer_certificates.count} Developer Certificates",
|
162
|
+
"- #{provisioned_devices.count} Provisioned Devices",
|
163
|
+
'- Entitlements:'
|
164
|
+
] + entitlements.to_hash.map { |key, value| " - #{key}: #{value}" }
|
162
165
|
lines.join("\n")
|
163
166
|
end
|
164
167
|
end
|
data/lib/pprof/version.rb
CHANGED
data/lib/pprof.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pprof
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Olivier Halligon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: plist
|
@@ -42,7 +42,8 @@ files:
|
|
42
42
|
homepage: https://github.com/AliSoftware/pprof
|
43
43
|
licenses:
|
44
44
|
- MIT
|
45
|
-
metadata:
|
45
|
+
metadata:
|
46
|
+
rubygems_mfa_required: 'true'
|
46
47
|
post_install_message:
|
47
48
|
rdoc_options: []
|
48
49
|
require_paths:
|
@@ -51,15 +52,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
52
|
requirements:
|
52
53
|
- - ">="
|
53
54
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2.
|
55
|
+
version: 2.6.4
|
55
56
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
57
|
requirements:
|
57
58
|
- - ">="
|
58
59
|
- !ruby/object:Gem::Version
|
59
60
|
version: '0'
|
60
61
|
requirements: []
|
61
|
-
|
62
|
-
rubygems_version: 2.5.2
|
62
|
+
rubygems_version: 3.2.19
|
63
63
|
signing_key:
|
64
64
|
specification_version: 4
|
65
65
|
summary: A Provisioning Profiles library
|