← Back to team overview

deja-dup-team team mailing list archive

[Merge] lp:~mterry/deja-dup/warn-on-bad-read into lp:deja-dup

 

Michael Terry has proposed merging lp:~mterry/deja-dup/warn-on-bad-read into lp:deja-dup.

Requested reviews:
  Ken VanDine (ken-vandine)
Related bugs:
  Bug #907846 in Déjà Dup: "Warn user if files weren't able to be read during backup"
  https://bugs.launchpad.net/deja-dup/+bug/907846

For more details, see:
https://code.launchpad.net/~mterry/deja-dup/warn-on-bad-read/+merge/86823

Tell user if we couldn't read a file during the backup.
-- 
https://code.launchpad.net/~mterry/deja-dup/warn-on-bad-read/+merge/86823
Your team Déjà Dup Developers is subscribed to branch lp:deja-dup.
=== modified file 'common/Duplicity.vala'
--- common/Duplicity.vala	2011-11-06 01:16:05 +0000
+++ common/Duplicity.vala	2011-12-23 18:39:25 +0000
@@ -30,7 +30,7 @@
    * vala withot the need of manually running duplicity command.
    */
 
-  public signal void done(bool success, bool cancelled);
+  public signal void done(bool success, bool cancelled, string? detail);
   public signal void raise_error(string errstr, string? detail);
   public signal void action_desc_changed(string action);
   public signal void action_file_changed(File file, bool actual);
@@ -108,6 +108,8 @@
   bool has_checked_contents = false;
   bool has_non_home_contents = false;
   List<File> homes = new List<File>();
+
+  List<File> read_error_files = null;
   
   bool checked_collection_info = false;
   bool got_collection_info = false;
@@ -169,7 +171,7 @@
     }
     catch (Error e) {
       raise_error(e.message, null);
-      done(false, false);
+      done(false, false, null);
       return;
     }
     this.backend = backend;
@@ -187,7 +189,7 @@
     delete_age = settings.get_int(DELETE_AFTER_KEY);
 
     if (!restart())
-      done(false, false);
+      done(false, false, null);
 
     if (!backend.is_native()) {
       Network.get().notify["connected"].connect(network_changed);
@@ -384,6 +386,7 @@
   bool restart()
   {
     state = State.NORMAL;
+    read_error_files = null;
     
     if (mode == Operation.Mode.INVALID)
       return false;
@@ -515,7 +518,7 @@
 
     if (!has_progress_total) {
       if (!restart())
-        done(false, false);
+        done(false, false, null);
       return;
     }
 
@@ -551,7 +554,7 @@
     }
     
     if (!restart())
-      done(false, false);
+      done(false, false, null);
   }
 
   bool cleanup() {
@@ -596,6 +599,8 @@
 
   void handle_done(DuplicityInstance? inst, bool success, bool cancelled)
   {
+    string detail = null;
+
     if (can_ignore_error())
       success = true;
 
@@ -666,6 +671,17 @@
           }
         }
         else if (mode == Operation.Mode.BACKUP) {
+          if (read_error_files != null) {
+            // OK, we succeeded yay!  But some files didn't make it into the backup
+            // because we couldn't read them.  So tell the user so they don't think
+            // everything is hunky dory.
+            detail = _("Could not back up the following files.  Please make sure you are able to open them.");
+            detail += "\n";
+            foreach (File f in read_error_files) {
+              detail += "\n%s".printf(f.get_parse_name());
+            }
+          }
+
           mode = Operation.Mode.INVALID; // mark 'done' so when we delete, we don't restart
           if (delete_files_if_needed())
             return;
@@ -681,9 +697,9 @@
     
     if (!success && !cancelled && !error_issued)
       show_error(_("Failed with an unknown error."));
-    
+
     inst = null;
-    done(success, cancelled);
+    done(success, cancelled, detail);
   }
   
   string saved_status;
@@ -802,6 +818,7 @@
   protected static const int WARNING_UNMATCHED_SIG = 4;
   protected static const int WARNING_INCOMPLETE_BACKUP = 5;
   protected static const int WARNING_ORPHANED_BACKUP = 6;
+  protected static const int WARNING_CANNOT_READ = 10;
   protected static const int DEBUG_GENERIC = 1;
 
   void delete_cache()
@@ -1264,7 +1281,22 @@
         // in ourselves, we may never get to it.
         if (mode == Operation.Mode.BACKUP && !this.cleaned_up_once)
           cleanup(); // stops current backup, cleans up, then resumes
-      break;
+        break;
+
+      case WARNING_CANNOT_READ:
+        // A file couldn't be backed up!  We should note the name and present
+        // the user with a list at the end.
+        if (firstline.length > 2) {
+          // Only add it if it's a child of one of our includes.  Sometimes
+          // Duplicity likes to talk to us about folders like /lost+found and
+          // such that we don't care about.
+          var error_file = make_file_obj(firstline[2]);
+          foreach (File f in includes) {
+            if (error_file.equal(f) || error_file.has_prefix(f))
+              read_error_files.append(error_file);
+          }
+        }
+        break;
       }
     }
   }
