mirror of
https://github.com/grahampugh/macadmin-scripts.git
synced 2025-12-17 17:56:33 +00:00
commit
d77936d477
36
README.md
36
README.md
@ -3,7 +3,9 @@
|
|||||||
Some scripts that might be of use to macOS admins. Might be related to Munki;
|
Some scripts that might be of use to macOS admins. Might be related to Munki;
|
||||||
might not.
|
might not.
|
||||||
|
|
||||||
These are only supported using Apple's Python 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 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
|
#### getmacosipsws.py
|
||||||
|
|
||||||
@ -13,7 +15,7 @@ Quick-and-dirty tool to download the macOS IPSW files currently advertised by Ap
|
|||||||
|
|
||||||
This script can create disk images containing macOS Installer applications available via Apple's softwareupdate catalogs.
|
This script can create disk images containing macOS Installer applications available via Apple's softwareupdate catalogs.
|
||||||
|
|
||||||
Run `./installinstallmacos.py --help` to see the available options.
|
Run `python ./installinstallmacos.py --help` to see the available options.
|
||||||
|
|
||||||
The tool assembles "Install macOS" applications by downloading the packages from Apple's softwareupdate servers and then installing them into a new empty disk image.
|
The tool assembles "Install macOS" applications by downloading the packages from Apple's softwareupdate servers and then installing them into a new empty disk image.
|
||||||
|
|
||||||
@ -39,38 +41,8 @@ Use a compatible Mac or select a different build compatible with your current ha
|
|||||||
##### Important note for Catalina+
|
##### Important note for Catalina+
|
||||||
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.
|
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.
|
||||||
|
|
||||||
##### October 2020 update
|
|
||||||
In late September, Apple made some changes to how their servers returned requested results. This led to `installinstallmacos.py` complaining about invalid XML and listing macOS installers with UNKNOWN build numbers, among other issues.
|
|
||||||
If you encounter these issues:
|
|
||||||
- Update to the current version of the script
|
|
||||||
- Run it at least once with the `--ignore-cache` option, or remove the content directory to remove corrupted files in the content cache.
|
|
||||||
|
|
||||||
##### Alternate implementations
|
##### Alternate implementations
|
||||||
Graham Pugh has a fork with a lot more features and bells and whistles. Check it out if your needs aren't met by this tool.
|
Graham Pugh has a fork with a lot more features and bells and whistles. Check it out if your needs aren't met by this tool.
|
||||||
https://github.com/grahampugh/macadmin-scripts
|
https://github.com/grahampugh/macadmin-scripts
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
### Legacy scripts no longer in development or supported
|
|
||||||
|
|
||||||
#### createbootvolfromautonbi.py
|
|
||||||
|
|
||||||
(This tool has not been tested/updated since before 10.14 shipped. It may not work as expected with current versions of macOS. There are currently no plans to update it.)
|
|
||||||
|
|
||||||
A tool to make bootable disk volumes from the output of autonbi. Especially
|
|
||||||
useful to make bootable disks containing Imagr and the 'SIP-ignoring' kernel,
|
|
||||||
which allows Imagr to run scripts that affect SIP state, set UAKEL options, and
|
|
||||||
run the `startosinstall` component, all of which might otherwise require network
|
|
||||||
booting from a NetInstall-style nbi.
|
|
||||||
|
|
||||||
This provides a way to create a bootable external disk that acts like the Netboot environment used by/needed by Imagr.
|
|
||||||
|
|
||||||
This command converts the output of Imagr's `make nbi` into a bootable external USB disk:
|
|
||||||
`sudo ./createbootvolfromautonbi.py --nbi ~/Desktop/10.13.6_Imagr.nbi --volume /Volumes/ExternalDisk`
|
|
||||||
|
|
||||||
|
|
||||||
#### make_firmwareupdater_pkg.sh
|
|
||||||
|
|
||||||
This script was used to extract the firmware updaters from early High Sierra installers and make a standalone installer package that could be used to upgrade Mac firmware before installing High Sierra via imaging.
|
|
||||||
|
|
||||||
Later High Sierra installer changes have broken this script; since installing High Sierra via imaging is not recommended or supported by Apple and several other alternatives are now available, I don't plan on attempting to fix or upgrade this tool.
|
|
||||||
|
|||||||
@ -1,210 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# encoding: utf-8
|
|
||||||
#
|
|
||||||
# Copyright 2017 Greg Neagle.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
'''A tool to make bootable disk volumes from the output of autonbi. Especially
|
|
||||||
useful to make bootable disks containing Imagr and the 'SIP-ignoring' kernel,
|
|
||||||
which allows Imagr to run scripts that affect SIP state, set UAKEL options, and
|
|
||||||
run the `startosinstall` component, all of which might otherwise require network
|
|
||||||
booting from a NetInstall-style nbi.'''
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import plistlib
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import urlparse
|
|
||||||
|
|
||||||
|
|
||||||
# dmg helpers
|
|
||||||
def mountdmg(dmgpath):
|
|
||||||
"""
|
|
||||||
Attempts to mount the dmg at dmgpath and returns first mountpoint
|
|
||||||
"""
|
|
||||||
mountpoints = []
|
|
||||||
dmgname = os.path.basename(dmgpath)
|
|
||||||
cmd = ['/usr/bin/hdiutil', 'attach', dmgpath,
|
|
||||||
'-mountRandom', '/tmp', '-nobrowse', '-plist',
|
|
||||||
'-owners', 'on']
|
|
||||||
proc = subprocess.Popen(cmd, bufsize=-1,
|
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
||||||
(pliststr, err) = proc.communicate()
|
|
||||||
if proc.returncode:
|
|
||||||
print >> sys.stderr, 'Error: "%s" while mounting %s.' % (err, dmgname)
|
|
||||||
return None
|
|
||||||
if pliststr:
|
|
||||||
plist = plistlib.readPlistFromString(pliststr)
|
|
||||||
for entity in plist['system-entities']:
|
|
||||||
if 'mount-point' in entity:
|
|
||||||
mountpoints.append(entity['mount-point'])
|
|
||||||
|
|
||||||
return mountpoints[0]
|
|
||||||
|
|
||||||
|
|
||||||
def unmountdmg(mountpoint):
|
|
||||||
"""
|
|
||||||
Unmounts the dmg at mountpoint
|
|
||||||
"""
|
|
||||||
proc = subprocess.Popen(['/usr/bin/hdiutil', 'detach', mountpoint],
|
|
||||||
bufsize=-1, stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
(dummy_output, err) = proc.communicate()
|
|
||||||
if proc.returncode:
|
|
||||||
print >> sys.stderr, 'Polite unmount failed: %s' % err
|
|
||||||
print >> sys.stderr, 'Attempting to force unmount %s' % mountpoint
|
|
||||||
# try forcing the unmount
|
|
||||||
retcode = subprocess.call(['/usr/bin/hdiutil', 'detach', mountpoint,
|
|
||||||
'-force'])
|
|
||||||
if retcode:
|
|
||||||
print >> sys.stderr, 'Failed to unmount %s' % mountpoint
|
|
||||||
|
|
||||||
|
|
||||||
def locate_basesystem_dmg(nbi):
|
|
||||||
'''Finds and returns the relative path to the BaseSystem.dmg within the
|
|
||||||
NetInstall.dmg'''
|
|
||||||
source_boot_plist = os.path.join(nbi, 'i386/com.apple.Boot.plist')
|
|
||||||
try:
|
|
||||||
boot_args = plistlib.readPlist(source_boot_plist)
|
|
||||||
except Exception, err:
|
|
||||||
print >> sys.stderr, err
|
|
||||||
sys.exit(-1)
|
|
||||||
kernel_flags = boot_args.get('Kernel Flags')
|
|
||||||
if not kernel_flags:
|
|
||||||
print >> sys.stderr, 'i386/com.apple.Boot.plist is missing Kernel Flags'
|
|
||||||
sys.exit(-1)
|
|
||||||
# kernel flags should in the form 'root-dmg=file:///path'
|
|
||||||
if not kernel_flags.startswith('root-dmg='):
|
|
||||||
print >> sys.stderr, 'Unexpected Kernel Flags: %s' % kernel_flags
|
|
||||||
sys.exit(-1)
|
|
||||||
file_url = kernel_flags[9:]
|
|
||||||
dmg_path = urlparse.unquote(urlparse.urlparse(file_url).path)
|
|
||||||
# return path minus leading slash
|
|
||||||
return dmg_path.lstrip('/')
|
|
||||||
|
|
||||||
|
|
||||||
def copy_system_version_plist(nbi, target_volume):
|
|
||||||
'''Copies System/Library/CoreServices/SystemVersion.plist from the
|
|
||||||
BaseSystem.dmg to the target volume.'''
|
|
||||||
netinstall_dmg = os.path.join(nbi, 'NetInstall.dmg')
|
|
||||||
if not os.path.exists(netinstall_dmg):
|
|
||||||
print >> sys.stderr, "Missing NetInstall.dmg from nbi folder"
|
|
||||||
sys.exit(-1)
|
|
||||||
print 'Mounting %s...' % netinstall_dmg
|
|
||||||
netinstall_mount = mountdmg(netinstall_dmg)
|
|
||||||
if not netinstall_mount:
|
|
||||||
sys.exit(-1)
|
|
||||||
basesystem_dmg = os.path.join(netinstall_mount, locate_basesystem_dmg(nbi))
|
|
||||||
print 'Mounting %s...' % basesystem_dmg
|
|
||||||
basesystem_mount = mountdmg(basesystem_dmg)
|
|
||||||
if not basesystem_mount:
|
|
||||||
unmountdmg(netinstall_mount)
|
|
||||||
sys.exit(-1)
|
|
||||||
source = os.path.join(
|
|
||||||
basesystem_mount, 'System/Library/CoreServices/SystemVersion.plist')
|
|
||||||
dest = os.path.join(
|
|
||||||
target_volume, 'System/Library/CoreServices/SystemVersion.plist')
|
|
||||||
try:
|
|
||||||
subprocess.check_call(
|
|
||||||
['/usr/bin/ditto', '-V', source, dest])
|
|
||||||
except subprocess.CalledProcessError, err:
|
|
||||||
print >> sys.stderr, err
|
|
||||||
unmountdmg(basesystem_mount)
|
|
||||||
unmountdmg(netinstall_mount)
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
unmountdmg(basesystem_mount)
|
|
||||||
unmountdmg(netinstall_mount)
|
|
||||||
|
|
||||||
|
|
||||||
def copy_boot_files(nbi, target_volume):
|
|
||||||
'''Copies some boot files, yo'''
|
|
||||||
files_to_copy = [
|
|
||||||
['NetInstall.dmg', 'NetInstall.dmg'],
|
|
||||||
['i386/PlatformSupport.plist',
|
|
||||||
'System/Library/CoreServices/PlatformSupport.plist'],
|
|
||||||
['i386/booter', 'System/Library/CoreServices/boot.efi'],
|
|
||||||
['i386/booter', 'usr/standalone/i386/boot.efi'],
|
|
||||||
['i386/x86_64/kernelcache',
|
|
||||||
'System/Library/PrelinkedKernels/prelinkedkernel']
|
|
||||||
]
|
|
||||||
for source, dest in files_to_copy:
|
|
||||||
full_source = os.path.join(nbi, source)
|
|
||||||
full_dest = os.path.join(target_volume, dest)
|
|
||||||
try:
|
|
||||||
subprocess.check_call(
|
|
||||||
['/usr/bin/ditto', '-V', full_source, full_dest])
|
|
||||||
except subprocess.CalledProcessError, err:
|
|
||||||
print >> sys.stderr, err
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
|
|
||||||
def make_boot_plist(nbi, target_volume):
|
|
||||||
'''Creates our com.apple.Boot.plist'''
|
|
||||||
source_boot_plist = os.path.join(nbi, 'i386/com.apple.Boot.plist')
|
|
||||||
try:
|
|
||||||
boot_args = plistlib.readPlist(source_boot_plist)
|
|
||||||
except Exception, err:
|
|
||||||
print >> sys.stderr, err
|
|
||||||
sys.exit(-1)
|
|
||||||
kernel_flags = boot_args.get('Kernel Flags')
|
|
||||||
if not kernel_flags:
|
|
||||||
print >> sys.stderr, 'i386/com.apple.Boot.plist is missing Kernel Flags'
|
|
||||||
sys.exit(-1)
|
|
||||||
# prepend the container-dmg path
|
|
||||||
boot_args['Kernel Flags'] = (
|
|
||||||
'container-dmg=file:///NetInstall.dmg ' + kernel_flags)
|
|
||||||
boot_plist = os.path.join(
|
|
||||||
target_volume,
|
|
||||||
'Library/Preferences/SystemConfiguration/com.apple.Boot.plist')
|
|
||||||
plist_dir = os.path.dirname(boot_plist)
|
|
||||||
if not os.path.exists(plist_dir):
|
|
||||||
os.makedirs(plist_dir)
|
|
||||||
try:
|
|
||||||
plistlib.writePlist(boot_args, boot_plist)
|
|
||||||
except Exception, err:
|
|
||||||
print >> sys.stderr, err
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
|
|
||||||
def bless(target_volume, label=None):
|
|
||||||
'''Bless the target volume'''
|
|
||||||
blessfolder = os.path.join(target_volume, 'System/Library/CoreServices')
|
|
||||||
if not label:
|
|
||||||
label = os.path.basename(target_volume)
|
|
||||||
try:
|
|
||||||
subprocess.check_call(
|
|
||||||
['/usr/sbin/bless', '--folder', blessfolder, '--label', label])
|
|
||||||
except subprocess.CalledProcessError, err:
|
|
||||||
print >> sys.stderr, err
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
'''Do the thing we were made for'''
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('--nbi', required=True, metavar='path_to_nbi',
|
|
||||||
help='Path to nbi folder created by autonbi.')
|
|
||||||
parser.add_argument('--volume', required=True,
|
|
||||||
metavar='path_to_disk_volume',
|
|
||||||
help='Path to disk volume.')
|
|
||||||
args = parser.parse_args()
|
|
||||||
copy_system_version_plist(args.nbi, args.volume)
|
|
||||||
copy_boot_files(args.nbi, args.volume)
|
|
||||||
make_boot_plist(args.nbi, args.volume)
|
|
||||||
bless(args.volume)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
#
|
#
|
||||||
# Copyright 2021 Greg Neagle.
|
# Copyright 2021-2022 Greg Neagle.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
#
|
#
|
||||||
# Copyright 2017 Greg Neagle.
|
# Copyright 2017-2022 Greg Neagle.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@ -33,7 +33,6 @@ import plistlib
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import xattr
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# python 2
|
# python 2
|
||||||
@ -45,23 +44,42 @@ from xml.dom import minidom
|
|||||||
from xml.parsers.expat import ExpatError
|
from xml.parsers.expat import ExpatError
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
|
try:
|
||||||
|
import xattr
|
||||||
|
except ImportError:
|
||||||
|
print(
|
||||||
|
"This tool requires the Python xattr module. "
|
||||||
|
"Perhaps run `pip install xattr` to install it."
|
||||||
|
)
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_SUCATALOGS = {
|
DEFAULT_SUCATALOGS = {
|
||||||
"17": "https://swscan.apple.com/content/catalogs/others/"
|
"17": (
|
||||||
|
"https://swscan.apple.com/content/catalogs/others/"
|
||||||
"index-10.13-10.12-10.11-10.10-10.9"
|
"index-10.13-10.12-10.11-10.10-10.9"
|
||||||
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
|
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
|
||||||
"18": "https://swscan.apple.com/content/catalogs/others/"
|
),
|
||||||
|
"18": (
|
||||||
|
"https://swscan.apple.com/content/catalogs/others/"
|
||||||
"index-10.14-10.13-10.12-10.11-10.10-10.9"
|
"index-10.14-10.13-10.12-10.11-10.10-10.9"
|
||||||
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
|
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
|
||||||
"19": "https://swscan.apple.com/content/catalogs/others/"
|
),
|
||||||
|
"19": (
|
||||||
|
"https://swscan.apple.com/content/catalogs/others/"
|
||||||
"index-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
|
"index-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
|
||||||
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
|
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
|
||||||
"20": "https://swscan.apple.com/content/catalogs/others/"
|
),
|
||||||
|
"20": (
|
||||||
|
"https://swscan.apple.com/content/catalogs/others/"
|
||||||
"index-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
|
"index-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
|
||||||
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
|
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
|
||||||
"21": "https://swscan.apple.com/content/catalogs/others/"
|
),
|
||||||
|
"21": (
|
||||||
|
"https://swscan.apple.com/content/catalogs/others/"
|
||||||
"index-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
|
"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",
|
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
SEED_CATALOGS_PLIST = (
|
SEED_CATALOGS_PLIST = (
|
||||||
@ -233,8 +251,9 @@ def get_seeding_programs():
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def get_default_catalog():
|
def get_default_catalog(darwin_major=None):
|
||||||
"""Returns the default softwareupdate catalog for the current OS"""
|
"""Returns the default softwareupdate catalog for the current OS"""
|
||||||
|
if not darwin_major:
|
||||||
darwin_major = os.uname()[2].split(".")[0]
|
darwin_major = os.uname()[2].split(".")[0]
|
||||||
return DEFAULT_SUCATALOGS.get(darwin_major)
|
return DEFAULT_SUCATALOGS.get(darwin_major)
|
||||||
|
|
||||||
@ -678,10 +697,13 @@ def os_installer_product_info(
|
|||||||
|
|
||||||
def get_latest_version(current_item, latest_item):
|
def get_latest_version(current_item, latest_item):
|
||||||
"""Compares versions between two values and returns the latest (highest) value"""
|
"""Compares versions between two values and returns the latest (highest) value"""
|
||||||
|
try:
|
||||||
if LooseVersion(current_item) > LooseVersion(latest_item):
|
if LooseVersion(current_item) > LooseVersion(latest_item):
|
||||||
return current_item
|
return current_item
|
||||||
else:
|
else:
|
||||||
return latest_item
|
return latest_item
|
||||||
|
except TypeError:
|
||||||
|
return current_item
|
||||||
|
|
||||||
|
|
||||||
def replicate_product(catalog, product_id, workdir, ignore_cache=False):
|
def replicate_product(catalog, product_id, workdir, ignore_cache=False):
|
||||||
@ -751,6 +773,12 @@ def main():
|
|||||||
help="Software Update catalog URL. This option "
|
help="Software Update catalog URL. This option "
|
||||||
"overrides any seedprogram option.",
|
"overrides any seedprogram option.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--catalog",
|
||||||
|
default="",
|
||||||
|
help="Software Update catalog for a specific macOS version. "
|
||||||
|
"This option overrides any seedprogram option.",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--workdir",
|
"--workdir",
|
||||||
metavar="path_to_working_dir",
|
metavar="path_to_working_dir",
|
||||||
@ -900,7 +928,9 @@ def main():
|
|||||||
su_catalog_url = args.catalogurl
|
su_catalog_url = args.catalogurl
|
||||||
elif args.seedprogram:
|
elif args.seedprogram:
|
||||||
su_catalog_url = get_seed_catalog(args.seedprogram)
|
su_catalog_url = get_seed_catalog(args.seedprogram)
|
||||||
if not su_catalog_url:
|
if su_catalog_url:
|
||||||
|
print("Using catalog for Seed Program {}.\n".format(args.seedprogram))
|
||||||
|
else:
|
||||||
print(
|
print(
|
||||||
"Could not find a catalog url for seed program %s" % args.seedprogram,
|
"Could not find a catalog url for seed program %s" % args.seedprogram,
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
@ -910,6 +940,16 @@ def main():
|
|||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
elif args.catalog:
|
||||||
|
su_catalog_url = get_default_catalog(args.catalog)
|
||||||
|
if su_catalog_url:
|
||||||
|
print("Using catalog for Darwin v{}.\n".format(args.catalog))
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
"Could not find a default catalog url for this OS version.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
exit(-1)
|
||||||
else:
|
else:
|
||||||
su_catalog_url = get_default_catalog()
|
su_catalog_url = get_default_catalog()
|
||||||
if not su_catalog_url:
|
if not su_catalog_url:
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Based on investigations and work by Pepijn Bruienne
|
|
||||||
# Expects a single /Applications/Install macOS High Sierra*.app on disk
|
|
||||||
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
IDENTIFIER="com.foo.FirmwareUpdateStandalone"
|
|
||||||
VERSION=1.0
|
|
||||||
|
|
||||||
# find the Install macOS High Sierra.app and mount the embedded InstallESD disk image
|
|
||||||
echo "Mounting High Sierra ESD disk image..."
|
|
||||||
/usr/bin/hdiutil mount /Applications/Install\ macOS\ High\ Sierra*.app/Contents/SharedSupport/InstallESD.dmg
|
|
||||||
|
|
||||||
# expand the FirmwareUpdate.pkg so we can copy resources from it
|
|
||||||
echo "Expanding FirmwareUpdate.pkg"
|
|
||||||
/usr/sbin/pkgutil --expand /Volumes/InstallESD/Packages/FirmwareUpdate.pkg /tmp/FirmwareUpdate
|
|
||||||
|
|
||||||
# we don't need the disk image any more
|
|
||||||
echo "Ejecting disk image..."
|
|
||||||
/usr/bin/hdiutil eject /Volumes/InstallESD
|
|
||||||
|
|
||||||
# make a place to stage our pkg resources
|
|
||||||
/bin/mkdir -p /tmp/FirmwareUpdateStandalone/scripts
|
|
||||||
|
|
||||||
# copy the needed resources
|
|
||||||
echo "Copying package resources..."
|
|
||||||
/bin/cp /tmp/FirmwareUpdate/Scripts/postinstall_actions/update /tmp/FirmwareUpdateStandalone/scripts/postinstall
|
|
||||||
# add an exit 0 at the end of the script
|
|
||||||
echo "" >> /tmp/FirmwareUpdateStandalone/scripts/postinstall
|
|
||||||
echo "" >> /tmp/FirmwareUpdateStandalone/scripts/postinstall
|
|
||||||
echo "exit 0" >> /tmp/FirmwareUpdateStandalone/scripts/postinstall
|
|
||||||
/bin/cp -R /tmp/FirmwareUpdate/Scripts/Tools /tmp/FirmwareUpdateStandalone/scripts/
|
|
||||||
|
|
||||||
# build the package
|
|
||||||
echo "Building standalone package..."
|
|
||||||
/usr/bin/pkgbuild --nopayload --scripts /tmp/FirmwareUpdateStandalone/scripts --identifier "$IDENTIFIER" --version "$VERSION" /tmp/FirmwareUpdateStandalone/FirmwareUpdateStandalone.pkg
|
|
||||||
|
|
||||||
# clean up
|
|
||||||
/bin/rm -r /tmp/FirmwareUpdate
|
|
||||||
/bin/rm -r /tmp/FirmwareUpdateStandalone/scripts
|
|
||||||
Loading…
x
Reference in New Issue
Block a user