pprof 0.5.1 → 1.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/README.md +35 -7
- data/bin/pprof +4 -0
- data/lib/pprof/output_formatter.rb +46 -38
- data/lib/pprof/provisioning_profile.rb +28 -11
- data/lib/pprof/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe023fb6399ea85e9aafbd5fe04e359134b37880148ab6796538db8a98bbfca9
|
4
|
+
data.tar.gz: 558e2fc9027127c7aeb87ffb7e80b85ef80439bc6ec4c2301e478b342fb767a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 825fa827ec95e13c0e18af1a4159d0c32a66e73f18d74e303018db47c4cc770eb500fcebe75537457045bc659a1128a13b7d7e24a42a46a9eb0ffa0d1d391d15
|
7
|
+
data.tar.gz: 34ac09512ae66a156695d8ed273b7c54b8b0381a03b02e4396fbd71f8bcbe880e7464a2c45dc7e1096e145eb05da9c66b6a06f5685d64c346c4770aaccc23a44
|
data/README.md
CHANGED
@@ -6,7 +6,9 @@
|
|
6
6
|
|
7
7
|
`pprof` is a ruby library and binary to manipulate Provisioning Profiles.
|
8
8
|
|
9
|
-
It can help you
|
9
|
+
It can help you manage the Provisioning Profiles installed on your Mac (find the profiles UUIDs from the app names or bundle IDs, find detailed information on a given profile, clean up expired profiles from your Mac…) directly from the command line.
|
10
|
+
|
11
|
+
It also supports printing the output in JSON format so you can pipe the result of printing provisioning profiles info into `jq` or similar tools.
|
10
12
|
|
11
13
|
## Installation
|
12
14
|
|
@@ -16,7 +18,7 @@ It can help you create ruby scripts to list, get information, find and filter lo
|
|
16
18
|
$ gem install pprof
|
17
19
|
```
|
18
20
|
|
19
|
-
_(You might need to run this command with `sudo` if your gem home is a system directory)_
|
21
|
+
_(You might need to run this command with `sudo` if your gem home is a system directory. Alternatively, we recommend to use a Ruby Version Manager like `rbenv`.)_
|
20
22
|
|
21
23
|
### Build from source
|
22
24
|
|
@@ -32,6 +34,8 @@ _(You might need to run this command with `sudo` if your gem home is a system di
|
|
32
34
|
|
33
35
|
### Using it from the command line
|
34
36
|
|
37
|
+
#### Listing (and filtering) provisioning profiles
|
38
|
+
|
35
39
|
```sh
|
36
40
|
# List all provisioning profiles
|
37
41
|
$ pprof
|
@@ -65,6 +69,8 @@ $ pprof --has-devices --aps --appid com.foo
|
|
65
69
|
$ pprof --exp -0 | xargs -0 rm
|
66
70
|
```
|
67
71
|
|
72
|
+
#### Printing info for a given Provisioning Profile
|
73
|
+
|
68
74
|
```sh
|
69
75
|
# Print info for a given Provisioning Profile
|
70
76
|
$ pprof '12345678-ABCD-EF90-1234-567890ABCDEF'
|
@@ -80,6 +86,25 @@ $ pprof --certs --devices --info '12345678-ABCD-EF90-1234-567890ABCDEF'
|
|
80
86
|
$ pprof -cdi '12345678-ABCD-EF90-1234-567890ABCDEF'
|
81
87
|
```
|
82
88
|
|
89
|
+
#### Printing output in JSON
|
90
|
+
|
91
|
+
```sh
|
92
|
+
# Print info about all your provisioning profiles as a JSON array
|
93
|
+
$ pprof --json
|
94
|
+
# Print info about all your provisioning profiles whose name contains "Foo", as a JSON array
|
95
|
+
$ pprof --name "Foo" --json
|
96
|
+
# Print info about all your provisioning profiles as a JSON array, including list of devices and certificates in each profile
|
97
|
+
$ pprof --json --devices --certs
|
98
|
+
|
99
|
+
# Print info about a specific provisioning profile as JSON object
|
100
|
+
$ pprof --json '12345678-ABCD-EF90-1234-567890ABCDEF'
|
101
|
+
# Print info about a specific provisioning profile as JSON object, including list of devices and certificates
|
102
|
+
$ pprof --json -c -d '12345678-ABCD-EF90-1234-567890ABCDEF'
|
103
|
+
|
104
|
+
# Use `jq` (https://stedolan.github.io/jq/) to post-process the JSON output and generate some custom JSON array of objects from it
|
105
|
+
$ pprof --name 'My App' --json --devices | jq '.[] | {uuid:.UUID, name:.AppIDName, nb_profiles: .ProvisionedDevices|length}'
|
106
|
+
```
|
107
|
+
|
83
108
|
### Using it in Ruby
|
84
109
|
|
85
110
|
```ruby
|
@@ -104,10 +129,13 @@ File.open('certs.txt', 'w') do |file|
|
|
104
129
|
end
|
105
130
|
|
106
131
|
# And you can easily loop on all provisioning profiles and manipulate each
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
132
|
+
profiles_dirs = PProf::ProvisioningProfile::DEFAULT_DIRS
|
133
|
+
# `*.mobileprovision` are typically for iOS profiles, `*.provisionprofile` for Mac profiles
|
134
|
+
profiles_dirs.each do |dir|
|
135
|
+
Dir["#{dir}/*.{mobileprovision,provisionprofile}"].each do |file|
|
136
|
+
p = PProf::ProvisioningProfile.new(file)
|
137
|
+
puts p.name
|
138
|
+
end
|
111
139
|
end
|
112
140
|
```
|
113
141
|
|
@@ -123,7 +151,7 @@ That plist payload itself contains various data, including some textual informat
|
|
123
151
|
|
124
152
|
```ruby
|
125
153
|
PProf::ProvisioningProfile
|
126
|
-
::
|
154
|
+
::DEFAULT_DIRS
|
127
155
|
new(file) => PProf::ProvisioningProfile
|
128
156
|
to_hash => Hash<String, Any>
|
129
157
|
|
data/bin/pprof
CHANGED
@@ -88,6 +88,10 @@ parser = OptionParser.new do |opts|
|
|
88
88
|
filters[:appid] = matcher(appid)
|
89
89
|
end
|
90
90
|
|
91
|
+
opts.on('--platform PLATFORM', 'Filter by Platform (OSX, iOS, xrOS/visionOS, …)') do |platform|
|
92
|
+
filters[:platform] = platform
|
93
|
+
end
|
94
|
+
|
91
95
|
opts.on('--uuid UUID', 'Filter by UUID') do |uuid|
|
92
96
|
filters[:uuid] = matcher(uuid)
|
93
97
|
end
|
@@ -7,7 +7,7 @@ module PProf
|
|
7
7
|
# A helper tool to pretty-print Provisioning Profile informations
|
8
8
|
class OutputFormatter
|
9
9
|
# List of properties of a `PProf::ProvisioningProfile` to print when using the `-i` flag
|
10
|
-
MAIN_PROFILE_KEYS = %i[name uuid app_id_name app_id_prefix creation_date expiration_date ttl team_ids team_name]
|
10
|
+
MAIN_PROFILE_KEYS = %i[path name uuid app_id_name app_id_prefix creation_date expiration_date ttl team_ids team_name].freeze
|
11
11
|
|
12
12
|
# Initialize a new OutputFormatter
|
13
13
|
#
|
@@ -110,6 +110,7 @@ module PProf
|
|
110
110
|
#
|
111
111
|
def as_json(profile, options = {})
|
112
112
|
hash = profile.to_hash.dup
|
113
|
+
hash['path'] = profile.path
|
113
114
|
hash.delete 'DER-Encoded-Profile'
|
114
115
|
hash.delete 'ProvisionedDevices' unless options[:devices]
|
115
116
|
if options[:certs]
|
@@ -157,21 +158,22 @@ module PProf
|
|
157
158
|
(filters[:has_devices].nil? || !(p.provisioned_devices || []).empty? == filters[:has_devices]) &&
|
158
159
|
(filters[:all_devices].nil? || p.provisions_all_devices == filters[:all_devices]) &&
|
159
160
|
(filters[:aps_env].nil? || match_aps_env(p.entitlements.aps_environment, filters[:aps_env])) &&
|
161
|
+
(filters[:platform].nil? || p.platform.include?(filters[:platform])) &&
|
160
162
|
true
|
161
163
|
end
|
162
164
|
end
|
163
165
|
|
164
166
|
# Prints the filtered list as a table
|
165
167
|
#
|
166
|
-
# @param [String]
|
167
|
-
# The
|
168
|
-
# Defaults to '~/Library/MobileDevice/Provisioning Profiles'
|
168
|
+
# @param [String] dirs
|
169
|
+
# The directories containing the mobileprovision/provisionprofile files to list.
|
170
|
+
# Defaults to ['~/Library/MobileDevice/Provisioning Profiles', '~/Library/Developer/Xcode/UserData/Provisioning Profiles']
|
169
171
|
#
|
170
172
|
# @yield each provisioning provile for filtering/validation
|
171
173
|
# The block is given ProvisioningProfile object and should
|
172
174
|
# return true to display the row, false to filter it out
|
173
175
|
#
|
174
|
-
def print_table(
|
176
|
+
def print_table(dirs: PProf::ProvisioningProfile::DEFAULT_DIRS)
|
175
177
|
count = 0
|
176
178
|
errors = []
|
177
179
|
|
@@ -180,19 +182,21 @@ module PProf
|
|
180
182
|
@output.puts table.row('UUID', 'Name', 'AppID', 'Expiration Date', ' ', 'Team Name')
|
181
183
|
@output.puts table.separator
|
182
184
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
185
|
+
dirs.each do |dir|
|
186
|
+
Dir['*.{mobileprovision,provisionprofile}', base: dir].each do |file_name|
|
187
|
+
file = File.join(dir, file_name)
|
188
|
+
begin
|
189
|
+
p = PProf::ProvisioningProfile.new(file)
|
187
190
|
|
188
|
-
|
191
|
+
next if block_given? && !yield(p)
|
189
192
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
193
|
+
state = DateTime.now < p.expiration_date ? "\u{2705}" : "\u{274c}" # 2705=checkmark, 274C=red X
|
194
|
+
@output.puts table.row(p.uuid, p.name, p.entitlements.app_id, p.expiration_date.to_time, state, p.team_name)
|
195
|
+
rescue StandardError => e
|
196
|
+
errors << { message: e, file: file }
|
197
|
+
end
|
198
|
+
count += 1
|
194
199
|
end
|
195
|
-
count += 1
|
196
200
|
end
|
197
201
|
|
198
202
|
@output.puts table.separator
|
@@ -203,55 +207,59 @@ module PProf
|
|
203
207
|
|
204
208
|
# Prints the filtered list of UUIDs or Paths only
|
205
209
|
#
|
206
|
-
# @param [String] dir
|
207
|
-
# The directory containing the mobileprovision files to list.
|
208
|
-
# Defaults to '~/Library/MobileDevice/Provisioning Profiles'
|
209
210
|
# @param [Hash] options
|
210
211
|
# The options hash typically filled while parsing the command line arguments.
|
211
212
|
# - :mode: will print the UUIDs if set to `:list`, the file path otherwise
|
212
213
|
# - :zero: will concatenate the entries with `\0` instead of `\n` if set
|
214
|
+
# @param [String] dirs
|
215
|
+
# The directories containing the mobileprovision/provisionprofile files to list.
|
216
|
+
# Defaults to ['~/Library/MobileDevice/Provisioning Profiles', '~/Library/Developer/Xcode/UserData/Provisioning Profiles']
|
213
217
|
#
|
214
218
|
# @yield each provisioning profile for filtering/validation
|
215
219
|
# The block is given ProvisioningProfile object and should
|
216
220
|
# return true to display the row, false to filter it out
|
217
221
|
#
|
218
|
-
def print_list(
|
222
|
+
def print_list(options:, dirs: PProf::ProvisioningProfile::DEFAULT_DIRS)
|
219
223
|
errors = []
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
+
dirs.each do |dir|
|
225
|
+
Dir['*.{mobileprovision,provisionprofile}', base: dir].each do |file_name|
|
226
|
+
file = File.join(dir, file_name)
|
227
|
+
p = PProf::ProvisioningProfile.new(file)
|
228
|
+
next if block_given? && !yield(p)
|
224
229
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
230
|
+
@output.print options[:mode] == :list ? p.uuid.chomp : file.chomp
|
231
|
+
@output.print options[:zero] ? "\0" : "\n"
|
232
|
+
rescue StandardError => e
|
233
|
+
errors << { message: e, file: file }
|
234
|
+
end
|
229
235
|
end
|
230
236
|
errors.each { |e| print_error(e[:message], e[:file]) } unless errors.empty?
|
231
237
|
end
|
232
238
|
|
233
239
|
# Prints the filtered list of profiles as a JSON array
|
234
240
|
#
|
235
|
-
# @param [String] dir
|
236
|
-
# The directory containing the mobileprovision files to list.
|
237
|
-
# Defaults to '~/Library/MobileDevice/Provisioning Profiles'
|
238
241
|
# @param [Hash] options
|
239
242
|
# The options hash typically filled while parsing the command line arguments.
|
240
243
|
# - :certs: will print the UUIDs if set to `:list`, the file path otherwise
|
241
244
|
# - :devices: will concatenate the entries with `\0` instead of `\n` if set
|
245
|
+
# @param [String] dirs
|
246
|
+
# The directories containing the mobileprovision/provisionprofile files to list.
|
247
|
+
# Defaults to ['~/Library/MobileDevice/Provisioning Profiles', '~/Library/Developer/Xcode/UserData/Provisioning Profiles']
|
242
248
|
#
|
243
249
|
# @yield each provisioning profile for filtering/validation
|
244
250
|
# The block is given ProvisioningProfile object and should
|
245
251
|
# return true to display the row, false to filter it out
|
246
252
|
#
|
247
|
-
def print_json_list(
|
253
|
+
def print_json_list(options:, dirs: PProf::ProvisioningProfile::DEFAULT_DIRS)
|
248
254
|
errors = []
|
249
|
-
profiles =
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
+
profiles = dirs.flat_map do |dir|
|
256
|
+
Dir['*.{mobileprovision,provisionprofile}', base: dir].map do |file_name|
|
257
|
+
file = File.join(dir, file_name)
|
258
|
+
p = PProf::ProvisioningProfile.new(file)
|
259
|
+
as_json(p, options) unless block_given? && !yield(p)
|
260
|
+
rescue StandardError => e
|
261
|
+
errors << { message: e, file: file }
|
262
|
+
end
|
255
263
|
end.compact
|
256
264
|
errors.each { |e| print_error(e[:message], e[:file]) } unless errors.empty?
|
257
265
|
@output.puts JSON.pretty_generate(profiles)
|
@@ -261,7 +269,7 @@ module PProf
|
|
261
269
|
return false if actual.nil? # false if no Push entitlements
|
262
270
|
return true if expected == true # true if Push present but we don't filter on specific env
|
263
271
|
|
264
|
-
actual =~ expected
|
272
|
+
actual =~ expected # true if Push present and we filter on specific env
|
265
273
|
end
|
266
274
|
end
|
267
275
|
end
|
@@ -9,26 +9,35 @@ module PProf
|
|
9
9
|
# Represents the content of a Provisioning Profile file
|
10
10
|
class ProvisioningProfile
|
11
11
|
# The default location where all the Provisioning Profiles are stored on a Mac
|
12
|
-
|
12
|
+
DEFAULT_DIRS = [
|
13
|
+
File.join(Dir.home, 'Library', 'MobileDevice', 'Provisioning Profiles'),
|
14
|
+
File.join(Dir.home, 'Library', 'Developer', 'Xcode', 'UserData', 'Provisioning Profiles')
|
15
|
+
].freeze
|
16
|
+
|
17
|
+
attr_reader :path
|
13
18
|
|
14
19
|
# Create a new ProvisioningProfile object from a file path or UUID
|
15
20
|
#
|
16
21
|
# - If the parameter given has the form of an UUID, a file named with this UUID
|
17
|
-
# and a `.mobileprovision` is searched in the default
|
22
|
+
# and a `.mobileprovision` is searched in the default directories `DEFAULT_DIRS`
|
18
23
|
# - Otherwise, the parameter is interpreted as a file path
|
19
24
|
#
|
20
25
|
# @param [String] file
|
21
26
|
# File path or UUID of the ProvisioningProfile
|
22
27
|
#
|
23
28
|
def initialize(file)
|
24
|
-
path = if file
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
@path = if file.match?(/^[0-9A-F-]*$/i)
|
30
|
+
PProf::ProvisioningProfile::DEFAULT_DIRS.flat_map do |dir|
|
31
|
+
Dir["#{dir}/#{file}.{mobileprovision,provisionprofile}"]
|
32
|
+
end.compact.first
|
33
|
+
else
|
34
|
+
file
|
35
|
+
end
|
36
|
+
raise "Unable to find Provisioning Profile with UUID #{file}." if @path.nil?
|
37
|
+
|
29
38
|
xml = nil
|
30
39
|
begin
|
31
|
-
pkcs7 = OpenSSL::PKCS7.new(File.read(path))
|
40
|
+
pkcs7 = OpenSSL::PKCS7.new(File.read(@path))
|
32
41
|
pkcs7.verify([], OpenSSL::X509::Store.new)
|
33
42
|
xml = pkcs7.data
|
34
43
|
raise 'Empty PKCS7 payload' if xml.nil? || xml.empty?
|
@@ -38,10 +47,10 @@ module PProf
|
|
38
47
|
# So as a fallback, we run the `security` command line.
|
39
48
|
# (We could use `security` everytime, but invoking a command line is generally less
|
40
49
|
# efficient than calling the OpenSSL gem if available, so for now it's just used as fallback)
|
41
|
-
xml = `security cms -D -i "#{path}" 2> /dev/null`
|
50
|
+
xml = `security cms -D -i "#{@path}" 2> /dev/null`
|
42
51
|
end
|
43
52
|
@plist = Plist.parse_xml(xml)
|
44
|
-
raise "Unable to parse file #{
|
53
|
+
raise "Unable to parse file #{@path}." if @plist.nil?
|
45
54
|
end
|
46
55
|
|
47
56
|
# The name of the Provisioning Profile
|
@@ -58,6 +67,14 @@ module PProf
|
|
58
67
|
@plist['UUID']
|
59
68
|
end
|
60
69
|
|
70
|
+
# The list of Platforms the Provisioning Profile is for.
|
71
|
+
# Typical values include `OSX`, `iOS`, `xrOS`, `visionOS`, …
|
72
|
+
#
|
73
|
+
# @return [Array<String>]
|
74
|
+
def platform
|
75
|
+
@plist['Platform']
|
76
|
+
end
|
77
|
+
|
61
78
|
# The name of the Application Identifier associated with this Provisioning Profile
|
62
79
|
#
|
63
80
|
# @note This is not the AppID itself, but rather the name you associated to that
|
@@ -154,7 +171,7 @@ module PProf
|
|
154
171
|
#
|
155
172
|
# @return [String]
|
156
173
|
def to_s
|
157
|
-
lines = %i[name uuid app_id_name app_id_prefix creation_date expiration_date ttl team_ids team_name].map do |key|
|
174
|
+
lines = %i[path name uuid app_id_name app_id_prefix creation_date expiration_date ttl team_ids team_name].map do |key|
|
158
175
|
"- #{key}: #{send(key.to_sym)}"
|
159
176
|
end +
|
160
177
|
[
|
data/lib/pprof/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pprof
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Olivier Halligon
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: plist
|
@@ -44,7 +43,6 @@ licenses:
|
|
44
43
|
- MIT
|
45
44
|
metadata:
|
46
45
|
rubygems_mfa_required: 'true'
|
47
|
-
post_install_message:
|
48
46
|
rdoc_options: []
|
49
47
|
require_paths:
|
50
48
|
- lib
|
@@ -59,8 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
57
|
- !ruby/object:Gem::Version
|
60
58
|
version: '0'
|
61
59
|
requirements: []
|
62
|
-
rubygems_version: 3.
|
63
|
-
signing_key:
|
60
|
+
rubygems_version: 3.6.8
|
64
61
|
specification_version: 4
|
65
62
|
summary: A Provisioning Profiles library
|
66
63
|
test_files: []
|