mirror of
https://github.com/timsutton/brigadier.git
synced 2025-06-06 01:31:19 -04:00
Merge fb230073d0
into fa6d26b49f
This commit is contained in:
commit
ee33f3b8bd
2 changed files with 257 additions and 138 deletions
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -1,6 +1,12 @@
|
|||
.DS_Store
|
||||
pyinstaller.zip
|
||||
pyinstaller-*
|
||||
brigadier*.zip
|
||||
/brigadier.plist
|
||||
|
||||
# virtualenv
|
||||
.venv
|
||||
|
||||
# possible brigadier outputs
|
||||
BootCamp-*
|
||||
|
||||
# pyinstaller
|
||||
build
|
||||
dist
|
||||
*.spec
|
||||
|
|
373
brigadier
373
brigadier
|
@ -1,49 +1,58 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import datetime
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import urllib2
|
||||
import platform
|
||||
import plistlib
|
||||
import re
|
||||
import tempfile
|
||||
import shutil
|
||||
import optparse
|
||||
import datetime
|
||||
import platform
|
||||
|
||||
from pprint import pprint
|
||||
from urllib import urlretrieve
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from urllib.request import urlopen, urlretrieve
|
||||
from xml.dom import minidom
|
||||
|
||||
SUCATALOG_URL = 'https://swscan.apple.com/content/catalogs/others/index-11-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog'
|
||||
SUCATALOG_URL = "https://swscan.apple.com/content/catalogs/others/index-11-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
|
||||
# 7-Zip MSI (15.14)
|
||||
SEVENZIP_URL = 'http://www.7-zip.org/a/7z1514-x64.msi'
|
||||
SEVENZIP_URL = "http://www.7-zip.org/a/7z1514-x64.msi"
|
||||
|
||||
|
||||
def status(msg):
|
||||
print "%s\n" % msg
|
||||
print("%s\n" % msg)
|
||||
|
||||
|
||||
def getCommandOutput(cmd):
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
out, err = p.communicate()
|
||||
return out
|
||||
|
||||
|
||||
# Returns this machine's model identifier, using wmic on Windows,
|
||||
# system_profiler on OS X
|
||||
def getMachineModel():
|
||||
if platform.system() == 'Windows':
|
||||
rawxml = getCommandOutput(['wmic', 'computersystem', 'get', 'model', '/format:RAWXML'])
|
||||
if platform.system() == "Windows":
|
||||
rawxml = getCommandOutput(
|
||||
["wmic", "computersystem", "get", "model", "/format:RAWXML"]
|
||||
)
|
||||
dom = minidom.parseString(rawxml)
|
||||
results = dom.getElementsByTagName("RESULTS")
|
||||
nodes = results[0].getElementsByTagName("CIM")[0].getElementsByTagName("INSTANCE")[0]\
|
||||
.getElementsByTagName("PROPERTY")[0].getElementsByTagName("VALUE")[0].childNodes
|
||||
nodes = (
|
||||
results[0]
|
||||
.getElementsByTagName("CIM")[0]
|
||||
.getElementsByTagName("INSTANCE")[0]
|
||||
.getElementsByTagName("PROPERTY")[0]
|
||||
.getElementsByTagName("VALUE")[0]
|
||||
.childNodes
|
||||
)
|
||||
model = nodes[0].data
|
||||
elif platform.system() == 'Darwin':
|
||||
plistxml = getCommandOutput(['system_profiler', 'SPHardwareDataType', '-xml'])
|
||||
plist = plistlib.readPlistFromString(plistxml)
|
||||
model = plist[0]['_items'][0]['machine_model']
|
||||
elif platform.system() == "Darwin":
|
||||
plistxml = getCommandOutput(["system_profiler", "SPHardwareDataType", "-xml"])
|
||||
plist = plistlib.loads(plistxml)
|
||||
model = plist[0]["_items"][0]["machine_model"]
|
||||
return model
|
||||
|
||||
|
||||
def downloadFile(url, filename):
|
||||
# http://stackoverflow.com/questions/13881092/
|
||||
# download-progressbar-for-python-3/13895723#13895723
|
||||
|
@ -52,27 +61,37 @@ def downloadFile(url, filename):
|
|||
if totalsize > 0:
|
||||
percent = readsofar * 1e2 / totalsize
|
||||
console_out = "\r%5.1f%% %*d / %d bytes" % (
|
||||
percent, len(str(totalsize)), readsofar, totalsize)
|
||||
percent,
|
||||
len(str(totalsize)),
|
||||
readsofar,
|
||||
totalsize,
|
||||
)
|
||||
sys.stderr.write(console_out)
|
||||
if readsofar >= totalsize: # near the end
|
||||
if readsofar >= totalsize: # near the end
|
||||
sys.stderr.write("\n")
|
||||
else: # total size is unknown
|
||||
else: # total size is unknown
|
||||
sys.stderr.write("read %d\n" % (readsofar,))
|
||||
|
||||
urlretrieve(url, filename, reporthook=reporthook)
|
||||
|
||||
def sevenzipExtract(arcfile, command='e', out_dir=None):
|
||||
cmd = [os.path.join(os.environ['SYSTEMDRIVE'] + "\\", "Program Files", "7-Zip", "7z.exe")]
|
||||
|
||||
def sevenzipExtract(arcfile, command="e", out_dir=None):
|
||||
cmd = [
|
||||
os.path.join(
|
||||
os.environ["SYSTEMDRIVE"] + "\\", "Program Files", "7-Zip", "7z.exe"
|
||||
)
|
||||
]
|
||||
cmd.append(command)
|
||||
if not out_dir:
|
||||
out_dir = os.path.dirname(arcfile)
|
||||
cmd.append("-o" + out_dir)
|
||||
cmd.append("-y")
|
||||
cmd.append(arcfile)
|
||||
status("Calling 7-Zip command: %s" % ' '.join(cmd))
|
||||
status("Calling 7-Zip command: %s" % " ".join(cmd))
|
||||
retcode = subprocess.call(cmd)
|
||||
if retcode:
|
||||
sys.exit("Command failure: %s exited %s." % (' '.join(cmd), retcode))
|
||||
sys.exit("Command failure: %s exited %s." % (" ".join(cmd), retcode))
|
||||
|
||||
|
||||
def postInstallConfig():
|
||||
regdata = """Windows Registry Editor Version 5.00
|
||||
|
@ -80,10 +99,11 @@ def postInstallConfig():
|
|||
[HKEY_CURRENT_USER\Software\Apple Inc.\Apple Keyboard Support]
|
||||
"FirstTimeRun"=dword:00000000"""
|
||||
handle, path = tempfile.mkstemp()
|
||||
fd = os.fdopen(handle, 'w')
|
||||
fd = os.fdopen(handle, "w")
|
||||
fd.write(regdata)
|
||||
fd.close()
|
||||
subprocess.call(['regedit.exe', '/s', path])
|
||||
subprocess.call(["regedit.exe", "/s", path])
|
||||
|
||||
|
||||
def findBootcampMSI(search_dir):
|
||||
"""Returns the path of the 64-bit BootCamp MSI"""
|
||||
|
@ -93,174 +113,221 @@ def findBootcampMSI(search_dir):
|
|||
# it's an AutoUnattend-based ESD as well, ie:
|
||||
# /Drivers/Apple/BootCamp64.msi, or
|
||||
# /BootCamp/Drivers/Apple/BootCamp.msi
|
||||
candidates = ['BootCamp64.msi', 'BootCamp.msi']
|
||||
candidates = ["BootCamp64.msi", "BootCamp.msi"]
|
||||
for root, dirs, files in os.walk(search_dir):
|
||||
for msi in candidates:
|
||||
if msi in files:
|
||||
return os.path.join(root, msi)
|
||||
|
||||
|
||||
def installBootcamp(msipath):
|
||||
logpath = os.path.abspath("/BootCamp_Install.log")
|
||||
cmd = ['cmd', '/c', 'msiexec', '/i', msipath, '/qb-', '/norestart', '/log', logpath]
|
||||
cmd = ["cmd", "/c", "msiexec", "/i", msipath, "/qb-", "/norestart", "/log", logpath]
|
||||
status("Executing command: '%s'" % " ".join(cmd))
|
||||
subprocess.call(cmd)
|
||||
status("Install log output:")
|
||||
with open(logpath, 'r') as logfd:
|
||||
with open(logpath, "r") as logfd:
|
||||
logdata = logfd.read()
|
||||
print logdata.decode('utf-16')
|
||||
print(logdata.decode("utf-16"))
|
||||
postInstallConfig()
|
||||
|
||||
|
||||
def main():
|
||||
scriptdir = os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
|
||||
o = optparse.OptionParser()
|
||||
o.add_option('-m', '--model', action="append",
|
||||
o.add_option(
|
||||
"-m",
|
||||
"--model",
|
||||
action="append",
|
||||
help="System model identifier to use (otherwise this machine's \
|
||||
model is used). This can be specified multiple times to download \
|
||||
multiple models in a single run.")
|
||||
o.add_option('-i', '--install', action="store_true",
|
||||
multiple models in a single run.",
|
||||
)
|
||||
o.add_option(
|
||||
"-i",
|
||||
"--install",
|
||||
action="store_true",
|
||||
help="After the installer is downloaded, perform the install automatically. \
|
||||
Can be used on Windows only.")
|
||||
o.add_option('-o', '--output-dir',
|
||||
Can be used on Windows only.",
|
||||
)
|
||||
o.add_option(
|
||||
"-o",
|
||||
"--output-dir",
|
||||
help="Base path where the installer files will be extracted into a folder named after the \
|
||||
product, ie. 'BootCamp-041-1234'. Uses the current directory if this option is omitted.")
|
||||
o.add_option('-k', '--keep-files', action="store_true",
|
||||
product, ie. 'BootCamp-041-1234'. Uses the current directory if this option is omitted.",
|
||||
)
|
||||
o.add_option(
|
||||
"-k",
|
||||
"--keep-files",
|
||||
action="store_true",
|
||||
help="Keep the files that were downloaded/extracted. Useful only with the \
|
||||
'--install' option on Windows.")
|
||||
o.add_option('-p', '--product-id',
|
||||
'--install' option on Windows.",
|
||||
)
|
||||
o.add_option(
|
||||
"-p",
|
||||
"--product-id",
|
||||
help="Specify an exact product ID to download (ie. '031-0787'), currently useful only for cases \
|
||||
where a model has multiple BootCamp ESDs available and is not downloading the desired version \
|
||||
according to the post date.")
|
||||
according to the post date.",
|
||||
)
|
||||
|
||||
opts, args = o.parse_args()
|
||||
if opts.install:
|
||||
if platform.system() == 'Darwin':
|
||||
if platform.system() == "Darwin":
|
||||
sys.exit("Installing Boot Camp can only be done on Windows!")
|
||||
if platform.system() == 'Windows' and platform.machine() != 'AMD64':
|
||||
sys.exit("Installing on anything other than 64-bit Windows is currently not supported!")
|
||||
if platform.system() == "Windows" and platform.machine() != "AMD64":
|
||||
sys.exit(
|
||||
"Installing on anything other than 64-bit Windows is currently not supported!"
|
||||
)
|
||||
|
||||
if opts.output_dir:
|
||||
if not os.path.isdir(opts.output_dir):
|
||||
sys.exit("Output directory %s that was specified doesn't exist!" % opts.output_dir)
|
||||
sys.exit(
|
||||
"Output directory %s that was specified doesn't exist!"
|
||||
% opts.output_dir
|
||||
)
|
||||
if not os.access(opts.output_dir, os.W_OK):
|
||||
sys.exit("Output directory %s is not writable by this user!" % opts.output_dir)
|
||||
sys.exit(
|
||||
"Output directory %s is not writable by this user!" % opts.output_dir
|
||||
)
|
||||
output_dir = opts.output_dir
|
||||
else:
|
||||
output_dir = os.getcwd()
|
||||
if output_dir.endswith('ystem32') or '\\system32\\' in output_dir.lower():
|
||||
output_dir = os.environ['SystemDrive'] + "\\"
|
||||
status("Changing output directory to %s to work around an issue \
|
||||
when running the installer out of 'system32'." % output_dir)
|
||||
if output_dir.endswith("ystem32") or "\\system32\\" in output_dir.lower():
|
||||
output_dir = os.environ["SystemDrive"] + "\\"
|
||||
status(
|
||||
"Changing output directory to %s to work around an issue \
|
||||
when running the installer out of 'system32'."
|
||||
% output_dir
|
||||
)
|
||||
|
||||
if opts.keep_files and not opts.install:
|
||||
sys.exit("The --keep-files option is only useful when used with --install option!")
|
||||
sys.exit(
|
||||
"The --keep-files option is only useful when used with --install option!"
|
||||
)
|
||||
|
||||
if opts.model:
|
||||
if opts.install:
|
||||
status("Ignoring '--model' when '--install' is used. The Boot Camp "
|
||||
"installer won't allow other models to be installed, anyway.")
|
||||
status(
|
||||
"Ignoring '--model' when '--install' is used. The Boot Camp "
|
||||
"installer won't allow other models to be installed, anyway."
|
||||
)
|
||||
models = opts.model
|
||||
else:
|
||||
models = [getMachineModel()]
|
||||
if len(models) > 1:
|
||||
status("Using Mac models: %s." % ', '.join(models))
|
||||
status("Using Mac models: %s." % ", ".join(models))
|
||||
else:
|
||||
status("Using Mac model: %s." % ', '.join(models))
|
||||
status("Using Mac model: %s." % ", ".join(models))
|
||||
|
||||
for model in models:
|
||||
sucatalog_url = SUCATALOG_URL
|
||||
# check if we defined anything in brigadier.plist
|
||||
config_plist = None
|
||||
plist_path = os.path.join(scriptdir, 'brigadier.plist')
|
||||
plist_path = os.path.join(scriptdir, "brigadier.plist")
|
||||
if os.path.isfile(plist_path):
|
||||
try:
|
||||
config_plist = plistlib.readPlist(plist_path)
|
||||
except:
|
||||
status("Config plist was found at %s but it could not be read. \
|
||||
Verify that it is readable and is an XML formatted plist." % plist_path)
|
||||
status(
|
||||
"Config plist was found at %s but it could not be read. \
|
||||
Verify that it is readable and is an XML formatted plist."
|
||||
% plist_path
|
||||
)
|
||||
if config_plist:
|
||||
if 'CatalogURL' in config_plist.keys():
|
||||
sucatalog_url = config_plist['CatalogURL']
|
||||
if "CatalogURL" in config_plist.keys():
|
||||
sucatalog_url = config_plist["CatalogURL"]
|
||||
|
||||
|
||||
urlfd = urllib2.urlopen(sucatalog_url)
|
||||
urlfd = urlopen(sucatalog_url)
|
||||
data = urlfd.read()
|
||||
p = plistlib.readPlistFromString(data)
|
||||
allprods = p['Products']
|
||||
p = plistlib.loads(data)
|
||||
allprods = p["Products"]
|
||||
|
||||
# Get all Boot Camp ESD products
|
||||
bc_prods = []
|
||||
for (prod_id, prod_data) in allprods.items():
|
||||
if 'ServerMetadataURL' in prod_data.keys():
|
||||
bc_match = re.search('BootCamp', prod_data['ServerMetadataURL'])
|
||||
if "ServerMetadataURL" in prod_data.keys():
|
||||
bc_match = re.search("BootCamp", prod_data["ServerMetadataURL"])
|
||||
if bc_match:
|
||||
bc_prods.append((prod_id, prod_data))
|
||||
# Find the ESD(s) that applies to our model
|
||||
pkg_data = []
|
||||
re_model = "([a-zA-Z]{4,12}[1-9]{1,2}\,[1-6])"
|
||||
for bc_prod in bc_prods:
|
||||
if 'English' in bc_prod[1]['Distributions'].keys():
|
||||
disturl = bc_prod[1]['Distributions']['English']
|
||||
distfd = urllib2.urlopen(disturl)
|
||||
dist_data = distfd.read()
|
||||
if "English" in bc_prod[1]["Distributions"].keys():
|
||||
disturl = bc_prod[1]["Distributions"]["English"]
|
||||
distfd = urlopen(disturl)
|
||||
dist_data = distfd.read().decode("utf-8")
|
||||
if re.search(model, dist_data):
|
||||
supported_models = []
|
||||
pkg_data.append({bc_prod[0]: bc_prod[1]})
|
||||
model_matches_in_dist = re.findall(re_model, dist_data)
|
||||
for supported_model in model_matches_in_dist:
|
||||
supported_models.append(supported_model)
|
||||
status("Model supported in package distribution file at %s." % disturl)
|
||||
status("Distribution %s supports the following models: %s." %
|
||||
(bc_prod[0], ", ".join(supported_models)))
|
||||
status(
|
||||
"Model supported in package distribution file at %s." % disturl
|
||||
)
|
||||
status(
|
||||
"Distribution %s supports the following models: %s."
|
||||
% (bc_prod[0], ", ".join(supported_models))
|
||||
)
|
||||
|
||||
# Ensure we have only one ESD
|
||||
if len(pkg_data) == 0:
|
||||
sys.exit("Couldn't find a Boot Camp ESD for the model %s in the given software update catalog." % model)
|
||||
sys.exit(
|
||||
"Couldn't find a Boot Camp ESD for the model %s in the given software update catalog."
|
||||
% model
|
||||
)
|
||||
if len(pkg_data) == 1:
|
||||
pkg_data = pkg_data[0]
|
||||
if opts.product_id:
|
||||
sys.exit("--product-id option is only applicable when multiple ESDs are found for a model.")
|
||||
sys.exit(
|
||||
"--product-id option is only applicable when multiple ESDs are found for a model."
|
||||
)
|
||||
if len(pkg_data) > 1:
|
||||
# sys.exit("There is more than one ESD product available for this model: %s. "
|
||||
# "Automically selecting the one with the most recent PostDate.."
|
||||
# % ", ".join([p.keys()[0] for p in pkg_data]))
|
||||
print "There is more than one ESD product available for this model:"
|
||||
print("There is more than one ESD product available for this model:")
|
||||
# Init latest to be epoch start
|
||||
latest_date = datetime.datetime.fromtimestamp(0)
|
||||
chosen_product = None
|
||||
for i, p in enumerate(pkg_data):
|
||||
product = p.keys()[0]
|
||||
postdate = p[product].get('PostDate')
|
||||
print "%s: PostDate %s" % (product, postdate)
|
||||
product = list(p)[0]
|
||||
postdate = p[product].get("PostDate")
|
||||
print("%s: PostDate %s" % (product, postdate))
|
||||
if postdate > latest_date:
|
||||
latest_date = postdate
|
||||
chosen_product = product
|
||||
|
||||
if opts.product_id:
|
||||
if opts.product_id not in [k.keys()[0] for k in pkg_data]:
|
||||
sys.exit("Product specified with '--product-id %s' either doesn't exist "
|
||||
"or was not found applicable to models: %s"
|
||||
% (opts.product_id, ", ".join(models)))
|
||||
if opts.product_id not in [list(k)[0] for k in pkg_data]:
|
||||
sys.exit(
|
||||
"Product specified with '--product-id %s' either doesn't exist "
|
||||
"or was not found applicable to models: %s"
|
||||
% (opts.product_id, ", ".join(models))
|
||||
)
|
||||
chosen_product = opts.product_id
|
||||
print "Selecting manually-chosen product %s." % chosen_product
|
||||
print("Selecting manually-chosen product %s." % chosen_product)
|
||||
else:
|
||||
print "Selecting %s as it's the most recently posted." % chosen_product
|
||||
print("Selecting %s as it's the most recently posted." % chosen_product)
|
||||
|
||||
for p in pkg_data:
|
||||
if p.keys()[0] == chosen_product:
|
||||
if list(p)[0] == chosen_product:
|
||||
selected_pkg = p
|
||||
pkg_data = selected_pkg
|
||||
|
||||
pkg_id = pkg_data.keys()[0]
|
||||
pkg_url = pkg_data.values()[0]['Packages'][0]['URL']
|
||||
pkg_id = list(pkg_data)[0]
|
||||
pkg_url = list(pkg_data.values())[0]["Packages"][0]["URL"]
|
||||
|
||||
# make a sub-dir in the output_dir here, named by product
|
||||
landing_dir = os.path.join(output_dir, 'BootCamp-' + pkg_id)
|
||||
landing_dir = os.path.join(output_dir, "BootCamp-" + pkg_id)
|
||||
if os.path.exists(landing_dir):
|
||||
status("Final output path %s already exists, removing it..." % landing_dir)
|
||||
if platform.system() == 'Windows':
|
||||
if platform.system() == "Windows":
|
||||
# using rmdir /qs because shutil.rmtree dies on the Doc files with foreign language characters
|
||||
subprocess.call(['cmd', '/c', 'rmdir', '/q', '/s', landing_dir])
|
||||
subprocess.call(["cmd", "/c", "rmdir", "/q", "/s", landing_dir])
|
||||
else:
|
||||
shutil.rmtree(landing_dir)
|
||||
|
||||
|
@ -268,58 +335,89 @@ when running the installer out of 'system32'." % output_dir)
|
|||
os.mkdir(landing_dir)
|
||||
|
||||
arc_workdir = tempfile.mkdtemp(prefix="bootcamp-unpack_")
|
||||
pkg_dl_path = os.path.join(arc_workdir, pkg_url.split('/')[-1])
|
||||
pkg_dl_path = os.path.join(arc_workdir, pkg_url.split("/")[-1])
|
||||
|
||||
status("Fetching Boot Camp product at URL %s." % pkg_url)
|
||||
downloadFile(pkg_url, pkg_dl_path)
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
if platform.system() == "Windows":
|
||||
we_installed_7zip = False
|
||||
sevenzip_binary = os.path.join(os.environ['SYSTEMDRIVE'] + "\\", 'Program Files', '7-Zip', '7z.exe')
|
||||
sevenzip_binary = os.path.join(
|
||||
os.environ["SYSTEMDRIVE"] + "\\", "Program Files", "7-Zip", "7z.exe"
|
||||
)
|
||||
# fetch and install 7-Zip
|
||||
if not os.path.exists(sevenzip_binary):
|
||||
tempdir = tempfile.mkdtemp()
|
||||
sevenzip_msi_dl_path = os.path.join(tempdir, SEVENZIP_URL.split('/')[-1])
|
||||
sevenzip_msi_dl_path = os.path.join(
|
||||
tempdir, SEVENZIP_URL.split("/")[-1]
|
||||
)
|
||||
downloadFile(SEVENZIP_URL, sevenzip_msi_dl_path)
|
||||
status("Downloaded 7-zip to %s." % sevenzip_msi_dl_path)
|
||||
status("We need to install 7-Zip..")
|
||||
retcode = subprocess.call(['msiexec', '/qn', '/i', sevenzip_msi_dl_path])
|
||||
retcode = subprocess.call(
|
||||
["msiexec", "/qn", "/i", sevenzip_msi_dl_path]
|
||||
)
|
||||
status("7-Zip install returned exit code %s." % retcode)
|
||||
we_installed_7zip = True
|
||||
|
||||
status("Extracting...")
|
||||
# BootCamp.pkg (xar) -> Payload (gzip) -> Payload~ (cpio) -> WindowsSupport.dmg
|
||||
for arc in [pkg_dl_path,
|
||||
os.path.join(arc_workdir, 'Payload'),
|
||||
os.path.join(arc_workdir, 'Payload~')]:
|
||||
for arc in [
|
||||
pkg_dl_path,
|
||||
os.path.join(arc_workdir, "Payload"),
|
||||
os.path.join(arc_workdir, "Payload~"),
|
||||
]:
|
||||
if os.path.exists(arc):
|
||||
sevenzipExtract(arc)
|
||||
# finally, 7-Zip also extracts the tree within the DMG to the output dir
|
||||
sevenzipExtract(os.path.join(arc_workdir, 'WindowsSupport.dmg'),
|
||||
command='x',
|
||||
out_dir=landing_dir)
|
||||
sevenzipExtract(
|
||||
os.path.join(arc_workdir, "WindowsSupport.dmg"),
|
||||
command="x",
|
||||
out_dir=landing_dir,
|
||||
)
|
||||
if we_installed_7zip:
|
||||
status("Cleaning up the 7-Zip install...")
|
||||
subprocess.call(['cmd', '/c', 'msiexec', '/qn', '/x', sevenzip_msi_dl_path])
|
||||
subprocess.call(
|
||||
["cmd", "/c", "msiexec", "/qn", "/x", sevenzip_msi_dl_path]
|
||||
)
|
||||
if opts.install:
|
||||
status("Installing Boot Camp...")
|
||||
installBootcamp(findBootcampMSI(landing_dir))
|
||||
if not opts.keep_files:
|
||||
subprocess.call(['cmd', '/c', 'rmdir', '/q', '/s', landing_dir])
|
||||
subprocess.call(["cmd", "/c", "rmdir", "/q", "/s", landing_dir])
|
||||
|
||||
# clean up the temp dir always
|
||||
subprocess.call(['cmd', '/c', 'rmdir', '/q', '/s', arc_workdir])
|
||||
subprocess.call(["cmd", "/c", "rmdir", "/q", "/s", arc_workdir])
|
||||
|
||||
|
||||
elif platform.system() == 'Darwin':
|
||||
elif platform.system() == "Darwin":
|
||||
status("Expanding flat package...")
|
||||
subprocess.call(['/usr/sbin/pkgutil', '--expand', pkg_dl_path,
|
||||
os.path.join(arc_workdir, 'pkg')])
|
||||
subprocess.call(
|
||||
[
|
||||
"/usr/sbin/pkgutil",
|
||||
"--expand",
|
||||
pkg_dl_path,
|
||||
os.path.join(arc_workdir, "pkg"),
|
||||
]
|
||||
)
|
||||
status("Extracting Payload...")
|
||||
subprocess.call(['/usr/bin/tar', '-xz', '-C', arc_workdir, '-f', os.path.join(arc_workdir, 'pkg', 'Payload')])
|
||||
output_file = os.path.join(landing_dir, 'WindowsSupport.dmg')
|
||||
shutil.move(os.path.join(arc_workdir, 'Library/Application Support/BootCamp/WindowsSupport.dmg'),
|
||||
output_file)
|
||||
subprocess.call(
|
||||
[
|
||||
"/usr/bin/tar",
|
||||
"-xz",
|
||||
"-C",
|
||||
arc_workdir,
|
||||
"-f",
|
||||
os.path.join(arc_workdir, "pkg", "Payload"),
|
||||
]
|
||||
)
|
||||
output_file = os.path.join(landing_dir, "WindowsSupport.dmg")
|
||||
shutil.move(
|
||||
os.path.join(
|
||||
arc_workdir,
|
||||
"Library/Application Support/BootCamp/WindowsSupport.dmg",
|
||||
),
|
||||
output_file,
|
||||
)
|
||||
status("Extracted to %s." % output_file)
|
||||
|
||||
# If we were to also copy out the contents from the .dmg we might do it like this, but if you're doing this
|
||||
|
@ -327,36 +425,51 @@ when running the installer out of 'system32'." % output_dir)
|
|||
# mountxml = getCommandOutput(['/usr/bin/hdiutil', 'attach',
|
||||
# os.path.join(arc_workdir, 'Library/Application Support/BootCamp/WindowsSupport.dmg'),
|
||||
# '-mountrandom', '/tmp', '-plist', '-nobrowse'])
|
||||
# mountplist = plistlib.readPlistFromString(mountxml)
|
||||
# mountplist = plistlib.loads(mountxml)
|
||||
# mntpoint = mountplist['system-entities'][0]['mount-point']
|
||||
# shutil.copytree(mntpoint, output_dir)
|
||||
# subprocess.call(['/usr/bin/hdiutil', 'eject', mntpoint])
|
||||
shutil.rmtree(arc_workdir)
|
||||
|
||||
elif platform.system() == 'Linux':
|
||||
elif platform.system() == "Linux":
|
||||
status("Extracting for Linux...")
|
||||
for arc in [pkg_dl_path,
|
||||
os.path.join(arc_workdir, 'Payload'),
|
||||
os.path.join(arc_workdir, 'Payload~')]:
|
||||
for arc in [
|
||||
pkg_dl_path,
|
||||
os.path.join(arc_workdir, "Payload"),
|
||||
os.path.join(arc_workdir, "Payload~"),
|
||||
]:
|
||||
if os.path.exists(arc):
|
||||
status("Extracting {}".format(arc))
|
||||
subprocess.call(['7z','x',arc, '-o{}'.format(arc_workdir)])
|
||||
subprocess.call(["7z", "x", arc, "-o{}".format(arc_workdir)])
|
||||
|
||||
# BootCamp.pkg (xar) -> Payload (gzip) -> Payload~ (cpio) -> WindowsSupport.dmg
|
||||
output_file = os.path.join(arc_workdir, 'WindowsSupport.dmg')
|
||||
shutil.move(os.path.join(arc_workdir, 'Library/Application Support/BootCamp/WindowsSupport.dmg'),
|
||||
output_file)
|
||||
subprocess.call(['7z','-o{}'.format(landing_dir),'x','WindowsSupport.dmg',])
|
||||
output_file = os.path.join(arc_workdir, "WindowsSupport.dmg")
|
||||
shutil.move(
|
||||
os.path.join(
|
||||
arc_workdir,
|
||||
"Library/Application Support/BootCamp/WindowsSupport.dmg",
|
||||
),
|
||||
output_file,
|
||||
)
|
||||
subprocess.call(
|
||||
[
|
||||
"7z",
|
||||
"-o{}".format(landing_dir),
|
||||
"x",
|
||||
"WindowsSupport.dmg",
|
||||
]
|
||||
)
|
||||
|
||||
status("Extracted to %s." % output_file)
|
||||
|
||||
if os.path.exists('/mnt/c/Windows/explorer.exe'):
|
||||
subprocess.call(['/mnt/c/Windows/explorer.exe','.'])
|
||||
if os.path.exists("/mnt/c/Windows/explorer.exe"):
|
||||
subprocess.call(["/mnt/c/Windows/explorer.exe", "."])
|
||||
else:
|
||||
print("Platform not supported! ({})".format(playform.system()))
|
||||
print("Platform not supported! ({})".format(platform.system()))
|
||||
pass
|
||||
|
||||
status("Done.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue