** Description changed:

  A persistent bug exists in the update notifier that affects the 
ttf-mscorefonts-installer and may also affect other packages.  On boot, a user 
is presented with an update notification indicating that the 
ttf-mscorefonts-installer failed to install and needs installation:
  ---snip---
  The following packages requested additional data downloads after package
  installation, but the data could not be downloaded or could not be
  processed.
  
    ttf-mscorefonts-installer
  
  The download will be attempted again later, or you can try the download
  again now.  Running this command requires an active Internet connection.
- ---snip---
+ ---endsnip---
  Running the command fails.  Manual installation of the 
ttf-mscorefonts-installer does not correct the notification.  The issue was 
traced to the /usr/lib/update-notifier/package-data-downloader script.
  
  There are several issues in the package-data-downloader script:
  
  1. The function process_download_requests() checks the hook date against the 
stamp date for a installation package, such as
      Hook File:  /usr/share/package-data-downloads/ttf-mscorefonts-installer
      Stamp File: 
/var/lib/update-notifier/package-data-downloads/ttf-mscorefonts-installer
  with the code:
  ---snip---
          try:
              hook_date = os.stat(file).st_mtime
              stamp_date = os.stat(stampfile).st_mtime
              if hook_date < stamp_date:
                  continue
- ---snip---
+ ---endsnip---
  The stamp file exist if there was a previous installation that did not 
produce a permanent failure. However, a normal failure sets up the condition to 
run this script.  The failure condition is not cleared on success.  The code 
related to determining success and failure is:
  ---snip---
                      result = subprocess.call(command)
                      if result:
                          # There's no sense redownloading if the script fails
                          permanent_failures.append(relfile)
                      else:
                          create_or_update_stampfile(stampfile)
- ---snip---
+ ---endsnip---
  Therefore, in the event of a non-permanent failure, the stamp file is created 
or updated which prevents an followup download to correct the non-permanent 
failure.
  
  2. The function process_download_requests() also tests for keywords 'script', 
'should-download', 'url', and 'sha256' in the para list from the Hook file to 
determine action:
- "
+ ---snip---
          for para in hook.iter_paragraphs(open(file)):
  
-           * if 'script' in para:
+ *********** if 'script' in para:
                  if not files:
                      record_failure(relfile)
                      break
- *               command = [para['script']]
- 
- *               if 'should-download' in para:
+ *************** command = [para['script']]
+ 
+ *************** if 'should-download' in para:
                      db = debconf.DebconfCommunicator('update-notifier')
                      try:
- *                       should = db.get(para['should-download'])
+ *********************** should = db.get(para['should-download'])
                          if should == "false":
                              # Do nothing with this file.
                              break
                      except:
                          pass
                      finally:
                          db.shutdown()
  
                  # Download each file and verify the sum
                  try:
                      downloaded = set()
                      for i in range(len(files)):
                          print("%s: downloading %s" % (relfile, files[i]))
                          dest_file = download_file(files[i], sums[i])
                          if dest_file:
                              command.append(dest_file)
                              downloaded.add(dest_file)
                          else:
                              record_failure(relfile)
                              break
                      if relfile in failures + permanent_failures:
                          break
  
                      sys.stdout.flush()
                      result = subprocess.call(command)
                      if result:
                          # There's no sense redownloading if the script fails
                          permanent_failures.append(relfile)
                      else:
                          create_or_update_stampfile(stampfile)
                      # cleanup
                      for f in downloaded:
                          os.remove(f)
                      break
                  except Exception:
                      traceback.print_exc(file=sys.stderr)
  
                  record_failure(relfile)
                  # The 'script' is always the last stanza
                  break
  
              # Not in a 'script' stanza, so we should have some urls
              try:
- *               files.append(para['url'])
- *               sums.append(para['sha256'])
+ *************** files.append(para['url'])
+ *************** sums.append(para['sha256'])
              except Exception as e:
                  if not isinstance(e, KeyError):
                      traceback.print_exc(file=sys.stderr)
                  record_failure(relfile)
                  break
- "
+ ---endsnip---
  where * note the lines affected.  These keywords begin with an uppercase in 
