deja-dup-team team mailing list archive
-
deja-dup-team team
-
Mailing list archive
-
Message #00673
[Merge] lp:~mwrius/deja-dup/GCS into lp:deja-dup
Marius Nuennerich has proposed merging lp:~mwrius/deja-dup/GCS into lp:deja-dup.
Requested reviews:
Déjà Dup Developers (deja-dup-hackers)
For more details, see:
https://code.launchpad.net/~mwrius/deja-dup/GCS/+merge/276188
Add support for Google Cloud Storage.
--
Your team Déjà Dup Developers is requested to review the proposed merge of lp:~mwrius/deja-dup/GCS into lp:deja-dup.
=== modified file 'AUTHORS'
--- AUTHORS 2014-10-25 13:52:17 +0000
+++ AUTHORS 2015-10-29 20:58:01 +0000
@@ -17,6 +17,10 @@
Copyright: 2008–2013 Rosetta Contributors and Canonical Ltd
License: GPL-3+
+Files: libdeja/BackendGCS.vala deja-dup/widgets/ConfigLocationGCS.vala
+Copyright: 2015 Marius Nünnerich <mnu@xxxxxxxxxx>
+License: GPL-3+
+
Files: libdeja/uriutils.c libdeja/uriutils.h
Copyright: 2006–2007 Red Hat, Inc
License: GPL-3+
=== modified file 'data/org.gnome.DejaDup.gschema.xml.in'
--- data/org.gnome.DejaDup.gschema.xml.in 2014-04-29 02:38:47 +0000
+++ data/org.gnome.DejaDup.gschema.xml.in 2015-10-29 20:58:01 +0000
@@ -65,6 +65,7 @@
<choices>
<choice value='auto'/>
<choice value='file'/>
+ <choice value='gcs'/>
<choice value='gdrive'/>
<choice value='rackspace'/>
<choice value='s3'/>
@@ -76,6 +77,7 @@
</key>
<child name="rackspace" schema="org.gnome.DejaDup.Rackspace"/>
<child name="s3" schema="org.gnome.DejaDup.S3"/>
+ <child name="gcs" schema="org.gnome.DejaDup.GCS"/>
<child name="gdrive" schema="org.gnome.DejaDup.GDrive"/>
<child name="file" schema="org.gnome.DejaDup.File"/>
</schema>
@@ -96,6 +98,23 @@
<_description>An optional folder name to store files in. This folder will be created in the chosen bucket.</_description>
</key>
</schema>
+ <schema id="org.gnome.DejaDup.GCS" path="/org/gnome/deja-dup/gcs/">
+ <key name="id" type="s">
+ <default>''</default>
+ <_summary>Google Cloud Storage Access Key ID</_summary>
+ <_description>Your Google Cloud Storage Access Key Identifier. This acts as your Google Cloud Storage username.</_description>
+ </key>
+ <key name="bucket" type="s">
+ <default>''</default>
+ <_summary>The Google Cloud Storage bucket name to use</_summary>
+ <_description>Which Google Cloud Storage bucket to store files in. This does not need to exist already. Only legal hostname strings are valid.</_description>
+ </key>
+ <key name="folder" type="s">
+ <default>'$HOSTNAME'</default>
+ <_summary>The Google Cloud Storage folder</_summary>
+ <_description>An optional folder name to store files in. This folder will be created in the chosen bucket.</_description>
+ </key>
+ </schema>
<schema id="org.gnome.DejaDup.GDrive" path="/org/gnome/deja-dup/gdrive/">
<key name="email" type="s">
<default>''</default>
=== modified file 'debian/control'
--- debian/control 2014-09-20 14:51:29 +0000
+++ debian/control 2015-10-29 20:58:01 +0000
@@ -36,6 +36,7 @@
policykit-1,
Suggests: deja-dup-backend-cloudfiles,
deja-dup-backend-s3,
+ deja-dup-backend-gcs,
Description: Back up your files
Déjà Dup is a simple backup tool. It hides the complexity of backing up the
Right Way (encrypted, off-site, and regular) and uses duplicity as the
@@ -73,6 +74,18 @@
.
This package adds Rackspace Cloudfiles support to Déjà Dup.
+Package: deja-dup-backend-gcs
+Architecture: all
+Depends: ${misc:Depends},
+ deja-dup,
+ python-boto (>= 2.20),
+Description: Google Cloud Storage support for Déjà Dup
+ Déjà Dup is a simple backup tool. It hides the complexity of backing up the
+ Right Way (encrypted, off-site, and regular) and uses duplicity as the
+ backend.
+ .
+ This package adds Google Cloud Storage support to Déjà Dup.
+
#Package: deja-dup-backend-gdrive
#Architecture: all
#Depends: ${misc:Depends},
=== modified file 'deja-dup/widgets/CMakeLists.txt'
--- deja-dup/widgets/CMakeLists.txt 2014-04-29 02:38:47 +0000
+++ deja-dup/widgets/CMakeLists.txt 2015-10-29 20:58:01 +0000
@@ -31,6 +31,7 @@
ConfigLocationDAV.vala
ConfigLocationFile.vala
ConfigLocationFTP.vala
+ ConfigLocationGCS.vala
ConfigLocationGDrive.vala
ConfigLocationRackspace.vala
ConfigLocationS3.vala
=== modified file 'deja-dup/widgets/ConfigLocation.vala'
--- deja-dup/widgets/ConfigLocation.vala 2014-04-29 02:38:47 +0000
+++ deja-dup/widgets/ConfigLocation.vala 2015-10-29 20:58:01 +0000
@@ -61,6 +61,7 @@
int index_ftp;
int index_dav;
int index_s3 = -2;
+ int index_gcs = -2;
int index_gdrive = -2;
int index_rackspace = -2;
int index_u1 = -2;
@@ -112,6 +113,7 @@
// Insert cloud providers
insert_u1();
insert_s3();
+ insert_gcs();
insert_gdrive();
insert_rackspace();
@@ -180,6 +182,14 @@
ref index_s3, insert_s3);
}
+ void insert_gcs() {
+ insert_cloud_if_available("gcs", BackendGCS.get_checker(),
+ new ThemedIcon("deja-dup-cloud"),
+ _("Google Cloud Storage"),
+ new ConfigLocationGCS(label_sizes),
+ ref index_gcs, insert_gcs);
+ }
+
void insert_gdrive() {
insert_cloud_if_available("gdrive", BackendGDrive.get_checker(),
new ThemedIcon("deja-dup-cloud"),
@@ -424,6 +434,8 @@
var backend = Backend.get_default_type();
if (backend == "s3")
index = index_s3;
+ else if (backend == "gcs")
+ index = index_gcs;
else if (backend == "gdrive")
index = index_gdrive;
else if (backend == "rackspace")
@@ -516,6 +528,8 @@
if (index == index_s3)
settings.set_string(BACKEND_KEY, "s3");
+ else if (index == index_gcs)
+ settings.set_string(BACKEND_KEY, "gcs");
else if (index == index_gdrive)
settings.set_string(BACKEND_KEY, "gdrive");
else if (index == index_rackspace)
=== added file 'deja-dup/widgets/ConfigLocationGCS.vala'
--- deja-dup/widgets/ConfigLocationGCS.vala 1970-01-01 00:00:00 +0000
+++ deja-dup/widgets/ConfigLocationGCS.vala 2015-10-29 20:58:01 +0000
@@ -0,0 +1,41 @@
+/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 2 -*- */
+/*
+ This file is part of Déjà Dup.
+ For copyright information, see AUTHORS.
+
+ Déjà Dup is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Déjà Dup is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Déjà Dup. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+using GLib;
+
+namespace DejaDup {
+
+public class ConfigLocationGCS : ConfigLocationTable
+{
+ public ConfigLocationGCS(Gtk.SizeGroup sg) {
+ Object(label_sizes: sg);
+ }
+
+ construct {
+ add_widget(_("Google Cloud Storage Access Key I_D"),
+ new ConfigEntry(DejaDup.GCS_ID_KEY, DejaDup.GCS_ROOT));
+ add_widget(_("_Bucket"),
+ new ConfigEntry(DejaDup.GCS_BUCKET_KEY, DejaDup.GCS_ROOT));
+ add_widget(_("_Folder"),
+ new ConfigFolder(DejaDup.GCS_FOLDER_KEY, DejaDup.GCS_ROOT));
+ }
+}
+
+}
+
=== modified file 'libdeja/Backend.vala'
--- libdeja/Backend.vala 2014-04-29 02:38:47 +0000
+++ libdeja/Backend.vala 2015-10-29 20:58:01 +0000
@@ -57,6 +57,7 @@
if (backend != "auto" &&
backend != "s3" &&
+ backend != "gcs" &&
backend != "gdrive" &&
backend != "rackspace" &&
backend != "u1" &&
@@ -71,6 +72,8 @@
var backend_name = get_default_type();
if (backend_name == "s3")
return new BackendS3();
+ else if (backend_name == "gcs")
+ return new BackendGCS();
else if (backend_name == "gdrive")
return new BackendGDrive();
else if (backend_name == "u1")
=== modified file 'libdeja/BackendAuto.vala'
--- libdeja/BackendAuto.vala 2014-04-29 02:38:47 +0000
+++ libdeja/BackendAuto.vala 2015-10-29 20:58:01 +0000
@@ -50,6 +50,7 @@
static bool started = false;
static bool done = false;
+ Checker gcs_checker;
Checker gdrive_checker;
Checker s3checker;
construct {
@@ -59,10 +60,13 @@
started = true;
ref(); // Give us time to finish
- // List is (in order): gdrive, s3, file
+ // List is (in order): gdrive, gcs, s3, file
gdrive_checker = BackendGDrive.get_checker();
gdrive_checker.notify["complete"].connect(examine_checkers);
+ gcs_checker = BackendGCS.get_checker();
+ gcs_checker.notify["complete"].connect(examine_checkers);
+
s3checker = BackendS3.get_checker();
s3checker.notify["complete"].connect(examine_checkers);
@@ -78,11 +82,15 @@
if (gdrive_checker.complete) {
if (gdrive_checker.available)
finish("gdrive");
- else if (s3checker.complete) {
- if (s3checker.available)
- finish("s3");
- else
- finish("file");
+ else if (gcs_checker.complete) {
+ if (gcs_checker.available)
+ finish("gcs");
+ else if (s3checker.complete) {
+ if (s3checker.available)
+ finish("s3");
+ else
+ finish("file");
+ }
}
}
}
=== added file 'libdeja/BackendGCS.vala'
--- libdeja/BackendGCS.vala 1970-01-01 00:00:00 +0000
+++ libdeja/BackendGCS.vala 2015-10-29 20:58:01 +0000
@@ -0,0 +1,173 @@
+/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 2 -*- */
+/*
+ This file is part of Déjà Dup.
+ For copyright information, see AUTHORS.
+
+ Déjà Dup is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Déjà Dup is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Déjà Dup. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+using GLib;
+
+namespace DejaDup {
+
+public const string GCS_ROOT = "GCS";
+public const string GCS_ID_KEY = "id";
+public const string GCS_BUCKET_KEY = "bucket";
+public const string GCS_FOLDER_KEY = "folder";
+
+const string GCS_SERVER = "www.googleapis.com";
+
+public class BackendGCS : Backend
+{
+ public static Checker get_checker() {
+ return PythonChecker.get_checker("boto");
+ }
+
+ public override Backend clone() {
+ return new BackendGCS();
+ }
+
+ public override bool is_native() {
+ return false;
+ }
+
+ public override Icon? get_icon() {
+ return new ThemedIcon("deja-dup-cloud");
+ }
+
+ public override async bool is_ready(out string when) {
+ when = _("Backup will begin when a network connection becomes available.");
+ return yield Network.get().can_reach ("http://%s/".printf(GCS_SERVER));
+ }
+
+ public override string get_location(ref bool as_root)
+ {
+ var settings = get_settings(GCS_ROOT);
+
+ var bucket = settings.get_string(GCS_BUCKET_KEY);
+ var folder = get_folder_key(settings, GCS_FOLDER_KEY);
+
+ return "gs://%s/%s".printf(bucket, folder);
+ }
+
+ public override string get_location_pretty()
+ {
+ var settings = get_settings(GCS_ROOT);
+ var bucket = settings.get_string(GCS_BUCKET_KEY);
+ var folder = get_folder_key(settings, GCS_FOLDER_KEY);
+ if (folder == "")
+ return _("Google Cloud Storage");
+ else
+ // Translators: %s/%s is a folder.
+ return _("%s/%s on Google Cloud Storage").printf(bucket, folder);
+ }
+
+ string settings_id;
+ string id;
+ string secret_key;
+ public override async void get_envp() throws Error
+ {
+ var settings = get_settings(GCS_ROOT);
+ settings_id = settings.get_string(GCS_ID_KEY);
+ id = settings_id == null ? "" : settings_id;
+
+ if (id != "" && secret_key != null) {
+ // We've already been run before and got the key
+ got_secret_key();
+ return;
+ }
+
+ if (id != "") {
+ // First, try user's keyring
+ try {
+ secret_key = yield Secret.password_lookup(Secret.SCHEMA_COMPAT_NETWORK,
+ null,
+ "user", id,
+ "server", GCS_SERVER,
+ "protocol", "https");
+ if (secret_key != null) {
+ got_secret_key();
+ return;
+ }
+ }
+ catch (Error e) {
+ // fall through to ask_password below
+ }
+ }
+
+ // Didn't find it, so ask user
+ ask_password();
+ }
+
+ async void got_password_reply(MountOperation mount_op, MountOperationResult result)
+ {
+ if (result != MountOperationResult.HANDLED) {
+ envp_ready(false, new List<string>(), _("Permission denied"));
+ return;
+ }
+
+ id = mount_op.username;
+ secret_key = mount_op.password;
+
+ // Save it
+ var remember = mount_op.password_save;
+ if (remember != PasswordSave.NEVER) {
+ string where = (remember == PasswordSave.FOR_SESSION) ?
+ Secret.COLLECTION_SESSION : Secret.COLLECTION_DEFAULT;
+ try {
+ yield Secret.password_store(Secret.SCHEMA_COMPAT_NETWORK,
+ where,
+ "%s@%s".printf(id, GCS_SERVER),
+ secret_key,
+ null,
+ "user", id,
+ "server", GCS_SERVER,
+ "protocol", "https");
+ }
+ catch (Error e) {
+ warning("%s\n", e.message);
+ }
+ }
+
+ got_secret_key();
+ }
+
+ void ask_password() {
+ mount_op.set("label_help", _("You can sign up for a Google Cloud Storage account <a href=\"%s\">online</a>. Remember to enable Interoperability and create keys.").printf("http://cloud.google.com"));
+ mount_op.set("label_title", _("Connect to Google Cloud Storage"));
+ mount_op.set("label_username", _("_Access key ID"));
+ mount_op.set("label_password", _("_Secret access key"));
+ mount_op.set("label_show_password", _("S_how secret access key"));
+ mount_op.set("label_remember_password", _("_Remember secret access key"));
+ mount_op.reply.connect(got_password_reply);
+ mount_op.ask_password("", id, "",
+ AskPasswordFlags.NEED_PASSWORD |
+ AskPasswordFlags.NEED_USERNAME |
+ AskPasswordFlags.SAVING_SUPPORTED);
+ }
+
+ void got_secret_key() {
+ var settings = get_settings(GCS_ROOT);
+ if (id != settings_id)
+ settings.set_string(GCS_ID_KEY, id);
+
+ List<string> envp = new List<string>();
+ envp.append("GS_ACCESS_KEY_ID=%s".printf(id));
+ envp.append("GS_SECRET_ACCESS_KEY=%s".printf(secret_key));
+ envp_ready(true, envp);
+ }
+}
+
+} // end namespace
+
=== modified file 'libdeja/CMakeLists.txt'
--- libdeja/CMakeLists.txt 2014-04-29 02:38:47 +0000
+++ libdeja/CMakeLists.txt 2015-10-29 20:58:01 +0000
@@ -20,6 +20,7 @@
Backend.vala
BackendAuto.vala
BackendFile.vala
+ BackendGCS.vala
BackendGDrive.vala
BackendRackspace.vala
BackendS3.vala
Follow ups