Ejemplo n.º 1
0
def handleNewUpdate(latest):
    """ A new update has been found, the Sparkle framework will now take control
    and perform user interaction and automatic update on our behalf. Since the
    appcast has already been fetched and parsed by the crossplatform code, Sparkle 
    is actually not used in *full* automatic mode so we have to short-circuit 
    some of its code and manually call the parts we are interested in.
    
    This includes:
    - manually building a clean dictionary containing the RSS item corresponding 
      to the latest version of the software and then creating an SUAppcastItem 
      with this dictionary.
    - manually setting the global updater 'updateItem' ivar to the SUAppcastItem
      instance we just created. This is slightly hackish, but this is the *only* 
      way to make it work correctly in our case, otherwise Sparkle will fail to
      download the update and throw a 'bad URL' error.
    - manually creating and calling an SUUpdateAlert object (which we must retain
      to prevent it to be automatically released by the Python garbage collector
      and therefore cause bad crashes).
    """
    if not _host_supported(latest):
        logging.warn("Update available but host system not supported.")
        return

    dictionary = dict()
    _transfer(latest, 'title', dictionary)
    _transfer(latest, 'pubdate', dictionary, 'pubDate')
    _transfer(latest, 'description', dictionary)
    _transfer(latest, 'releasenoteslink', dictionary,
              'sparkle:releaseNotesLink')

    enclosure = latest['enclosures'][0]
    suEnclosure = dict()
    _transfer(enclosure, 'sparkle:dsaSignature', suEnclosure)
    _transfer(enclosure, 'sparkle:md5Sum', suEnclosure)
    _transfer(enclosure, 'sparkle:version', suEnclosure)
    _transfer(enclosure, 'sparkle:shortVersionString', suEnclosure)
    _transfer(enclosure, 'url', suEnclosure)
    dictionary['enclosure'] = suEnclosure

    suItem = SUAppcastItem.alloc().initWithDictionary_(dictionary)
    skipped_version = app.config.get(SUSkippedVersionPref)

    if suItem.fileVersion() == skipped_version:
        logging.debug("Skipping update by user request")
    else:
        global updater
        objc.setInstanceVariable(updater, 'updateItem', suItem, True)

        global alerter  # keep a reference around
        alerter = SUUpdateAlert.alloc().initWithAppcastItem_(suItem)
        alerter.setDelegate_(updater)
        alerter.showWindow_(updater)
Ejemplo n.º 2
0
    def testClassMod(self):
        # It's scary as hell, but updating the class of an object does "work"
        # (for some perverted interpretation of the word)

        class DummyClass (NSObject):
            __slots__ = ()

        o = NSObject.alloc().init()
        self.assertIsInstance(o, NSObject)
        self.assertIsNotInstance(o, DummyClass)

        objc.setInstanceVariable(o, "isa", DummyClass)
        self.assertIsInstance(o, DummyClass)
Ejemplo n.º 3
0
    def testClassMod(self):
        # It's scary as hell, but updating the class of an object does "work"
        # (for some perverted interpretation of the word)

        class DummyClass(NSObject):
            __slots__ = ()

        o = NSObject.alloc().init()
        self.assertIsInstance(o, NSObject)
        self.assertIsNotInstance(o, DummyClass)

        objc.setInstanceVariable(o, "isa", DummyClass)
        self.assertIsInstance(o, DummyClass)
