Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Brigadier

> **Change Notice:**
> The following features have been added by HungryHenry (me):
> 1. Added two parameters: `--no-ssl-check` & `--7zip-path`
> 2. The script will skip downloading if the `.pkg` file already exists in `landing_dir`

A Windows- and OS X-compatible Python script that fetches, from Apple's or your software update server, the Boot Camp ESD ("Electronic Software Distribution") for a specific model of Mac. It unpacks the multiple layers of archives within the flat package and if the script is run on Windows with the `--install` option, it also runs the 64-bit MSI installer.

On Windows, the archives are unpacked using [7-Zip](http://www.7-zip.org), and the 7-Zip MSI is downloaded and installed, and removed later if Brigadier installed it. This tool used to use [dmg2img](http://vu1tur.eu.org/tools/) to perform the extraction of files from Apple's `WindowsSupport.dmg` file, but more recent versions of 7-Zip have included more completely support for DMGs, so dmg2img seems to be no longer needed.
Expand Down
66 changes: 30 additions & 36 deletions brigadier
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def getMachineModel():
model = plist[0]['_items'][0]['machine_model']
return model

def downloadFile(url, filename, use_requests=False):
def downloadFile(url, filename, use_requests=False, verify=True):
# http://stackoverflow.com/questions/13881092/
# download-progressbar-for-python-3/13895723#13895723
def reporthook(blocknum, blocksize, totalsize):
Expand All @@ -62,18 +62,24 @@ def downloadFile(url, filename, use_requests=False):
sys.stderr.write("read %d\n" % (readsofar,))

if use_requests:
resp = requests.get(url, stream=True)
resp = requests.get(url, stream=True,verify=verify)
with open(filename, 'wb') as fd:
for chunk in resp.iter_content(chunk_size=1024):
fd.write(chunk)
return

if not verify:
status("Warning: SSL certificate verification is disabled.")

# urlretrieve method will likely just go away soon, and we'll use only requests
# with some kind of report/progress output
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, exe_path=None):
if not exe_path:
exe_path = os.path.join(os.environ['SYSTEMDRIVE'] + "\\", "Program Files", "7-Zip", "7z.exe")
status("Using 7-Zip executable: %s" % exe_path)
cmd = [exe_path]
cmd.append(command)
if not out_dir:
out_dir = os.path.dirname(arcfile)
Expand Down Expand Up @@ -144,6 +150,10 @@ where a model has multiple BootCamp ESDs available and is not downloading the de
according to the post date.")
o.add_option('-V', '--version', action="store_true",
help="Output the version of brigadier.")
o.add_option('--no-ssl-check', action="store_false", dest="ssl_check", default=True,
help="Disable SSL certificate verification (not recommended). Default is to verify SSL certificates.")
o.add_option('--7zip-path', dest="zip_path",
help="Specify custom path to 7-Zip executable. If not specified, will look in default locations.")

opts, args = o.parse_args()
if opts.version:
Expand Down Expand Up @@ -273,51 +283,35 @@ when running the installer out of 'system32'." % output_dir)

# make a sub-dir in the output_dir here, named by product
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':
# using rmdir /qs because shutil.rmtree dies on the Doc files with foreign language characters
subprocess.call(['cmd', '/c', 'rmdir', '/q', '/s', landing_dir])
else:
shutil.rmtree(landing_dir)

status("Making directory %s.." % landing_dir)
os.mkdir(landing_dir)

arc_workdir = tempfile.mkdtemp(prefix="bootcamp-unpack_")
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 os.path.exists(landing_dir):
if os.path.exists(os.path.join(landing_dir, pkg_url.split('/')[-1])):
status("Boot Camp installer already exists in %s. Skipping download." % landing_dir)
shutil.copyfile(os.path.join(landing_dir, pkg_url.split('/')[-1]), pkg_dl_path)
else:
status("Fetching Boot Camp product at URL %s." % pkg_url)
downloadFile(pkg_url, pkg_dl_path, verify=opts.ssl_check)
else:
status("Making directory %s.." % landing_dir)
os.mkdir(landing_dir)
status("Fetching Boot Camp product at URL %s." % pkg_url)
downloadFile(pkg_url, pkg_dl_path, verify=opts.ssl_check)

if platform.system() == 'Windows':
we_installed_7zip = False
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])
downloadFile(SEVENZIP_URL, sevenzip_msi_dl_path, use_requests=True)
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])
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~')]:
if os.path.exists(arc):
sevenzipExtract(arc)
sevenzipExtract(arc, exe_path=opts.zip_path)
# 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)
if we_installed_7zip:
status("Cleaning up the 7-Zip install...")
subprocess.call(['cmd', '/c', 'msiexec', '/qn', '/x', sevenzip_msi_dl_path])
out_dir=landing_dir,
exe_path=opts.zip_path
)
if opts.install:
status("Installing Boot Camp...")
installBootcamp(findBootcampMSI(landing_dir))
Expand Down