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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21276029f4a059802fcc59cdf37a843caa2b38cc11d6af22f76fa2969bf24975
4
- data.tar.gz: 02eedbe630b35226f7a00c531d0b8075b11ab6f4c705434e2f4e4f3445251c8d
3
+ metadata.gz: fe023fb6399ea85e9aafbd5fe04e359134b37880148ab6796538db8a98bbfca9
4
+ data.tar.gz: 558e2fc9027127c7aeb87ffb7e80b85ef80439bc6ec4c2301e478b342fb767a7
5
5
  SHA512:
6
- metadata.gz: 48eb1f57db15c832e6a9acf454d9c6a5ce3be07dc7db4d5877cccb7c32c96f6cfddcf7b3be78a8af8c2c9374148961273a0a1e22a5f51e13b0d8df7359b20ed7
7
- data.tar.gz: fdb8efa34984352bc61242ae6452c3e5f6a6e3c11708735c0061d202dae12d8c232458ad88f02d572579221e7d1b8e7e30b1c457048ad626097d80d9825e5aba
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 create ruby scripts to list, get information, find and filter local Provisioning Profiles easily.
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
- dir = PProf::ProvisioningProfile::DEFAULT_DIR
108
- Dir["#{dir}/*.mobileprovision"].each do |file|
109
- p = PProf::ProvisioningProfile.new(file)
110
- puts p.name
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
- ::DEFAULT_DIR
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] dir
167
- # The directory containing the mobileprovision files to list.
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(dir: PProf::ProvisioningProfile::DEFAULT_DIR)
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
- Dir['*.mobileprovision', base: dir].each do |file_name|
184
- file = File.join(dir, file_name)
185
- begin
186
- p = PProf::ProvisioningProfile.new(file)
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
- next if block_given? && !yield(p)
191
+ next if block_given? && !yield(p)
189
192
 
190
- state = DateTime.now < p.expiration_date ? "\u{2705}" : "\u{274c}" # 2705=checkmark, 274C=red X
191
- @output.puts table.row(p.uuid, p.name, p.entitlements.app_id, p.expiration_date.to_time, state, p.team_name)
192
- rescue StandardError => e
193
- errors << { message: e, file: file }
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(dir: PProf::ProvisioningProfile::DEFAULT_DIR, options:) # rubocop:disable Style/OptionalArguments
222
+ def print_list(options:, dirs: PProf::ProvisioningProfile::DEFAULT_DIRS)
219
223
  errors = []
220
- Dir['*.mobileprovision', base: dir].each do |file_name|
221
- file = File.join(dir, file_name)
222
- p = PProf::ProvisioningProfile.new(file)
223
- next if block_given? && !yield(p)
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
- @output.print options[:mode] == :list ? p.uuid.chomp : file.chomp
226
- @output.print options[:zero] ? "\0" : "\n"
227
- rescue StandardError => e
228
- errors << { message: e, file: file }
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(dir: PProf::ProvisioningProfile::DEFAULT_DIR, options:) # rubocop:disable Style/OptionalArguments
253
+ def print_json_list(options:, dirs: PProf::ProvisioningProfile::DEFAULT_DIRS)
248
254
  errors = []
249
- profiles = Dir['*.mobileprovision', base: dir].map do |file_name|
250
- file = File.join(dir, file_name)
251
- p = PProf::ProvisioningProfile.new(file)
252
- as_json(p, options) unless block_given? && !yield(p)
253
- rescue StandardError => e
254
- errors << { message: e, file: file }
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 # true if Push present and we filter on specific env
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
- DEFAULT_DIR = "#{ENV['HOME']}/Library/MobileDevice/Provisioning Profiles"
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 directory `DEFAULT_DIR`
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 =~ /^[0-9A-F-]*$/i
25
- "#{PProf::ProvisioningProfile::DEFAULT_DIR}/#{file}.mobileprovision"
26
- else
27
- file
28
- end
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 #{file}." if @plist.nil?
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module PProf
4
4
  # Module version
5
- VERSION = '0.5.1'
5
+ VERSION = '1.1.0'
6
6
  end
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: 0.5.1
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: 2022-05-09 00:00:00.000000000 Z
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.0.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: []