Ejemplo n.º 4
0
def handleNewUpdate(latest):
    """ A new update has been found, the Sparkle framework will now take control
    and perform user interaction and automatic update on our behalf. Since the
    appcast has already been fetched and parsed by the crossplatform code, Sparkle 
    is actually not used in *full* automatic mode so we have to short-circuit 
    some of its code and manually call the parts we are interested in.
    
    This includes:
    - manually building a clean dictionary containing the RSS item corresponding 
      to the latest version of the software and then creating an SUAppcastItem 
      with this dictionary.
    - manually setting the global updater 'updateItem' ivar to the SUAppcastItem
      instance we just created. This is slightly hackish, but this is the *only* 
      way to make it work correctly in our case, otherwise Sparkle will fail to
      download the update and throw a 'bad URL' error.
    - manually creating and calling an SUUpdateAlert object (which we must retain
      to prevent it to be automatically released by the Python garbage collector
      and therefore cause bad crashes).
    """
    if not _host_supported(latest):
        logging.info("Update available but host system not supported.")
        return
    
    dictionary = dict()
    _transfer(latest, 'title',            dictionary)
    _transfer(latest, 'pubdate',          dictionary, 'pubDate')
    _transfer(latest, 'description',      dictionary)
    _transfer(latest, 'releasenoteslink', dictionary, 'sparkle:releaseNotesLink')

    enclosure = latest['enclosures'][0]
    suEnclosure = dict()
    _transfer(enclosure, 'sparkle:dsaSignature',       suEnclosure)
    _transfer(enclosure, 'sparkle:md5Sum',             suEnclosure)
    _transfer(enclosure, 'sparkle:version',            suEnclosure)
    _transfer(enclosure, 'sparkle:shortVersionString', suEnclosure)
    _transfer(enclosure, 'url',                        suEnclosure)
    dictionary['enclosure'] = suEnclosure

    suItem = SUAppcastItem.alloc().initWithDictionary_(dictionary)
    skipped_version = app.config.get(SUSkippedVersionPref)
    
    if suItem.fileVersion() == skipped_version:
        logging.info("Skipping update by user request")
    else:
        global updater
        objc.setInstanceVariable(updater, 'updateItem', suItem, True)

        global alerter
        alerter = SUUpdateAlert.alloc().initWithAppcastItem_(suItem)
        alerter.setDelegate_(updater)
        alerter.showWindow_(updater)
Ejemplo n.º 5
0
    def updateAlert_finishedWithChoice_(self, alert, choice):
        alert.release()

        if choice == 0:    # SUInstallUpdateChoice
            app.config.set(SUSkippedVersionPref, '')
            self.beginDownload()

        elif choice == 1:  # SURemindMeLaterChoice
            objc.setInstanceVariable(self, 'updateInProgress', objc.NO, True)
            app.config.set(SUSkippedVersionPref, '')
            self.scheduleCheckWithInterval_(30 * 60)

        elif choice == 2:  # SUSkipThisVersionChoice
            objc.setInstanceVariable(self, 'updateInProgress', objc.NO, True)
            suItem = objc.getInstanceVariable(updater, 'updateItem')
            app.config.set(SUSkippedVersionPref, suItem.fileVersion())
Ejemplo n.º 6
0
    def updateAlert_finishedWithChoice_(self, alert, choice):
        global alerter  # release our kept reference
        alerter = None

        if choice == 0:  # SUInstallUpdateChoice
            app.config.set(SUSkippedVersionPref, '')
            self.beginDownload()

        elif choice == 1:  # SURemindMeLaterChoice
            objc.setInstanceVariable(self, 'updateInProgress', objc.NO, True)
            app.config.set(SUSkippedVersionPref, '')
            self.scheduleCheckWithInterval_(30 * 60)

        elif choice == 2:  # SUSkipThisVersionChoice
            objc.setInstanceVariable(self, 'updateInProgress', objc.NO, True)
            suItem = objc.getInstanceVariable(updater, 'updateItem')
            app.config.set(SUSkippedVersionPref, suItem.fileVersion())
Ejemplo n.º 7
0
    def downloadDidFinish_(self, d):
        url = d.request().URL()
        temp_url = NSURL.alloc().initWithScheme_host_path_('https', url.host(),
                                                           url.path())
        appcast_url = objc.getInstanceVariable(self, 'appcastURL')
        temp_appcast_url = NSURL.alloc().initWithScheme_host_path_('https',
                                                           appcast_url.host(),
                                                           appcast_url.path())
        request = NSURLRequest.requestWithURL_(temp_url)
        fake_d = DummyURLDownload.alloc().initWithRequest_(request)

        objc.setInstanceVariable(self, 'appcastURL', temp_appcast_url, objc.YES)

        # Back to your regular scheduled programming ..
        SUUIBasedUpdateDriver.downloadDidFinish_(self, fake_d)

        # Restoring values to what they were previously.
        objc.setInstanceVariable(self, 'appcastURL', appcast_url, objc.YES)
