Compare commits

..

No commits in common. "main" and "v26.0" have entirely different histories.
main ... v26.0

3 changed files with 19 additions and 136 deletions

View File

@ -3,9 +3,9 @@
Some scripts that might be of use to macOS admins. Might be related to Munki;
might not.
These are only supported on macOS. There is no support for running these on Windows or Linux.
These are currently only supported using Apple's Python on macOS. There is no support for running these on Windows or Linux.
In macOS 12.3, Apple stopped providung Python as part of macOS. You'll need to provide your own Python to use these scripts. You may also need to install additional Python modules.
In macOS 12.3, Apple will be removing its Python 2.7 install. You'll need to provide your own Python to use these scripts. You may also need to install additional Python modules.
#### getmacosipsws.py
@ -39,7 +39,7 @@ Product installation failed.
Use a compatible Mac or select a different build compatible with your current hardware and try again. You may also have success running the script in a VM; the InstallationCheck script in versions of the macOS installer to date skips the checks (and returns success) when run on a VM.
##### Important note for Catalina+
macOS privacy protections might interfere with the operation of this tool if you run it from ~/Desktop, ~/Documents, ~/Downloads or other directories protected in macOS Catalina or later. Consider using /Users/Shared (or subdirectory) as the "working space" for this tool.
Catalina privacy protections might interfere with the operation of this tool if you run it from ~/Desktop, ~/Documents, ~/Downloads or other directories protected in Catalina. Consider using /Users/Shared (or subdirectory) as the "working space" for this tool.
##### Alternate implementations

View File