@@ -1405,7 +1437,7 @@
     }
     catch (Error e) {
       show_error(e.message);
-      done(false, false);
+      done(false, false, null);
     }
   }
 }

=== modified file 'common/Operation.vala'
--- common/Operation.vala	2011-11-06 01:16:05 +0000
+++ common/Operation.vala	2011-12-23 18:39:25 +0000
@@ -32,7 +32,7 @@
    * but it is provided to provide easier development and an abstraction layer
    * in case Deja Dup project ever replaces its backend.
    */
-  public signal void done(bool success, bool cancelled);
+  public signal void done(bool success, bool cancelled, string? detail);
   public signal void raise_error(string errstr, string? detail);
   public signal void action_desc_changed(string action);
   public signal void action_file_changed(File file, bool actual);
@@ -115,7 +115,7 @@
     }
     catch (Error e) {
       raise_error(e.message, null);
-      done(false, false);
+      done(false, false, null);
       return;
     }
 
@@ -179,7 +179,7 @@
     /*
      * Connect Deja Dup to signals
      */
-    dup.done.connect((d, o, c) => {operation_finished(d, o, c);});
+    dup.done.connect((d, o, c, detail) => {operation_finished(d, o, c, detail);});
     dup.raise_error.connect((d, s, detail) => {raise_error(s, detail);});
     dup.action_desc_changed.connect((d, s) => {action_desc_changed(s);});
     dup.action_file_changed.connect((d, f, b) => {action_file_changed(f, b);});
@@ -214,7 +214,7 @@
     }
     catch (Error e) {
       raise_error(e.message, null);
-      operation_finished(dup, false, false);
+      operation_finished(dup, false, false, null);
     }
   }
   
@@ -230,7 +230,7 @@
     if (!success) {
       if (error != null)
         raise_error(error, null);
-      operation_finished(dup, false, false);
+      operation_finished(dup, false, false, null);
       return;
     }
 
@@ -242,18 +242,18 @@
     }
     catch (Error e) {
       raise_error(e.message, null);
-      operation_finished(dup, false, false);
+      operation_finished(dup, false, false, null);
       return;
     }
   }
   
-  internal async virtual void operation_finished(Duplicity dup, bool success, bool cancelled)
+  internal async virtual void operation_finished(Duplicity dup, bool success, bool cancelled, string? detail)
   {
     finished = true;
 
     unclaim_bus();
 
-    done(success, cancelled);
+    done(success, cancelled, detail);
   }
   
   protected virtual List<string>? make_argv() throws Error

=== modified file 'common/OperationBackup.vala'
--- common/OperationBackup.vala	2011-11-06 01:16:05 +0000
+++ common/OperationBackup.vala	2011-12-23 18:39:25 +0000
@@ -27,13 +27,13 @@
     Object(xid: xid, mode: Mode.BACKUP);
   }
   
-  internal async override void operation_finished(Duplicity dup, bool success, bool cancelled)
+  internal async override void operation_finished(Duplicity dup, bool success, bool cancelled, string? detail)
   {
     /* If successfully completed, update time of last backup and run base operation_finished */
     if (success)
       DejaDup.update_last_run_timestamp(DejaDup.TimestampType.BACKUP);
     
-    base.operation_finished(dup, success, cancelled);
+    base.operation_finished(dup, success, cancelled, detail);
   }
   
   protected override List<string>? make_argv() throws Error

=== modified file 'common/OperationRestore.vala'
--- common/OperationRestore.vala	2011-11-06 01:16:05 +0000
+++ common/OperationRestore.vala	2011-12-23 18:39:25 +0000
@@ -70,12 +70,12 @@
     return argv;
   }
   
-  internal async override void operation_finished(Duplicity dup, bool success, bool cancelled)
+  internal async override void operation_finished(Duplicity dup, bool success, bool cancelled, string? detail)
   {
     if (success)
       DejaDup.update_last_run_timestamp(DejaDup.TimestampType.RESTORE);
 
-    base.operation_finished(dup, success, cancelled);
+    base.operation_finished(dup, success, cancelled, detail);
   }
 }
 

=== modified file 'deja-dup/AssistantBackup.vala'
--- deja-dup/AssistantBackup.vala	2011-09-15 15:34:42 +0000
+++ deja-dup/AssistantBackup.vala	2011-12-23 18:39:25 +0000
@@ -90,7 +90,11 @@
         set_page_title(page, _("Backup Failed"));
       }
       else {
-        Idle.add(() => {do_close(); return false;});
+        set_page_title(page, _("Backup Finished"));
+
+        // If we don't have a special message to show the user, just bail.
+        if (!detail_widget.get_visible())
+          Idle.add(() => {do_close(); return false;});
       }
     }
     else if (page == progress_page) {

=== modified file 'deja-dup/AssistantOperation.vala'
--- deja-dup/AssistantOperation.vala	2011-10-20 16:09:37 +0000
+++ deja-dup/AssistantOperation.vala	2011-12-23 18:39:25 +0000
@@ -68,8 +68,8 @@
   protected Gtk.Widget progress_page {get; private set;}
   
   protected Gtk.Label summary_label;
-  Gtk.Widget error_widget;
-  Gtk.TextView error_text_view;
+  protected Gtk.Widget detail_widget;
+  Gtk.TextView detail_text_view;
   protected Gtk.Widget summary_page {get; private set;}
   
   protected Gdk.Pixbuf op_icon {get; private set;}
@@ -266,22 +266,24 @@
 
     return page;
   }