the related files:
  ---snip---
  Url: http://downloads.sourceforge.net/corefonts/webdin32.exe
  Sha256: 64595b5abc1080fba8610c5c34fab5863408e806aafe84653ca8575bed17d75a
  
  Script: /usr/lib/msttcorefonts/update-ms-fonts
  Should-Download: msttcorefonts/accepted-mscorefonts-eula
- ---snip---
+ ---endsnip---
  
  3. The function process_download_requests() tracks so called "failures" and 
"permanent_failures".  When a failure occurs, the following code sets up the 
condition for reprocessing later using the function trigger_update_notifier():
  ---snip---
      previous_failures = existing_permanent_failures()
  
      # We only report about "permanent" failures when there are new ones,
      # but we want the whole list of permanently-failing hooks so when
      # we clobber the update-notifier file we don't lose information the
      # user may not have seen yet
      if permanent_failures:
          new_failures = False
          for failure in permanent_failures:
              if failure not in previous_failures:
                  mark_hook_failed(failure, permanent=True)
                  previous_failures.append(failure)
                  new_failures = True
          if new_failures:
              trigger_update_notifier(previous_failures, permanent=True)
  
      # Filter out new failure reports for permanently-failed packages
      our_failures = [x for x in failures if x not in previous_failures]
  
      if our_failures:
          for failure in our_failures:
              mark_hook_failed(failure)
          trigger_update_notifier(our_failures)
- ---snip---
+ ---endsnip---
  
  SOLUTION:
  ====================
  The existing code set up several conditions based on the existence of the 
following files:
    stamp file
    notifier file
    notifier permanent file
  The conditions are:
    EXISTS ( stamp file )
    EXISTS ( stamp file AND notifier file )
    EXISTS ( notifier file AND notifier permanent file )
    EXISTS ( notifier permanent file )
  
  When no permanent failures are found (no notifier permanent file), the
  stamp file is set even when normal failures exist (notifier file).  This
  causes the next script execution to skip to the next install item.  In
  the event of success, failure conditions are cleared, but the notifier
  files are never cleared causing persistent requests to update that never
  get fulfilled.
  
  For part 1, adding code handle the failure condition when a stamp file exists 
would be prudent:
  ---snip---
          try:
- >           if not os.path.exists(NOTIFIER_FILE) and not 
os.path.exists(NOTIFIER_PERMANENT_FILE):
- >>>>            hook_date = os.stat(file).st_mtime
- >>>>            stamp_date = os.stat(stampfile).st_mtime
- >>>>            if hook_date < stamp_date:
- >>>>                continue
- >           elif os.path.exists(stampfile):
- >               os.unlink(stampfile)
- ---snip---
+ >>>>>>>>>>> if not os.path.exists(NOTIFIER_FILE) and not 
os.path.exists(NOTIFIER_PERMANENT_FILE):
+ >>>>>>>>>>>>>>> hook_date = os.stat(file).st_mtime
+ >>>>>>>>>>>>>>> stamp_date = os.stat(stampfile).st_mtime
+ >>>>>>>>>>>>>>> if hook_date < stamp_date:
+ >>>>>>>>>>>>>>>>>>> continue
+ >>>>>>>>>>> elif os.path.exists(stampfile):
+ >>>>>>>>>>>>>>> os.unlink(stampfile)
+ ---endsnip---
  where > indicated the added/modded code.  This corrects the problem by 
allowing any perceived failures, permanent or not, to reinstall the downloads.  
It always removes the stampfile so that if a permanent failure develops, it is 
handled correctly later.
  
  For part 2, the paragraph keyword lookups may or may not care about case, but 
update the keywords:
      'script', 'should-download', 'url', 'sha256'
  to:
      'Script', 'Should-Download', 'Url', 'Sha256'
  so that they match the file.
  
  For part 3, the comment suggests that the so called "update-notifier file" 
will be clobbered, but it never is.  On a non-permament failure, the failed and 
permanent-failure marker files are removed when function 
create_or_update_stampfile() is called.  The code should be changed to handle 
cleared failure conditions (i.e., empty failure lists) as follows:
  ---snip---
      previous_failures = existing_permanent_failures()
  
      # We only report about "permanent" failures when there are new ones,
      # but we want the whole list of permanently-failing hooks so when
      # we clobber the update-notifier file we don't lose information the
      # user may not have seen yet
      if permanent_failures:
          new_failures = False
          for failure in permanent_failures:
              if failure not in previous_failures:
                  mark_hook_failed(failure, permanent=True)
                  previous_failures.append(failure)
                  new_failures = True
          if new_failures:
              trigger_update_notifier(previous_failures, permanent=True)
