mirror of
https://github.com/foxlet/macOS-Simple-KVM.git
synced 2025-02-17 05:25:02 +01:00
[TOOLS] Support downloading all releases at once
This commit is contained in:
parent
b51ffa63af
commit
99d08b8da6
2 changed files with 86 additions and 35 deletions
|
@ -12,6 +12,7 @@ print_usage() {
|
|||
echo " -s, --high-sierra Fetch High Sierra media."
|
||||
echo " -m, --mojave Fetch Mojave media."
|
||||
echo " -c, --catalina Fetch Catalina media."
|
||||
echo " -a, --all Fetch ALL media."
|
||||
echo
|
||||
}
|
||||
|
||||
|
@ -31,6 +32,14 @@ case $argument in
|
|||
-c|--catalina|*)
|
||||
$TOOLS/FetchMacOS/fetch.sh -l -c DeveloperSeed || exit 1;
|
||||
;;
|
||||
-a|--all)
|
||||
$TOOLS/FetchMacOS/fetch.sh -a -k BaseSystem || exit 1;
|
||||
for p in $(ls -1 $TOOLS/FetchMacOS/SoftwareUpdate/) do
|
||||
dmg2img $TOOLS/FetchMacOS/SoftwareUpdate/$p/BaseSystem.dmg $TOOLS/FetchMacOS/SoftwareUpdate/$p/BaseSystem.img;
|
||||
done;
|
||||
echo "NOTE: Because you chose to download ALL media instead of a specific version, you can find each image in ./tools/FetchMacOS/SoftwareUpdate/\$VERSION/BaseSystem.img instead of the default location."
|
||||
;;
|
||||
|
||||
-h|--help)
|
||||
print_usage
|
||||
;;
|
||||
|
|
|
@ -9,6 +9,7 @@ import errno
|
|||
import click
|
||||
import requests
|
||||
import sys
|
||||
import re
|
||||
|
||||
__author__ = "Foxlet"
|
||||
__copyright__ = "Copyright 2019, FurCode Project"
|
||||
|
@ -59,28 +60,48 @@ class SoftwareService:
|
|||
"PublicRelease13":"https://swscan.apple.com/content/catalogs/others/index-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"}
|
||||
|
||||
def __init__(self, catalog_id):
|
||||
self.catalog_url = self.catalogs.get(catalog_id, self.catalogs["PublicRelease"])
|
||||
self.catalog_data = ""
|
||||
self.catalog_data = list()
|
||||
self.catalog_url = list()
|
||||
|
||||
def getcatalog(self):
|
||||
logging.info("Network Request: %s", "Fetching {}".format(self.catalog_url))
|
||||
catalog_raw = requests.get(self.catalog_url, headers=ClientMeta.swupdate)
|
||||
self.catalog_data = catalog_raw.text.encode('UTF-8')
|
||||
return catalog_raw.text.encode('UTF-8')
|
||||
if catalog_id == "__ALL__":
|
||||
# Automatically generate each version's catalog URL from the latest
|
||||
match = re.match(r'(https://swscan.apple.com/content/catalogs/others/index-)([\w.-]+)(\.merged-1\.sucatalog)', self.catalogs.get("DeveloperSeed"))
|
||||
releases = match.group(2).split('-')
|
||||
for i in range(len(releases)):
|
||||
self.catalog_url.append(match.group(1) + str().join([x + '-' for x in releases]).rstrip('-') + match.group(3))
|
||||
releases.remove(releases[0])
|
||||
else:
|
||||
self.catalog_url.append(self.catalogs.get(catalog_id))
|
||||
|
||||
def getcatalogs(self):
|
||||
self.catalog_raw = list()
|
||||
for url in self.catalog_url:
|
||||
logging.info("Network Request: %s", "Fetching {}".format(url))
|
||||
self.catalog_raw.append(requests.get(url, headers=ClientMeta.swupdate))
|
||||
|
||||
self.catalog_data = [datum.text.encode('UTF-8') for datum in self.catalog_raw]
|
||||
return self.catalog_data
|
||||
|
||||
def getosinstall(self):
|
||||
# Load catalogs based on Py3/2 lib
|
||||
if sys.version_info > (3, 0):
|
||||
root = plistlib.loads(self.catalog_data)
|
||||
else:
|
||||
root = plistlib.readPlistFromString(self.catalog_data)
|
||||
roots = list()
|
||||
for index, datum in enumerate(self.catalog_data):
|
||||
if sys.version_info > (3, 0):
|
||||
# Ignore any missing/corrupted catalogs
|
||||
try:
|
||||
roots.append(plistlib.loads(datum))
|
||||
except plistlib.InvalidFileException:
|
||||
logging.warning("Catalog at {} corrupted or missing, contents won't be downloaded.".format(self.catalog_url[index]))
|
||||
else:
|
||||
roots.append(plistlib.readPlistFromString(datum))
|
||||
|
||||
# Iterate to find valid OSInstall packages
|
||||
ospackages = []
|
||||
products = root['Products']
|
||||
for product in products:
|
||||
if products.get(product, {}).get('ExtendedMetaInfo', {}).get('InstallAssistantPackageIdentifiers', {}).get('OSInstall', {}) == 'com.apple.mpkg.OSInstall':
|
||||
ospackages.append(product)
|
||||
ospackages = list()
|
||||
for root in roots:
|
||||
products = root['Products']
|
||||
for product in products:
|
||||
if products.get(product, {}).get('ExtendedMetaInfo', {}).get('InstallAssistantPackageIdentifiers', {}).get('OSInstall', {}) == 'com.apple.mpkg.OSInstall':
|
||||
ospackages.append(product)
|
||||
return ospackages
|
||||
|
||||
|
||||
|
@ -107,32 +128,53 @@ class MacOSProduct:
|
|||
|
||||
@click.command()
|
||||
@click.option('-o', '--output-dir', default="BaseSystem/", help="Target directory for package output.")
|
||||
@click.option('-c', '--catalog-id', default="PublicRelease", help="Name of catalog.")
|
||||
@click.option('-a', '--fetch-all', is_flag=True, help="Get all available macOS packages. Implies --package=\"__ALL__\", --catalog-id=\"__ALL__\", and --output-dir=\"SoftwareUpdate\". Conflicts with -l.")
|
||||
@click.option('-l', '--latest', is_flag=True, help="Get latest available macOS package. Conflicts with -a.")
|
||||
@click.option('-c', '--catalog-id', default="PublicRelease", help="Name of catalog. Specify \"__ALL__\" to attempt to fetch all catalogs.")
|
||||
@click.option('-p', '--product-id', default="", help="Product ID (as seen in SoftwareUpdate).")
|
||||
@click.option('-l', '--latest', is_flag=True, help="Get latest available macOS package.")
|
||||
def fetchmacos(output_dir="BaseSystem/", catalog_id="PublicRelease", product_id="", latest=False):
|
||||
@click.option('-k', '--package', default="BaseSystem", help="Package keyword (as seen in SoftwareUpdate). Specify \"__ALL__\" a package to download all packages. Defaults to BaseSystem for backwards compatibility.")
|
||||
def fetchmacos(output_dir="BaseSystem", catalog_id="PublicRelease", product_id="", latest=False, fetch_all=False, package="BaseSystem"):
|
||||
# Apply implicit options of --fetch-all
|
||||
if fetch_all:
|
||||
output_dir="SoftwareUpdate"
|
||||
catalog_id="__ALL__"
|
||||
package=None
|
||||
|
||||
# Get the remote catalog data
|
||||
remote = SoftwareService(catalog_id)
|
||||
catalog = remote.getcatalog()
|
||||
catalogs = remote.getcatalogs()
|
||||
|
||||
# If latest is used, find the latest OSInstall package
|
||||
if latest:
|
||||
product_id = remote.getosinstall()[-1]
|
||||
else:
|
||||
if product_id == "":
|
||||
print("You must provide a Product ID (or pass the -l flag) to continue.")
|
||||
exit(1)
|
||||
|
||||
# Fetch the given Product ID
|
||||
try:
|
||||
product = MacOSProduct(catalog, product_id)
|
||||
except KeyError:
|
||||
print("Product ID {} could not be found.".format(product_id))
|
||||
# Ensure there's no conflicting flags
|
||||
if latest and fetch_all:
|
||||
print("You can only provide ONE OF the -l or -a flags, NOT both.")
|
||||
exit(1)
|
||||
logging.info("Selected macOS Product: {}".format(product_id))
|
||||
# If latest is used, find the latest OSInstall package
|
||||
elif latest:
|
||||
product_id = remote.getosinstall()[0][-1]
|
||||
# If fetch_all is used, find ALL the OSInstall packages
|
||||
elif fetch_all:
|
||||
logging.info("Selected ALL macOS Products")
|
||||
for catalog in catalogs:
|
||||
for product in remote.getosinstall():
|
||||
print("Downloading product: {}".format(product))
|
||||
p = MacOSProduct(catalog, product)
|
||||
p.fetchpackages(os.path.join(output_dir, product))
|
||||
exit(0)
|
||||
elif product_id:
|
||||
# Fetch the given Product ID
|
||||
try:
|
||||
product = MacOSProduct(catalogs[0], product_id)
|
||||
logging.info("Selected macOS Product: {}".format(product_id))
|
||||
except KeyError:
|
||||
print("Product ID could not be found: {}".format(product_id))
|
||||
exit(1)
|
||||
else:
|
||||
print("You must provide a Product ID (or pass one of the -l or -a flags) to continue.")
|
||||
exit(1)
|
||||
|
||||
|
||||
# Download package to disk
|
||||
product.fetchpackages(output_dir, keyword="BaseSystem")
|
||||
product.fetchpackages(output_dir, keyword=package)
|
||||
|
||||
if __name__ == "__main__":
|
||||
fetchmacos()
|
||||
|
|
Loading…
Add table
Reference in a new issue