-  
+
+  void show_detail(string detail)
+  {
+    page_box.set_size_request(300, 200);
+    detail_widget.no_show_all = false;
+    detail_widget.show_all();
+    detail_text_view.buffer.set_text(detail, -1);
+  }
+
   public virtual void show_error(string error, string? detail)
   {
     error_occurred = true;
     
     summary_label.label = error;
-    summary_label.wrap = true;
     summary_label.selectable = true;
-    summary_label.max_width_chars = 25;
     
-    if (detail != null) {
-      page_box.set_size_request(300, 200);
-      error_widget.no_show_all = false;
-      error_widget.show_all();
-      error_text_view.buffer.set_text(detail, -1);
-    }
+    if (detail != null)
+      show_detail(detail);
     
     go_to_page(summary_page);
     set_header_icon(Gtk.Stock.DIALOG_ERROR);
@@ -408,23 +410,25 @@
   {
     summary_label = new Gtk.Label("");
     summary_label.set("xalign", 0.0f);
+    summary_label.wrap = true;
+    summary_label.max_width_chars = 25;
     
-    error_text_view = new Gtk.TextView();
-    error_text_view.editable = false;
-    error_text_view.wrap_mode = Gtk.WrapMode.WORD;
-    error_text_view.height_request = 150;
+    detail_text_view = new Gtk.TextView();
+    detail_text_view.editable = false;
+    detail_text_view.wrap_mode = Gtk.WrapMode.WORD;
+    detail_text_view.height_request = 150;
 
     var scroll = new Gtk.ScrolledWindow(null, null);
-    scroll.add(error_text_view);
+    scroll.add(detail_text_view);
     scroll.no_show_all = true; // only will be shown if an error occurs
-    error_widget = scroll;
+    detail_widget = scroll;
     
     var page = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
     page.set("child", summary_label,
-             "child", error_widget,
+             "child", detail_widget,
              "border-width", 12);
     page.child_set(summary_label, "expand", false);
-    page.child_set(error_widget, "expand", true);
+    page.child_set(detail_widget, "expand", true);
     
     return page;
   }
@@ -472,10 +476,10 @@
     summary_page = page;
   }
   