- >   if not previous_failures and os.path.exists(NOTIFIER_PERMANENT_FILE):
- >       os.unlink(NOTIFIER_PERMANENT_FILE)
+ >>> if not previous_failures and os.path.exists(NOTIFIER_PERMANENT_FILE):
+ >>>>>>> os.unlink(NOTIFIER_PERMANENT_FILE)
  
      # Filter out new failure reports for permanently-failed packages
      our_failures = [x for x in failures if x not in previous_failures]
  
      if our_failures:
          for failure in our_failures:
              mark_hook_failed(failure)
          trigger_update_notifier(our_failures)
- >   elif os.path.exists(NOTIFIER_FILE):
- >       os.unlink(NOTIFIER_FILE)
- ---snip---
+ >>> elif os.path.exists(NOTIFIER_FILE):
+ >>>>>>> os.unlink(NOTIFIER_FILE)
+ ---endsnip---
  where > indicated the added code.
  
  In total, when no failure is found, the script will create the stamp
  file and clear the notifier files.  For permanent failures, the stamp
  file is not created and any notifier files will persist until the next
  attempted update.  For normal failures, the stamp and non-permanent
  notifier file persists until the next attempted update.  On any update,
  if notifier files exist, the script will attempt to correct the install.
  If just the stamp file exists, then that install is skipped.

** Description changed:

  A persistent bug exists in the update notifier that affects the 
ttf-mscorefonts-installer and may also affect other packages.  On boot, a user 
is presented with an update notification indicating that the 
ttf-mscorefonts-installer failed to install and needs installation:
  ---snip---
  The following packages requested additional data downloads after package
  installation, but the data could not be downloaded or could not be
  processed.
  
    ttf-mscorefonts-installer
  
  The download will be attempted again later, or you can try the download
  again now.  Running this command requires an active Internet connection.
  ---endsnip---
  Running the command fails.  Manual installation of the 
ttf-mscorefonts-installer does not correct the notification.  The issue was 
traced to the /usr/lib/update-notifier/package-data-downloader script.
  
  There are several issues in the package-data-downloader script:
  
  1. The function process_download_requests() checks the hook date against the 
stamp date for a installation package, such as
      Hook File:  /usr/share/package-data-downloads/ttf-mscorefonts-installer
      Stamp File: 
/var/lib/update-notifier/package-data-downloads/ttf-mscorefonts-installer
  with the code:
  ---snip---
          try:
              hook_date = os.stat(file).st_mtime
              stamp_date = os.stat(stampfile).st_mtime
              if hook_date < stamp_date:
                  continue
  ---endsnip---
  The stamp file exist if there was a previous installation that did not 
produce a permanent failure. However, a normal failure sets up the condition to 
run this script.  The failure condition is not cleared on success.  The code 
related to determining success and failure is:
  ---snip---
                      result = subprocess.call(command)
                      if result:
                          # There's no sense redownloading if the script fails
                          permanent_failures.append(relfile)
                      else:
                          create_or_update_stampfile(stampfile)
  ---endsnip---
  Therefore, in the event of a non-permanent failure, the stamp file is created 
or updated which prevents an followup download to correct the non-permanent 
failure.
  
  2. The function process_download_requests() also tests for keywords 'script', 
'should-download', 'url', and 'sha256' in the para list from the Hook file to 
determine action:
  ---snip---
          for para in hook.iter_paragraphs(open(file)):
  
- *********** if 'script' in para:
+ * . . . . . if 'script' in para:
                  if not files:
                      record_failure(relfile)
                      break
- *************** command = [para['script']]
- 
- *************** if 'should-download' in para:
+ * . . . . . . . command = [para['script']]
+ 
+ * . . . . . . . if 'should-download' in para:
                      db = debconf.DebconfCommunicator('update-notifier')
                      try:
- *********************** should = db.get(para['should-download'])
+ * . . . . . . . . . . . should = db.get(para['should-download'])
                          if should == "false":
                              # Do nothing with this file.
                              break
                      except:
                          pass
                      finally:
                          db.shutdown()
  
                  # Download each file and verify the sum
                  try:
                      downloaded = set()
                      for i in range(len(files)):
                          print("%s: downloading %s" % (relfile, files[i]))
                          dest_file = download_file(files[i], sums[i])
                          if dest_file:
                              command.append(dest_file)
                              downloaded.add(dest_file)
                          else:
                              record_failure(relfile)
                              break
                      if relfile in failures + permanent_failures:
                          break
  
                      sys.stdout.flush()
                      result = subprocess.call(command)
                      if result:
                          # There's no sense redownloading if the script fails
                          permanent_failures.append(relfile)
                      else:
                          create_or_update_stampfile(stampfile)
                      # cleanup
                      for f in downloaded:
                          os.remove(f)
                      break
                  except Exception:
                      traceback.print_exc(file=sys.stderr)
  
                  record_failure(relfile)
                  # The 'script' is always the last stanza
                  break
  
              # Not in a 'script' stanza, so we should have some urls
              try:
- *************** files.append(para['url'])
- *************** sums.append(para['sha256'])
+ * . . . . . . . files.append(para['url'])
+ * . . . . . . . sums.append(para['sha256'])
              except Exception as e:
                  if not isinstance(e, KeyError):
                      traceback.print_exc(file=sys.stderr)
                  record_failure(relfile)
                  break
  ---endsnip---
  where * note the lines affected.  These keywords begin with an uppercase in 
the related files:
  ---snip---
  Url: http://downloads.sourceforge.net/corefonts/webdin32.exe
  Sha256: 64595b5abc1080fba8610c5c34fab5863408e806aafe84653ca8575bed17d75a
  
  Script: /usr/lib/msttcorefonts/update-ms-fonts
  Should-Download: msttcorefonts/accepted-mscorefonts-eula
  ---endsnip---
  
  3. The function process_download_requests() tracks so called "failures" and 
"permanent_failures".  When a failure occurs, the following code sets up the 
condition for reprocessing later using the function trigger_update_notifier():
  ---snip---
      previous_failures = existing_permanent_failures()
  
      # We only report about "permanent" failures when there are new ones,
      # but we want the whole list of permanently-failing hooks so when
      # we clobber the update-notifier file we don't lose information the
      # user may not have seen yet
      if permanent_failures:
          new_failures = False
          for failure in permanent_failures:
              if failure not in previous_failures:
                  mark_hook_failed(failure, permanent=True)
                  previous_failures.append(failure)
                  new_failures = True
          if new_failures:
              trigger_update_notifier(previous_failures, permanent=True)
  
      # Filter out new failure reports for permanently-failed packages
      our_failures = [x for x in failures if x not in previous_failures]
  
      if our_failures:
          for failure in our_failures:
              mark_hook_failed(failure)
          trigger_update_notifier(our_failures)
  ---endsnip---
  
  SOLUTION:
  ====================
  The existing code set up several conditions based on the existence of the 
following files:
    stamp file
    notifier file
    notifier permanent file
  The conditions are:
    EXISTS ( stamp file )
    EXISTS ( stamp file AND notifier file )
    EXISTS ( notifier file AND notifier permanent file )
    EXISTS ( notifier permanent file )
  
  When no permanent failures are found (no notifier permanent file), the
  stamp file is set even when normal failures exist (notifier file).  This
  causes the next script execution to skip to the next install item.  In
  the event of success, failure conditions are cleared, but the notifier
  files are never cleared causing persistent requests to update that never
  get fulfilled.
  
  For part 1, adding code handle the failure condition when a stamp file exists 
would be prudent:
  ---snip---
          try:
- >>>>>>>>>>> if not os.path.exists(NOTIFIER_FILE) and not 
os.path.exists(NOTIFIER_PERMANENT_FILE):
- >>>>>>>>>>>>>>> hook_date = os.stat(file).st_mtime
- >>>>>>>>>>>>>>> stamp_date = os.stat(stampfile).st_mtime
- >>>>>>>>>>>>>>> if hook_date < stamp_date:
- >>>>>>>>>>>>>>>>>>> continue
- >>>>>>>>>>> elif os.path.exists(stampfile):
- >>>>>>>>>>>>>>> os.unlink(stampfile)
+ > . . . . . if not os.path.exists(NOTIFIER_FILE) and not 
os.path.exists(NOTIFIER_PERMANENT_FILE):
+ > . . . . . . . hook_date = os.stat(file).st_mtime
+ > . . . . . . . stamp_date = os.stat(stampfile).st_mtime
+ > . . . . . . . if hook_date < stamp_date:
+ > . . . . . . . . . continue
+ > . . . . . elif os.path.exists(stampfile):
+ > . . . . . . . os.unlink(stampfile)
  ---endsnip---
  where > indicated the added/modded code.  This corrects the problem by 
allowing any perceived failures, permanent or not, to reinstall the downloads.  
It always removes the stampfile so that if a permanent failure develops, it is 
handled correctly later.
  
  For part 2, the paragraph keyword lookups may or may not care about case, but 
update the keywords:
      'script', 'should-download', 'url', 'sha256'
  to:
      'Script', 'Should-Download', 'Url', 'Sha256'
  so that they match the file.
  
  For part 3, the comment suggests that the so called "update-notifier file" 
will be clobbered, but it never is.  On a non-permament failure, the failed and 
permanent-failure marker files are removed when function 
create_or_update_stampfile() is called.  The code should be changed to handle 
cleared failure conditions (i.e., empty failure lists) as follows:
  ---snip---
      previous_failures = existing_permanent_failures()
  
      # We only report about "permanent" failures when there are new ones,
      # but we want the whole list of permanently-failing hooks so when
      # we clobber the update-notifier file we don't lose information the
      # user may not have seen yet
      if permanent_failures:
          new_failures = False
          for failure in permanent_failures:
              if failure not in previous_failures:
                  mark_hook_failed(failure, permanent=True)
                  previous_failures.append(failure)
                  new_failures = True
          if new_failures:
              trigger_update_notifier(previous_failures, permanent=True)
- >>> if not previous_failures and os.path.exists(NOTIFIER_PERMANENT_FILE):
- >>>>>>> os.unlink(NOTIFIER_PERMANENT_FILE)
+ > . if not previous_failures and os.path.exists(NOTIFIER_PERMANENT_FILE):
+ > . . . os.unlink(NOTIFIER_PERMANENT_FILE)
  
      # Filter out new failure reports for permanently-failed packages
      our_failures = [x for x in failures if x not in previous_failures]
  
      if our_failures:
          for failure in our_failures:
              mark_hook_failed(failure)
          trigger_update_notifier(our_failures)
- >>> elif os.path.exists(NOTIFIER_FILE):
- >>>>>>> os.unlink(NOTIFIER_FILE)
+ > . elif os.path.exists(NOTIFIER_FILE):
+ > . . . os.unlink(NOTIFIER_FILE)
  ---endsnip---
  where > indicated the added code.
  
  In total, when no failure is found, the script will create the stamp
  file and clear the notifier files.  For permanent failures, the stamp
  file is not created and any notifier files will persist until the next
  attempted update.  For normal failures, the stamp and non-permanent
  notifier file persists until the next attempted update.  On any update,
  if notifier files exist, the script will attempt to correct the install.
  If just the stamp file exists, then that install is skipped.

** Description changed:

  A persistent bug exists in the update notifier that affects the 
ttf-mscorefonts-installer and may also affect other packages.  On boot, a user 
is presented with an update notification indicating that the 
ttf-mscorefonts-installer failed to install and needs installation:
  ---snip---
  The following packages requested additional data downloads after package
  installation, but the data could not be downloaded or could not be
  processed.
  
    ttf-mscorefonts-installer
  
  The download will be attempted again later, or you can try the download
  again now.  Running this command requires an active Internet connection.
  ---endsnip---
  Running the command fails.  Manual installation of the 
ttf-mscorefonts-installer does not correct the notification.  The issue was 
traced to the /usr/lib/update-notifier/package-data-downloader script.
  
  There are several issues in the package-data-downloader script:
  
  1. The function process_download_requests() checks the hook date against the 