Ejemplo n.º 8
0
    def downloadDidFinish_(self, d):
        url = d.request().URL()
        temp_url = NSURL.alloc().initWithScheme_host_path_(
            'https', url.host(), url.path())
        appcast_url = objc.getInstanceVariable(self, 'appcastURL')
        temp_appcast_url = NSURL.alloc().initWithScheme_host_path_(
            'https', appcast_url.host(), appcast_url.path())
        request = NSURLRequest.requestWithURL_(temp_url)
        fake_d = DummyURLDownload.alloc().initWithRequest_(request)

        objc.setInstanceVariable(self, 'appcastURL', temp_appcast_url,
                                 objc.YES)

        # Back to your regular scheduled programming ..
        SUUIBasedUpdateDriver.downloadDidFinish_(self, fake_d)

        # Restoring values to what they were previously.
        objc.setInstanceVariable(self, 'appcastURL', appcast_url, objc.YES)
Ejemplo n.º 9
0
def handleNewUpdate(latest):
    """A new update has been found, the Sparkle framework will now take control
    and perform user interaction and automatic update on our behalf. Since the
    appcast has already been fetched and parsed by the crossplatform code,
    Sparkle is actually not used in *full* automatic mode so we have to
    short-circuit some of its code and manually call the parts we are
    interested in.
    
    This includes:
    - manually building a clean dictionary containing the RSS item
      corresponding to the latest version of the software and then
      creating an SUAppcastItem with this dictionary.

    - manually allocating and initializing a driver for the updater.  The
      driver determines the policy for doing updates (e.g. auto updates,
      UI, etc).  We use our own driver based on the SUUIBasedUpdateDriver,
      which has overrides for a couple of functions to bypass functionality
      which we don't implement yet, or if we have extra work that needs to be
      done (possibly by calling portable code).

    - manually setting ivar updateItem, host, appcastURL into the driver, which
      would normally be done by Sparkle internally.  Set the driver to be an
      ivar of the updater object, which was created at startup.  We ask the
      bridge to retain these for us, as they would be if they were done by
      Sparkle internally.  A bit hackish but it is the only way to make the
      Sparkle guts happy since we are creating things manually.

    - manually creating and calling an SUUpdateAlert object (which we must
      retain to prevent it to be automatically released by the Python
      garbage collector and therefore cause bad crashes).

    - Set the delegate of the alerter to be the driver - which will handle
      callbacks in response to state changes in the alerter.
    """
    if not _host_supported(latest):
        logging.warn("Update available but host system not supported.")
        return

    # If already running don't bother.
    global updater
    if updater.updateInProgress():
        # Update currently in progress.
        return

    dictionary = dict()
    _transfer(latest, 'title',            dictionary)
    _transfer(latest, 'pubdate',          dictionary, 'pubDate')
    _transfer(latest, 'description',      dictionary)
    _transfer(latest, 'releasenoteslink', dictionary, 'sparkle:releaseNotesLink')

    enclosure = latest['enclosures'][0]
    suEnclosure = dict()
    _transfer(enclosure, 'sparkle:dsaSignature',       suEnclosure)
    _transfer(enclosure, 'sparkle:md5Sum',             suEnclosure)
    _transfer(enclosure, 'sparkle:version',            suEnclosure)
    _transfer(enclosure, 'sparkle:shortVersionString', suEnclosure)
    _transfer(enclosure, 'url',                        suEnclosure)
    dictionary['enclosure'] = suEnclosure

    suItem = SUAppcastItem.alloc().initWithDictionary_(dictionary)
    skipped_version = app.config.get(SUSkippedVersionPref)
    
    if suItem.versionString() == skipped_version:
        logging.debug("Skipping update by user request")
    else:
        host = objc.getInstanceVariable(updater, 'host')

        global alerter # keep a reference around

        final = app.config.get(prefs.APP_FINAL_RELEASE)
        pref = prefs.AUTOUPDATE_URL if final else prefs.AUTOUPDATE_BETA_URL
        appcast_url = NSURL.alloc().initWithString_(app.config.get(pref))
        
        alerter = SUUpdateAlert.alloc().initWithAppcastItem_host_(suItem, host)
        driver = MiroUpdateDriver.alloc().initWithUpdater_(updater)
        objc.setInstanceVariable(driver, 'updateItem', suItem, True)
        objc.setInstanceVariable(driver, 'host', host, True)
        objc.setInstanceVariable(driver, 'appcastURL', appcast_url, True)
        objc.setInstanceVariable(updater, 'driver', driver, True)

        alerter.setDelegate_(driver)
        alerter.showWindow_(updater)