@ -42,12 +42,7 @@ except ImportError:
from urlparse import urlsplit
from xml.dom import minidom
from xml.parsers.expat import ExpatError
try:
from packaging.version import LegacyVersion
except ImportError:
# python <=3.9
from distutils.version import LooseVersion as LegacyVersion
from distutils.version import LooseVersion
try:
import xattr
@ -85,38 +80,6 @@ DEFAULT_SUCATALOGS = {
"index-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"22": (
"https://swscan.apple.com/content/catalogs/others/"
"index-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"23": (
"https://swscan.apple.com/content/catalogs/others/"
"index-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"24": (
"https://swscan.apple.com/content/catalogs/others/"
"index-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"25": (
"https://swscan.apple.com/content/catalogs/others/"
"index-16seed-16-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"22": "https://swscan.apple.com/content/catalogs/others/"
"index-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
"23": "https://swscan.apple.com/content/catalogs/others/"
"index-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
"24": "https://swscan.apple.com/content/catalogs/others/"
"index-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
"25": "https://swscan.apple.com/content/catalogs/others/"
"index-26-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
}
SEED_CATALOGS_PLIST = (
@ -297,12 +260,11 @@ def get_default_catalog(darwin_major=None):
def make_sparse_image(volume_name, output_path):
"""Make a sparse disk image we can install a product to"""
# note: for macOS 26 Tahoe we needed to increase the size
cmd = [
"/usr/bin/hdiutil",
"create",
"-size",
"20g",
"16g",
"-fs",
"HFS+",
"-volname",
@ -412,12 +374,7 @@ def install_product(dist_path, target_vol):
# set CM_BUILD env var to make Installer bypass eligibilty checks
# when installing packages (for machine-specific OS builds)
os.environ["CM_BUILD"] = "CM_BUILD"
# cmd = ['/usr/sbin/installer', '-pkg', dist_path, '-target', target_vol]
# a hack to work around a change in macOS 15.6+ since installing a .dist
# file no longer works
dist_dir = os.path.dirname(dist_path)
install_asst_pkg = os.path.join(dist_dir, "InstallAssistant.pkg")
cmd = ["/usr/sbin/installer", "-pkg", install_asst_pkg, "-target", target_vol]
cmd = ["/usr/sbin/installer", "-pkg", dist_path, "-target", target_vol]
try:
subprocess.check_call(cmd)
except subprocess.CalledProcessError as err:
@ -741,7 +698,7 @@ def os_installer_product_info(
def get_latest_version(current_item, latest_item):
"""Compares versions between two values and returns the latest (highest) value"""
try:
if LegacyVersion(current_item) > LegacyVersion(latest_item):
if LooseVersion(current_item) > LooseVersion(latest_item):
return current_item
else:
return latest_item
@ -1105,7 +1062,7 @@ def main():
# determine the latest valid build ID and select this
# when using auto, os and version options
if args.auto or args.version or args.os or args.list:
if args.auto or args.version or args.os:
if args.beta or "Beta" not in product_info[product_id]["title"]:
try:
latest_valid_build
@ -1175,10 +1132,10 @@ def main():
valid_build_found is False
and not args.build
and not args.current
and args.validate
and not args.validate
and not args.list
):
print("No valid build found for this computer")
print("No valid build found for this hardware")
exit(0)
# clear content directory in workdir if requested
@ -1190,18 +1147,6 @@ def main():
# Output a plist of available updates and quit if list option chosen
if args.list:
if args.os:
print("\nBuild checked against OS filter: %s" % (args.os))
pl["validity_filter"] = "OS: %s" % (args.os)
elif args.version:
print("\nBuild checked against version filter: %s" % (args.version))
pl["validity_filter"] = "Version: %s" % (args.version)
try:
print("\nLatest valid build: %s (# %s)" % (latest_valid_build, answer))
pl["latest_valid_build"] = latest_valid_build
except NameError:
pl["latest_valid_build"] = ""
print("\nNo valid build found")
write_plist(pl, output_plist)
print("\nValid seeding programs are: %s\n" % ", ".join(get_seeding_programs()))
exit(0)
@ -1213,21 +1158,23 @@ def main():
except NameError:
print(
"\n"
"A valid installer for build %s is not available for this computer. "
"Build %s is not available. "
"Run again without --build argument "
"to select a valid build to download "
"or run without --validate option to download anyway.\n" % args.build
)
exit(0)
else:
print("\n" "Build %s valid. Downloading #%s...\n" % (args.build, answer))
print(
"\n" "Build %s available. Downloading #%s...\n" % (args.build, answer)
)
elif args.current:
try:
answer
except NameError:
print(
"\n"
"A valid installer for build %s is not available for this computer. "
"Build %s is not available. "
"Run again without --current argument "
"to select a valid build to download.\n" % build_info[0]
)
@ -1275,7 +1222,7 @@ def main():
except NameError:
print(
"\n"
"A valid installer for version %s is not available for this computer. "
"Version %s is not available. "
"Run again without --version argument "
"to select a valid build to download.\n" % args.version
)
@ -1291,7 +1238,7 @@ def main():
except NameError:
print(
"\n"
"A valid installer for OS %s is not available for this computer. "
"OS %s is not available. "
"Run again without --os argument "
"to select a valid build to download.\n" % args.os
)
@ -1307,7 +1254,7 @@ def main():
except NameError:
print(
"\n"
"No valid version available for this computer. "
"No valid version available. "
"Run again without --auto argument "
"to select a valid build to download.\n"
)
@ -1397,9 +1344,7 @@ def main():
% seeding_program
)
xattr.setxattr(
installer_app,
"SeedProgram",
seeding_program.encode("UTF-8").encode(),
installer_app, "SeedProgram", seeding_program.encode()
)
print("Product downloaded and installed to %s" % sparse_diskimage_path)
if args.raw:

View File

@ -1,62 +0,0 @@
#!/usr/local/munki/munki-python
import os
import plistlib
import sys
sys.path.append("/usr/local/munki")
from munkilib import dmgutils
from munkilib import pkgutils
if len(sys.argv) != 2:
print('Need exactly one parameter: path to a munki repo!', file=sys.stderr)
sys.exit(-1)
repo_path = sys.argv[1]
all_catalog = os.path.join(repo_path, "catalogs/all")
with open(all_catalog, mode="rb") as FILE:
all_items = plistlib.load(FILE)
dmg_items = [{"name": item["name"],
"version": item["version"],
"location": item["installer_item_location"],
"package_path": item.get("package_path", "")}
for item in all_items
if item.get("installer_item_location", "").endswith(".dmg") and
item.get("installer_type") is None]
items_with_bundle_style_pkgs = []
for item in dmg_items:
full_path = os.path.join(repo_path, "pkgs", item["location"])
print("Checking %s..." % full_path)
mountpoints = dmgutils.mountdmg(full_path)
if mountpoints:
pkg_path = item["package_path"]
if pkg_path:
itempath = os.path.join(mountpoints[0], pkg_path)
if os.path.isdir(itempath):
print("***** %s--%s has a bundle-style pkg"
% (item["name"], item["version"]))
items_with_bundle_style_pkgs.append(item)
else:
for file_item in os.listdir(mountpoints[0]):
if pkgutils.hasValidInstallerItemExt(file_item):
itempath = os.path.join(mountpoints[0], file_item)
if os.path.isdir(itempath):
print("***** %s--%s has a bundle-style pkg"
% (item["name"], item["version"]))
items_with_bundle_style_pkgs.append(item)
break
dmgutils.unmountdmg(mountpoints[0])
else:
print("No filesystems mounted from %s" % full_path)
continue
print("Found %s items with bundle-style pkgs."
% len(items_with_bundle_style_pkgs))
for item in sorted(items_with_bundle_style_pkgs, key=lambda d: d["name"]):
print("%s--%s"% (item["name"], item["version"]))
print(" %s" % item["location"])