-  protected virtual void apply_finished(DejaDup.Operation op, bool success, bool cancelled)
+  protected virtual void apply_finished(DejaDup.Operation op, bool success, bool cancelled, string? detail)
   {
     if (status_icon != null) {
-      status_icon.done(success, cancelled);
+      status_icon.done(success, cancelled, detail);
       status_icon = null;
     }
     this.op = null;
@@ -489,6 +493,20 @@
     else {
       if (success) {
         succeeded = true;
+
+        if (detail != null) {
+          // Expect one paragraph followed by a blank line.  The first paragraph
+          // is an explanation before the full detail content.  So split it out
+          // into a proper label to look nice.
+          var halves = detail.split("\n\n", 2);
+          if (halves.length == 1) // no full detail content
+            summary_label.label = detail;
+          else if (halves.length == 2) {
+            summary_label.label = halves[0];
+            show_detail(halves[1]);
+          }
+        }
+
         go_to_page(summary_page);
       }
       else // show error
@@ -579,7 +597,7 @@
   {
     hide();
     if (status_icon != null) {
-      status_icon.done(false, true);
+      status_icon.done(false, true, null);
       status_icon = null; // hide immediately to seem responsive
     }
   }

=== modified file 'deja-dup/AssistantRestore.vala'
--- deja-dup/AssistantRestore.vala	2011-10-20 18:03:00 +0000
+++ deja-dup/AssistantRestore.vala	2011-12-23 18:39:25 +0000
@@ -362,7 +362,7 @@
       show_error(_("No backups to restore"), null);
   }
   
-  protected virtual void query_finished(DejaDup.Operation op, bool success, bool cancelled)
+  protected virtual void query_finished(DejaDup.Operation op, bool success, bool cancelled, string? detail)
   {
     this.op_state = op.get_state();
     this.query_op = null;

=== modified file 'deja-dup/AssistantRestoreMissing.vala'
--- deja-dup/AssistantRestoreMissing.vala	2011-10-07 14:43:17 +0000
+++ deja-dup/AssistantRestoreMissing.vala	2011-12-23 18:39:25 +0000
@@ -326,7 +326,7 @@
 
     // Don't start if queue is empty.
     if (backups_queue.get_length() == 0) {
-      query_files_finished(query_op_files, true, false);
+      query_files_finished(query_op_files, true, false, null);
       return;
     }
     
@@ -385,7 +385,7 @@
     query_op_files.start();
   }
   
-  protected override void query_finished(DejaDup.Operation op, bool success, bool cancelled)
+  protected override void query_finished(DejaDup.Operation op, bool success, bool cancelled, string? detail)
   {
     query_op = null;
     op_state = this.op.get_state();
@@ -410,7 +410,7 @@
     base.do_cancel();
   }
 
-  protected override void apply_finished(DejaDup.Operation op, bool success, bool cancelled)
+  protected override void apply_finished(DejaDup.Operation op, bool success, bool cancelled, string? detail)
   {
     /*
      * Ran after assistant finishes applying restore operation.
@@ -444,7 +444,7 @@
     }
   }
   
-  protected void query_files_finished(DejaDup.Operation? op, bool success, bool cancelled)
+  protected void query_files_finished(DejaDup.Operation? op, bool success, bool cancelled, string? detail)
   {
     query_op_files = null;
     this.op = null;

=== modified file 'deja-dup/StatusIcon.vala'
--- deja-dup/StatusIcon.vala	2011-10-10 02:27:25 +0000
+++ deja-dup/StatusIcon.vala	2011-12-23 18:39:25 +0000
@@ -109,7 +109,7 @@
     update_progress();
   }
 
-  public virtual void done(bool success, bool cancelled)
+  public virtual void done(bool success, bool cancelled, string? detail)
   {
     if (note != null) {
       try {
@@ -122,9 +122,16 @@
     }
 
     if (success && !cancelled && op.mode == DejaDup.Operation.Mode.BACKUP) {
+      string msg = _("Backup completed");
+
+      string more = null;
+      if (detail != null) {
+        msg = _("Backup finished");
+        more = _("Not all files were successfully backed up.  See dialog for more details.");
+      }
+
       Notify.init(_("Backup"));
-      note = new Notify.Notification(_("Backup completed"), null,
-                                     "deja-dup");
+      note = new Notify.Notification(msg, more, "deja-dup");
       try {
         note.show();
       }

=== modified file 'po/deja-dup.pot'
--- po/deja-dup.pot	2011-10-31 13:15:46 +0000
+++ po/deja-dup.pot	2011-12-23 18:39:25 +0000
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: mike@xxxxxxxxxxx\n"
-"POT-Creation-Date: 2011-10-28 12:39-0400\n"
+"POT-Creation-Date: 2011-12-23 13:34-0500\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -19,10 +19,10 @@
 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
 
 #. Translators: "Backup" is a noun
-#: ../data/deja-dup.desktop.in.h:1 ../data/deja-dup-ccpanel.desktop.in.h:2
-#: ../data/deja-dup-preferences.desktop.in.in.h:2 ../deja-dup/Prompt.vala:93
-#: ../deja-dup/Prompt.vala:127 ../deja-dup/StatusIcon.vala:125
-#: ../deja-dup/StatusIcon.vala:224 ../monitor/monitor.vala:115
+#: ../data/deja-dup.desktop.in.h:1 ../data/deja-dup-ccpanel.desktop.in.h:1
+#: ../data/deja-dup-preferences.desktop.in.in.h:1 ../deja-dup/Prompt.vala:93
+#: ../deja-dup/Prompt.vala:127 ../deja-dup/StatusIcon.vala:133
+#: ../deja-dup/StatusIcon.vala:231 ../monitor/monitor.vala:115
 #: ../preferences/preferences-main.vala:52
 #: ../preferences/preferences-main.vala:66
 msgid "Backup"
@@ -39,20 +39,20 @@
 msgid "Déjà Dup Backup Tool"
 msgstr ""
 
-#: ../data/deja-dup-ccpanel.desktop.in.h:1
-#: ../data/deja-dup-preferences.desktop.in.in.h:1
-msgid "Back Up Now"
-msgstr ""
-
-#: ../data/deja-dup-ccpanel.desktop.in.h:3
-#: ../data/deja-dup-preferences.desktop.in.in.h:3
+#: ../data/deja-dup-ccpanel.desktop.in.h:2
+#: ../data/deja-dup-preferences.desktop.in.in.h:2
 msgid "Change your backup settings"
 msgstr ""
 
 #. These keywords are used when searching for applications in dashes, etc.
+#: ../data/deja-dup-ccpanel.desktop.in.h:4
+#: ../data/deja-dup-preferences.desktop.in.in.h:4
+msgid "déjà;deja;dup;"
+msgstr ""
+
 #: ../data/deja-dup-ccpanel.desktop.in.h:5
 #: ../data/deja-dup-preferences.desktop.in.in.h:5
-msgid "déjà;deja;dup;"
+msgid "Back Up Now"
 msgstr ""
 
 #. Translators: Monitor in this sense means something akin to 'watcher', not
@@ -67,251 +67,251 @@
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:1
-msgid "Amazon S3 Access Key ID"
+#: ../preferences/Preferences.vala:160
+msgid "Folders to back up"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:2
 msgid ""
-"An optional folder name to store files in. This folder will be created in "
-"the chosen bucket."
+"This list of directories will be backed up. Reserved values $HOME, $DESKTOP, "
+"$DOCUMENTS, $DOWNLOAD, $MUSIC, $PICTURES, $PUBLIC_SHARE, $TEMPLATES, $TRASH, "
+"and $VIDEO are recognized as the user’s special directories. Relative "
+"entries are relative to the user’s home directory."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:3
-#: ../deja-dup/AssistantRestore.vala:221 ../preferences/Preferences.vala:151
-msgid "Backup location"
+#: ../preferences/Preferences.vala:168
+msgid "Folders to ignore"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:4
-msgid "Folder type"
+msgid ""
+"This list of directories will not be backed up. Reserved values $HOME, "
+"$DESKTOP, $DOCUMENTS, $DOWNLOAD, $MUSIC, $PICTURES, $PUBLIC_SHARE, "
+"$TEMPLATES, $TRASH, and $VIDEO are recognized as the user’s special "
+"directories. Relative entries are relative to the user’s home directory."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:5
-#: ../preferences/Preferences.vala:160
-msgid "Folders to back up"
+msgid "Whether the welcome screen has been dismissed"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:6
-#: ../preferences/Preferences.vala:168
-msgid "Folders to ignore"
+msgid "Whether to request the root password"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:7
-msgid "Full name of the external volume"
+msgid ""
+"Whether to request the root password when backing up from or restoring to "
+"system folders."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:8
-msgid "How long to keep backup files"
+msgid "The last time Déjà Dup was run"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:9
-msgid "How often to periodically back up"
+msgid ""
+"The last time Déjà Dup was successfully run. This time should be in ISO 8601 "
+"format."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:10
-msgid "Icon of the external volume"
+msgid "The last time Déjà Dup backed up"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:11
 msgid ""
-"If the backup location is on an external volume, this is its unique "
-"filesystem identifier."
+"The last time Déjà Dup successfully completed a backup. This time should be "
+"in ISO 8601 format."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:12
-msgid ""
-"If the backup location is on an external volume, this is the path of the "
-"folder on that volume."
+msgid "The last time Déjà Dup restored"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:13
 msgid ""
-"If the backup location is on an external volume, this is the volume’s icon."
+"The last time Déjà Dup successfully completed a restore. This time should be "
+"in ISO 8601 format."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:14
-msgid ""
-"If the backup location is on an external volume, this is the volume’s longer "
-"descriptive name."
+msgid "Whether to periodically back up"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:15
-msgid ""
-"If the backup location is on an external volume, this is the volume’s "
-"shorter name."
+msgid "Whether to automatically back up on a regular schedule."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:16
-msgid "Location in which to hold the backup files."
+msgid "How often to periodically back up"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:17
-msgid "Obsolete"
+msgid "The number of days between backups."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:18
-msgid "Relative path under the external volume"
+msgid ""
+"The first time Déjà Dup checked whether it should prompt about backing up"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:19
-msgid "Short name of the external volume"
+msgid ""
+"When a user logs in, the Déjà Dup monitor checks whether it should prompt "
+"about backing up. This is used to increase discoverability for users that "
+"don’t know about backups. This time should be either ‘disabled’ to turn off "
+"this check or in ISO 8601 format."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:20
-msgid "The Amazon S3 bucket name to use"
-msgstr ""
-
-#. Left this way for historical reasons, should be '$HOSTNAME'.  See convert_s3_folder_to_hostname()
+msgid "How long to keep backup files"
+msgstr ""
+
+#: ../data/org.gnome.DejaDup.gschema.xml.in.h:21
+msgid ""
+"The number of days to keep backup files on the backup location. A value of 0 "
+"means forever. This is a minimum number of days; the files may be kept "
+"longer."
+msgstr ""
+
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:22
-msgid "The Amazon S3 folder"
+msgid "Type of location to store backup"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:23
-msgid "The Rackspace Cloud Files container"
+msgid ""
+"The type of backup location. If ‘auto’, a default will be chosen based on "
+"what is available."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:24
-msgid "The Ubuntu One folder"
+msgid "Amazon S3 Access Key ID"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:25
-msgid ""
-"The first time Déjà Dup checked whether it should prompt about backing up"
+msgid "Your Amazon S3 Access Key Identifier. This acts as your S3 username."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:26
-msgid ""
-"The folder name to store files in. If ‘$HOSTNAME’, it will default to a "
-"folder based on the name of the computer."
+msgid "The Amazon S3 bucket name to use"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:27
-msgid "The last time Déjà Dup backed up"
-msgstr ""
-
-#: ../data/org.gnome.DejaDup.gschema.xml.in.h:28
-msgid "The last time Déjà Dup restored"
-msgstr ""
-
+msgid ""
+"Which Amazon S3 bucket to store files in. This does not need to exist "
+"already. Only legal hostname strings are valid."
+msgstr ""
+
+#. Left this way for historical reasons, should be '$HOSTNAME'.  See convert_s3_folder_to_hostname()
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:29
-msgid ""
-"The last time Déjà Dup successfully completed a backup. This time should be "
-"in ISO 8601 format."
+msgid "The Amazon S3 folder"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:30
 msgid ""
-"The last time Déjà Dup successfully completed a restore. This time should be "
-"in ISO 8601 format."
+"An optional folder name to store files in. This folder will be created in "
+"the chosen bucket."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:31
-msgid "The last time Déjà Dup was run"
+msgid "The Rackspace Cloud Files container"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:32
 msgid ""
-"The last time Déjà Dup was successfully run. This time should be in ISO 8601 "
-"format."
+"Which Rackspace Cloud Files container to store files in. This does not need "
+"to exist already. Only legal hostname strings are valid."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:33
-msgid "The number of days between backups."
+msgid "Your Rackspace username"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:34
-msgid ""
-"The number of days to keep backup files on the backup location. A value of 0 "
-"means forever. This is a minimum number of days; the files may be kept "
-"longer."
+msgid "This is your username for the Rackspace Cloud Files service."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:35
-msgid ""
-"The type of backup location. If ‘auto’, a default will be chosen based on "
-"what is available."
+msgid "The Ubuntu One folder"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:36
-msgid "This is your username for the Rackspace Cloud Files service."
+msgid ""
+"The folder name to store files in. If ‘$HOSTNAME’, it will default to a "
+"folder based on the name of the computer."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:37
-msgid ""
-"This list of directories will be backed up. Reserved values $HOME, $DESKTOP, "
-"$DOCUMENTS, $DOWNLOAD, $MUSIC, $PICTURES, $PUBLIC_SHARE, $TEMPLATES, $TRASH, "
-"and $VIDEO are recognized as the user’s special directories. Relative "
-"entries are relative to the user’s home directory."
+#: ../deja-dup/AssistantRestore.vala:221 ../preferences/Preferences.vala:151
+msgid "Backup location"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:38
-msgid ""
-"This list of directories will not be backed up. Reserved values $HOME, "
-"$DESKTOP, $DOCUMENTS, $DOWNLOAD, $MUSIC, $PICTURES, $PUBLIC_SHARE, "
-"$TEMPLATES, $TRASH, and $VIDEO are recognized as the user’s special "
-"directories. Relative entries are relative to the user’s home directory."
+msgid "Location in which to hold the backup files."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:39
-msgid "Type of location to store backup"
+msgid "Folder type"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:40
-msgid "Unique ID of the external volume"
+msgid ""
+"Whether the backup location is a mounted external volume or a normal folder."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:41
-msgid ""
-"When a user logs in, the Déjà Dup monitor checks whether it should prompt "
-"about backing up. This is used to increase discoverability for users that "
-"don’t know about backups. This time should be either ‘disabled’ to turn off "
-"this check or in ISO 8601 format."
+msgid "Relative path under the external volume"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:42
 msgid ""
-"Whether the backup location is a mounted external volume or a normal folder."
+"If the backup location is on an external volume, this is the path of the "
+"folder on that volume."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:43
-msgid "Whether the welcome screen has been dismissed"
+msgid "Unique ID of the external volume"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:44
-msgid "Whether to automatically back up on a regular schedule."
+msgid ""
+"If the backup location is on an external volume, this is its unique "
+"filesystem identifier."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:45
-msgid "Whether to periodically back up"
+msgid "Full name of the external volume"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:46
-msgid "Whether to request the root password"
+msgid ""
+"If the backup location is on an external volume, this is the volume’s longer "
+"descriptive name."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:47
-msgid ""
-"Whether to request the root password when backing up from or restoring to "
-"system folders."
+msgid "Short name of the external volume"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:48
 msgid ""
-"Which Amazon S3 bucket to store files in. This does not need to exist "
-"already. Only legal hostname strings are valid."
+"If the backup location is on an external volume, this is the volume’s "
+"shorter name."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:49
-msgid ""
-"Which Rackspace Cloud Files container to store files in. This does not need "
-"to exist already. Only legal hostname strings are valid."
+msgid "Icon of the external volume"
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:50
-msgid "Your Amazon S3 Access Key Identifier. This acts as your S3 username."
+msgid ""
+"If the backup location is on an external volume, this is the volume’s icon."
 msgstr ""
 
 #: ../data/org.gnome.DejaDup.gschema.xml.in.h:51
-msgid "Your Rackspace username"
+msgid "Obsolete"
 msgstr ""
 
 #: ../data/ui/restore-missing.ui.h:1
@@ -515,41 +515,50 @@
 "only found version %d.%d.%.2d"
 msgstr ""
 
-#: ../common/Duplicity.vala:132 ../common/Duplicity.vala:186
+#: ../common/Duplicity.vala:135 ../common/Duplicity.vala:198
 msgid "Paused (no network)"
 msgstr ""
 
-#: ../common/Duplicity.vala:392 ../common/Duplicity.vala:399
-#: ../common/Duplicity.vala:418 ../common/Duplicity.vala:423
+#: ../common/Duplicity.vala:405 ../common/Duplicity.vala:412
+#: ../common/Duplicity.vala:431 ../common/Duplicity.vala:436
 #: ../common/Operation.vala:79 ../common/Operation.vala:111
 msgid "Preparing…"
 msgstr ""
 
 #. Was not even a file path (maybe something goofy like computer://)
-#: ../common/Duplicity.vala:450
+#: ../common/Duplicity.vala:463
 #, c-format
 msgid "Could not restore ‘%s’: Not a valid file location"
 msgstr ""
 
 #. Tiny backup location.  Suggest they get a larger one.
-#: ../common/Duplicity.vala:516
+#: ../common/Duplicity.vala:529
 msgid "Backup location is too small.  Try using one with more space."
 msgstr ""
 
-#: ../common/Duplicity.vala:538
+#: ../common/Duplicity.vala:551
 msgid "Backup location does not have enough free space."
 msgstr ""
 
-#: ../common/Duplicity.vala:557 ../common/Duplicity.vala:571
+#: ../common/Duplicity.vala:570 ../common/Duplicity.vala:584
 msgid "Cleaning up…"
 msgstr ""
 
-#: ../common/Duplicity.vala:673 ../common/Duplicity.vala:1062
-#: ../deja-dup/AssistantOperation.vala:519
+#. OK, we succeeded yay!  But some files didn't make it into the backup
+#. because we couldn't read them.  So tell the user so they don't think
+#. everything is hunky dory.
+#: ../common/Duplicity.vala:678
+msgid ""
+"Could not back up the following files.  Please make sure you are able to "
+"open them."
+msgstr ""
+
+#: ../common/Duplicity.vala:699 ../common/Duplicity.vala:1088
+#: ../deja-dup/AssistantOperation.vala:537
 msgid "Failed with an unknown error."
 msgstr ""
 
-#: ../common/Duplicity.vala:901
+#: ../common/Duplicity.vala:928
 #, c-format
 msgid "Could not restore ‘%s’: File not found in backup"
 msgstr ""
@@ -557,16 +566,16 @@
 #. notify upper layers, if they want to do anything
 #. Duplicity tried to ask the user what the encryption password is.
 #. notify upper layers, if they want to do anything
-#: ../common/Duplicity.vala:907 ../common/Duplicity.vala:1009
-#: ../common/Duplicity.vala:1013
+#: ../common/Duplicity.vala:934 ../common/Duplicity.vala:1036
+#: ../common/Duplicity.vala:1040
 msgid "Bad encryption password."
 msgstr ""
 
-#: ../common/Duplicity.vala:912
+#: ../common/Duplicity.vala:939
 msgid "Computer name changed"
 msgstr ""
 
-#: ../common/Duplicity.vala:912
+#: ../common/Duplicity.vala:939
 #, c-format
 msgid ""
 "The existing backup is of a computer named %s, but the current computer’s "
@@ -574,67 +583,67 @@
 "location."
 msgstr ""
 
-#: ../common/Duplicity.vala:947
+#: ../common/Duplicity.vala:974
 #, c-format
 msgid "Permission denied when trying to create ‘%s’."
 msgstr ""
 
 #. assume error is on backend side
-#: ../common/Duplicity.vala:951 ../common/Duplicity.vala:955
+#: ../common/Duplicity.vala:978 ../common/Duplicity.vala:982
 #, c-format
 msgid "Permission denied when trying to read ‘%s’."
 msgstr ""
 
-#: ../common/Duplicity.vala:959
+#: ../common/Duplicity.vala:986
 #, c-format
 msgid "Permission denied when trying to delete ‘%s’."
 msgstr ""
 
-#: ../common/Duplicity.vala:966
+#: ../common/Duplicity.vala:993
 #, c-format
 msgid "Backup location ‘%s’ does not exist."
 msgstr ""
 
-#: ../common/Duplicity.vala:972 ../common/Duplicity.vala:1032
+#: ../common/Duplicity.vala:999 ../common/Duplicity.vala:1059
 msgid "No space left."
 msgstr ""
 
-#: ../common/Duplicity.vala:986
+#: ../common/Duplicity.vala:1013
 msgid "Invalid ID."
 msgstr ""
 
-#: ../common/Duplicity.vala:988
+#: ../common/Duplicity.vala:1015
 msgid "Invalid secret key."
 msgstr ""
 
-#: ../common/Duplicity.vala:990
+#: ../common/Duplicity.vala:1017
 msgid "Your Amazon Web Services account is not signed up for the S3 service."
 msgstr ""
 
-#: ../common/Duplicity.vala:1003
+#: ../common/Duplicity.vala:1030
 msgid "S3 bucket name is not available."
 msgstr ""
 
-#: ../common/Duplicity.vala:1017
+#: ../common/Duplicity.vala:1044
 #, c-format
 msgid "Error reading file ‘%s’."
 msgstr ""
 
-#: ../common/Duplicity.vala:1019
+#: ../common/Duplicity.vala:1046
 #, c-format
 msgid "Error writing file ‘%s’."
 msgstr ""
 
-#: ../common/Duplicity.vala:1034
+#: ../common/Duplicity.vala:1061
 #, c-format
 msgid "No space left in ‘%s’."
 msgstr ""
 
-#: ../common/Duplicity.vala:1042
+#: ../common/Duplicity.vala:1069
 msgid "No backup files found"
 msgstr ""
 
-#: ../common/Duplicity.vala:1093
+#: ../common/Duplicity.vala:1119
 msgid "Uploading…"
 msgstr ""
 
@@ -692,7 +701,11 @@
 msgid "Backup Failed"
 msgstr ""
 
-#: ../deja-dup/AssistantBackup.vala:97
+#: ../deja-dup/AssistantBackup.vala:93
+msgid "Backup Finished"
+msgstr ""
+
+#: ../deja-dup/AssistantBackup.vala:101
 msgid "Backing Up…"
 msgstr ""
 
@@ -704,51 +717,51 @@
 msgid "_Details"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:302
+#: ../deja-dup/AssistantOperation.vala:304
 msgid "_Allow restoring without a password"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:308
+#: ../deja-dup/AssistantOperation.vala:310
 msgid "_Password-protect your backup"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:322
+#: ../deja-dup/AssistantOperation.vala:324
 #, c-format
 msgid ""
 "You will need your password to restore your files. You might want to write "
 "it down."
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:337
+#: ../deja-dup/AssistantOperation.vala:339
 msgid "E_ncryption password"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:354
+#: ../deja-dup/AssistantOperation.vala:356
 msgid "Confir_m password"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:367
+#: ../deja-dup/AssistantOperation.vala:369
 msgid "_Show password"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:376
+#: ../deja-dup/AssistantOperation.vala:378
 #: ../deja-dup/MountOperationAssistant.vala:40
 msgid "_Remember password"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:443
+#: ../deja-dup/AssistantOperation.vala:447
 msgid "Summary"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:712
+#: ../deja-dup/AssistantOperation.vala:730
 msgid "Require Password?"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:714
+#: ../deja-dup/AssistantOperation.vala:732
 msgid "Encryption Password Needed"
 msgstr ""
 
-#: ../deja-dup/AssistantOperation.vala:760
+#: ../deja-dup/AssistantOperation.vala:778
 msgid "Backup encryption password"
 msgstr ""
 
@@ -1025,24 +1038,33 @@
 msgid "_Skip Backup"
 msgstr ""
 
-#: ../deja-dup/StatusIcon.vala:126
+#: ../deja-dup/StatusIcon.vala:125
 msgid "Backup completed"
 msgstr ""
 
-#: ../deja-dup/StatusIcon.vala:225
+#: ../deja-dup/StatusIcon.vala:129
+msgid "Backup finished"
+msgstr ""
+
+#: ../deja-dup/StatusIcon.vala:130
+msgid ""
+"Not all files were successfully backed up.  See dialog for more details."
+msgstr ""
+
+#: ../deja-dup/StatusIcon.vala:232
 msgid "Starting scheduled backup"
 msgstr ""
 
-#: ../deja-dup/StatusIcon.vala:227
+#: ../deja-dup/StatusIcon.vala:234
 msgid "Show Progress"
 msgstr ""
 
-#: ../deja-dup/StatusIcon.vala:265
+#: ../deja-dup/StatusIcon.vala:272
 #, c-format
 msgid "%.1f%% complete"
 msgstr ""
 
-#: ../deja-dup/StatusIcon.vala:278
+#: ../deja-dup/StatusIcon.vala:285
 msgid "Show _Progress"
 msgstr ""
 
@@ -1114,6 +1136,10 @@
 msgid "Schedule"
 msgstr ""
 
+#: ../preferences/Preferences.vala:365
+msgid "Categories"
+msgstr ""
+
 #: ../widgets/ConfigDelete.vala:43
 msgid "At least a month"
 msgstr ""

=== modified file 'tests/common/common.vala'
--- tests/common/common.vala	2011-12-23 05:21:48 +0000
+++ tests/common/common.vala	2011-12-23 18:39:25 +0000
@@ -145,9 +145,11 @@
 {
   var loop = new MainLoop(null);
   var op = new DejaDup.OperationBackup();
-  op.done.connect((op, s, c) => {
+  op.done.connect((op, s, c, d) => {
+    Test.message("Done: %d, %d, %s", (int)s, (int)c, d);
     assert(success == s);
     assert(cancelled == c);
+    assert(detail == d);
     loop.quit();
   });
 
@@ -226,6 +228,45 @@
   run_basic_backup();
 }
 
+void read_error()
+{
+  Test.bug("907846");
+  var user = Environment.get_user_name();
+  set_script("""
+ARGS: collection-status %s
+RETURN: 0
+
+INFO 3
+
+=== deja-dup ===
+ARGS: full %s
+RETURN: 0
+
+WARNING 10 '/blarg'
+
+WARNING 10 '/home/%s/1'
+
+WARNING 10 '/home/%s/2'
+
+=== deja-dup ===
+ARGS: full %s
+RETURN: 0
+
+WARNING 10 '/blarg'
+
+WARNING 10 '/home/%s/1'
+
+WARNING 10 '/home/%s/2'
+
+""".printf(default_args(),
+           default_args(Mode.DRY), user, user,
+           default_args(Mode.BACKUP), user, user));
+  run_basic_backup(true, false, """Could not back up the following files.  Please make sure you are able to open them.
+
+/home/%s/1
+/home/%s/2""".printf(user, user));
+}
+
 int main(string[] args)
 {
   Test.init(ref args);
@@ -242,6 +283,7 @@
 
   var backup = new TestSuite("backup");
   backup.add(new TestCase("bad_hostname", backup_setup, bad_hostname, backup_teardown));
+  backup.add(new TestCase("read_error", backup_setup, read_error, backup_teardown));
   TestSuite.get_root().add_suite(backup);
 
   return Test.run();


Follow ups