Added --currrent and --auto options

This commit is contained in:
G Pugh 2018-09-23 14:17:45 +02:00
parent 691725e61f
commit 4b7323d63d

View File

@ -36,6 +36,8 @@ import urlparse
import xattr import xattr
from xml.dom import minidom from xml.dom import minidom
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
from operator import itemgetter
from distutils.version import LooseVersion
DEFAULT_SUCATALOG = ( DEFAULT_SUCATALOG = (
@ -74,7 +76,20 @@ def get_hw_model():
return hw_model return hw_model
def get_seeding_program(sucatalog_url): def get_current_build():
'''Gets the local system build'''
sw_vers_cmd = ['/usr/bin/sw_vers']
try:
sw_vers_output = subprocess.check_output(sw_vers_cmd).splitlines()
for line in sw_vers_output:
if 'BuildVersion' in line:
os_build = line.split("\t")[-1]
return os_build
except subprocess.CalledProcessError, err:
raise ReplicationError(err)
return os_build
'''Returns a seeding program name based on the sucatalog_url''' '''Returns a seeding program name based on the sucatalog_url'''
try: try:
seed_catalogs = plistlib.readPlist(SEED_CATALOGS_PLIST) seed_catalogs = plistlib.readPlist(SEED_CATALOGS_PLIST)
@ -429,12 +444,21 @@ def find_installer_app(mountpoint):
return None return None
def get_lowest_version(current_item, lowest_item):
'''Compares versions between two values and returns the lowest value'''
if LooseVersion(current_item) < LooseVersion(lowest_item):
return current_item
else:
return lowest_item
def main(): def main():
'''Do the main thing here''' '''Do the main thing here'''
print print ('\n'
print "installinstallmacos.py - get macOS installers from Apple's software catalog" 'installinstallmacos.py - get macOS installers '
print 'from the Apple software catalog'
'\n')
if os.getuid() != 0: if os.getuid() != 0:
sys.exit('This command requires root (to install packages), so please ' sys.exit('This command requires root (to install packages), so please '
@ -467,9 +491,15 @@ def main():
parser.add_argument('--list', action='store_true', parser.add_argument('--list', action='store_true',
help='Output the available updates to a plist ' help='Output the available updates to a plist '
'and quit.') 'and quit.')
parser.add_argument('--current', action='store_true',
help='Automatically select the current installed '
'build.')
parser.add_argument('--validate', action='store_true', parser.add_argument('--validate', action='store_true',
help='Validate builds for board ID and hardware model ' help='Validate builds for board ID and hardware model '
'and only show appropriate builds.') 'and only show appropriate builds.')
parser.add_argument('--auto', action='store_true',
help='Automatically select the appropriate valid build '
'for the current device.')
args = parser.parse_args() args = parser.parse_args()
# show this Mac's hardware model # show this Mac's hardware model
@ -478,7 +508,8 @@ def main():
# show this Mac's board-id # show this Mac's board-id
board_id = get_board_id() board_id = get_board_id()
print "This Mac's Board ID: %s" % board_id print "This Mac's Board ID: %s" % board_id
print os_build = get_current_build()
print "This Mac's Current Build ID: %s\n" % os_build
# download sucatalog and look for products that are for macOS installers # download sucatalog and look for products that are for macOS installers
catalog = download_and_parse_sucatalog( catalog = download_and_parse_sucatalog(
@ -496,22 +527,39 @@ def main():
pl['result'] = [] pl['result'] = []
# display a menu of choices (some seed catalogs have multiple installers) # display a menu of choices (some seed catalogs have multiple installers)
print '%2s %12s %10s %8s %11s %s' % ('#', 'ProductID', 'Version', print '%2s %-15s %-10s %-8s %-11s %-20s %s' % ('#', 'ProductID', 'Version',
'Build', 'Post Date', 'Title') 'Build', 'Post Date', 'Title', 'Notes')
for index, product_id in enumerate(product_info): for index, product_id in enumerate(product_info):
if args.validate: not_valid = ''
if board_id not in product_info[product_id]['BoardIDs']: if board_id not in product_info[product_id]['BoardIDs']:
continue not_valid = 'Not valid on this device'
if hw_model in product_info[product_id]['UnsupportedModels']: if hw_model in product_info[product_id]['UnsupportedModels']:
continue not_valid = 'Not valid on this device'
print '%2s %12s %10s %8s %11s %s' % ( print '%2s %-15s %-10s %-8s %-11s %-20s %s' % (
index + 1, index + 1,
product_id, product_id,
product_info[product_id]['version'], product_info[product_id]['version'],
product_info[product_id]['BUILD'], product_info[product_id]['BUILD'],
product_info[product_id]['PostDate'].strftime('%Y-%m-%d'), product_info[product_id]['PostDate'].strftime('%Y-%m-%d'),
product_info[product_id]['title'] product_info[product_id]['title'],
not_valid
) )
if not_valid and (args.validate or args.auto):
continue
if args.auto and 'Beta' not in product_info[product_id]['BUILD']:
try:
lowest_valid_build
except NameError:
lowest_valid_build = product_info[product_id]['BUILD']
answer = index+1
else:
lowest_valid_build = get_lowest_version(
product_info[product_id]['BUILD'],
lowest_valid_build)
if lowest_valid_build == product_info[product_id]['BUILD']:
answer = index+1
pl_index = {'index': index+1, pl_index = {'index': index+1,
'product_id': product_id, 'product_id': product_id,
@ -519,12 +567,16 @@ def main():
'build': product_info[product_id]['BUILD'], 'build': product_info[product_id]['BUILD'],
'title': product_info[product_id]['title'], 'title': product_info[product_id]['title'],
} }
pl['result'].append(pl_index) pl['result'].append(pl_index)
if args.build: if args.build:
if args.build == product_info[product_id]['BUILD']: if args.build == product_info[product_id]['BUILD']:
answer = index+1 answer = index+1
break
elif args.current:
if os_build == product_info[product_id]['BUILD']:
answer = index+1
break
# Output a plist of available updates and quit if --list option chosen # Output a plist of available updates and quit if --list option chosen
@ -537,11 +589,35 @@ def main():
try: try:
answer answer
except NameError: except NameError:
print ('No valid build chosen. Run again without --build argument' print ('\n'
'to select a valid build to download.') 'Build %s is not available. '
'Run again without --build argument '
'to select a valid build to download.\n' % args.build)
exit(0) exit(0)
else: else:
print '# %s chosen.' % answer print '\nBuild %s available. Downloading...\n' % args.build
elif args.current:
try:
answer
except NameError:
print ('\n'
'Build %s is not available. '
'Run again without --current argument '
'to select a valid build to download.\n' % os_build)
exit(0)
else:
print '\nBuild %s available. Downloading...\n' % os_build
elif args.auto:
try:
answer
except NameError:
print ('\n'
'Item # %s is not available. '
'Run again without --auto argument '
'to select a valid build to download.\n' % answer)
exit(0)
else:
print '\nBuild %s selected. Downloading...\n' % lowest_valid_build
else: else:
answer = raw_input( answer = raw_input(
'\nChoose a product to download (1-%s): ' % len(product_info)) '\nChoose a product to download (1-%s): ' % len(product_info))