stamp date for a installation package, such as
      Hook File:  /usr/share/package-data-downloads/ttf-mscorefonts-installer
      Stamp File: 
/var/lib/update-notifier/package-data-downloads/ttf-mscorefonts-installer
  with the code:
  ---snip---
          try:
              hook_date = os.stat(file).st_mtime
              stamp_date = os.stat(stampfile).st_mtime
              if hook_date < stamp_date:
                  continue
  ---endsnip---
  The stamp file exist if there was a previous installation that did not 
produce a permanent failure. However, a normal failure sets up the condition to 
run this script.  The failure condition is not cleared on success.  The code 
related to determining success and failure is:
  ---snip---
                      result = subprocess.call(command)
                      if result:
                          # There's no sense redownloading if the script fails
                          permanent_failures.append(relfile)
                      else:
                          create_or_update_stampfile(stampfile)
  ---endsnip---
  Therefore, in the event of a non-permanent failure, the stamp file is created 
or updated which prevents an followup download to correct the non-permanent 
failure.
  
  2. The function process_download_requests() also tests for keywords 'script', 
'should-download', 'url', and 'sha256' in the para list from the Hook file to 
determine action:
  ---snip---
          for para in hook.iter_paragraphs(open(file)):
  
  * . . . . . if 'script' in para:
                  if not files:
                      record_failure(relfile)
                      break
  * . . . . . . . command = [para['script']]
  
  * . . . . . . . if 'should-download' in para:
                      db = debconf.DebconfCommunicator('update-notifier')
                      try:
  * . . . . . . . . . . . should = db.get(para['should-download'])
                          if should == "false":
                              # Do nothing with this file.
                              break
-                     except:
-                         pass
-                     finally:
-                         db.shutdown()
- 
-                 # Download each file and verify the sum
-                 try:
-                     downloaded = set()
-                     for i in range(len(files)):
-                         print("%s: downloading %s" % (relfile, files[i]))
-                         dest_file = download_file(files[i], sums[i])
-                         if dest_file:
-                             command.append(dest_file)
-                             downloaded.add(dest_file)
-                         else:
-                             record_failure(relfile)
-                             break
-                     if relfile in failures + permanent_failures:
-                         break
- 
-                     sys.stdout.flush()
-                     result = subprocess.call(command)
-                     if result:
-                         # There's no sense redownloading if the script fails
-                         permanent_failures.append(relfile)
-                     else:
-                         create_or_update_stampfile(stampfile)
-                     # cleanup
-                     for f in downloaded:
-                         os.remove(f)
-                     break
-                 except Exception:
-                     traceback.print_exc(file=sys.stderr)
- 
-                 record_failure(relfile)
-                 # The 'script' is always the last stanza
-                 break
- 
+ ---endsnip---
+ ---snip---
              # Not in a 'script' stanza, so we should have some urls
              try:
  * . . . . . . . files.append(para['url'])
  * . . . . . . . sums.append(para['sha256'])
              except Exception as e:
-                 if not isinstance(e, KeyError):
-                     traceback.print_exc(file=sys.stderr)
-                 record_failure(relfile)
-                 break
  ---endsnip---
  where * note the lines affected.  These keywords begin with an uppercase in 
the related files:
  ---snip---
  Url: http://downloads.sourceforge.net/corefonts/webdin32.exe
  Sha256: 64595b5abc1080fba8610c5c34fab5863408e806aafe84653ca8575bed17d75a
  
  Script: /usr/lib/msttcorefonts/update-ms-fonts
  Should-Download: msttcorefonts/accepted-mscorefonts-eula
  ---endsnip---
  
  3. The function process_download_requests() tracks so called "failures" and 
"permanent_failures".  When a failure occurs, the following code sets up the 
condition for reprocessing later using the function trigger_update_notifier():
  ---snip---
      previous_failures = existing_permanent_failures()
  
      # We only report about "permanent" failures when there are new ones,
      # but we want the whole list of permanently-failing hooks so when
      # we clobber the update-notifier file we don't lose information the
      # user may not have seen yet
      if permanent_failures:
          new_failures = False
          for failure in permanent_failures:
              if failure not in previous_failures:
                  mark_hook_failed(failure, permanent=True)
                  previous_failures.append(failure)
                  new_failures = True
          if new_failures:
              trigger_update_notifier(previous_failures, permanent=True)
  
      # Filter out new failure reports for permanently-failed packages
      our_failures = [x for x in failures if x not in previous_failures]
  
      if our_failures:
          for failure in our_failures:
              mark_hook_failed(failure)
          trigger_update_notifier(our_failures)
  ---endsnip---
  
  SOLUTION:
  ====================
  The existing code set up several conditions based on the existence of the 
