diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7..5ace414 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -3,4 +3,4 @@
-
\ No newline at end of file
+
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..4fb5a96
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,16 @@
+repos:
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v2.4.0
+ hooks:
+ - id: check-added-large-files
+ args: ['--maxkb=100']
+ - id: check-ast
+ - id: check-byte-order-marker
+ - id: check-case-conflict
+ - id: check-docstring-first
+ - id: check-executables-have-shebangs
+ - id: check-merge-conflict
+ - id: end-of-file-fixer
+ - id: fix-encoding-pragma
+ - id: mixed-line-ending
+ - id: trailing-whitespace
diff --git a/README.md b/README.md
index 19fd34c..99c2dde 100644
--- a/README.md
+++ b/README.md
@@ -33,12 +33,12 @@ Usage: yaml-plist.py []
**Notes:**
-1. With `plistyamlplist.py`, if you do not specify an `output-file` value, the script determines if the `input-file` is
- a plist or yaml file. If a plist file, the `input-file` name will be appended with `.yaml` for the output file. If a
+1. With `plistyamlplist.py`, if you do not specify an `output-file` value, the script determines if the `input-file` is
+ a plist or yaml file. If a plist file, the `input-file` name will be appended with `.yaml` for the output file. If a
yaml file, the output file name will be the `input-file` name with `.yaml` removed.
-2. With `plist_yaml.py`, if you do not specify an `output-file` value, the `input-file` name will be appended with
+2. With `plist_yaml.py`, if you do not specify an `output-file` value, the `input-file` name will be appended with
`.yaml` for the output file.
-3. With `yaml_plist.py`, if you do not specify an `output-file` value, and the `input-file` name ends with `.yaml`,
+3. With `yaml_plist.py`, if you do not specify an `output-file` value, and the `input-file` name ends with `.yaml`,
the output file name will be the `input-file` name with `.yaml` removed.
4. With `plist_yaml.py`, you may have to first convert a binary plist to text format using `plutil`.
@@ -69,15 +69,15 @@ $ ./plistyamlplist.py ~/Downloads/com.something.plist.yaml
## YAML folder
-If you have a folder named `YAML` in your path, and you do not supply a destination, the script will determine if a
+If you have a folder named `YAML` in your path, and you do not supply a destination, the script will determine if a
corresponding folder exists in the path without 'YAML'. For example, consider the following file:
/Users/myuser/gitrepo/YAML/product/com.something.plist.yaml
-
-If the folder `/Users/myuser/gitrepo/product` exists, the converted file will be created/overwritten at:
+
+If the folder `/Users/myuser/gitrepo/product` exists, the converted file will be created/overwritten at:
/Users/myuser/gitrepo/product/com.something.plist
-
+
If there is no `YAML` folder in the path, the converted file will be placed in the same folder
# Credits
diff --git a/plist_yaml.py b/plist_yaml.py
index 4ebcc68..dc63b38 100755
--- a/plist_yaml.py
+++ b/plist_yaml.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python
+# -*- coding: utf-8 -*-
-"""
-If this script is run directly, it takes an input file and an output file from
-the command line. The input file must be in PLIST format.
-The output file will be in YAML format:
+"""If this script is run directly, it takes an input file and an output file
+from the command line. The input file must be in PLIST format. The output file
+will be in YAML format:
plist_yaml.py
@@ -12,50 +12,92 @@
"""
import sys
+from collections import OrderedDict
+
+try:
+ from plistlib import Data # Python 3
+ from plistlib import load as load_plist
+except ImportError:
+ from plistlib import Data # Python 2
+ from plistlib import readPlist as load_plist
+
import yaml
-from os import path
-from plistlib import readPlist, Data
-def normalize_types(input):
- """
- This allows YAML and JSON to store Data fields as strings. However, this
- operation is irreversible. Only use if read-only access to the plist is
- required.
+def represent_ordereddict(dumper, data):
+ value = []
+
+ for item_key, item_value in data.items():
+ node_key = dumper.represent_data(item_key)
+ node_value = dumper.represent_data(item_value)
+
+ value.append((node_key, node_value))
+
+ return yaml.nodes.MappingNode(u"tag:yaml.org,2002:map", value)
+
+
+def normalize_types(input_data):
+ """This allows YAML and JSON to store Data fields as strings.
+
+ However, this operation is irreversible. Only use if read-only
+ access to the plist is required.
"""
- if isinstance(input, Data): return input.data
- if isinstance(input, list):
+ if isinstance(input_data, Data):
+ return input_data.data
+ if isinstance(input_data, list):
retval = []
- for child in input:
+ for child in input_data:
retval.append(normalize_types(child))
return retval
- if isinstance(input, dict):
+ if isinstance(input_data, dict):
retval = {}
- for key, child in input.iteritems():
- retval[key] = normalize_types(child)
+ for key in input_data:
+ retval[key] = normalize_types(input_data[key])
return retval
- return input
+ return input_data
+
+
+def sort_autopkg_processes(recipe):
+ """If input is an AutoPkg recipe, adjust the processor dictionaries such
+ that the Arguments key is ordered last.
+
+ This usually puts the Processor key first, which makes the process
+ list more human-readable.
+ """
+ if "Process" in recipe:
+ process = recipe["Process"]
+ new_process = []
+ for processor in process:
+ if "Arguments" in processor:
+ processor = OrderedDict(processor)
+ processor.move_to_end("Arguments")
+ new_process.append(processor)
+ recipe["Process"] = new_process
+ return recipe
def convert(xml):
- """Do the conversion"""
- return yaml.dump(xml, width=float('inf'), default_flow_style=False)
+ """Do the conversion."""
+ yaml.add_representer(OrderedDict, represent_ordereddict)
+ return yaml.dump(xml, width=float("inf"), default_flow_style=False)
def plist_yaml(in_path, out_path):
- """Convert plist to yaml"""
- in_file = open(in_path, 'r')
- input = readPlist(in_file)
+ """Convert plist to yaml."""
+ with open(in_path, "rb") as in_file:
+ input_data = load_plist(in_file)
- normalized = normalize_types(input)
+ normalized = normalize_types(input_data)
+ if sys.version_info.major == 3 and in_path.endswith((".recipe", ".recipe.plist")):
+ normalized = sort_autopkg_processes(normalized)
output = convert(normalized)
- out_file = open(out_path, 'w')
+ out_file = open(out_path, "w")
out_file.writelines(output)
def main():
- """Get the command line inputs if running this script directly"""
+ """Get the command line inputs if running this script directly."""
if len(sys.argv) < 2:
print("Usage: plist_yaml.py ")
sys.exit(1)
@@ -72,5 +114,5 @@ def main():
plist_yaml(in_path, out_path)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/plistyamlplist.py b/plistyamlplist.py
index cf6d507..f65ad24 100755
--- a/plistyamlplist.py
+++ b/plistyamlplist.py
@@ -1,8 +1,8 @@
#!/usr/bin/env python
+# -*- coding: utf-8 -*-
-"""
-If this script is run directly, it takes an input file and an output file from
-the command line. It detects if the input file is a YAML or a PLIST file,
+"""If this script is run directly, it takes an input file and an output file
+from the command line. It detects if the input file is a YAML or a PLIST file,
and converts to the other format:
plistyamlplist.py
@@ -13,27 +13,32 @@
import sys
from os import path
+
from plist_yaml import plist_yaml
from yaml_plist import yaml_plist
def usage():
- """print help"""
+ """print help."""
print("Usage: plistyamlplist.py \n")
- print("If is a PLIST and is omitted,\n"
- " is converted to .yaml\n")
- print("If ends in .yaml or .yml and is omitted,\n"
- ".yaml is converted to PLIST format with name \n")
+ print(
+ "If is a PLIST and is omitted,\n"
+ " is converted to .yaml\n"
+ )
+ print(
+ "If ends in .yaml or .yml and is omitted,\n"
+ ".yaml is converted to PLIST format with name \n"
+ )
def check_if_plist(in_path):
- """rather than restrict by filename, check if the file is a plist by reading
- the second line of the file for the PLIST declaration"""
+ """rather than restrict by filename, check if the file is a plist by
+ reading the second line of the file for the PLIST declaration."""
with open(in_path) as fp:
for i, line in enumerate(fp):
if i == 1:
# print line
- if line.find('PLIST 1.0') == -1:
+ if line.find("PLIST 1.0") == -1:
is_plist = False
else:
is_plist = True
@@ -43,26 +48,29 @@ def check_if_plist(in_path):
def check_for_yaml_folder(check_path):
- """Check folder hierarchy for a YAML folder. Output to same folder structure outwith YAML
- folder if it exists,
- e.g. /path/to/YAML/folder/subfolder/my.plist.yaml ==> /path/to/folder/subfolder/my.plist
- Note there is no reverse option at this time"""
+ """Check folder hierarchy for a YAML folder.
+
+ Output to same folder structure outwith YAML folder if it exists,
+ e.g. /path/to/YAML/folder/subfolder/my.plist.yaml ==>
+ /path/to/folder/subfolder/my.plist Note there is no reverse option
+ at this time
+ """
check_abspath = path.abspath(check_path)
- if 'YAML' in check_abspath:
- print('YAML folder exists : {}'.format(check_abspath))
- top_path, base_path = check_abspath.split('YAML/')
+ if "YAML" in check_abspath:
+ print("YAML folder exists : {}".format(check_abspath))
+ top_path, base_path = check_abspath.split("YAML/")
out_path = path.dirname(path.join(top_path, base_path))
if path.exists(out_path):
- print('Path exists : {}'.format(out_path))
+ print("Path exists : {}".format(out_path))
return out_path
else:
- print('Path does not exist : {}'.format(out_path))
- print('Please create this folder and try again')
+ print("Path does not exist : {}".format(out_path))
+ print("Please create this folder and try again")
exit(1)
def main():
- """get the command line inputs if running this script directly"""
+ """get the command line inputs if running this script directly."""
if len(sys.argv) < 2:
usage()
exit(1)
@@ -71,7 +79,7 @@ def main():
try:
sys.argv[2]
except IndexError:
- if in_path.endswith('.yaml') or in_path.endswith('.yml'):
+ if in_path.endswith(".yaml") or in_path.endswith(".yml"):
out_dir = check_for_yaml_folder(in_path)
if out_dir:
filename, file_extension = path.splitext(path.basename(in_path))
@@ -90,7 +98,7 @@ def main():
out_path = sys.argv[2]
# auto-determine which direction the conversion should go
- if in_path.endswith('.yaml'):
+ if in_path.endswith(".yaml"):
yaml_plist(in_path, out_path)
else:
if check_if_plist(in_path):
@@ -99,8 +107,8 @@ def main():
print("\nERROR: Input File is neither PLIST nor YAML format.\n")
usage()
exit(1)
- print('Wrote to : {}'.format(out_path))
+ print("Wrote to : {}".format(out_path))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/yaml_plist.py b/yaml_plist.py
index 2aa45bb..12b7b37 100755
--- a/yaml_plist.py
+++ b/yaml_plist.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python
+# -*- coding: utf-8 -*-
-"""
-If this script is run directly, it takes an input file and an output file from
-the command lineThe input file must be in YAML format.
-The output file will be in PLIST format:
+"""If this script is run directly, it takes an input file and an output file
+from the command lineThe input file must be in YAML format. The output file
+will be in PLIST format:
yaml_plist.py
@@ -14,31 +14,32 @@
"""
import sys
-import yaml
from os import path
from plistlib import writePlistToString
+import yaml
+
-def convert(yaml):
- """Do the conversion"""
- lines = writePlistToString(yaml).splitlines()
- lines.append('')
+def convert(data):
+ """Do the conversion."""
+ lines = writePlistToString(data).splitlines()
+ lines.append("")
return "\n".join(lines)
def yaml_plist(in_path, out_path):
- """Convert yaml to plist"""
- in_file = open(in_path, 'r')
- out_file = open(out_path, 'w')
+ """Convert yaml to plist."""
+ in_file = open(in_path, "r")
+ out_file = open(out_path, "w")
- input = yaml.safe_load(in_file)
- output = convert(input)
+ input_data = yaml.safe_load(in_file)
+ output = convert(input_data)
out_file.writelines(output)
def main():
- """Get the command line inputs if running this script directly"""
+ """Get the command line inputs if running this script directly."""
if len(sys.argv) < 2:
print("Usage: yaml_plist.py ")
sys.exit(1)
@@ -47,7 +48,7 @@ def main():
try:
sys.argv[2]
except Exception as e:
- if in_path.endswith('.yaml'):
+ if in_path.endswith(".yaml"):
filename, file_extension = path.splitext(in_path)
out_path = filename
else:
@@ -59,5 +60,5 @@ def main():
yaml_plist(in_path, out_path)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()