pprof 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b298d026ed403f21ea18ce7023b6a31369b749c1
4
+ data.tar.gz: 9dbfec58d992aa3d80decc8bbb3f8167f2839a0a
5
+ SHA512:
6
+ metadata.gz: 4be4244290d618ceb0a91b23ef21d9d327dadee0840e4291ac8d854b8f2a137269099898fb8c1001f08863df9eeabd37609b58431cb1340a1e71110aad275c4a
7
+ data.tar.gz: f00597c5cf7be23cf250861d47c8ac3cb5e75a43b15440155733a405baf7b5e8a4603caf6489a5e601bea7c6338ee23aba632268c0b4652b1da13e1edde899c7
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ - MIT LICENSE -
2
+
3
+ Copyright (c) 2016 Olivier Halligon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,168 @@
1
+ # pprof
2
+
3
+ [![Twitter: @aligatr](https://img.shields.io/badge/contact-@aligatr-blue.svg?style=flat)](https://twitter.com/aligatr)
4
+ [![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/AliSoftware/pprof/blob/master/LICENSE)
5
+
6
+ `pprof` is a ruby library and binary to manipulate Provisioning Profiles.
7
+
8
+ It can help you create ruby scripts to list, get information, find and filter Provisioning Profiles easily.
9
+
10
+ ## Installation
11
+
12
+ ### Rubygems
13
+
14
+ As of now this library is very early stage and [hasn't been pushed on RubyGems yet](https://github.com/AliSoftware/pprof/issues/4).
15
+ I intend to push it as soon as [#2](https://github.com/AliSoftware/pprof/issues/4) (unit tests) and [#3](https://github.com/AliSoftware/pprof/issues/4) (CHANGELOG) are addressed.
16
+
17
+ ### Build from source
18
+
19
+ * Clone the repository
20
+ * Build it using `gem build pprof.gemspec`
21
+ * Install it using `gem install pprof-0.3.1.gem`
22
+
23
+ ## Example usages
24
+
25
+ * Find all the Provisioning Profiles that are attached to a given Team, or with a given AppID, or that will expire after a given date.
26
+
27
+ * List all your Provisioning Profiles and their inner information, like the provisioned device UDIDs, the list of certificates (with their associated subject/name), etc.
28
+
29
+ ### Using it from the command line
30
+
31
+ ```sh
32
+ # List all provisioning profiles
33
+ $ pprof
34
+
35
+ # Filter provisioning profiles by name
36
+ $ pprof --name foo # only ones containing 'foo', case sensitive
37
+ $ pprof --name /foo/i # only ones containing 'foo', case insensitive
38
+ $ pprof --name '/foo|bar/' # only ones containing 'foo' or 'bar'
39
+ $ pprof --name /^foo$/ # only the ones exactly matching 'foo'
40
+
41
+ # Filter by AppID
42
+ $ pprof --appid com.foo # only ones containing 'com.foo'
43
+ $ pprof --appid '/com\.(foo|bar)/' # only ones containing 'com.foo' or 'com.bar'
44
+
45
+ # List only provisioning profiles having push notifications
46
+ $ pprof --aps
47
+ $ pprof --aps development
48
+ $ pprof --aps production
49
+
50
+ # List only provisioning profiles being expired or not
51
+ $ pprof --exp
52
+ $ pprof --no-exp
53
+
54
+ # List only provisioning profiles containing provisioned devices
55
+ $ pprof --has-devices
56
+
57
+ # Combine filters
58
+ $ pprof --has-devices --aps --appid com.foo
59
+ ```
60
+ ```sh
61
+ # Print info for a given Provisioning Profile
62
+ $ pprof '12345678-ABCD-EF90-1234-567890ABCDEF'
63
+
64
+ # Print certificates in a given PP
65
+ $ pprof --certs '12345678-ABCD-EF90-1234-567890ABCDEF'
66
+
67
+ # Print devices in a given PP
68
+ $ pprof --devices '12345678-ABCD-EF90-1234-567890ABCDEF'
69
+
70
+ # Print all info on a given PP
71
+ $ pprof --certs --devices --info '12345678-ABCD-EF90-1234-567890ABCDEF'
72
+ $ pprof -cdi '12345678-ABCD-EF90-1234-567890ABCDEF'
73
+ ```
74
+
75
+ ### Using it in Ruby
76
+
77
+ ```ruby
78
+ require 'pprof'
79
+ # Load the Provisioning Profile
80
+ p = PProf::ProvisioningProfile.new('12345678-ABCD-EF90-1234-567890ABCDEF')
81
+
82
+ # Print various informations
83
+ puts p.name
84
+ puts p.team_name
85
+ puts p.entitlements.aps_environment
86
+ puts p.provisioned_devices.count
87
+
88
+ # Use an OutputFormatter to pretty-print the info
89
+ o = PProf::OutputFormatter.new
90
+ o.print_info(p)
91
+
92
+ # You can also print into any IO other than $stdout, like a File
93
+ File.open('certs.txt', 'w') do |file|
94
+ o2 = PProf::OutputFormatter.new(file)
95
+ o2.print_info(p, :certs => true)
96
+ end
97
+
98
+ # And you can easily loop on all provisioning profiles and manipulate each
99
+ dir = PProf::ProvisioningProfile::DEFAULT_DIR
100
+ Dir["#{dir}/*.mobileprovision"].each do |file|
101
+ p = PProf::ProvisioningProfile.new(file)
102
+ puts p.name
103
+ end
104
+ ```
105
+
106
+
107
+ ## Anatomy of a Provisioning Profile
108
+
109
+ Provisioning Profiles are in fact PKCS7 files which contain a plist payload.
110
+
111
+ That plist payload itself contains various data, including some textual information (Team Name, AppID, …), dates (expiration date, etc) but also X509 Certificates (`OpenSSL::X509::Certificate`).
112
+
113
+ <details>
114
+ <summary>Outline of the two main classes `ProvisioningProfile` and `Entitlements`</summary>
115
+
116
+ ```ruby
117
+ PProf::ProvisioningProfile
118
+ ::DEFAULT_DIR
119
+ new(file) => PProf::ProvisioningProfile
120
+ to_hash => Hash<String, Any>
121
+
122
+ name => String
123
+ uuid => String
124
+ app_id_name => String
125
+ app_id_prefix => String
126
+ creation_date => DateTime
127
+ expiration_date => DateTime
128
+ ttl => Int
129
+ team_ids => Array<String>
130
+ team_name => String
131
+ developer_certificates => Array<OpenSSL::X509::Certificate>
132
+ entitlements => PProf::Entitlements
133
+ provisioned_devices => Array<String>
134
+ provisions_all_devices => Bool
135
+
136
+ PProf::Entitlements
137
+ new(dict) => PProf::Entitlements
138
+ to_hash => Hash<String, Any>
139
+ [](key) => Any
140
+ has_key?(key) => Bool
141
+ keys => Array<String>
142
+
143
+ keychain_access_groups => Array<String>
144
+ get_task_allow => Bool
145
+ app_id => String
146
+ team_id => String
147
+ aps_environment => String
148
+ app_groups => Array<String>
149
+ beta_reports_active => Bool
150
+ healthkit => Bool
151
+ ubiquity_container_identifiers => Array<String>
152
+ ubiquity_kvstore_identifier => String
153
+ ```
154
+ </details>
155
+
156
+ ## Contributing
157
+
158
+ There's plenty of room for improvement, including:
159
+
160
+ * Additional filters
161
+ * Ability to change the output format
162
+ * Parsing of additional entitlement keys
163
+
164
+ Don't hesitate to contribute, either with an Issue to give ideas or additional keys that aren't parsed yet, or via a Pull Request to provide new features yourself!
165
+
166
+ ## License
167
+
168
+ This project is under the MIT license. See `LICENSE` file for more details.
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pprof'
4
+ require 'optparse'
5
+
6
+
7
+ def matcher(string)
8
+ m = string.match(%r[^/(.*)/(.*)$])
9
+ if m.nil?
10
+ Regexp.new(Regexp.escape(string))
11
+ else
12
+ Regexp.new(m[1], m[2].empty? ? nil : m[2])
13
+ end
14
+ end
15
+
16
+ # Command Line Parsing
17
+
18
+ filters = {}
19
+ options = {}
20
+ parser = OptionParser.new do |opts|
21
+ opts.banner = <<-BANNER.gsub(/^ *\|/,'')
22
+ |Usage:
23
+ | pprof [options] [PATH|UUID]
24
+ | pprof [filters]
25
+ |
26
+ |Note: All filters expecting a string are interpreted as regular expressions if surrounded by slashes
27
+ BANNER
28
+
29
+ opts.separator ""
30
+ opts.separator "Print options"
31
+
32
+ opts.on("-i", "--info", "Print general info (default)") do
33
+ options[:info] = true
34
+ end
35
+ opts.on("-c", "--certs", "Print certificates") do
36
+ options[:certs] = true
37
+ end
38
+ opts.on("-d", "--devices", "Print provisioned devices") do
39
+ options[:devices] = true
40
+ end
41
+
42
+ opts.separator ""
43
+ opts.separator "Filters"
44
+
45
+ opts.on("-n", "--name NAME", "Filter by name") do |name|
46
+ filters[:name] = matcher(name)
47
+ end
48
+
49
+ opts.on("--appid-name APPID", "Filter by App ID Name") do |appid_name|
50
+ filters[:appid_name] = matcher(appid_name)
51
+ end
52
+
53
+ opts.on("-a", "--appid APPID", "Filter by App ID") do |appid|
54
+ filters[:appid] = matcher(appid)
55
+ end
56
+
57
+ opts.on("--uuid UUID", "Filter by UUID") do |uuid|
58
+ filters[:uuid] = matcher(uuid)
59
+ end
60
+
61
+ opts.on("-e", "--[no-]exp", "Only profiles (not) expired") do |flag|
62
+ filters[:exp] = flag
63
+ end
64
+
65
+ opts.on("--[no-]has-devices", "Filter by profiles having (no) provisioned devices") do |d|
66
+ filters[:has_devices] = d
67
+ end
68
+
69
+ opts.on("--[no-]all-devices", "Filter by profiles (not) provisioning all devices") do |d|
70
+ filters[:all_devices] = d
71
+ end
72
+
73
+ opts.on("--aps [ENV]", "Only profiles having Push entitlements (on a specific aps env)") do |env|
74
+ filters[:aps_env] = env.nil? ? true : matcher(env)
75
+ end
76
+
77
+
78
+ opts.separator ""
79
+ opts.separator "Misc"
80
+
81
+ opts.on_tail("-h", "--help", "Show this message") do
82
+ puts opts
83
+ exit
84
+ end
85
+
86
+ opts.on_tail("-v", "--version", "Show version") do
87
+ puts PProf::VERSION
88
+ exit
89
+ end
90
+ end
91
+
92
+ # Parse the options, catching parse errors nicely
93
+ begin
94
+ parser.parse!
95
+ rescue OptionParser::InvalidOption => err
96
+ puts err
97
+ puts parser.help()
98
+ exit 1
99
+ end
100
+
101
+ # Don't mix filters and options together, that doesn't make sense
102
+
103
+ unless filters.empty? || ARGV.empty?
104
+ puts "You should use either filter flags to filter the whole list, or an specific path, not both."
105
+ puts parser # Usage
106
+ exit
107
+ end
108
+
109
+ unless options.empty? || !ARGV.empty?
110
+ puts "You should use option flags only when providing an specific path."
111
+ puts parser # Usage
112
+ exit
113
+ end
114
+
115
+ # Call the appropriate action
116
+
117
+ if ARGV.empty?
118
+ # Print list of matching profiles
119
+ o = PProf::OutputFormatter.new
120
+ o.print_filtered_list(PProf::ProvisioningProfile::DEFAULT_DIR, filters)
121
+ else
122
+ # Print info about given profile path/UUID
123
+ p = PProf::ProvisioningProfile.new(ARGV[0])
124
+
125
+ o = PProf::OutputFormatter.new
126
+ options = { :info => true } if options.empty?
127
+ o.print_info(p, options)
128
+ end
@@ -0,0 +1,6 @@
1
+ require 'pprof/version'
2
+
3
+ require 'pprof/provisioning_profile'
4
+ require 'pprof/entitlements'
5
+
6
+ require 'pprof/output_formatter'
@@ -0,0 +1,93 @@
1
+ module PProf
2
+ class Entitlements
3
+ def initialize(dict)
4
+ @dict = dict
5
+ end
6
+
7
+ # @return [Array<String>]
8
+ def keychain_access_groups
9
+ @dict['keychain-access-groups']
10
+ end
11
+
12
+ # @return [Bool]
13
+ def get_task_allow
14
+ @dict['get-task-allow']
15
+ end
16
+
17
+ # @return [String]
18
+ def app_id
19
+ @dict['application-identifier']
20
+ end
21
+
22
+ # @return [String]
23
+ def team_id
24
+ @dict['com.apple.developer.team-identifier']
25
+ end
26
+
27
+ # @return [String]
28
+ def aps_environment
29
+ @dict['aps-environment']
30
+ end
31
+
32
+ # @return [Array<String>]
33
+ def app_groups
34
+ @dict['com.apple.security.application-groups']
35
+ end
36
+
37
+ # @return [Bool]
38
+ def beta_reports_active
39
+ @dict['beta-reports-active']
40
+ end
41
+
42
+ # @return [Bool]
43
+ def healthkit
44
+ @dict['com.apple.developer.healthkit']
45
+ end
46
+
47
+ # @return [Array<String>]
48
+ def ubiquity_container_identifiers
49
+ @dict['com.apple.developer.ubiquity-container-identifiers']
50
+ end
51
+
52
+ # @return [String]
53
+ def ubiquity_kvstore_identifier
54
+ @dict['com.apple.developer.ubiquity-kvstore-identifier']
55
+ end
56
+
57
+ # Access entitlements by key
58
+ #
59
+ # @param [#to_s] key
60
+ # The entitlement key to read
61
+ #
62
+ def [](key)
63
+ @dict[key.to_s]
64
+ end
65
+
66
+ # Check if a given entitlement key is present
67
+ #
68
+ # @param [#to_s] key
69
+ # The key to check
70
+ #
71
+ def has_key?(key)
72
+ @dict.has_key?(key.to_s)
73
+ end
74
+
75
+ # The list of entitlement keys as String
76
+ #
77
+ # @return [Array<String>]
78
+ #
79
+ def keys
80
+ @dict.keys.map(&:to_s)
81
+ end
82
+
83
+ def to_hash
84
+ @dict
85
+ end
86
+
87
+ def to_s
88
+ @dict.map do |key, value|
89
+ "- #{key}: #{value}"
90
+ end.join("\n")
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,119 @@
1
+ module PProf
2
+ class OutputFormatter
3
+ # Initialize a new OutputFormatter
4
+ #
5
+ # @param [IO] output
6
+ # The output destination where to print the formatted data.
7
+ # Defaults to $stdout
8
+ #
9
+ def initialize(output = $stdout)
10
+ @output = output
11
+ end
12
+
13
+ # A small helper to print ASCII tables
14
+ class ASCIITable
15
+ def initialize(*widths)
16
+ @widths = widths
17
+ end
18
+
19
+ def row(*cols)
20
+ '| ' + cols.zip(@widths).map do |c,w|
21
+ (c || '<nil>').to_s.ljust(w)[0...w]
22
+ end.join(' | ') + ' |'
23
+ end
24
+
25
+ def separator
26
+ '+' + @widths.map { |w| '-' * (w+2) }.join('+') + '+'
27
+ end
28
+ end
29
+
30
+ # Prints the description of a Provisioning Profile
31
+ #
32
+ # @param [PProf::ProvisioningProfile] profile
33
+ # The ProvisioningProfile object to print
34
+ # @param [Hash<Symbol,Bool>] options
35
+ # Decide what to print. Valid keys are :info, :certs and :devices
36
+ #
37
+ def print_info(profile, options = nil)
38
+ options ||= { :info => true }
39
+ if options[:info]
40
+ keys = [:name, :uuid, :app_id_name, :app_id_prefix, :creation_date, :expiration_date, :ttl, :team_ids, :team_name]
41
+ keys.each do |key|
42
+ @output.puts "- #{key.to_s}: #{profile.send(key.to_sym)}"
43
+ end
44
+ @output.puts "- Entitlements:"
45
+ @output.puts profile.entitlements.to_s.split("\n").map { |line| " #{line}" }
46
+ end
47
+
48
+ if options[:info] || options[:certs]
49
+ @output.puts "- #{profile.developer_certificates.count} Developer Certificates"
50
+ profile.developer_certificates.each { |cert| @output.puts " - #{cert.subject}" } if options[:certs]
51
+ end
52
+ if options[:info] || options[:devices]
53
+ @output.puts "- #{(profile.provisioned_devices || []).count} Provisioned Devices"
54
+ profile.provisioned_devices.each { |udid| @output.puts " - #{udid}" } if options[:devices]
55
+ @output.puts "- Provision all devices: #{profile.provisions_all_devices.inspect}"
56
+ end
57
+ end
58
+
59
+ # Prints the filtered list of Provisioning Profiles
60
+ #
61
+ # Convenience method. Calls self.print_list with a filter block build from a filter hash
62
+ #
63
+ # @param [Hash<Symbol,Any>] filters
64
+ # The hash describing the applied filters
65
+ #
66
+ def print_filtered_list(dir = PProf::ProvisioningProfile::DEFAULT_DIR, filters = {})
67
+ print_list(dir) do |p|
68
+ (filters[:name].nil? || p.name =~ filters[:name]) &&
69
+ (filters[:appid_name].nil? || p.app_id_name =~ filters[:appid_name]) &&
70
+ (filters[:appid].nil? || p.entitlements.app_id =~ filters[:appid]) &&
71
+ (filters[:uuid].nil? || p.uuid =~ filters[:uuid]) &&
72
+ (filters[:exp].nil? || (p.expiration_date < DateTime.now) == filters[:exp]) &&
73
+ (filters[:has_devices].nil? || !(p.provisioned_devices || []).empty? == filters[:has_devices]) &&
74
+ (filters[:all_devices].nil? || p.provisions_all_devices == filters[:all_devices]) &&
75
+ (filters[:aps_env].nil? || match_aps_env(p.entitlements.aps_environment, filters[:aps_env])) &&
76
+ true
77
+ end
78
+ end
79
+
80
+ # Prints the filtered list
81
+ #
82
+ # @param [String] dir
83
+ # The directory containing the mobileprovision files to list.
84
+ # Defaults to '~/Library/MobileDevice/Provisioning Profiles'
85
+ #
86
+ # @yield each provisioning provile for filtering/validation
87
+ # The block is given ProvisioningProfile object and should
88
+ # return true to display the row, false to filter it out
89
+ #
90
+ def print_list(dir = PProf::ProvisioningProfile::DEFAULT_DIR)
91
+ count = 0
92
+
93
+ table = PProf::OutputFormatter::ASCIITable.new(36, 60, 45, 25, 2, 10)
94
+ @output.puts table.separator
95
+ @output.puts table.row('UUID', 'Name', 'AppID', 'Expiration Date', ' ', 'Team Name')
96
+ @output.puts table.separator
97
+
98
+ Dir[dir + '/*.mobileprovision'].each do |file|
99
+ p = PProf::ProvisioningProfile.new(file)
100
+
101
+ next if block_given? && !yield(p)
102
+
103
+ state = DateTime.now < p.expiration_date ? "\u{2705}" : "\u{274c}" # 2705=checkmark, 274C=red X
104
+ @output.puts table.row(p.uuid, p.name, p.entitlements.app_id, p.expiration_date.to_time, state, p.team_name)
105
+ count += 1
106
+ end
107
+
108
+ @output.puts table.separator
109
+ @output.puts "#{count} Provisioning Profiles found."
110
+ end
111
+
112
+ private
113
+ def self.match_aps_env(actual, expected)
114
+ return false if actual.nil? # false if no Push entitlements
115
+ return true if expected === true # true if Push present but we don't filter on specific env
116
+ return actual =~ expected # true if Push present and we filter on specific env
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,103 @@
1
+ require 'openssl'
2
+ require 'plist'
3
+ require 'time'
4
+
5
+ module PProf
6
+ class ProvisioningProfile
7
+ DEFAULT_DIR="#{ENV['HOME']}/Library/MobileDevice/Provisioning Profiles"
8
+
9
+ def initialize(file)
10
+ if file =~ %r/^[0-9A-F-]*$/i
11
+ path = "#{PProf::ProvisioningProfile::DEFAULT_DIR}/#{file}.mobileprovision"
12
+ else
13
+ path = file
14
+ end
15
+ pkcs7 = OpenSSL::PKCS7.new(File.read(path))
16
+ pkcs7.verify([], OpenSSL::X509::Store.new)
17
+ @plist = Plist::parse_xml(pkcs7.data)
18
+ end
19
+
20
+ # @return [String]
21
+ def name
22
+ @plist['Name']
23
+ end
24
+
25
+ # @return [String]
26
+ def uuid
27
+ @plist['UUID']
28
+ end
29
+
30
+ # @return [String]
31
+ def app_id_name
32
+ @plist['AppIDName']
33
+ end
34
+
35
+ # @return [String]
36
+ def app_id_prefix
37
+ @plist['ApplicationIdentifierPrefix']
38
+ end
39
+
40
+ # @return [DateTime]
41
+ def creation_date
42
+ @plist['CreationDate']
43
+ end
44
+
45
+ # @return [DateTime]
46
+ def expiration_date
47
+ @plist['ExpirationDate']
48
+ end
49
+
50
+ # @return [Int]
51
+ def ttl
52
+ @plist['TimeToLive'].to_i
53
+ end
54
+
55
+ # @return [Array<String>]
56
+ def team_ids
57
+ @plist['TeamIdentifier']
58
+ end
59
+
60
+ # @return [String]
61
+ def team_name
62
+ @plist['TeamName']
63
+ end
64
+
65
+ # @return [Array<OpenSSL::X509::Certificate>] List of certificates associated with this profile
66
+ def developer_certificates
67
+ @plist['DeveloperCertificates'].map do |data|
68
+ OpenSSL::X509::Certificate.new(data.string)
69
+ end
70
+ end
71
+
72
+ # @return [Entitlements] All the entitlements associated with this profile
73
+ def entitlements
74
+ PProf::Entitlements.new(@plist['Entitlements'])
75
+ end
76
+
77
+ # @return [Array<String>] List of provisioned devices if any
78
+ def provisioned_devices
79
+ @plist['ProvisionedDevices']
80
+ end
81
+
82
+ # @return [Bool]
83
+ def provisions_all_devices
84
+ @plist['ProvisionsAllDevices'] || false
85
+ end
86
+
87
+ def to_hash
88
+ @dict
89
+ end
90
+
91
+ def to_s
92
+ lines = [:name, :uuid, :app_id_name, :app_id_prefix, :creation_date, :expiration_date, :ttl, :team_ids, :team_name].map do |key|
93
+ "- #{key.to_s}: #{self.send(key.to_sym)}"
94
+ end +
95
+ [
96
+ "- #{developer_certificates.count} Developer Certificates",
97
+ "- #{provisioned_devices.count} Provisioned Devices",
98
+ "- Entitlements:"
99
+ ] + entitlements.to_hasg.map { |key, value| " - #{key}: #{value}" }
100
+ lines.join("\n")
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ module PProf
2
+ VERSION = '0.3.2'
3
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pprof
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.2
5
+ platform: ruby
6
+ authors:
7
+ - Olivier Halligon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-09-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: plist
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ description: library and binary tool to manipulate Provisioning Profile files
28
+ email: olivier@halligon.net
29
+ executables:
30
+ - pprof
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE
35
+ - README.md
36
+ - bin/pprof
37
+ - lib/pprof.rb
38
+ - lib/pprof/entitlements.rb
39
+ - lib/pprof/output_formatter.rb
40
+ - lib/pprof/provisioning_profile.rb
41
+ - lib/pprof/version.rb
42
+ homepage: http://rubygems.org/gems/pp
43
+ licenses:
44
+ - MIT
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.0.0
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.6.7
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: A Provisioning Profiles library
66
+ test_files: []