Skip to content

Instantly share code, notes, and snippets.

@homebysix
Created January 4, 2021 02:11
Show Gist options
  • Save homebysix/1428e8b31cc6dc676ba822f4b1d376d0 to your computer and use it in GitHub Desktop.
Save homebysix/1428e8b31cc6dc676ba822f4b1d376d0 to your computer and use it in GitHub Desktop.
URLMover
#!/usr/local/autopkg/python
# encoding: utf-8
# URLMover
# Copyright 2019-2021 Elliot Jordan
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""url_mover.py.
Script for moving URLs from input variables into processor arguments in
AutoPkg recipes.
"""
import argparse
import os
import plistlib
from xml.parsers.expat import ExpatError
def build_argument_parser():
"""Build and return the argument parser."""
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("repo_path", help="Path to search for AutoPkg recipes.")
parser.add_argument(
"--auto",
action="store_true",
default=False,
help="Automatically apply suggested changes to recipes. Only recommended "
"for repos you manage or are submitting a pull request to. (Applying "
"changes to repos added using `autopkg repo-add` may result in failure "
"to update the repo in the future.)",
)
parser.add_argument(
"-v",
"--verbose",
action="count",
default=0,
help="Print additional output useful for "
"troubleshooting. (Can be specified multiple times.)",
)
return parser
def evaluate(recipe, recipe_path, args):
"""Evaluate whether a recipe is eligible to move URL from Input keys into
processor arguments."""
if args.verbose > 0:
print("Evaluating %s..." % (recipe_path))
if "Process" not in recipe:
if args.verbose > 1:
print(" Skipping: This recipe has no process.")
return
url_map = {
"DOWNLOAD_URL": ("URLDownloader", "url"),
"GITHUB_REPO": ("GitHubReleasesInfoProvider", "github_repo"),
"SPARKLE_FEED_URL": ("SparkleUpdateInfoProvider", "appcast_url"),
}
process = recipe.get("Process")
for url_src, url_dest in url_map.items():
if url_src not in recipe.get("Input", {}):
continue
proc_idx = [
idx for idx, x in enumerate(process) if x["Processor"] == url_dest[0]
]
if len(proc_idx) != 1:
continue
proc_idx = proc_idx[0]
if not args.auto:
print(
"✨ Recipe %s is eligible for moving %s to %s arguments."
% (recipe_path, url_src, url_dest[0])
)
else:
print(
"✨ Recipe %s: moving %s to %s arguments."
% (recipe_path, url_src, url_dest[0])
)
# Save the URL value and remove from Input.
url_value = recipe["Input"][url_src]
del recipe["Input"][url_src]
# Replace the processor arguments.
recipe["Process"][proc_idx]["Arguments"][url_dest[1]] = url_value
with open(recipe_path, "wb") as openfile:
plistlib.dump(recipe, openfile)
def main():
"""Main process."""
# Parse command line arguments.
argparser = build_argument_parser()
args = argparser.parse_args()
# Extensions to include in converting.
target_file_exts = (".download.recipe",)
# Gather list of eligible files.
for root, dirs, files in os.walk(os.path.expanduser(args.repo_path)):
dirs[:] = [d for d in dirs if not d.startswith(".")]
for idx, filename in enumerate(files):
if filename.endswith(target_file_exts):
recipe_path = os.path.join(root, filename)
try:
with open(recipe_path, "rb") as openfile:
recipe = plistlib.load(openfile)
evaluate(recipe, recipe_path, args)
except ExpatError:
print("[ERROR] Unable to read %s", recipe_path)
continue
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment