コード例 #1
0
ファイル: IEDController.py プロジェクト: bing050802/AutoDMG
 def sourceSucceeded_(self, info):
     self.installerName = info["name"]
     self.installerVersion = info["version"]
     self.installerBuild = info["build"]
     self.sourceLabel.setStringValue_(
         "%s %s %s" % (info["name"], info["version"], info["build"]))
     self.sourceLabel.setTextColor_(NSColor.controlTextColor())
     self.updateController.loadProfileForVersion_build_(
         info["version"], info["build"])
     template = info["template"]
     if template:
         LogInfo("Template found in image: %@", repr(template))
         # Don't default to applying updates to an image that was built
         # with updates applied, and vice versa.
         if template.applyUpdates:
             self.updateController.applyUpdatesCheckbox.setState_(
                 NSOffState)
         else:
             self.updateController.applyUpdatesCheckbox.setState_(NSOnState)
     else:
         if info["sourceType"] == IEDWorkflow.SYSTEM_IMAGE:
             LogInfo("No template found in image")
             # If the image doesn't have a template inside, assume that updates
             # were applied.
             self.updateController.applyUpdatesCheckbox.setState_(
                 NSOffState)
     self.setBusy_(False)
コード例 #2
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))
コード例 #3
0
    def taskInstall(self):
        LogNotice("Install task running")

        # The script is wrapped with progresswatcher.py which parses script
        # output and sends it back as notifications to IEDSocketListener.
        args = [
            NSBundle.mainBundle().pathForResource_ofType_(
                "progresswatcher", "py"),
            "--cd",
            NSBundle.mainBundle().resourcePath(),
            "--socket",
            self.listenerPath,
            "installesdtodmg",
            "--user",
            str(os.getuid()),
            "--group",
            str(os.getgid()),
            "--fstype",
            self.filesystem(),
            "--output",
            self.outputPath(),
            "--volume-name",
            self.volumeName(),
            "--size",
            str(self.volumeSize()),
            "--template",
            self.templatePath,
        ]
        if self.sourceType == IEDWorkflow.SYSTEM_IMAGE:
            args.extend(["--baseimage", self.source()])
        args.extend(self.packagesToInstall)
        LogInfo("Launching install with arguments:")
        for arg in args:
            LogInfo("    '%@'", arg)
        self.performSelectorInBackground_withObject_(self.launchScript_, args)
コード例 #4
0
 def setAdditionalPackages_(self, packagePaths):
     for packagePath in packagePaths:
         path = IEDUtil.resolvePath_(os.path.expanduser(packagePath))
         if not path:
             LogError(u"Package '%@' not found", packagePath)
             return False
         if path not in self.additionalPackages:
             LogInfo(u"Adding '%@' to additional packages", path)
             self.additionalPackages.append(IEDUtil.resolvePath_(path))
         else:
             LogInfo(u"Skipping duplicate package '%@'", path)
     return True
コード例 #5
0
ファイル: IEDAppDelegate.py プロジェクト: keeleysam/AutoDMG
    def initialize(self):
        # Log version info on startup.
        version, build = IEDUtil.getAppVersion()
        LogInfo("AutoDMG v%@ build %@", version, build)
        name, version, build = IEDUtil.readSystemVersion_("/")
        LogInfo("%@ %@ %@", name, version, build)
        LogInfo("%@ %@ (%@)", platform.python_implementation(),
                platform.python_version(), platform.python_compiler())
        LogInfo("PyObjC %@", pyObjCVersion)

        # Initialize user defaults before application starts.
        defaultsPath = NSBundle.mainBundle().pathForResource_ofType_(
            "Defaults", "plist")
        defaultsDict = NSDictionary.dictionaryWithContentsOfFile_(defaultsPath)
        defaults.registerDefaults_(defaultsDict)
コード例 #6
0
 def checkForProfileUpdates_(self, sender):
     LogInfo(u"Checking for updates")
     self.disableControls()
     defaults = NSUserDefaults.standardUserDefaults()
     url = NSURL.URLWithString_(
         defaults.stringForKey_(u"UpdateProfilesURL"))
     self.profileController.updateFromURL_(url)