following files:
    stamp file
    notifier file
    notifier permanent file
  The conditions are:
    EXISTS ( stamp file )
    EXISTS ( stamp file AND notifier file )
    EXISTS ( notifier file AND notifier permanent file )
    EXISTS ( notifier permanent file )
  
  When no permanent failures are found (no notifier permanent file), the
  stamp file is set even when normal failures exist (notifier file).  This
  causes the next script execution to skip to the next install item.  In
  the event of success, failure conditions are cleared, but the notifier
  files are never cleared causing persistent requests to update that never
  get fulfilled.
  
  For part 1, adding code handle the failure condition when a stamp file exists 
would be prudent:
  ---snip---
          try:
  > . . . . . if not os.path.exists(NOTIFIER_FILE) and not 
os.path.exists(NOTIFIER_PERMANENT_FILE):
  > . . . . . . . hook_date = os.stat(file).st_mtime
  > . . . . . . . stamp_date = os.stat(stampfile).st_mtime
  > . . . . . . . if hook_date < stamp_date:
  > . . . . . . . . . continue
  > . . . . . elif os.path.exists(stampfile):
  > . . . . . . . os.unlink(stampfile)
  ---endsnip---
  where > indicated the added/modded code.  This corrects the problem by 
allowing any perceived failures, permanent or not, to reinstall the downloads.  
It always removes the stampfile so that if a permanent failure develops, it is 
handled correctly later.
  
  For part 2, the paragraph keyword lookups may or may not care about case, but 
update the keywords:
      'script', 'should-download', 'url', 'sha256'
  to:
      'Script', 'Should-Download', 'Url', 'Sha256'
  so that they match the file.
  
  For part 3, the comment suggests that the so called "update-notifier file" 
will be clobbered, but it never is.  On a non-permament failure, the failed and 
permanent-failure marker files are removed when function 
create_or_update_stampfile() is called.  The code should be changed to handle 
cleared failure conditions (i.e., empty failure lists) as follows:
  ---snip---
      previous_failures = existing_permanent_failures()
  
      # We only report about "permanent" failures when there are new ones,
      # but we want the whole list of permanently-failing hooks so when
      # we clobber the update-notifier file we don't lose information the
      # user may not have seen yet
      if permanent_failures:
          new_failures = False
          for failure in permanent_failures:
              if failure not in previous_failures:
                  mark_hook_failed(failure, permanent=True)
                  previous_failures.append(failure)
                  new_failures = True
          if new_failures:
              trigger_update_notifier(previous_failures, permanent=True)
  > . if not previous_failures and os.path.exists(NOTIFIER_PERMANENT_FILE):
  > . . . os.unlink(NOTIFIER_PERMANENT_FILE)
  
      # Filter out new failure reports for permanently-failed packages
      our_failures = [x for x in failures if x not in previous_failures]
  
      if our_failures:
          for failure in our_failures:
              mark_hook_failed(failure)
          trigger_update_notifier(our_failures)
  > . elif os.path.exists(NOTIFIER_FILE):
  > . . . os.unlink(NOTIFIER_FILE)
  ---endsnip---
  where > indicated the added code.
  
  In total, when no failure is found, the script will create the stamp
  file and clear the notifier files.  For permanent failures, the stamp
  file is not created and any notifier files will persist until the next
  attempted update.  For normal failures, the stamp and non-permanent
  notifier file persists until the next attempted update.  On any update,
  if notifier files exist, the script will attempt to correct the install.
  If just the stamp file exists, then that install is skipped.

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/1621629

Title:
  package-data-downloader fails to process download requests

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/update-notifier/+bug/1621629/+subscriptions

-- 
ubuntu-bugs mailing list
ubuntu-bugs@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to