Example #1
0
    def nextTask(self):
        LogDebug("nextTask, currentTask == %@", self.currentTask)

        if self.currentTask:
            if self.currentTask["phases"]:
                for phase in self.currentTask["phases"]:
                    if not phase.get("optional", False):
                        details = NSString.stringWithFormat_(
                            "Phases remaining: %@", self.currentTask["phases"])
                        self.fail_details_("Task finished prematurely",
                                           details)
                        return
        if self.tasks:
            self.currentTask = self.tasks.pop(0)
            LogNotice("Starting task %@ with %d phases",
                      self.currentTask["title"],
                      len(self.currentTask["phases"]))
            self.nextPhase()
            LogDebug("Calling %@()", self.currentTask["title"])
            self.currentTask["method"]()
            LogDebug("Returned from %@()", self.currentTask["title"])
        else:
            LogNotice("Build finished successfully, image saved to %@",
                      self.outputPath())
            self.delegate.buildSucceeded()
            self.stop()
Example #2
0
 def getInstalledPkgSizeFromInstaller_(cls, pkgPath):
     pkgFileName = os.path.os.path.basename(pkgPath)
     tempdir = tempfile.mkdtemp()
     try:
         symlinkPath = os.path.join(tempdir, pkgFileName)
         os.symlink(pkgPath, symlinkPath)
         p = subprocess.Popen([
             "/usr/sbin/installer", "-pkginfo", "-verbose", "-plist",
             "-pkg", symlinkPath
         ],
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
         out, err = p.communicate()
     finally:
         try:
             shutil.rmtree(tempdir)
         except BaseException as e:
             LogWarning("Unable to remove tempdir: %@", str(e))
     if p.returncode != 0:
         LogDebug(
             "/usr/sbin/installer failed to determine size requirements")
         return None
     outData = NSData.dataWithBytes_length_(out, len(out))
     plist, format, error = NSPropertyListSerialization.propertyListWithData_options_format_error_(
         outData, NSPropertyListImmutable, None, None)
     if not plist:
         LogError("Error decoding plist: %@", error)
         return None
     LogDebug("Installer says %@ requires %@", pkgPath,
              cls.formatByteSize_(int(plist["Size"]) * 1024))
     return int(plist["Size"]) * 1024
Example #3
0
 def hdiutilDetach_(self, args):
     try:
         dmgPath, target, selector = args
         LogDebug(u"Detaching %@", dmgPath)
         try:
             cmd = [u"/usr/bin/hdiutil", u"detach", self.dmgs[dmgPath]]
         except KeyError:
             target.performSelectorOnMainThread_withObject_waitUntilDone_(
                 selector, {
                     u"success": False,
                     u"dmg-path": dmgPath,
                     u"error-message": u"%s not mounted" % dmgPath
                 }, False)
             return
         del self.dmgs[dmgPath]
         maxtries = 5
         for tries in range(maxtries):
             LogDebug(u"Detaching %@, attempt %d/%d", dmgPath, tries + 1,
                      maxtries)
             if tries == maxtries >> 1:
                 LogDebug(u"Adding -force to detach arguments")
                 cmd.append(u"-force")
             p = subprocess.Popen(cmd,
                                  bufsize=1,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE)
             out, err = p.communicate()
             if p.returncode == 0:
                 target.performSelectorOnMainThread_withObject_waitUntilDone_(
                     selector, {
                         u"success": True,
                         u"dmg-path": dmgPath
                     }, False)
                 return
             elif tries == maxtries - 1:
                 errstr = u"hdiutil detach failed with return code %d" % p.returncode
                 if err:
                     errstr += u": %s" % err.decode(u"utf-8")
                 target.performSelectorOnMainThread_withObject_waitUntilDone_(
                     selector, {
                         u"success": False,
                         u"dmg-path": dmgPath,
                         u"error-message": errstr
                     }, False)
             else:
                 time.sleep(1)
     except Exception as e:
         try:
             exceptionInfo = traceback.format_exc()
         except:
             exceptionInfo = u"(no traceback available)"
         msg = u"Detach of %s crashed with exception %s:\n%s" % (
             dmgPath, e, exceptionInfo)
         target.performSelectorOnMainThread_withObject_waitUntilDone_(
             selector, {
                 u"success": False,
                 u"dmg-path": dmgPath,
                 u"error-message": msg
             }, False)
Example #4
0
 def filesystem(self):
     if IEDUtil.hostMajorVersion() < 13:
         LogDebug("Workflow filesystem is always hfs for this OS version")
         return "hfs"
     elif self._filesystem:
         LogDebug("Workflow filesystem is set to '%@'", self._filesystem)
         return self._filesystem
     else:
         LogDebug("Workflow filesystem defaults to apfs for this OS version")
         return "apfs"
Example #5
0
 def connection_willSendRequest_redirectResponse_(self, connection, request,
                                                  response):
     try:
         if response:
             url = response.URL()
             code = response.statusCode()
             LogDebug("%d redirect to %@", code, url)
     except BaseException as e:
         LogDebug("Exception: %@", repr(e))
     return request
Example #6
0
 def filesystem(self):
     osMajor = IEDUtil.hostVersionTuple()[1]
     if osMajor < 13:
         LogDebug("Workflow filesystem is always hfs for this OS version")
         return "hfs"
     elif self._filesystem:
         LogDebug("Workflow filesystem is set to '%@'", self._filesystem)
         return self._filesystem
     else:
         LogDebug(
             "Workflow filesystem defaults to apfs for this OS version")
         return "apfs"
Example #7
0
    def attachedDMGs(self):
        dmgMounts = dict()

        LogDebug(u"Finding already attached dmgs")
        p = subprocess.Popen([u"/usr/bin/hdiutil", u"info", u"-plist"],
                             bufsize=1,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        out, err = p.communicate()
        if p.returncode != 0:
            errstr = u"hdiutil info failed with return code %d" % p.returncode
            if err:
                errstr += u": %s" % err.decode(u"utf-8")
            LogWarning("%@", errstr)
            return dmgMounts

        # Strip EULA text.
        outXML = out[out.find("<?xml"):]
        outData = NSData.dataWithBytes_length_(outXML, len(outXML))
        plist, format, error = \
            NSPropertyListSerialization.propertyListWithData_options_format_error_(outData,
                                                                                   NSPropertyListImmutable,
                                                                                   None,
                                                                                   None)
        for dmgInfo in plist[u"images"]:
            for entity in dmgInfo.get(u"system-entities", []):
                try:
                    image_path = dmgInfo[u"image-path"]
                    alias_path = u""
                    bookmark = CFURLCreateBookmarkDataFromAliasRecord(
                        kCFAllocatorDefault, dmgInfo[u"image-alias"])
                    if bookmark:
                        url, stale, error = CFURLCreateByResolvingBookmarkData(
                            None, bookmark, kCFBookmarkResolutionWithoutUIMask,
                            None, None, None, None)
                        if url:
                            alias_path = url.path()
                        else:
                            LogDebug(u"Couldn't resolve bookmark: %@",
                                     error.localizedDescription())
                    for path in set(x for x in (image_path, alias_path) if x):
                        dmgMounts[path] = entity[u"mount-point"]
                        LogDebug(u"'%@' is already mounted at '%@'", path,
                                 entity[u"mount-point"])
                    break
                except IndexError:
                    pass
                except KeyError:
                    pass

        return dmgMounts
Example #8
0
 def listenOnSocket_withDelegate_(self, path, delegate):
     for oldsocket in glob.glob("%s.*" % path):
         LogDebug("Removing old socket %@", oldsocket)
         try:
             os.unlink(oldsocket)
         except:
             pass
     self.socketPath = NSString.stringWithFormat_("%@.%@", path, os.urandom(8).encode("hex"))
     LogDebug("Creating socket at %@", self.socketPath)
     self.delegate = delegate
     self.watchThread = NSThread.alloc().initWithTarget_selector_object_(self, "listenInBackground:", None)
     self.watchThread.start()
     return self.socketPath
Example #9
0
 def connection_didReceiveResponse_(self, connection, response):
     LogDebug("%@ status code %d", connection, response.statusCode())
     if response.expectedContentLength() == NSURLResponseUnknownLength:
         LogDebug("unknown response length")
     else:
         LogDebug("Downloading profile with %d bytes",
                  response.expectedContentLength())
         if self.profileUpdateWindow:
             self.progressBar.setMaxValue_(
                 float(response.expectedContentLength()))
             self.progressBar.setDoubleValue_(
                 float(response.expectedContentLength()))
             self.progressBar.setIndeterminate_(False)
Example #10
0
    def handleSourceMountResult_(self, result):
        LogDebug("handleSourceMountResult:%@", result)

        if not result["success"]:
            self.delegate.sourceFailed_text_(
                "Failed to mount %s" % result["dmg-path"],
                result["error-message"])
            return

        mountPoint = result["mount-point"]

        # Update the icon if we find an installer app.
        for path in glob.glob(os.path.join(mountPoint, "Install*.app")):
            self.delegate.foundSourceForIcon_(path)

        # Don't set this again since 10.9 mounts BaseSystem.dmg after InstallESD.dmg.
        if self.installerMountPoint is None:
            # Check if the source is an InstallESD, BaseSystem or system image.
            if os.path.exists(
                    os.path.join(mountPoint, "Packages", "OSInstall.mpkg")):
                self.installerMountPoint = mountPoint
                self.sourceType = IEDWorkflow.INSTALL_ESD
                LogDebug("sourceType = INSTALL_ESD")
            elif glob.glob(os.path.join(mountPoint, "Install*.app")):
                self.sourceType = IEDWorkflow.INSTALL_INFO
                LogDebug("sourceType = INSTALL_INFO")
            else:
                self.installerMountPoint = mountPoint
                self.sourceType = IEDWorkflow.SYSTEM_IMAGE
                LogDebug("sourceType = SYSTEM_IMAGE")

        baseSystemPath = os.path.join(mountPoint, "BaseSystem.dmg")

        # If we find a SystemVersion.plist we proceed to the next step.
        if os.path.exists(os.path.join(mountPoint, IEDUtil.VERSIONPLIST_PATH)):
            self.checkVersion_(mountPoint)
        # Otherwise check if there's a BaseSystem.dmg that we need to examine.
        elif os.path.exists(baseSystemPath):
            self.baseSystemMountedFromPath = baseSystemPath
            self.dmgHelper.attach_selector_(baseSystemPath,
                                            self.handleSourceMountResult_)
        else:
            if (self.sourceType == IEDWorkflow.INSTALL_ESD) and \
               (IEDUtil.hostMajorVersion() >= 13):
                self.delegate.sourceFailed_text_(
                    "Invalid source",
                    "InstallESD images aren't valid installers on 10.13+.")
                return
            self.delegate.sourceFailed_text_("Invalid source",
                                             "Couldn't find system version.")
Example #11
0
    def listenInBackground_(self, ignored):
        try:
            sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF,
                            (IEDSL_MAX_MSG_SIZE + 16) * IEDSL_MAX_MSG_COUNT)
            sock.bind(self.socketPath)
        except socket.error as e:
            LogError("Error creating datagram socket at %@: %@",
                     self.socketPath, str(e))
            return

        LogDebug("Listening to socket in background thread")
        while True:
            msg = sock.recv(IEDSL_MAX_MSG_SIZE, socket.MSG_WAITALL)
            if not msg:
                continue
            msgData = NSData.dataWithBytes_length_(msg, len(msg))
            plist, format, error = NSPropertyListSerialization.propertyListWithData_options_format_error_(
                msgData, NSPropertyListImmutable, None, None)
            if not plist:
                LogError("Error decoding plist: %@", error)
                continue
            if self.delegate.respondsToSelector_("socketReceivedMessage:"):
                self.delegate.performSelectorOnMainThread_withObject_waitUntilDone_(
                    "socketReceivedMessage:", plist, False)
Example #12
0
    def taskFinalize(self):
        LogNotice(u"Finalize task running")

        self.delegate.buildSetProgressMessage_(
            u"Scanning disk image for restore")
        # The script is wrapped with progresswatcher.py which parses script
        # output and sends it back as notifications to IEDSocketListener.
        args = [
            NSBundle.mainBundle().pathForResource_ofType_(
                u"progresswatcher", u"py"),
            u"--socket",
            self.listenerPath,
            u"imagescan",
            self.outputPath(),
        ]
        LogInfo(u"Launching finalize with arguments:")
        for arg in args:
            LogInfo(u"    '%@'", arg)
        try:
            p = subprocess.Popen(args,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT)
            out = p.communicate()[0].decode(u"utf-8")
            LogDebug(u"Finalize exited with status %d and output '%@'",
                     p.returncode, out)
            if p.returncode != 0:
                errMsg = u"Finalize task failed with status %d" % p.returncode
                LogError(u"%@: %@", errMsg, out)
                self.fail_details_(errMsg, out)
        except BaseException as e:
            LogError(u"Failed to launch finalize task: %@", unicode(e))
            self.fail_details_(u"Failed to launch finalize task", unicode(e))
Example #13
0
    def checkVersion_(self, mountPoint):
        LogDebug(u"checkVersion:%@", mountPoint)

        # We're now examining InstallESD.dmg for 10.7/10.8, BaseSystem.dmg for
        # 10.9, or a system image.
        name, version, build = IEDUtil.readSystemVersion_(mountPoint)
        if self.baseSystemMountedFromPath:
            self.dmgHelper.detach_selector_(self.baseSystemMountedFromPath,
                                            self.handleDetachResult_)
        installerVersion = tuple(int(x) for x in version.split(u"."))
        runningVersion = tuple(
            int(x) for x in platform.mac_ver()[0].split(u"."))
        LogNotice(u"Found source: %@ %@ %@", name, version, build)
        if installerVersion[:2] != runningVersion[:2]:
            self.delegate.ejectingSource()
            self.dmgHelper.detachAll_(self.rejectSource_)
            return
        LogNotice(u"Accepted source %@: %@ %@ %@", self.newSourcePath, name,
                  version, build)
        self._source = self.newSourcePath
        self.installerName = name
        self.installerVersion = version
        self.installerBuild = build
        info = {
            u"name": name,
            u"version": version,
            u"build": build,
            u"template": self.loadImageTemplate_(mountPoint),
            u"sourceType": self.sourceType,
        }
        self.delegate.sourceSucceeded_(info)
        # There's no reason to keep the dmg mounted if it's not an installer.
        if self.sourceType == IEDWorkflow.SYSTEM_IMAGE:
            self.dmgHelper.detachAll_(self.ejectSystemImage_)
Example #14
0
 def stopListening(self):
     LogDebug("stopListening")
     self.watchThread.cancel()
     try:
         os.unlink(self.socketPath)
     except BaseException as e:
         LogWarning("Couldn't remove listener socket %@: %@", self.socketPath, str(e))
Example #15
0
    def continueSetSource_(self, failedUnmounts):
        LogDebug("continueSetSource:%@", failedUnmounts)

        self.alertFailedUnmounts_(failedUnmounts)

        pathCandidates = [
            os.path.join(self.newSourcePath,
                         "Contents/SharedSupport/BaseSystem.dmg"),
            os.path.join(self.newSourcePath,
                         "Contents/SharedSupport/InstallESD.dmg"),
            self.newSourcePath,
        ]
        for path in pathCandidates:
            if os.path.exists(path):
                dmgPath = path
                break
        else:
            self.delegate.sourceFailed_text_(
                "Failed to mount %s" % self.newSourcePath,
                "No system dmg found")
            return

        self.delegate.examiningSource_(self.newSourcePath)

        self.installerMountPoint = None
        self.baseSystemMountedFromPath = None
        self.dmgHelper.attach_selector_(dmgPath, self.handleSourceMountResult_)
Example #16
0
    def awakeFromNib(self):
        LogDebug(u"awakeFromNib")

        # Initialize UI.
        self.buildProgressBar.setMaxValue_(100.0)
        self.buildProgressMessage.setStringValue_(u"")

        # We're a delegate for the drag and drop target, protocol:
        #   (void)acceptInstaller:(NSString *)path
        self.sourceBox.setDelegate_(self)
        self.sourceImage.setDelegate_(self)
        self.sourceLabel.setDelegate_(self)

        # We're a delegate for the update controller, protocol:
        #   (void)updateControllerChanged
        self.updateController.setDelegate_(self)

        # Main workflow logic.
        self.workflow = IEDWorkflow.alloc().initWithDelegate_(self)

        # Enabled state for main window.
        self.enabled = True

        # When busy is true quitting gets a confirmation prompt.
        self._busy = False

        # Currently loaded template.
        self.templateURL = None
Example #17
0
 def handleLaunchScriptError_(self, error):
     if isinstance(error, int):
         try:
             msg = {
                 -60001: "The authorization rights are invalid.",
                 -60002: "The authorization reference is invalid.",
                 -60003: "The authorization tag is invalid.",
                 -60004: "The returned authorization is invalid.",
                 -60005: "The authorization was denied.",
                 -60006: "The authorization was cancelled by the user.",
                 -60007: "The authorization was denied since no user interaction was possible.",
                 -60008: "Unable to obtain authorization for this operation.",
                 -60009: "The authorization is not allowed to be converted to an external format.",
                 -60010: "The authorization is not allowed to be created from an external format.",
                 -60011: "The provided option flag(s) are invalid for this authorization operation.",
                 -60031: "The specified program could not be executed.",
                 -60032: "An invalid status was returned during execution of a privileged tool.",
                 -60033: "The requested socket address is invalid (must be 0-1023 inclusive).",
             }[error]
         except KeyError:
             msg = "Unknown error (%d)." % error
     else:
         msg = error
     if error == -60006:
         LogDebug("User cancelled auth.")
         # User cancelled.
         self.stop()
     else:
         self.fail_details_("Build failed", msg)
Example #18
0
 def continueSetSource_(self, failedUnmounts):
     LogDebug("continueSetSource:%@", failedUnmounts)
     
     self.alertFailedUnmounts_(failedUnmounts)
     
     pathCandidates = [
         os.path.join(self.newSourcePath, "Contents/SharedSupport/BaseSystem.dmg"),
         os.path.join(self.newSourcePath, "Contents/SharedSupport/InstallESD.dmg"),
         self.newSourcePath,
     ]
     for path in pathCandidates:
         if os.path.isfile(path):
             dmgPath = path
             break
     else:
         iaToolPath = os.path.join(self.newSourcePath, "Contents/Resources/InstallAssistantTool")
         baseName = os.path.basename(self.newSourcePath)
         if os.path.exists(iaToolPath):
             self.delegate.sourceFailed_text_("Incomplete installer",
                                              "Installation resources are missing from '%s'. " % baseName +
                                              "Try downloading a new installer from the App Store straight from " +
                                              "Apple without using an internal Software Update or caching server.")
         else:
             self.delegate.sourceFailed_text_("Failed to mount %s" % self.newSourcePath,
                                              "No system dmg found")
         return
     
     self.delegate.examiningSource_(self.newSourcePath)
     
     self.installerMountPoint = None
     self.baseSystemMountedFromPath = None
     self.dmgHelper.attach_selector_(dmgPath, self.handleSourceMountResult_)
Example #19
0
 def handleDetachAllResult_(self, result):
     LogDebug("handleDetachAllResult:%@", result)
     if not result["success"]:
         self.detachAllFailed[result["dmg-path"]] = result["error-message"]
     self.detachAllRemaining -= 1
     if self.detachAllRemaining == 0:
         self.tellDelegate_message_(self.detachAllSelector, self.detachAllFailed)
Example #20
0
    def listApfsVolumes(cls):
        LogDebug("Listing APFS volumes")
        if cls.hostVersionTuple()[1] < 13:
            return {}
        p = subprocess.Popen(["/usr/sbin/diskutil", "apfs", "list", "-plist"],
                             bufsize=1,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        out, err = p.communicate()
        if p.returncode != 0:
            LogError("diskutil apfs list failed with return code %d" %
                     p.returncode)
            return None
        outData = NSData.dataWithBytes_length_(out, len(out))
        plist, format, error = \
            NSPropertyListSerialization.propertyListWithData_options_format_error_(outData,
                                                                                   NSPropertyListImmutable,
                                                                                   None,
                                                                                   None)
        if "Containers" not in plist:
            LogError("diskutil apfs list does not have any Containers")
            return None

        volumes = {}
        for container in plist["Containers"]:
            for volume in container.get("Volumes", []):
                volumes[volume["DeviceIdentifier"]] = volume
        return volumes
Example #21
0
    def downloadNextUpdate(self):
        if self.updates:
            self.package = self.updates.pop(0)
            self.bytesReceived = 0
            self.checksum = hashlib.sha1()
            self.delegate.downloadStarting_(self.package)

            path = self.cacheTmpPath_(self.package.sha1())
            if not NSFileManager.defaultManager(
            ).createFileAtPath_contents_attributes_(path, None, None):
                error = "Couldn't create temporary file at %s" % path
                self.delegate.downloadFailed_withError_(self.package, error)
                return
            self.fileHandle = NSFileHandle.fileHandleForWritingAtPath_(path)
            if not self.fileHandle:
                error = "Couldn't open %s for writing" % path
                self.delegate.downloadFailed_withError_(self.package, error)
                return

            LogDebug("Downloading %@ from %@", self.package.name(),
                     self.package.url())
            url = NSURL.URLWithString_(self.package.url())
            request = NSURLRequest.requestWithURL_(url)
            self.connection = NSURLConnection.connectionWithRequest_delegate_(
                request, self)
            if self.connection:
                self.delegate.downloadStarted_(self.package)
        else:
            self.delegate.downloadAllDone()
Example #22
0
    def saveTemplateToURL_(self, url):
        LogDebug("saveTemplateToURL:%@", url)
        self.templateURL = url
        NSDocumentController.sharedDocumentController(
        ).noteNewRecentDocumentURL_(url)

        # Create a template from the current state.
        template = IEDTemplate.alloc().init()
        if self.workflow.source():
            template.setSourcePath_(self.workflow.source())
        if self.updateController.packagesToInstall():
            template.setApplyUpdates_(True)
        else:
            template.setApplyUpdates_(False)
        if self.volumeName.stringValue():
            template.setVolumeName_(self.volumeName.stringValue())
        if self.volumeSize.intValue():
            template.setVolumeSize_(self.volumeSize.intValue())
        if self.finalizeAsrImagescan.state() == NSOffState:
            template.setFinalizeAsrImagescan_(False)
        if IEDUtil.hostMajorVersion() >= 13:
            template.setFilesystem_(
                self.filesystem.selectedItem().representedObject())
        template.setAdditionalPackages_(
            [x.path() for x in self.addPkgController.packagesToInstall()])

        error = template.saveTemplateAndReturnError_(url.path())
        if error:
            self.displayAlert_text_("Couldn't save template", error)
Example #23
0
    def getInstalledPkgSize_(cls, pkgPath):
        # For apps just return the size on disk.
        ext = os.path.splitext(pkgPath)[1].lower()
        if ext == ".app":
            return cls.getPackageSize_(pkgPath)
        elif ext in (".pkg", ".mpkg"):
            # For packages first try to get the size requirements with
            # installer.
            size = cls.getInstalledPkgSizeFromInstaller_(pkgPath)
            if size is None:
                # If this fails, manually extract the size requirements from
                # the package.
                return cls.calculateInstalledPkgSize_(pkgPath)
            else:
                return size
        elif os.path.basename(pkgPath) == "InstallInfo.plist":
            iedPath = os.path.join(os.path.dirname(pkgPath), "InstallESD.dmg")
            try:
                iedSize = os.stat(iedPath).st_size
                estimatedSize = int(iedSize * 2.72127696157)
                LogDebug(
                    "Estimating size requirements of InstallInfo.plist to %@",
                    cls.formatByteSize_(estimatedSize))
                return estimatedSize
            except OSError:
                pass

        LogError("Don't know how to calculate installed size for '%@'",
                 pkgPath)
        return None
 def downloadAllDone(self):
     LogDebug("downloadAllDone")
     self.downloadWindow.orderOut_(self)
     self.countDownloads()
     self.enableControls()
     if self.delegate:
         self.delegate.updateControllerChanged()
 def loadProfileForVersion_build_(self, version, build):
     LogDebug("loadProfileForVersion:%@ build:%@", version, build)
     self.version = version
     self.build = build
     self.updates = list()
     profile = self.profileController.profileForVersion_Build_(
         version, build)
     if profile is None:
         # No update profile for this build, try to figure out why.
         self.profileWarning = self.profileController.whyNoProfileForVersion_build_(
             version, build)
     else:
         if self.profileController.deprecatedOS:
             self.profileWarning = "No longer updated by Apple"
         else:
             self.profileWarning = None
         for update in profile:
             package = IEDPackage.alloc().init()
             package.setName_(update["name"])
             package.setPath_(self.cache.updatePath_(update["sha1"]))
             package.setSize_(update["size"])
             package.setUrl_(update["url"])
             package.setSha1_(update["sha1"])
             # Image is set by countDownloads().
             self.updates.append(package)
     self.countDownloads()
Example #26
0
 def downloadStarting_(self, package):
     LogDebug("downloadStarting:")
     self.downloadProgressBar.setIndeterminate_(False)
     self.downloadProgressBar.setDoubleValue_(0.0)
     self.downloadProgressBar.setMaxValue_(package.size())
     self.downloadCounter += 1
     self.downloadLabel.setStringValue_("%s (%s)" % (package.name(), IEDUtil.formatByteSize_(package.size())))
Example #27
0
 def hdiutilAttach_(self, args):
     try:
         dmgPath, selector = args
         LogDebug(u"Attaching %@", dmgPath)
         p = subprocess.Popen([u"/usr/bin/hdiutil",
                               u"attach",
                               dmgPath,
                               u"-mountRandom", u"/tmp",
                               u"-nobrowse",
                               u"-noverify",
                               u"-plist"],
                              bufsize=1,
                              stdin=subprocess.PIPE,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
         out, err = p.communicate(u"Y\n")
         LogDebug(u"Checking result of attaching %@", dmgPath)
         if p.returncode != 0:
             errstr = u"hdiutil attach failed with return code %d" % p.returncode
             if err:
                 errstr += u": %s" % err.decode(u"utf-8")
             self.tellDelegate_message_(selector, {u"success": False,
                                                   u"dmg-path": dmgPath,
                                                   u"error-message": errstr})
             return
         # Strip EULA text.
         xmlStartIndex = out.find("<?xml")
         plist = plistlib.readPlistFromString(out[xmlStartIndex:])
         for partition in plist[u"system-entities"]:
             if partition.get(u"potentially-mountable") == 1:
                 if u"mount-point" in partition:
                     self.dmgs[dmgPath] = partition[u"mount-point"]
                     break
         else:
             self.tellDelegate_message_(selector, {u"success": False,
                                                   u"dmg-path": dmgPath,
                                                   u"error-message": u"No mounted filesystem in %s" % dmgPath})
             return
         self.tellDelegate_message_(selector, {u"success": True,
                                               u"dmg-path": dmgPath,
                                               u"mount-point": self.dmgs[dmgPath]})
     except Exception:
         exceptionInfo = traceback.format_exc()
         msg = u"Attach of %s crashed with exception:\n%s" % (dmgPath, exceptionInfo)
         self.tellDelegate_message_(selector, {u"success": False,
                                               u"dmg-path": dmgPath,
                                               u"error-message": msg})
Example #28
0
 def checkAppleBugWarning_(self, path):
     LogDebug("checkAppleBugWarning:%@", path)
     if (IEDUtil.hostMajorVersion() != 14):
         return True
     LogDebug("We're running on Mojave")
     if not path.endswith(".app"):
         return True
     LogDebug("The source is a .app")
     if IEDUtil.volumePathForPath_(path) != "/":
         return True
     LogError("The source is an installer app on a Mojave system volume")
     text = "A bug in the OS installer (radar 43296160) causes installs to fail " \
         "if the Mojave installer is on the system volume. Copy it to an external " \
         "volume or wrap it in a dmg before dropping it on AutoDMG."
     self.delegate.sourceFailed_text_("Install will fail due to Apple bug",
                                      text)
     return False
Example #29
0
 def connection_didReceiveResponse_(self, connection, response):
     LogDebug(u"%@ status code %d", self.package.name(), response.statusCode())
     if response.statusCode() >= 400:
         connection.cancel()
         self.fileHandle.closeFile()
         error = u"%s failed with HTTP %d" % (self.package.name(), response.statusCode())
         self.delegate.downloadFailed_withError_(self.package, error)
         self.delegate.downloadAllDone()
Example #30
0
 def setSource_(self, path):
     LogDebug(u"setSource:%@", path)
     
     self._source = None
     self.newSourcePath = path
     if self.installerMountPoint:
         self.delegate.ejectingSource()
         self.dmgHelper.detachAll_(self.continueSetSource_)
     else:
         self.continueSetSource_({})