コード例 #7
0
ファイル: IEDWorkflow.py プロジェクト: cev2107/AutoDMG
 def taskFinalize(self):
     LogNotice("Finalize task running")
     
     self.delegate.buildSetProgressMessage_("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_("progresswatcher", "py"),
         "--socket", self.listenerPath,
         "imagescan",
         self.outputPath(),
     ]
     LogInfo("Launching finalize with arguments:")
     for arg in args:
         LogInfo("    '%@'", arg)
     self.performSelectorInBackground_withObject_(self.launchFinalize_, args)
コード例 #8
0
    def loadProfilesFromPlist_(self, plist):
        """Load UpdateProfiles from a plist dictionary."""

        LogInfo(u"Loading update profiles with PublicationDate %@",
                plist[u"PublicationDate"])
        self.profiles = dict()
        for name, updates in plist[u"Profiles"].iteritems():
            profile = list()
            for update in updates:
                profile.append(plist[u"Updates"][update])
            self.profiles[name] = profile
        self.publicationDate = plist[u"PublicationDate"]
        self.updatePaths = dict()
        for name, update in plist[u"Updates"].iteritems():
            filename, ext = os.path.splitext(os.path.basename(update[u"url"]))
            self.updatePaths[update[u"sha1"]] = u"%s(%s)%s" % (
                filename, update[u"sha1"][:7], ext)
        self.deprecatedInstallerBuilds = dict()
        try:
            for replacement, builds in plist[
                    u"DeprecatedInstallers"].iteritems():
                for build in builds:
                    self.deprecatedInstallerBuilds[build] = replacement
        except KeyError:
            LogWarning(u"No deprecated installers")
        if self.delegate:
            self.delegate.profilesUpdated()
コード例 #9
0
 def doCheckForProfileUpdates(self):
     LogInfo("Checking for updates")
     self.dateBeforeUpdating = self.profileController.publicationDate
     self.disableControls()
     defaults = NSUserDefaults.standardUserDefaults()
     url = NSURL.URLWithString_(defaults.stringForKey_("UpdateProfilesURL"))
     self.profileController.updateFromURL_(url)
コード例 #10
0
 def connectionDidFinishLoading_(self, connection):
     LogInfo(u"%@ finished downloading to %@", self.package.name(),
             self.cacheTmpPath_(self.package.sha1()))
     self.fileHandle.closeFile()
     self.delegate.downloadStopped_(self.package)
     if self.checksum.hexdigest() == self.package.sha1():
         try:
             os.rename(self.cacheTmpPath_(self.package.sha1()),
                       self.cachePath_(self.package.sha1()))
         except OSError as e:
             error = u"Failed when moving download to %s: %s" % (
                 self.cachePath_(self.package.sha1()), unicode(e))
             LogError(error)
             self.delegate.downloadFailed_withError_(self.package, error)
             return
         linkPath = self.updatePath_(self.package.sha1())
         try:
             os.symlink(self.package.sha1(), linkPath)
         except OSError as e:
             error = u"Failed when creating link from %s to %s: %s" % (
                 self.package.sha1(), linkPath, unicode(e))
             LogError(error)
             self.delegate.downloadFailed_withError_(self.package, error)
             return
         LogNotice(u"%@ added to cache with sha1 %@", self.package.name(),
                   self.package.sha1())
         self.delegate.downloadSucceeded_(self.package)
         self.downloadNextUpdate()
     else:
         error = u"Expected sha1 checksum %s but got %s" % (
             sha1.lower(), m.hexdigest().lower())
         LogError(error)
         self.delegate.downloadFailed_withError_(self.package, error)
コード例 #11
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)
     subprocess.Popen(args)
コード例 #12
0
    def saveUsersProfiles_(self, plist):
        """Save UpdateProfiles.plist to application support."""

        LogInfo("Saving update profiles with PublicationDate %@",
                plist["PublicationDate"])
        if not plist.writeToFile_atomically_(self.userUpdateProfilesPath,
                                             False):
            LogError("Failed to write %@", self.userUpdateProfilesPath)
コード例 #13
0
ファイル: IEDTemplate.py プロジェクト: yungmichael/AutoDMG
    def loadTemplateAndReturnError_(self, path):
        if path in self.loadedTemplates:
            return "%s included recursively" % path
        else:
            self.loadedTemplates.add(path)

        plist = NSDictionary.dictionaryWithContentsOfFile_(path)
        if not plist:
            error = "Couldn't read dictionary from plist at %s" % (path)
            LogWarning("%@", error)
            return error

        templateFormat = plist.get("TemplateFormat", "1.0")

        if templateFormat not in ["1.0", "1.1"]:
            LogWarning("Unknown format version %@", templateFormat)

        for key in plist.iterkeys():
            if key == "IncludeTemplates":
                for includePath in plist["IncludeTemplates"]:
                    LogInfo("Including template %@", includePath)
                    error = self.loadTemplateAndReturnError_(includePath)
                    if error:
                        return error
            elif key == "SourcePath":
                self.setSourcePath_(plist["SourcePath"])
            elif key == "ApplyUpdates":
                self.setApplyUpdates_(plist["ApplyUpdates"])
            elif key == "AdditionalPackages":
                if not self.setAdditionalPackages_(
                        plist["AdditionalPackages"]):
                    msg = "Additional packages failed verification"
                    if self.additionalPackageError:
                        msg += ":\n" + self.additionalPackageError
                    return msg
            elif key == "OutputPath":
                self.setOutputPath_(plist["OutputPath"])
            elif key == "VolumeName":
                self.setVolumeName_(plist["VolumeName"])
            elif key == "VolumeSize":
                self.setVolumeSize_(plist["VolumeSize"])
            elif key == "FinalizeAsrImagescan":
                self.setFinalizeAsrImagescan_(plist["FinalizeAsrImagescan"])
            elif key == "Filesystem":
                if plist["Filesystem"] not in ["apfs", "hfs"]:
                    error = "Unknown Filesystem value '%s'" % plist[
                        "Filesystem"]
                    return error
                self.setFilesystem_(plist["Filesystem"])
            elif key == "TemplateFormat":
                pass

            else:
                LogWarning("Unknown key '%@' in template", key)

        return None
コード例 #14
0
 def downloadGotData_bytesRead_(self, package, bytes):
     percent = 100.0 * float(bytes) / float(package.size())
     # Log progress if we've downloaded more than 10%, more than one second
     # has passed, or if we're at 100%.
     if (abs(percent - self.lastProgressPercent) >= 10.0) or \
        (abs(self.lastProgressTimestamp.timeIntervalSinceNow()) >= 1.0) or \
        (bytes == package.size()):
         LogInfo("progress: %.1f%%", percent)
         self.lastProgressPercent = percent
         self.lastProgressTimestamp = NSDate.alloc().init()
コード例 #15
0
 def setAdditionalPackages_(self, packagePaths):
     self.additionalPackageError = None
     for packagePath in packagePaths:
         path = IEDUtil.resolvePath_(
             os.path.abspath(os.path.expanduser(packagePath)))
         if not os.path.exists(path):
             self.additionalPackageError = u"Package '%s' not found" % packagePath
             LogError(u"'%@'", self.additionalPackageError)
             return False
         name, ext = os.path.splitext(path)
         if ext.lower() not in IEDUtil.PACKAGE_EXTENSIONS:
             self.additionalPackageError = u"'%s' is not valid software package" % packagePath
             LogError(u"'%@'", self.additionalPackageError)
             return False
         if path not in self.additionalPackages:
             LogInfo(u"Adding '%@' to additional packages", path)
             self.additionalPackages.append(IEDUtil.resolvePath_(path))
         else:
             LogInfo(u"Skipping duplicate package '%@'", path)
     return True
コード例 #16
0
    def profileForVersion_Build_(self, version, build):
        """Return the update profile for a certain OS X version and build."""

        try:
            profile = self.profiles["%s-%s" % (version, build)]
            LogInfo("Update profile for %@ %@: %@", version, build,
                    ", ".join(u["name"] for u in profile))
        except KeyError:
            profile = None
            LogNotice("No update profile for %@ %@", version, build)
        return profile