Ejemplo n.º 10
0
def handleNewUpdate(latest):
    """A new update has been found, the Sparkle framework will now take control
    and perform user interaction and automatic update on our behalf. Since the
    appcast has already been fetched and parsed by the crossplatform code,
    Sparkle is actually not used in *full* automatic mode so we have to
    short-circuit some of its code and manually call the parts we are
    interested in.
    
    This includes:
    - manually building a clean dictionary containing the RSS item
      corresponding to the latest version of the software and then
      creating an SUAppcastItem with this dictionary.

    - manually allocating and initializing a driver for the updater.  The
      driver determines the policy for doing updates (e.g. auto updates,
      UI, etc).  We use our own driver based on the SUUIBasedUpdateDriver,
      which has overrides for a couple of functions to bypass functionality
      which we don't implement yet, or if we have extra work that needs to be
      done (possibly by calling portable code).

    - manually setting ivar updateItem, host, appcastURL into the driver, which
      would normally be done by Sparkle internally.  Set the driver to be an
      ivar of the updater object, which was created at startup.  We ask the
      bridge to retain these for us, as they would be if they were done by
      Sparkle internally.  A bit hackish but it is the only way to make the
      Sparkle guts happy since we are creating things manually.

    - manually creating and calling an SUUpdateAlert object (which we must
      retain to prevent it to be automatically released by the Python
      garbage collector and therefore cause bad crashes).

    - Set the delegate of the alerter to be the driver - which will handle
      callbacks in response to state changes in the alerter.
    """
    if not _host_supported(latest):
        logging.warn("Update available but host system not supported.")
        return

    # If already running don't bother.
    global updater
    if updater.updateInProgress():
        # Update currently in progress.
        return

    dictionary = dict()
    _transfer(latest, 'title', dictionary)
    _transfer(latest, 'pubdate', dictionary, 'pubDate')
    _transfer(latest, 'description', dictionary)
    _transfer(latest, 'releasenoteslink', dictionary,
              'sparkle:releaseNotesLink')

    enclosure = latest['enclosures'][0]
    suEnclosure = dict()
    _transfer(enclosure, 'sparkle:dsaSignature', suEnclosure)
    _transfer(enclosure, 'sparkle:md5Sum', suEnclosure)
    _transfer(enclosure, 'sparkle:version', suEnclosure)
    _transfer(enclosure, 'sparkle:shortVersionString', suEnclosure)
    _transfer(enclosure, 'url', suEnclosure)
    dictionary['enclosure'] = suEnclosure

    suItem = SUAppcastItem.alloc().initWithDictionary_(dictionary)
    skipped_version = app.config.get(SUSkippedVersionPref)

    if suItem.versionString() == skipped_version:
        logging.debug("Skipping update by user request")
    else:
        host = objc.getInstanceVariable(updater, 'host')

        global alerter  # keep a reference around

        final = app.config.get(prefs.APP_FINAL_RELEASE)
        pref = prefs.AUTOUPDATE_URL if final else prefs.AUTOUPDATE_BETA_URL
        appcast_url = NSURL.alloc().initWithString_(app.config.get(pref))

        alerter = SUUpdateAlert.alloc().initWithAppcastItem_host_(suItem, host)
        driver = MiroUpdateDriver.alloc().initWithUpdater_(updater)
        objc.setInstanceVariable(driver, 'updateItem', suItem, True)
        objc.setInstanceVariable(driver, 'host', host, True)
        objc.setInstanceVariable(driver, 'appcastURL', appcast_url, True)
        objc.setInstanceVariable(updater, 'driver', driver, True)

        alerter.setDelegate_(driver)
        alerter.showWindow_(updater)