protool 3.0.0__tar.gz → 3.0.1__tar.gz
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.
- {protool-3.0.0 → protool-3.0.1}/PKG-INFO +12 -3
- {protool-3.0.0 → protool-3.0.1}/README.md +7 -0
- {protool-3.0.0 → protool-3.0.1}/protool/__init__.py +25 -27
- {protool-3.0.0 → protool-3.0.1}/protool/command_line.py +2 -2
- {protool-3.0.0 → protool-3.0.1}/pyproject.toml +2 -2
- {protool-3.0.0 → protool-3.0.1}/LICENSE +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: protool
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.1
|
|
4
4
|
Summary: A tool for dealing with provisioning profiles
|
|
5
|
-
Home-page: https://github.com/Microsoft/protool
|
|
6
5
|
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
7
|
Keywords: provisioning,profiles,apple,ios,xcode,mobileprovision
|
|
8
8
|
Author: Dale Myers
|
|
9
9
|
Author-email: dalemy@microsoft.com
|
|
@@ -17,12 +17,14 @@ Classifier: Programming Language :: Python :: 3
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
22
|
Classifier: Programming Language :: Python :: 3.8
|
|
22
23
|
Classifier: Programming Language :: Python :: 3.9
|
|
23
24
|
Classifier: Topic :: Software Development
|
|
24
25
|
Classifier: Topic :: Utilities
|
|
25
26
|
Requires-Dist: pyOpenSSL (>=25.1.0,<26.0.0)
|
|
27
|
+
Project-URL: Homepage, https://github.com/Microsoft/protool
|
|
26
28
|
Project-URL: Repository, https://github.com/Microsoft/protool
|
|
27
29
|
Description-Content-Type: text/markdown
|
|
28
30
|
|
|
@@ -72,6 +74,13 @@ Alternatively, from the command line:
|
|
|
72
74
|
# Get the raw XML (identical to using `security cms -D -i /path/to/profile`)
|
|
73
75
|
protool decode --profile /path/to/profile
|
|
74
76
|
|
|
77
|
+
Custom diff commands (`tool_override` in Python or `--tool` on the command line)
|
|
78
|
+
accept an executable and optional arguments, for example `--tool 'diff -u'`.
|
|
79
|
+
Quote executable paths or arguments containing spaces within the command string,
|
|
80
|
+
for example `--tool '"/path with spaces/diff" -u'`. Commands run directly, without
|
|
81
|
+
a shell: pipes, redirection, environment-variable expansion, and command
|
|
82
|
+
substitution are not supported. Profile paths are always passed as literal arguments.
|
|
83
|
+
|
|
75
84
|
|
|
76
85
|
# Contributing
|
|
77
86
|
|
|
@@ -44,6 +44,13 @@ Alternatively, from the command line:
|
|
|
44
44
|
# Get the raw XML (identical to using `security cms -D -i /path/to/profile`)
|
|
45
45
|
protool decode --profile /path/to/profile
|
|
46
46
|
|
|
47
|
+
Custom diff commands (`tool_override` in Python or `--tool` on the command line)
|
|
48
|
+
accept an executable and optional arguments, for example `--tool 'diff -u'`.
|
|
49
|
+
Quote executable paths or arguments containing spaces within the command string,
|
|
50
|
+
for example `--tool '"/path with spaces/diff" -u'`. Commands run directly, without
|
|
51
|
+
a shell: pipes, redirection, environment-variable expansion, and command
|
|
52
|
+
substitution are not supported. Profile paths are always passed as literal arguments.
|
|
53
|
+
|
|
47
54
|
|
|
48
55
|
# Contributing
|
|
49
56
|
|
|
@@ -8,7 +8,7 @@ import copy
|
|
|
8
8
|
import datetime
|
|
9
9
|
import os
|
|
10
10
|
import plistlib
|
|
11
|
-
import
|
|
11
|
+
import shlex
|
|
12
12
|
import subprocess
|
|
13
13
|
import sys
|
|
14
14
|
import tempfile
|
|
@@ -201,9 +201,9 @@ class ProvisioningProfile:
|
|
|
201
201
|
if not os.path.exists(self.file_path):
|
|
202
202
|
raise Exception(f"File does not exist: {self.file_path}")
|
|
203
203
|
|
|
204
|
-
security_cmd =
|
|
204
|
+
security_cmd = ["security", "cms", "-D", "-i", self.file_path]
|
|
205
205
|
return subprocess.check_output(
|
|
206
|
-
security_cmd, universal_newlines=True,
|
|
206
|
+
security_cmd, universal_newlines=True, stderr=subprocess.DEVNULL
|
|
207
207
|
).strip()
|
|
208
208
|
|
|
209
209
|
|
|
@@ -239,14 +239,17 @@ def diff(
|
|
|
239
239
|
ignore_keys: list[str] | None = None,
|
|
240
240
|
tool_override: str | None = None,
|
|
241
241
|
) -> str:
|
|
242
|
-
"""Diff two provisioning profiles."""
|
|
242
|
+
"""Diff two provisioning profiles without shell expansion of tool_override."""
|
|
243
243
|
|
|
244
244
|
# pylint: disable=too-many-locals
|
|
245
245
|
|
|
246
246
|
if tool_override is None:
|
|
247
|
-
|
|
247
|
+
diff_command = ["opendiff"]
|
|
248
248
|
else:
|
|
249
|
-
|
|
249
|
+
diff_command = shlex.split(tool_override)
|
|
250
|
+
|
|
251
|
+
if not diff_command or not diff_command[0]:
|
|
252
|
+
raise ValueError("Diff command must include an executable")
|
|
250
253
|
|
|
251
254
|
profile_a = ProvisioningProfile(a_path, sort_keys=sort_keys)
|
|
252
255
|
profile_b = ProvisioningProfile(b_path, sort_keys=sort_keys)
|
|
@@ -271,31 +274,26 @@ def diff(
|
|
|
271
274
|
a_xml = plistlib.dumps(a_dict).decode("utf-8")
|
|
272
275
|
b_xml = plistlib.dumps(b_dict).decode("utf-8")
|
|
273
276
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
b_temp_path = os.path.join(temp_dir, profile_b.file_name)
|
|
278
|
-
|
|
279
|
-
with open(a_temp_path, "w", encoding="utf-8") as temp_profile:
|
|
280
|
-
temp_profile.write(a_xml)
|
|
277
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
278
|
+
a_temp_path = os.path.join(temp_dir, profile_a.file_name)
|
|
279
|
+
b_temp_path = os.path.join(temp_dir, profile_b.file_name)
|
|
281
280
|
|
|
282
|
-
|
|
283
|
-
|
|
281
|
+
with open(a_temp_path, "w", encoding="utf-8") as temp_profile:
|
|
282
|
+
temp_profile.write(a_xml)
|
|
284
283
|
|
|
285
|
-
|
|
286
|
-
|
|
284
|
+
with open(b_temp_path, "w", encoding="utf-8") as temp_profile:
|
|
285
|
+
temp_profile.write(b_xml)
|
|
287
286
|
|
|
288
|
-
|
|
289
|
-
diff_contents = subprocess.check_output(
|
|
290
|
-
diff_command, universal_newlines=True, shell=True
|
|
291
|
-
).strip()
|
|
292
|
-
except subprocess.CalledProcessError as ex:
|
|
293
|
-
# Diff tools usually return a non-0 exit code if there are differences,
|
|
294
|
-
# so we just swallow this error
|
|
295
|
-
diff_contents = ex.output
|
|
287
|
+
diff_command.extend([a_temp_path, b_temp_path])
|
|
296
288
|
|
|
297
|
-
|
|
298
|
-
|
|
289
|
+
try:
|
|
290
|
+
diff_contents = subprocess.check_output(
|
|
291
|
+
diff_command, universal_newlines=True
|
|
292
|
+
).strip()
|
|
293
|
+
except subprocess.CalledProcessError as ex:
|
|
294
|
+
# Diff tools usually return a non-0 exit code if there are differences,
|
|
295
|
+
# so we just swallow this error
|
|
296
|
+
diff_contents = ex.output
|
|
299
297
|
|
|
300
298
|
return diff_contents
|
|
301
299
|
|
|
@@ -131,7 +131,7 @@ def _handle_arguments() -> int:
|
|
|
131
131
|
dest="tool",
|
|
132
132
|
action="store",
|
|
133
133
|
default=None,
|
|
134
|
-
help="Specify a diff
|
|
134
|
+
help="Specify a diff executable with optional quoted arguments (no shell expansion). It should take two file paths as the final two arguments. Defaults to opendiff", # pylint: disable=line-too-long
|
|
135
135
|
)
|
|
136
136
|
|
|
137
137
|
diff_parser.add_argument(
|
|
@@ -177,7 +177,7 @@ def _handle_arguments() -> int:
|
|
|
177
177
|
dest="tool",
|
|
178
178
|
action="store",
|
|
179
179
|
default=None,
|
|
180
|
-
help="Specify a diff
|
|
180
|
+
help="Specify a diff executable with optional quoted arguments (no shell expansion). It should take two file paths as the final two arguments. Defaults to opendiff", # pylint: disable=line-too-long
|
|
181
181
|
)
|
|
182
182
|
|
|
183
183
|
gitdiff_parser.add_argument(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "protool"
|
|
3
|
-
version = "3.0.
|
|
3
|
+
version = "3.0.1"
|
|
4
4
|
description = "A tool for dealing with provisioning profiles"
|
|
5
5
|
|
|
6
6
|
license = "MIT"
|
|
@@ -46,7 +46,7 @@ pyOpenSSL = "^25.1.0"
|
|
|
46
46
|
black = "^26.1.0"
|
|
47
47
|
mypy = "^1.19.1"
|
|
48
48
|
pylint = "^4.0.4"
|
|
49
|
-
pytest = "^9.0.
|
|
49
|
+
pytest = "^9.0.3"
|
|
50
50
|
pytest-cov = "^7.0.0"
|
|
51
51
|
types-pyOpenSSL = "^24.1.0.20240722"
|
|
52
52
|
|
|
File without changes
|