コード例 #17
0
ファイル: IEDWorkflow.py プロジェクト: cev2107/AutoDMG
 def taskPrepare(self):
     LogDebug("taskPrepare")
     
     # Attach any disk images containing update packages.
     self.attachedPackageDMGs = dict()
     self.numberOfDMGsToAttach = 0
     for package in self.additionalPackages:
         if package.path().endswith(".dmg"):
             self.numberOfDMGsToAttach += 1
             LogInfo("Attaching %@", package.path())
             self.dmgHelper.attach_selector_(package.path(), self.attachPackageDMG_)
     if self.numberOfDMGsToAttach == 0:
         self.continuePrepare()
コード例 #18
0
    def loadTemplateAndReturnError_(self, path):
        if path in self.loadedTemplates:
            return u"%s included recursively" % path
        else:
            self.loadedTemplates.add(path)

        plist = NSDictionary.dictionaryWithContentsOfFile_(path)
        if not plist:
            error = u"Couldn't read dictionary from plist at %s" % (path)
            LogWarning(u"%@", error)
            return error

        templateFormat = plist.get(u"TemplateFormat", u"1.0")

        if templateFormat != u"1.0":
            LogWarning(u"Unknown format version %@", templateFormat)

        for key in plist.keys():
            if key == u"IncludeTemplates":
                for includePath in plist[u"IncludeTemplates"]:
                    LogInfo(u"Including template %@", includePath)
                    error = self.loadTemplateAndReturnError_(includePath)
                    if error:
                        return error
            elif key == u"SourcePath":
                self.setSourcePath_(plist[u"SourcePath"])
            elif key == u"ApplyUpdates":
                self.setApplyUpdates_(plist[u"ApplyUpdates"])
            elif key == u"AdditionalPackages":
                if not self.setAdditionalPackages_(
                        plist[u"AdditionalPackages"]):
                    msg = u"Additional packages failed verification"
                    if self.additionalPackageError:
                        msg += u":\n" + self.additionalPackageError
                    return msg
            elif key == u"OutputPath":
                self.setOutputPath_(plist[u"OutputPath"])
            elif key == u"VolumeName":
                self.setVolumeName_(plist[u"VolumeName"])
            elif key == u"VolumeSize":
                self.setVolumeSize_(plist[u"VolumeSize"])
            elif key == u"FinalizeAsrImagescan":
                self.setFinalizeAsrImagescan_(plist[u"FinalizeAsrImagescan"])
            elif key == u"TemplateFormat":
                pass

            else:
                LogWarning(u"Unknown key '%@' in template", key)

        return None
コード例 #19
0
    def loadProfilesFromPlist_(self, plist):
        """Load UpdateProfiles from a plist dictionary."""

        LogInfo("Loading update profiles with PublicationDate %@",
                plist["PublicationDate"])

        try:
            # FIXME: Add profile verification.

            self.profiles = dict()
            for name, updates in plist["Profiles"].iteritems():
                profile = list()
                for update in updates:
                    profile.append(plist["Updates"][update])
                self.profiles[name] = profile

            self.publicationDate = plist["PublicationDate"]

            self.updatePaths = dict()
            for name, update in plist["Updates"].iteritems():
                filename, ext = os.path.splitext(
                    os.path.basename(update["url"]))
                self.updatePaths[update["sha1"]] = "%s(%s)%s" % (
                    filename, update["sha1"][:7], ext)

            self.deprecatedInstallerBuilds = dict()
            try:
                for replacement, builds in plist[
                        "DeprecatedInstallers"].iteritems():
                    for build in builds:
                        self.deprecatedInstallerBuilds[build] = replacement
            except KeyError:
                LogWarning("No deprecated installers in profile")

            self.deprecatedOS = False
            try:
                for osVerStr in plist["DeprecatedOSVersions"]:
                    deprecatedVerMajor = IEDUtil.splitVersion(osVerStr)[1]
                    if IEDUtil.hostMajorVersion() <= deprecatedVerMajor:
                        self.deprecatedOS = True
                        LogWarning("%@ is no longer being updated by Apple",
                                   osVerStr)
                        break
            except KeyError:
                LogWarning("No deprecated OS versions in profile")

            if self.delegate:
                self.delegate.profilesUpdated()
        except BaseException as e:
            LogError("Failed to load profile: %@", unicode(e))
コード例 #20
0
    def socketReceivedMessage_(self, msg):
        # The message is a dictionary with "action" as the only required key.
        action = msg["action"]

        if action == "update_progress":
            percent = msg["percent"]
            currentProgress = self.progress + self.currentPhase[
                "weight"] * percent / 100.0
            self.delegate.buildSetProgress_(currentProgress)

        elif action == "update_message":
            if self.lastUpdateMessage != msg["message"]:
                # Only log update messages when they change.
                LogInfo("%@", msg["message"])
            self.lastUpdateMessage = msg["message"]
            self.delegate.buildSetProgressMessage_(msg["message"])

        elif action == "select_phase":
            LogNotice("Script phase: %@", msg["phase"])
            self.nextPhase()

        elif action == "log_message":
            LogMessage(msg["log_level"], msg["message"])

        elif action == "notify_failure":
            self.fail_details_("Build failed", msg["message"])

        elif action == "notify_success":
            LogNotice("Build success: %@", msg["message"])

        elif action == "task_done":
            status = msg["termination_status"]
            if status == 0:
                self.nextTask()
            else:
                details = NSString.stringWithFormat_(
                    "Task exited with status %@", msg["termination_status"])
                LogError("%@", details)
                # Status codes 100-199 are from installesdtodmg.sh, and have
                # been preceeded by a "notify_failure" message.
                if (status < 100) or (status > 199):
                    self.fail_details_("Build failed", details)

        else:
            self.fail_details_("Unknown progress notification", "Message: %@",
                               msg)
コード例 #21
0
    def nextPhase(self):
        LogDebug("nextPhase, currentPhase == %@", self.currentPhase)

        if self.currentPhase:
            self.progress += self.currentPhase["weight"]
            LogInfo("Phase %@ with weight %ld finished after %.3f seconds",
                    self.currentPhase["title"], self.currentPhase["weight"],
                    time.time() - self.phaseStartTime)
        self.phaseStartTime = time.time()
        try:
            self.currentPhase = self.currentTask["phases"].pop(0)
        except IndexError:
            self.fail_details_("No phase left in task",
                               traceback.format_stack())
            return
        LogNotice("Starting phase: %@", self.currentPhase["title"])
        self.delegate.buildSetPhase_(self.currentPhase["title"])
        self.delegate.buildSetProgress_(self.progress)
コード例 #22
0
    def pruneAndCreateSymlinks(self, symlinks):
        LogInfo(u"Pruning cache")

        self.symlinks = symlinks

        # Create a reverse dictionary and a set of filenames.
        names = dict()
        filenames = set()
        for sha1, name in symlinks.iteritems():
            names[name] = sha1
            filenames.add(name)
            filenames.add(sha1)

        for item in os.listdir(self.updateDir):
            try:
                itempath = os.path.join(self.updateDir, item)
                if item not in filenames:
                    LogInfo(u"Removing %s" % item)
                    os.unlink(itempath)
            except OSError as e:
                LogWarning(u"Cache pruning of %s failed: %s" %
                           (item, unicode(e)))
        for sha1 in symlinks.iterkeys():
            sha1Path = self.cachePath_(sha1)
            linkPath = self.updatePath_(sha1)
            name = os.path.basename(linkPath)
            if os.path.exists(sha1Path):
                if os.path.lexists(linkPath):
                    if os.readlink(linkPath) == sha1:
                        LogInfo(u"Found %s -> %s" % (name, sha1))
                        continue
                    LogInfo(u"Removing stale link %s -> %s" %
                            (name, os.readlink(linkPath)))
                    try:
                        os.unlink(linkPath)
                    except OSError as e:
                        LogWarning(u"Cache pruning of %s failed: %s" %
                                   (name, unicode(c)))
                        continue
                LogInfo(u"Creating %s -> %s" % (name, sha1))
                os.symlink(sha1, linkPath)
            else:
                if os.path.lexists(linkPath):
                    LogInfo(u"Removing stale link %s -> %s" %
                            (name, os.readlink(linkPath)))
                    try:
                        os.unlink(linkPath)
                    except OSError as e:
                        LogWarning(u"Cache pruning of %s failed: %s" %
                                   (name, unicode(c)))
コード例 #23
0
def cli_main(argv):
    IEDLog.IEDLogToController = False
    IEDLog.IEDLogToSyslog = True
    IEDLog.IEDLogToStdOut = True
    IEDLog.IEDLogToFile = False

    from IEDCLIController import IEDCLIController
    clicontroller = IEDCLIController.alloc().init()

    try:
        # Initialize user defaults before application starts.
        defaults = NSUserDefaults.standardUserDefaults()
        defaultsPath = NSBundle.mainBundle().pathForResource_ofType_(
            u"Defaults", u"plist")
        defaultsDict = NSDictionary.dictionaryWithContentsOfFile_(defaultsPath)
        defaults.registerDefaults_(defaultsDict)

        p = argparse.ArgumentParser()
        p.add_argument(u"-v",
                       u"--verbose",
                       action=u"store_true",
                       help=u"Verbose output")
        p.add_argument(u"-L",
                       u"--log-level",
                       type=int,
                       choices=range(0, 8),
                       default=6,
                       metavar=u"LEVEL",
                       help=u"Log level (0-7), default 6")
        p.add_argument(u"-l", u"--logfile", help=u"Log to file")
        p.add_argument(u"-r",
                       u"--root",
                       action=u"store_true",
                       help=u"Allow running as root")
        sp = p.add_subparsers(title=u"subcommands", dest=u"subcommand")

        # Populate subparser for each verb.
        for verb in clicontroller.listVerbs():
            verb_method = getattr(clicontroller, u"cmd%s_" % verb.capitalize())
            addargs_method = getattr(clicontroller,
                                     u"addargs%s_" % verb.capitalize())
            parser = sp.add_parser(verb, help=verb_method.__doc__)
            addargs_method(parser)
            parser.set_defaults(func=verb_method)

        args = p.parse_args(argv)

        if args.verbose:
            IEDLog.IEDLogStdOutLogLevel = IEDLog.IEDLogLevelInfo
        else:
            IEDLog.IEDLogStdOutLogLevel = IEDLog.IEDLogLevelNotice

        IEDLog.IEDLogFileLogLevel = args.log_level

        if args.logfile == u"-":
            # Redirect log to stdout instead.
            IEDLog.IEDLogFileHandle = sys.stdout
            IEDLog.IEDLogToFile = True
            IEDLog.IEDLogToStdOut = False
        else:
            try:
                if args.logfile:
                    logFile = args.logfile
                else:
                    logFile = os.path.join(
                        get_log_dir(), u"AutoDMG-%s.log" % get_date_string())
                IEDLog.IEDLogFileHandle = open(logFile, u"a", buffering=1)
            except OSError as e:
                print >> sys.stderr, (u"Couldn't open %s for writing" %
                                      logFile).encode(u"utf-8")
                return os.EX_CANTCREAT
            IEDLog.IEDLogToFile = True

        # Check if we're running with root.
        if os.getuid() == 0:
            if args.root:
                fm = NSFileManager.defaultManager()
                url, error = fm.URLForDirectory_inDomain_appropriateForURL_create_error_(
                    NSApplicationSupportDirectory, NSUserDomainMask, None,
                    False, None)
                LogWarning(u"Running as root, using %@",
                           os.path.join(url.path(), u"AutoDMG"))
            else:
                LogError(
                    u"Running as root isn't recommended (use -r to override)")
                return os.EX_USAGE

        # Log version info on startup.
        version, build = IEDUtil.getAppVersion()
        LogInfo(u"AutoDMG v%@ build %@", version, build)
        name, version, build = IEDUtil.readSystemVersion_(u"/")
        LogInfo(u"%@ %@ %@", name, version, build)
        LogInfo(u"%@ %@ (%@)", platform.python_implementation(),
                platform.python_version(), platform.python_compiler())
        LogInfo(u"PyObjC %@", objc.__version__)

        return args.func(args)
    finally:
        clicontroller.cleanup()
コード例 #24
0
    def start(self):
        LogNotice("Starting build")
        LogNotice("Using installer: %@ %@ %@", self.installerName,
                  self.installerVersion, self.installerBuild)
        LogNotice("Using output path: %@", self.outputPath())
        LogNotice("TMPDIR is set to: %@", os.getenv("TMPDIR"))
        self.delegate.buildStartingWithOutput_(self.outputPath())

        self.createTempDir()
        LogDebug("Created temporary directory at %@", self.tempDir)

        if not self.template():
            self.fail_details_(
                "Template missing",
                "A template for inclusion in the image is required.")
            return

        datestamp = datetime.datetime.today().strftime("%Y%m%d")
        self.templatePath = os.path.join(self.tempDir,
                                         "AutoDMG-%s.adtmpl" % datestamp)
        LogDebug("Saving template to %@", self.templatePath)
        error = self.template().saveTemplateAndReturnError_(self.templatePath)
        if error:
            self.fail_details_("Couldn't save template to tempdir", error)
            return

        # The workflow is split into tasks, and each task has one or more
        # phases. Each phase of the installation is given a weight for the
        # progress bar, calculated from the size of the installer package.
        # Phases that don't install packages get an estimated weight.

        self.tasks = list()

        # Prepare for install.
        self.tasks.append({
            "title":
            "Prepare",
            "method":
            self.taskPrepare,
            "phases": [
                {
                    "title": "Preparing",
                    "weight": 34 * 1024 * 1024
                },
            ],
        })

        # Perform installation.
        installerPhases = [
            {
                "title": "Starting install",
                "weight": 21 * 1024 * 1024
            },
            {
                "title": "Creating disk image",
                "weight": 21 * 1024 * 1024
            },
        ]
        if self.sourceType != IEDWorkflow.SYSTEM_IMAGE:
            installerPhases.append({
                "title": "Installing OS",
                "weight": 4 * 1024 * 1024 * 1024,
            })
        for package in self.additionalPackages:
            installerPhases.append({
                "title":
                "Installing %s" % package.name(),
                # Add 100 MB to the weight to account for overhead.
                "weight":
                package.size() + 100 * 1024 * 1024,
            })
        installerPhases.extend([
            # hdiutil convert.
            {
                "title": "Converting disk image",
                "weight": 313 * 1024 * 1024
            },
        ])
        self.tasks.append({
            "title": "Install",
            "method": self.taskInstall,
            "phases": installerPhases,
        })

        # Finalize image. (Skip adding this task if Finalize: Scan for restore is unchecked.)
        if self._finalizeAsrImagescan:
            self.tasks.append({
                "title":
                "Finalize",
                "method":
                self.taskFinalize,
                "phases": [
                    {
                        "title": "Scanning disk image",
                        "weight": 2 * 1024 * 1024
                    },
                    {
                        "title": "Scanning disk image",
                        "weight": 1 * 1024 * 1024
                    },
                    {
                        "title": "Scanning disk image",
                        "weight": 150 * 1024 * 1024
                    },
                    {
                        "title": "Scanning disk image",
                        "weight": 17 * 1024 * 1024,
                        "optional": True
                    },
                ],
            })

        # Finish build.
        self.tasks.append({
            "title":
            "Finish",
            "method":
            self.taskFinish,
            "phases": [
                {
                    "title": "Finishing",
                    "weight": 1 * 1024 * 1024
                },
            ],
        })

        # Calculate total weight of all phases.
        self.totalWeight = 0
        for task in self.tasks:
            LogInfo("Task %@ with %d phases:", task["method"].__name__,
                    len(task["phases"]))
            for phase in task["phases"]:
                LogInfo("    Phase '%@' with weight %.1f", phase["title"],
                        phase["weight"] / 1048576.0)
                self.totalWeight += phase["weight"]
        self.delegate.buildSetTotalWeight_(self.totalWeight)

        # Start the first task.
        self.progress = 0
        self.currentTask = None
        self.currentPhase = None
        self.nextTask()
コード例 #25
0
 def cancelUpdateDownload(self):
     LogInfo("User canceled profile update")
     self.connection.cancel()
     self.profileUpdateWindow.orderOut_(self)
コード例 #26
0
    def continuePrepare(self):
        LogDebug("continuePrepare")

        # Generate a list of packages to install.
        self.packagesToInstall = list()
        if self.sourceType == IEDWorkflow.INSTALL_ESD:
            self.packagesToInstall.append(
                os.path.join(self.installerMountPoint, "Packages",
                             "OSInstall.mpkg"))
        elif self.sourceType == IEDWorkflow.INSTALL_INFO:
            self.packagesToInstall.append(
                os.path.join(self.newSourcePath, "Contents", "SharedSupport",
                             "InstallInfo.plist"))
        for package in self.additionalPackages:
            if package.path().endswith(".dmg"):
                mountPoint = self.attachedPackageDMGs[package.path()]
                LogDebug("Looking for packages and applications in %@: %@",
                         mountPoint, glob.glob(os.path.join(mountPoint, "*")))
                packagePaths = glob.glob(os.path.join(mountPoint, "*.mpkg"))
                packagePaths += glob.glob(os.path.join(mountPoint, "*.pkg"))
                packagePaths += glob.glob(os.path.join(mountPoint, "*.app"))
                if len(packagePaths) == 0:
                    self.fail_details_(
                        "Nothing found to install",
                        "No package or application found in %s" %
                        package.name())
                    return
                elif len(packagePaths) > 1:
                    LogWarning("Multiple items found in %@, using %@",
                               package.path(), packagePaths[0])
                self.packagesToInstall.append(packagePaths[0])
            else:
                self.packagesToInstall.append(package.path())
        if len(self.packagesToInstall) == 0:
            self.delegate.buildFailed_details_(
                "Nothing to do", "There are no packages to install")
            self.stop()
            return

        # Calculate disk image size requirements.
        sizeRequirement = 0
        LogInfo("%d packages to install:", len(self.packagesToInstall))
        for path in self.packagesToInstall:
            try:
                installedSize = IEDUtil.getInstalledPkgSize_(path)
            except BaseException as e:
                LogError("Size calculation of %@ failed: %@", path, unicode(e))
                installedSize = None
            if installedSize is None:
                self.delegate.buildFailed_details_(
                    "Failed to determine installed size",
                    "Unable to determine installation size requirements for %s"
                    % path)
                self.stop()
                return
            LogInfo("    %@ requires %@", path,
                    IEDUtil.formatByteSize_(installedSize))
            sizeRequirement += installedSize
        sizeReqStr = IEDUtil.formatByteSize_(sizeRequirement)
        LogInfo("Workflow requires a %@ disk image", sizeReqStr)

        if self.volumeSize() is None:
            # Calculate DMG size. Multiply package requirements by 1.1, round
            # to the nearest GB, and add 23.
            self.setVolumeSize_(
                int((float(sizeRequirement) * 1.1) /
                    (1000.0 * 1000.0 * 1000.0) + 23.5))
        else:
            # Make sure user specified image size is large enough.
            if sizeRequirement > self.volumeSize() * 1000 * 1000 * 1000:
                details = "Workflow requires %s and disk image is %d GB" % (
                    sizeReqStr, self.volumeSize())
                self.delegate.buildFailed_details_(
                    "Disk image too small for workflow", details)
                self.stop()
                return
        LogInfo("Using a %d GB disk image", self.volumeSize())

        # Task done.
        self.nextTask()
コード例 #27
0
 def buildSetProgressMessage_(self, message):
     if message != self.lastMessage:
         LogInfo("message: %@", message)
         self.lastMessage = message
コード例 #28
0
 def buildSetProgress_(self, progress):
     percent = 100.0 * progress / self.progressMax
     if abs(percent - self.lastProgressPercent) >= 0.1:
         LogInfo("progress: %.1f%%", percent)
         self.lastProgressPercent = percent
コード例 #29
0
 def examiningSource_(self, path):
     LogInfo("%@", "Examining source…")
コード例 #30
0
 def ejectingSource(self):
     LogInfo("%@", "Ejecting source…")