summaryrefslogtreecommitdiff
path: root/tickets/10d72738d6ce4ab7b0fc3f21c15635bc
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2016-02-20 22:10:13 +0200
committerLars Wirzenius <liw@liw.fi>2016-02-20 22:10:13 +0200
commit8c087e41fdda5d9508b9c95ea57fbd079142633d (patch)
tree44bbbcec3aac27d6ca26d498ac1b4f77ae15c190 /tickets/10d72738d6ce4ab7b0fc3f21c15635bc
parentea12bbd09cf9e03d4b50f139f55925aad10dcec0 (diff)
downloadobnam-dev-distix-8c087e41fdda5d9508b9c95ea57fbd079142633d.tar.gz
imported mails
Diffstat (limited to 'tickets/10d72738d6ce4ab7b0fc3f21c15635bc')
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/cur/.this-dir-not-empty/.empty/empty-file0
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/.this-dir-not-empty/.empty/empty-file0
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M673089P17339Q108.exolobe1123
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M699945P17339Q109.exolobe1123
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M711251P17339Q110.exolobe1114
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999008.M207056P17339Q191.exolobe1205
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999008.M852087P17339Q198.exolobe1224
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999010.M812138P17339Q216.exolobe1648
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999010.M898823P17339Q219.exolobe1106
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/tmp/.this-dir-not-empty/.empty/empty-file0
-rw-r--r--tickets/10d72738d6ce4ab7b0fc3f21c15635bc/ticket.yaml4
11 files changed, 1547 insertions, 0 deletions
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/cur/.this-dir-not-empty/.empty/empty-file b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/cur/.this-dir-not-empty/.empty/empty-file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/cur/.this-dir-not-empty/.empty/empty-file
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/.this-dir-not-empty/.empty/empty-file b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/.this-dir-not-empty/.empty/empty-file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/.this-dir-not-empty/.empty/empty-file
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M673089P17339Q108.exolobe1 b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M673089P17339Q108.exolobe1
new file mode 100644
index 0000000..e020600
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M673089P17339Q108.exolobe1
@@ -0,0 +1,123 @@
+Return-Path: <obnam-dev-bounces@obnam.org>
+X-Original-To: distix@pieni.net
+Delivered-To: distix@pieni.net
+Received: from bagpuss.pepperfish.net (bagpuss.pepperfish.net [148.251.8.16])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPS id EDAFA2B4B0
+ for <distix@pieni.net>; Sun, 7 Dec 2014 15:34:59 +0100 (CET)
+Received: from platypus.pepperfish.net (unknown [10.112.100.20])
+ by bagpuss.pepperfish.net (Postfix) with ESMTP id 54DE6CE2;
+ Sun, 7 Dec 2014 14:34:59 +0000 (GMT)
+Received: from localhost ([::1] helo=platypus.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XxcvL-00030z-7n; Sun, 07 Dec 2014 14:34:59 +0000
+Received: from inmail ([10.112.100.10] helo=mx0.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XxcvJ-00030t-OW
+ for <obnam-dev@obnam.org>; Sun, 07 Dec 2014 14:34:57 +0000
+Received: from xvm-166-37.ghst.net
+ ([95.142.166.37] helo=pieni.net ident=postfix)
+ by mx0.pepperfish.net with esmtps (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256)
+ (Exim 4.80) (envelope-from <liw@liw.fi>) id 1XxcvG-0003cH-Sy
+ for obnam-dev@obnam.org; Sun, 07 Dec 2014 14:34:57 +0000
+Received: from exolobe1.liw.fi (82-181-8-107.bb.dnainternet.fi [82.181.8.107])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPSA id D5EA92B4B0;
+ Sun, 7 Dec 2014 15:34:51 +0100 (CET)
+Received: from exolobe1.liw.fi (localhost [127.0.0.1])
+ by exolobe1.liw.fi (Postfix) with ESMTPS id 2B14F45CD4;
+ Sun, 7 Dec 2014 16:34:51 +0200 (EET)
+Date: Sun, 7 Dec 2014 16:34:49 +0200
+From: Lars Wirzenius <liw@liw.fi>
+To: Matthew Dawson <matthew@mjdsystems.ca>
+Message-ID: <20141207143449.GH17184@exolobe1.liw.fi>
+References: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+ <20141206192247.GK6438@exolobe1.liw.fi>
+ <1531092.aY1fI7Af0k@cwmtaff>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <1531092.aY1fI7Af0k@cwmtaff>
+User-Agent: Mutt/1.5.21 (2010-09-15)
+X-Spam-Score: -3.0
+X-Spam-Score-int: -29
+X-Spam-Bar: ---
+X-Scanned-By: pepperfish.net, Sun, 07 Dec 2014 14:34:57 +0000
+X-Spam-Report: Content analysis details: (-3.0 points)
+ pts rule name description
+ ---- ---------------------- --------------------------------------------------
+ -1.0 PPF_USER_AGENT_MUTT User-Agent: contains Mutt (Mutt isn't a spam
+ tool) -0.5 PPF_USER_AGENT User-Agent: exists
+ 0.2 PPF_INREPLYTO_NODOTS In-Reply-To contains no dots after the @
+ 0.2 PPF_REFERENCES_NODOTS References contains no dots after the @
+ -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%
+ [score: 0.0000]
+Cc: obnam-dev@obnam.org
+Subject: Re: [PATCH 0/3] RFC: Add support for Openstack Swift as backup
+ repository
+X-BeenThere: obnam-dev@obnam.org
+X-Mailman-Version: 2.1.5
+Precedence: list
+List-Id: Obnam development discussions <obnam-dev-obnam.org>
+List-Unsubscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=unsubscribe>
+List-Archive: <http://listmaster.pepperfish.net/pipermail/obnam-dev-obnam.org>
+List-Post: <mailto:obnam-dev@obnam.org>
+List-Help: <mailto:obnam-dev-request@obnam.org?subject=help>
+List-Subscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=subscribe>
+Sender: obnam-dev-bounces@obnam.org
+Errors-To: obnam-dev-bounces@obnam.org
+
+On Sat, Dec 06, 2014 at 05:54:39PM -0500, Matthew Dawson wrote:
+> Sounds good to me. I'll work on cleaning everything up. Regarding
+> the test cases, I'm not sure what you are looking for. As the Swift
+> support only plugs into the VFS layer, there isn't really anything
+> sitting between the two. I do have a set of tests like the SFTP
+> does, so that the regular test suite passes.
+
+I'd like to have:
+
+* Some tests that at least ensure syntactic correctness of the Python,
+ and getting it nitpicked by the nitpicky tests (line lengths,
+ copyright statements, etc) when the normal test suite ("./check") is
+ run, even if it doesn't test at all that the Swift plugin works.
+ Having the plugin in the source tree so it gets loaded when ./obnam
+ starts is probably sufficient.
+
+* Something to run separately to test the Swift plugin against an
+ existing Swift instance, including documentation of how to get
+ access to one and how to set things up so that the tests can be run.
+ The test-swift script is probably doing this already.
+
+I suspect you're pretty much there, already, actually. :)
+
+> If you want, I can try to make a mock instance of Swift, but I'd bet
+> I'd create more bugs in the mock than the actual code. Alternately,
+> if you just want a free place to try the code against, hubic.com
+> provides 25G free storage using swift.
+
+Unless there's a general mockup of Swift, which others are using
+anyway, I don't think this is worthwhile.
+
+> > Going forward, will you be available to maintain this code?
+
+> As long as I'm using Obnam/this code in my backup strategy, yes I'm
+> happy to do so. Should that change in the future, I can try to
+> continue to help out. For the foreseeable future, that shouldn't be
+> a problem.
+
+Cool. That's all I can ask for, really.
+
+Thank you!
+
+--
+http://gtdfh.branchable.com/ -- GTD for hackers
+http://obnam.org/ -- HAVE YOU BACKED UP TODAY?
+
+_______________________________________________
+obnam-dev mailing list
+obnam-dev@obnam.org
+http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M699945P17339Q109.exolobe1 b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M699945P17339Q109.exolobe1
new file mode 100644
index 0000000..e020600
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M699945P17339Q109.exolobe1
@@ -0,0 +1,123 @@
+Return-Path: <obnam-dev-bounces@obnam.org>
+X-Original-To: distix@pieni.net
+Delivered-To: distix@pieni.net
+Received: from bagpuss.pepperfish.net (bagpuss.pepperfish.net [148.251.8.16])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPS id EDAFA2B4B0
+ for <distix@pieni.net>; Sun, 7 Dec 2014 15:34:59 +0100 (CET)
+Received: from platypus.pepperfish.net (unknown [10.112.100.20])
+ by bagpuss.pepperfish.net (Postfix) with ESMTP id 54DE6CE2;
+ Sun, 7 Dec 2014 14:34:59 +0000 (GMT)
+Received: from localhost ([::1] helo=platypus.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XxcvL-00030z-7n; Sun, 07 Dec 2014 14:34:59 +0000
+Received: from inmail ([10.112.100.10] helo=mx0.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XxcvJ-00030t-OW
+ for <obnam-dev@obnam.org>; Sun, 07 Dec 2014 14:34:57 +0000
+Received: from xvm-166-37.ghst.net
+ ([95.142.166.37] helo=pieni.net ident=postfix)
+ by mx0.pepperfish.net with esmtps (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256)
+ (Exim 4.80) (envelope-from <liw@liw.fi>) id 1XxcvG-0003cH-Sy
+ for obnam-dev@obnam.org; Sun, 07 Dec 2014 14:34:57 +0000
+Received: from exolobe1.liw.fi (82-181-8-107.bb.dnainternet.fi [82.181.8.107])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPSA id D5EA92B4B0;
+ Sun, 7 Dec 2014 15:34:51 +0100 (CET)
+Received: from exolobe1.liw.fi (localhost [127.0.0.1])
+ by exolobe1.liw.fi (Postfix) with ESMTPS id 2B14F45CD4;
+ Sun, 7 Dec 2014 16:34:51 +0200 (EET)
+Date: Sun, 7 Dec 2014 16:34:49 +0200
+From: Lars Wirzenius <liw@liw.fi>
+To: Matthew Dawson <matthew@mjdsystems.ca>
+Message-ID: <20141207143449.GH17184@exolobe1.liw.fi>
+References: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+ <20141206192247.GK6438@exolobe1.liw.fi>
+ <1531092.aY1fI7Af0k@cwmtaff>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <1531092.aY1fI7Af0k@cwmtaff>
+User-Agent: Mutt/1.5.21 (2010-09-15)
+X-Spam-Score: -3.0
+X-Spam-Score-int: -29
+X-Spam-Bar: ---
+X-Scanned-By: pepperfish.net, Sun, 07 Dec 2014 14:34:57 +0000
+X-Spam-Report: Content analysis details: (-3.0 points)
+ pts rule name description
+ ---- ---------------------- --------------------------------------------------
+ -1.0 PPF_USER_AGENT_MUTT User-Agent: contains Mutt (Mutt isn't a spam
+ tool) -0.5 PPF_USER_AGENT User-Agent: exists
+ 0.2 PPF_INREPLYTO_NODOTS In-Reply-To contains no dots after the @
+ 0.2 PPF_REFERENCES_NODOTS References contains no dots after the @
+ -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%
+ [score: 0.0000]
+Cc: obnam-dev@obnam.org
+Subject: Re: [PATCH 0/3] RFC: Add support for Openstack Swift as backup
+ repository
+X-BeenThere: obnam-dev@obnam.org
+X-Mailman-Version: 2.1.5
+Precedence: list
+List-Id: Obnam development discussions <obnam-dev-obnam.org>
+List-Unsubscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=unsubscribe>
+List-Archive: <http://listmaster.pepperfish.net/pipermail/obnam-dev-obnam.org>
+List-Post: <mailto:obnam-dev@obnam.org>
+List-Help: <mailto:obnam-dev-request@obnam.org?subject=help>
+List-Subscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=subscribe>
+Sender: obnam-dev-bounces@obnam.org
+Errors-To: obnam-dev-bounces@obnam.org
+
+On Sat, Dec 06, 2014 at 05:54:39PM -0500, Matthew Dawson wrote:
+> Sounds good to me. I'll work on cleaning everything up. Regarding
+> the test cases, I'm not sure what you are looking for. As the Swift
+> support only plugs into the VFS layer, there isn't really anything
+> sitting between the two. I do have a set of tests like the SFTP
+> does, so that the regular test suite passes.
+
+I'd like to have:
+
+* Some tests that at least ensure syntactic correctness of the Python,
+ and getting it nitpicked by the nitpicky tests (line lengths,
+ copyright statements, etc) when the normal test suite ("./check") is
+ run, even if it doesn't test at all that the Swift plugin works.
+ Having the plugin in the source tree so it gets loaded when ./obnam
+ starts is probably sufficient.
+
+* Something to run separately to test the Swift plugin against an
+ existing Swift instance, including documentation of how to get
+ access to one and how to set things up so that the tests can be run.
+ The test-swift script is probably doing this already.
+
+I suspect you're pretty much there, already, actually. :)
+
+> If you want, I can try to make a mock instance of Swift, but I'd bet
+> I'd create more bugs in the mock than the actual code. Alternately,
+> if you just want a free place to try the code against, hubic.com
+> provides 25G free storage using swift.
+
+Unless there's a general mockup of Swift, which others are using
+anyway, I don't think this is worthwhile.
+
+> > Going forward, will you be available to maintain this code?
+
+> As long as I'm using Obnam/this code in my backup strategy, yes I'm
+> happy to do so. Should that change in the future, I can try to
+> continue to help out. For the foreseeable future, that shouldn't be
+> a problem.
+
+Cool. That's all I can ask for, really.
+
+Thank you!
+
+--
+http://gtdfh.branchable.com/ -- GTD for hackers
+http://obnam.org/ -- HAVE YOU BACKED UP TODAY?
+
+_______________________________________________
+obnam-dev mailing list
+obnam-dev@obnam.org
+http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M711251P17339Q110.exolobe1 b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M711251P17339Q110.exolobe1
new file mode 100644
index 0000000..6a39e2d
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999000.M711251P17339Q110.exolobe1
@@ -0,0 +1,114 @@
+Return-Path: <obnam-dev-bounces@obnam.org>
+X-Original-To: distix@pieni.net
+Delivered-To: distix@pieni.net
+Received: from bagpuss.pepperfish.net (bagpuss.pepperfish.net [148.251.8.16])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPS id 543562AB46
+ for <distix@pieni.net>; Sat, 6 Dec 2014 20:22:57 +0100 (CET)
+Received: from platypus.pepperfish.net (unknown [10.112.100.20])
+ by bagpuss.pepperfish.net (Postfix) with ESMTP id CBC5129FB;
+ Sat, 6 Dec 2014 19:22:56 +0000 (GMT)
+Received: from localhost ([::1] helo=platypus.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XxKwS-0004rz-Nd; Sat, 06 Dec 2014 19:22:56 +0000
+Received: from inmail ([10.112.100.10] helo=mx0.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XxKwS-0004rt-4Z
+ for <obnam-dev@obnam.org>; Sat, 06 Dec 2014 19:22:56 +0000
+Received: from xvm-166-37.ghst.net
+ ([95.142.166.37] helo=pieni.net ident=postfix)
+ by mx0.pepperfish.net with esmtps (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256)
+ (Exim 4.80) (envelope-from <liw@liw.fi>) id 1XxKwL-000508-UX
+ for obnam-dev@obnam.org; Sat, 06 Dec 2014 19:22:56 +0000
+Received: from exolobe1.liw.fi (82-181-8-107.bb.dnainternet.fi [82.181.8.107])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPSA id D395E2AB46;
+ Sat, 6 Dec 2014 20:22:48 +0100 (CET)
+Received: from exolobe1.liw.fi (localhost [127.0.0.1])
+ by exolobe1.liw.fi (Postfix) with ESMTPS id 3D7A242AC7;
+ Sat, 6 Dec 2014 21:22:48 +0200 (EET)
+Date: Sat, 6 Dec 2014 21:22:47 +0200
+From: Lars Wirzenius <liw@liw.fi>
+To: Matthew Dawson <matthew@mjdsystems.ca>
+Message-ID: <20141206192247.GK6438@exolobe1.liw.fi>
+References: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+In-Reply-To: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+User-Agent: Mutt/1.5.21 (2010-09-15)
+X-Spam-Score: -3.4
+X-Spam-Score-int: -33
+X-Spam-Bar: ---
+X-Scanned-By: pepperfish.net, Sat, 06 Dec 2014 19:22:56 +0000
+X-Spam-Report: Content analysis details: (-3.4 points)
+ pts rule name description
+ ---- ---------------------- --------------------------------------------------
+ -1.0 PPF_USER_AGENT_MUTT User-Agent: contains Mutt (Mutt isn't a spam
+ tool) -0.5 PPF_USER_AGENT User-Agent: exists
+ -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%
+ [score: 0.0000]
+Cc: obnam-dev@obnam.org
+Subject: Re: [PATCH 0/3] RFC: Add support for Openstack Swift as backup
+ repository
+X-BeenThere: obnam-dev@obnam.org
+X-Mailman-Version: 2.1.5
+Precedence: list
+List-Id: Obnam development discussions <obnam-dev-obnam.org>
+List-Unsubscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=unsubscribe>
+List-Archive: <http://listmaster.pepperfish.net/pipermail/obnam-dev-obnam.org>
+List-Post: <mailto:obnam-dev@obnam.org>
+List-Help: <mailto:obnam-dev-request@obnam.org?subject=help>
+List-Subscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=subscribe>
+Sender: obnam-dev-bounces@obnam.org
+Errors-To: obnam-dev-bounces@obnam.org
+
+Hi, Matthew,
+
+Thanks for the preliminary patches. As you said they're not ready for
+merging yet, I haven't tried that, but I've had a glimpse at the code.
+
+On Sun, Nov 30, 2014 at 09:08:29PM -0500, Matthew Dawson wrote:
+> This patch set contains an experimental work in progress Openstack Swift VFS for
+> Obnam. I've only just got it working (thus it's not merge ready) but it does
+> pass the VFS unit tests except for reinit support. I've done initial testing
+> against hubiC's implementation, and the code has managed an initial backup +
+> verify on some (real) test data.
+>
+> I'm posting it here for initial comments, and also to find out if such a backend
+> is wanted in Obnam. If this is wanted, I'll continue improving the
+> backend.
+
+I would welcome such a backend. While I haven't used such a thing
+myself (also not an Amazon S3 instance), it's good for Obnam to
+support a variety of storage options.
+
+Since I don't know much about Swift, I can't comment on whether the
+plugin you're working on does sensible things. I'm going to trust you
+on that.
+
+I noticed the Python code isn't formatted quite like PEP8 specifies,
+and I'd prefer to see that fixed. Most importantly, source code lines
+(after TAB expansion with a width of 8) should be strictly less than
+80 columns. (It's something that's a bit controversion in the modern
+world, but it's a rule I impose on myself and the Obnam code base.)
+
+I'm happy to include this in the Obnam code base, assuming clean code
+and suitable tests, including some that work without access to a real
+Swift instance (obviously the code doesn't then need to do much, but
+it shouldn't crash). Some end-user documentation would also be nice.
+
+Going forward, will you be available to maintain this code?
+
+--
+http://gtdfh.branchable.com/ -- GTD for hackers
+http://obnam.org/ -- HAVE YOU BACKED UP TODAY?
+
+_______________________________________________
+obnam-dev mailing list
+obnam-dev@obnam.org
+http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999008.M207056P17339Q191.exolobe1 b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999008.M207056P17339Q191.exolobe1
new file mode 100644
index 0000000..d531a77
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999008.M207056P17339Q191.exolobe1
@@ -0,0 +1,205 @@
+Return-Path: <obnam-dev-bounces@obnam.org>
+X-Original-To: distix@pieni.net
+Delivered-To: distix@pieni.net
+Received: from bagpuss.pepperfish.net (bagpuss.pepperfish.net [148.251.8.16])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPS id 33F5921C1D
+ for <distix@pieni.net>; Mon, 1 Dec 2014 03:08:47 +0100 (CET)
+Received: from platypus.pepperfish.net (unknown [10.112.100.20])
+ by bagpuss.pepperfish.net (Postfix) with ESMTP id CD1203526;
+ Mon, 1 Dec 2014 02:08:46 +0000 (GMT)
+Received: from localhost ([::1] helo=platypus.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XvGPu-0002tj-LY; Mon, 01 Dec 2014 02:08:46 +0000
+Received: from inmail ([10.112.100.10] helo=mx0.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XvGPs-0002rY-09
+ for <obnam-dev@obnam.org>; Mon, 01 Dec 2014 02:08:44 +0000
+Received: from scadrial.mjdsystems.ca ([198.100.154.185])
+ by mx0.pepperfish.net with esmtp (Exim 4.80)
+ (envelope-from <matthew@mjdsystems.ca>) id 1XvGPo-00057F-Pw
+ for obnam-dev@obnam.org; Mon, 01 Dec 2014 02:08:43 +0000
+Received: from cwmtaff.housem.mjdsystems.ca
+ (CPE00045a5ba0db-CM602ad073c297.cpe.net.cable.rogers.com [99.229.22.8])
+ by scadrial.mjdsystems.ca (Postfix) with ESMTPSA id 1DD41185B31;
+ Sun, 30 Nov 2014 21:08:40 -0500 (EST)
+From: Matthew Dawson <matthew@mjdsystems.ca>
+To: obnam-dev@obnam.org
+Date: Sun, 30 Nov 2014 21:08:31 -0500
+Message-Id: <1417399711-8672-3-git-send-email-matthew@mjdsystems.ca>
+X-Mailer: git-send-email 2.0.4
+In-Reply-To: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+References: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+X-Spam-Score: -1.9
+X-Spam-Score-int: -18
+X-Spam-Bar: -
+X-Scanned-By: pepperfish.net, Mon, 01 Dec 2014 02:08:43 +0000
+X-Spam-Report: Content analysis details: (-1.9 points)
+ pts rule name description
+ ---- ---------------------- --------------------------------------------------
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay
+ domain
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%
+ [score: 0.0000]
+Cc: Matthew Dawson <matthew@mjdsystems.ca>
+Subject: [PATCH 2/3] Properly handle missing parent directories them.
+X-BeenThere: obnam-dev@obnam.org
+X-Mailman-Version: 2.1.5
+Precedence: list
+List-Id: Obnam development discussions <obnam-dev-obnam.org>
+List-Unsubscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=unsubscribe>
+List-Archive: <http://listmaster.pepperfish.net/pipermail/obnam-dev-obnam.org>
+List-Post: <mailto:obnam-dev@obnam.org>
+List-Help: <mailto:obnam-dev-request@obnam.org?subject=help>
+List-Subscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=subscribe>
+Sender: obnam-dev-bounces@obnam.org
+Errors-To: obnam-dev-bounces@obnam.org
+
+As Swift doesn't use directories, it allows files with paths specifying
+nonexistent directories. This patch ensures files are not created in missing
+directories, otherwise listdir/listdir2 fails to find them and breaks journal
+commits.
+
+---
+ obnamlib/plugins/swift_plugin.py | 58 ++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 56 insertions(+), 2 deletions(-)
+
+diff --git a/obnamlib/plugins/swift_plugin.py b/obnamlib/plugins/swift_plugin.py
+index ef51ad2..e569fd9 100644
+--- a/obnamlib/plugins/swift_plugin.py
++++ b/obnamlib/plugins/swift_plugin.py
+@@ -49,6 +49,44 @@ def ioerror_to_oserror(method):
+
+ return helper
+
++def verify_parent_dir_exists(method):
++ '''Decorator to convert an IOError exception to OSError.
++
++ Python's os.* raise OSError, mostly, but paramiko's corresponding
++ methods raise IOError. This decorator fixes that.
++
++ '''
++
++ def helper(self, filename, *args, **kwargs):
++ if os.path.dirname(os.path.normpath(os.path.join(self.path, filename))) != '/':
++ try:
++ self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.dirname(os.path.normpath(os.path.join(self.path, filename))))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise OSError('Parent directory %s not found!' % os.path.dirname(os.path.normpath(os.path.join(self.path, filename))), e)
++ return method(self, filename, *args, **kwargs)
++
++ return helper
++
++def verify_parent_dir_exists_rename(method):
++ '''Decorator to convert an IOError exception to OSError.
++
++ Python's os.* raise OSError, mostly, but paramiko's corresponding
++ methods raise IOError. This decorator fixes that.
++
++ '''
++
++ def helper(self, old, new, *args, **kwargs):
++ if os.path.dirname(os.path.normpath(os.path.join(self.path, new))) != '/':
++ try:
++ self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.dirname(os.path.normpath(os.path.join(self.path, new))))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise IOError('Parent directory %s not found!' % os.path.dirname(os.path.normpath(os.path.join(self.path, new))), e)
++ return method(self, old, new, *args, **kwargs)
++
++ return helper
++
+ class SwiftFile(object):
+ def __init__(self, swift, swift_container, filename, mode):
+ self._swift = swift
+@@ -243,7 +281,7 @@ class SwiftFS(obnamlib.VirtualFileSystem):
+ # just fail silently, but that would be silly.)
+ raise NotImplementedError('mknod on swift: %s' % pathname)
+
+- @ioerror_to_oserror
++ @verify_parent_dir_exists
+ def mkdir(self, pathname, mode=obnamlib.NEW_DIR_MODE):
+ tracing.trace('mkdir: %s with mode %o' % (pathname, mode))
+ try:
+@@ -251,7 +289,10 @@ class SwiftFS(obnamlib.VirtualFileSystem):
+ except swiftclient.ClientException, e:
+ if e.http_status == 404:
+ raise OSError('Parent doesn\'t exist')
++ self._mkdir(pathname, mode)
+
++ @ioerror_to_oserror
++ def _mkdir(self, pathname, mode=obnamlib.NEW_DIR_MODE):
+ try:
+ headers = self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
+ except swiftclient.ClientException, e:
+@@ -267,7 +308,7 @@ class SwiftFS(obnamlib.VirtualFileSystem):
+ parent = os.path.dirname(pathname)
+ if parent and parent != pathname and not self.exists(parent):
+ self.makedirs(parent)
+- self.mkdir(pathname, obnamlib.NEW_DIR_MODE)
++ self._mkdir(pathname, obnamlib.NEW_DIR_MODE)
+
+ @ioerror_to_oserror
+ def rmdir(self, pathname):
+@@ -302,6 +343,7 @@ class SwiftFS(obnamlib.VirtualFileSystem):
+ if e.errno != errno.ENOENT:
+ raise
+
++ @verify_parent_dir_exists_rename
+ @ioerror_to_oserror
+ def rename(self, old, new):
+ tracing.trace('rename %s (%s) to %s (%s)' % (old, os.path.normpath(os.path.join(self.path, old)), new, os.path.normpath(os.path.join(self.path, new))))
+@@ -374,6 +416,7 @@ class SwiftFS(obnamlib.VirtualFileSystem):
+ raise IOError('Not a symlink!')
+ return contents
+
++ @verify_parent_dir_exists
+ @ioerror_to_oserror
+ def symlink(self, source, destination):
+ tracing.trace('rename %s (%s) to %s (%s)' % (source, os.path.normpath(os.path.join(self.path, source)), destination, os.path.normpath(os.path.join(self.path, destination))))
+@@ -385,6 +428,7 @@ class SwiftFS(obnamlib.VirtualFileSystem):
+ return
+ raise IOError('Path exists!')
+
++ @verify_parent_dir_exists
+ def open(self, pathname, mode, bufsize=-1):
+ tracing.trace('open %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
+ if 'w' not in mode:
+@@ -409,6 +453,10 @@ class SwiftFS(obnamlib.VirtualFileSystem):
+ def write_file(self, pathname, contents):
+ tracing.trace('writefile %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
+ try:
++ self.makedirs(os.path.dirname(os.path.normpath(os.path.join(self.path, pathname))))
++ except Exception:
++ pass
++ try:
+ self._swift.head_object(self._swift_container, os.path.normpath(os.path.join(self.path, pathname))[1:])
+ except swiftclient.ClientException, e:
+ if e.http_status == 404:
+@@ -420,6 +468,12 @@ class SwiftFS(obnamlib.VirtualFileSystem):
+ @ioerror_to_oserror
+ def overwrite_file(self, pathname, contents):
+ tracing.trace('overwrite_file %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++
++ try:
++ self.makedirs(os.path.dirname(os.path.normpath(os.path.join(self.path, pathname))))
++ except:
++ pass
++
+ self._swift.put_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:], contents, headers={'x-object-meta-obnam-mode': obnamlib.NEW_FILE_MODE})
+ self.bytes_written += len(contents)
+
+--
+2.0.4
+
+
+_______________________________________________
+obnam-dev mailing list
+obnam-dev@obnam.org
+http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999008.M852087P17339Q198.exolobe1 b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999008.M852087P17339Q198.exolobe1
new file mode 100644
index 0000000..0b7d7a9
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999008.M852087P17339Q198.exolobe1
@@ -0,0 +1,224 @@
+Return-Path: <obnam-dev-bounces@obnam.org>
+X-Original-To: distix@pieni.net
+Delivered-To: distix@pieni.net
+Received: from bagpuss.pepperfish.net (bagpuss.pepperfish.net [148.251.8.16])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPS id DBE642AA4E
+ for <distix@pieni.net>; Sat, 6 Dec 2014 23:54:53 +0100 (CET)
+Received: from platypus.pepperfish.net (unknown [10.112.100.20])
+ by bagpuss.pepperfish.net (Postfix) with ESMTP id 3ABFDCDF;
+ Sat, 6 Dec 2014 22:54:53 +0000 (GMT)
+Received: from localhost ([::1] helo=platypus.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XxOFZ-00015x-4J; Sat, 06 Dec 2014 22:54:53 +0000
+Received: from inmail ([10.112.100.10] helo=mx0.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XxOFX-00015r-Oj
+ for <obnam-dev@obnam.org>; Sat, 06 Dec 2014 22:54:51 +0000
+Received: from scadrial.mjdsystems.ca ([198.100.154.185])
+ by mx0.pepperfish.net with esmtp (Exim 4.80)
+ (envelope-from <matthew@mjdsystems.ca>) id 1XxOFU-0002SQ-00
+ for obnam-dev@obnam.org; Sat, 06 Dec 2014 22:54:51 +0000
+Received: from cwmtaff.localnet (d24-141-188-31.home.cgocable.net
+ [24.141.188.31])
+ by scadrial.mjdsystems.ca (Postfix) with ESMTPSA id 73A3D1A5732;
+ Sat, 6 Dec 2014 17:54:45 -0500 (EST)
+From: Matthew Dawson <matthew@mjdsystems.ca>
+To: Lars Wirzenius <liw@liw.fi>
+Date: Sat, 06 Dec 2014 17:54:39 -0500
+Message-ID: <1531092.aY1fI7Af0k@cwmtaff>
+User-Agent: KMail/4.14.3 (Linux/3.17.4-gentoo; KDE/4.14.3; x86_64; ; )
+In-Reply-To: <20141206192247.GK6438@exolobe1.liw.fi>
+References: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+ <20141206192247.GK6438@exolobe1.liw.fi>
+MIME-Version: 1.0
+X-Spam-Score: -1.9
+X-Spam-Score-int: -18
+X-Spam-Bar: -
+X-Scanned-By: pepperfish.net, Sat, 06 Dec 2014 22:54:50 +0000
+X-Spam-Report: Content analysis details: (-1.9 points)
+ pts rule name description
+ ---- ---------------------- --------------------------------------------------
+ -0.5 PPF_USER_AGENT User-Agent: exists
+ 0.5 PPF_MESSAGEID_NODOTS Message-Id contains no dots after the @
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay
+ domain
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%
+ [score: 0.0000]
+Cc: obnam-dev@obnam.org
+Subject: Re: [PATCH 0/3] RFC: Add support for Openstack Swift as backup
+ repository
+X-BeenThere: obnam-dev@obnam.org
+X-Mailman-Version: 2.1.5
+Precedence: list
+List-Id: Obnam development discussions <obnam-dev-obnam.org>
+List-Unsubscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=unsubscribe>
+List-Archive: <http://listmaster.pepperfish.net/pipermail/obnam-dev-obnam.org>
+List-Post: <mailto:obnam-dev@obnam.org>
+List-Help: <mailto:obnam-dev-request@obnam.org?subject=help>
+List-Subscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=subscribe>
+Content-Type: multipart/mixed; boundary="===============0725680542757677411=="
+Mime-version: 1.0
+Sender: obnam-dev-bounces@obnam.org
+Errors-To: obnam-dev-bounces@obnam.org
+
+
+--===============0725680542757677411==
+Content-Type: multipart/signed; boundary="nextPart1933280.baVF2Uklju";
+ micalg="sha256"; protocol="application/pkcs7-signature"
+
+
+--nextPart1933280.baVF2Uklju
+Content-Transfer-Encoding: quoted-printable
+Content-Type: text/plain; charset="us-ascii"
+
+On December 6, 2014 09:22:47 PM Lars Wirzenius wrote:
+> Hi, Matthew,
+>=20
+> Thanks for the preliminary patches. As you said they're not ready for=
+
+> merging yet, I haven't tried that, but I've had a glimpse at the code=
+.
+<snip>
+>=20
+> I noticed the Python code isn't formatted quite like PEP8 specifies,
+> and I'd prefer to see that fixed. Most importantly, source code lines=
+
+> (after TAB expansion with a width of 8) should be strictly less than
+> 80 columns. (It's something that's a bit controversion in the modern
+> world, but it's a rule I impose on myself and the Obnam code base.)
+No problem, I'll move the code to that for the final set of patches.
+
+> I'm happy to include this in the Obnam code base, assuming clean code=
+
+> and suitable tests, including some that work without access to a real=
+
+> Swift instance (obviously the code doesn't then need to do much, but
+> it shouldn't crash). Some end-user documentation would also be nice.
+Sounds good to me. I'll work on cleaning everything up. Regarding the=
+ test=20
+cases, I'm not sure what you are looking for. As the Swift support onl=
+y plugs=20
+into the VFS layer, there isn't really anything sitting between the two=
+. I do=20
+have a set of tests like the SFTP does, so that the regular test suite =
+passes.
+
+If you want, I can try to make a mock instance of Swift, but I'd bet I'=
+d=20
+create more bugs in the mock than the actual code. Alternately, if you=
+ just=20
+want a free place to try the code against, hubic.com provides 25G free =
+storage=20
+using swift.
+
+> Going forward, will you be available to maintain this code?
+As long as I'm using Obnam/this code in my backup strategy, yes I'm hap=
+py to=20
+do so. Should that change in the future, I can try to continue to help=
+ out. =20
+For the foreseeable future, that shouldn't be a problem.
+
+I'll work on improving the code, and I'll post a new patch set once I h=
+ave=20
+something more presentable.=20
+=2D-=20
+Matthew
+--nextPart1933280.baVF2Uklju
+Content-Type: application/pkcs7-signature; name="smime.p7s"
+Content-Disposition: attachment; filename="smime.p7s"
+Content-Transfer-Encoding: base64
+
+MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCDJYw
+ggY0MIIEHKADAgECAgEgMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1T
+dGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTaWduaW5n
+MSkwJwYDVQQDEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNzEwMjQyMTAy
+NTVaFw0xNzEwMjQyMTAyNTVaMIGMMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMv
+U3RhcnRDb20gQ2xhc3MgMiBQcmltYXJ5IEludGVybWVkaWF0ZSBDbGllbnQgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLKIVFnAEs+xnyq6UzjCqgDcvQVe1dIoFnRsQPCFO+y92k
+8RK0Pn3MbQ2Gd+mehh9GBZ+36uUQA7Xj9AGM6wgPhEE34vKtfpAN5tJ8LcFxveDObCKrL7O5UT9W
+snAZHv7OYPYSR68mdmnEnJ83M4wQgKO19b+Rt8sPDAz9ptkQsntCn4GeJzg3q2SVc4QJTg/WHo7w
+F2ah5LMOeh8xJVSKGEmd6uPkSbj113yKMm8vmNptRPmM1+YgmVwcdOYJOjCgFtb2sOP79jji8uhW
+R91xx7TpM1K3hv/wrBZwffrmmEpUeuXHRs07JqCCvFh9coKF4UQZvfEg+x3/69xRCzb1AgMBAAGj
+ggGtMIIBqTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrlWDb+wx
+yrn3HfqvazHzyB3jrLswHwYDVR0jBBgwFoAUTgvvGqRAW6UXaYcwyjRoQ9BBrvIwZgYIKwYBBQUH
+AQEEWjBYMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5zdGFydHNzbC5jb20vY2EwLQYIKwYBBQUH
+MAKGIWh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3Nmc2NhLmNydDBbBgNVHR8EVDBSMCegJaAjhiFo
+dHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9zZnNjYS5jcmwwJ6AloCOGIWh0dHA6Ly9jcmwuc3RhcnRz
+c2wuY29tL3Nmc2NhLmNybDCBgAYDVR0gBHkwdzB1BgsrBgEEAYG1NwECATBmMC4GCCsGAQUFBwIB
+FiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMDQGCCsGAQUFBwIBFihodHRwOi8v
+d3d3LnN0YXJ0c3NsLmNvbS9pbnRlcm1lZGlhdGUucGRmMA0GCSqGSIb3DQEBBQUAA4ICAQA6qScN
+yNO0FpHvaZTQacVMXH33O51KyEKSRw3IvdQxRu31YR0ZDGdSfgSoOVDVMSBSdmfQfdDInHPzV3LO
+5DwUXZ+lxjv7z3PO2OkfnFkvTXPfn6dxJ5rJveDsTsCPcJ/Kp6/+qN5g+J6D/SaYcFD018B6L42r
+0Z4VEBy36P4tjRtF14Ex10tl5tJFVKM16qWKQHbpjIgf73s49UB0CQ5lHT2DHKfq3oPfdNc5Mk93
+w1v4ryVb+qVrZIej8NsrWU+5r4O2IV91edDb/OtHFddZqHFFXKgS79IHE/hwQ2LW7r3sTX7cDUCg
++dfdwO8zeLxuwk2JF8crUoyrl66RGrRIhT8VoG/OJ1Y9uUlOav69V4cG8upi4ZG2l7JZFbcBFk91
+Wp+Payo5SuF61CmGFrZ386umkmpObtFacXda2O/bVoQ9xHQrzoTc/0KZTWvlZCLK3Ke/vGYT9ZdW
+9lOjGsSFbXrlTA919L84iMK+48WGnvRWY28ZaVHpql43AtEGhXze6iNCbEDACy+4hkQYOytAqDgc
+xAnQ937mYpeZFPyz/XK9QSt9VNFMuudWxZwDDDJKoQAoSG59Hou9lZ26UrK60nRdAQBmEPL8h2nu
+WgoPh++XVQld9yuhbsWa39Pck8/lcfz5HUVGJF5mc/zk38iV7FDlF68puiryNq2KXHEpOTCCBlow
+ggVCoAMCAQICAkk+MA0GCSqGSIb3DQEBCwUAMIGMMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3Rh
+cnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4
+MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3MgMiBQcmltYXJ5IEludGVybWVkaWF0ZSBDbGllbnQgQ0Ew
+HhcNMTQwNDA4MTkzMjEyWhcNMTYwNDA5MDI1MjMwWjB0MQswCQYDVQQGEwJDQTEQMA4GA1UECBMH
+T250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExFzAVBgNVBAMTDk1hdHRoZXcgRGF3c29uMSQw
+IgYJKoZIhvcNAQkBFhVtYXR0aGV3QG1qZHN5c3RlbXMuY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCsTBWcCXBFDqO0tNTX30rmz1FCb08jhd6basnhtyWBdA3ecLoE0l5JgBX9fX8c
+4N7o7AKK19VSjV7kigeT6DT2EGzsbzijkpareFq6JdZZzPuuJEP9r+uQ7YfUMKQsb64SbJMu3ewQ
+pMYyuPAKkLFgeKmXkhcO6ybVyc5j0eYmt7U2J85a0RA1zJbtdEgJoR3FPTLM4aize9V8V9sBxu7U
+tAm9eUd64GRzn45DlHKDUdTh5WaYrMEGmc0FKrmUp4ghuVevzRAk7+pLU/n3zTIu+p+hgi+w5nII
+gU6yCIGk0ihNX1+bsKvIBfH/n0stq/nt0BHdQ4vh8S+RK8ynhxDhAgMBAAGjggLbMIIC1zAJBgNV
+HRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwHQYDVR0O
+BBYEFLKlaP5rHiPpOlakPhNpGcU/vEkNMB8GA1UdIwQYMBaAFK5Vg2/sMcq59x36r2sx88gd46y7
+MCAGA1UdEQQZMBeBFW1hdHRoZXdAbWpkc3lzdGVtcy5jYTCCAUwGA1UdIASCAUMwggE/MIIBOwYL
+KwYBBAGBtTcBAgMwggEqMC4GCCsGAQUFBwIBFiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xp
+Y3kucGRmMIH3BggrBgEFBQcCAjCB6jAnFiBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eTADAgEBGoG+VGhpcyBjZXJ0aWZpY2F0ZSB3YXMgaXNzdWVkIGFjY29yZGluZyB0byB0aGUgQ2xh
+c3MgMiBWYWxpZGF0aW9uIHJlcXVpcmVtZW50cyBvZiB0aGUgU3RhcnRDb20gQ0EgcG9saWN5LCBy
+ZWxpYW5jZSBvbmx5IGZvciB0aGUgaW50ZW5kZWQgcHVycG9zZSBpbiBjb21wbGlhbmNlIG9mIHRo
+ZSByZWx5aW5nIHBhcnR5IG9ibGlnYXRpb25zLjA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0c3NsLmNvbS9jcnR1Mi1jcmwuY3JsMIGOBggrBgEFBQcBAQSBgTB/MDkGCCsGAQUFBzAB
+hi1odHRwOi8vb2NzcC5zdGFydHNzbC5jb20vc3ViL2NsYXNzMi9jbGllbnQvY2EwQgYIKwYBBQUH
+MAKGNmh0dHA6Ly9haWEuc3RhcnRzc2wuY29tL2NlcnRzL3N1Yi5jbGFzczIuY2xpZW50LmNhLmNy
+dDAjBgNVHRIEHDAahhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQELBQADggEB
+AFRc8hOlsUqFsEULBPO5N1RzzlD5wHksYelS8h2eS8KsF3kqME6VA/SuF5TQ+CIGbg2hJGsoKzAU
+MPqvIiw/beB9sBp2OGMSPTWZtch3d+2feMGr/qyRX6jpXQTUsYaVYryKwehLk2uMME1GYjWMxTZO
+W8/5XBEVrlS3nmHgJIozPEbgIHR36PmuJTjU7isl+qJ1zqlXTN2GkicYeMK7hhWDT1tnLlEa2yv6
+LA6WYc69H9ECruWyYp3D17hhHtuW1JXhe+45l2AeO48gBiUzJf7SbmPL6CPeY4u8XP1UBtH18ZY8
+0E5MG184+a0GSqSsE5PNSiayDUGFTfBq7g+vhwYxggJVMIICUQIBATCBkzCBjDELMAkGA1UEBhMC
+SUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRp
+ZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1l
+ZGlhdGUgQ2xpZW50IENBAgJJPjANBglghkgBZQMEAgEFAKCBkzAYBgkqhkiG9w0BCQMxCwYJKoZI
+hvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNDEyMDYyMjU0MzlaMCgGCSqGSIb3DQEJDzEbMBkwCwYJ
+YIZIAWUDBAECMAoGCCqGSIb3DQMHMC8GCSqGSIb3DQEJBDEiBCDgqZVXKIWlrAUGYL8e+YyvHsuK
+EWVp0fSKzX24XB3BrjANBgkqhkiG9w0BAQEFAASCAQCPlrZM2Pp5b07YAngCM0ydrg9aebVYLCB9
+CoK0pBIcgfrj6HG4ZFJCSk1soDisJtxVct1M6pYJATUDWjidTr2zgGEiFQ0pBzIQCTVuTEK6tH++
+ZzYjY+27v5MZ1wfjKOfEsnGQdjhSnnOlHauHuzEyGrbVkgisw0NlMUeJoSQqs8xj1FK/CHapCyYl
+uT86S/uokJQ5ZscZC3+TyHK2KkKaqfu92qw4XlpMx/AJP7AVb024C6PSbDVdsPGoR4LA1fJ9pfex
+IXGIbKElOzDqDBt/uF5cN/tvyr6ado/6rRB+bU+Rfsy0p1YpGOpqelc93mh297ZyAJiB0m9PcdYC
+F8SWAAAAAAAA
+
+--nextPart1933280.baVF2Uklju--
+
+
+
+--===============0725680542757677411==
+Content-Type: text/plain; charset="us-ascii"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+_______________________________________________
+obnam-dev mailing list
+obnam-dev@obnam.org
+http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org
+
+--===============0725680542757677411==--
+
+
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999010.M812138P17339Q216.exolobe1 b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999010.M812138P17339Q216.exolobe1
new file mode 100644
index 0000000..13da0c8
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999010.M812138P17339Q216.exolobe1
@@ -0,0 +1,648 @@
+Return-Path: <obnam-dev-bounces@obnam.org>
+X-Original-To: distix@pieni.net
+Delivered-To: distix@pieni.net
+Received: from bagpuss.pepperfish.net (bagpuss.pepperfish.net [148.251.8.16])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPS id 98D2121B02
+ for <distix@pieni.net>; Mon, 1 Dec 2014 03:08:46 +0100 (CET)
+Received: from platypus.pepperfish.net (unknown [10.112.100.20])
+ by bagpuss.pepperfish.net (Postfix) with ESMTP id 4834834F2;
+ Mon, 1 Dec 2014 02:08:46 +0000 (GMT)
+Received: from localhost ([::1] helo=platypus.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XvGPu-0002tE-5D; Mon, 01 Dec 2014 02:08:46 +0000
+Received: from inmail ([10.112.100.10] helo=mx0.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XvGPr-0002rH-Pa
+ for <obnam-dev@obnam.org>; Mon, 01 Dec 2014 02:08:43 +0000
+Received: from scadrial.mjdsystems.ca ([198.100.154.185])
+ by mx0.pepperfish.net with esmtp (Exim 4.80)
+ (envelope-from <matthew@mjdsystems.ca>) id 1XvGPn-00057E-HC
+ for obnam-dev@obnam.org; Mon, 01 Dec 2014 02:08:43 +0000
+Received: from cwmtaff.housem.mjdsystems.ca
+ (CPE00045a5ba0db-CM602ad073c297.cpe.net.cable.rogers.com [99.229.22.8])
+ by scadrial.mjdsystems.ca (Postfix) with ESMTPSA id AC2EC185B30;
+ Sun, 30 Nov 2014 21:08:38 -0500 (EST)
+From: Matthew Dawson <matthew@mjdsystems.ca>
+To: obnam-dev@obnam.org
+Date: Sun, 30 Nov 2014 21:08:30 -0500
+Message-Id: <1417399711-8672-2-git-send-email-matthew@mjdsystems.ca>
+X-Mailer: git-send-email 2.0.4
+In-Reply-To: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+References: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+X-Spam-Score: -1.8
+X-Spam-Score-int: -17
+X-Spam-Bar: -
+X-Scanned-By: pepperfish.net, Mon, 01 Dec 2014 02:08:42 +0000
+X-Spam-Report: Content analysis details: (-1.8 points)
+ pts rule name description
+ ---- ---------------------- --------------------------------------------------
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay
+ domain
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%
+ [score: 0.0000]
+ 0.1 PPF_SPLIT_TAG RAW: Body contains a split HTML tag
+Cc: Matthew Dawson <matthew@mjdsystems.ca>
+Subject: [PATCH 1/3] Initial swift support, with passing tests.
+X-BeenThere: obnam-dev@obnam.org
+X-Mailman-Version: 2.1.5
+Precedence: list
+List-Id: Obnam development discussions <obnam-dev-obnam.org>
+List-Unsubscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=unsubscribe>
+List-Archive: <http://listmaster.pepperfish.net/pipermail/obnam-dev-obnam.org>
+List-Post: <mailto:obnam-dev@obnam.org>
+List-Help: <mailto:obnam-dev-request@obnam.org?subject=help>
+List-Subscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=subscribe>
+Sender: obnam-dev-bounces@obnam.org
+Errors-To: obnam-dev-bounces@obnam.org
+
+This adds an Openstack Swift VFS plugin, which passes most tests.
+
+---
+ obnamlib/plugins/swift_plugin.py | 437 +++++++++++++++++++++++++++++++++++++++
+ obnamlib/vfs.py | 4 +-
+ test-swift | 85 ++++++++
+ without-tests | 1 +
+ 4 files changed, 525 insertions(+), 2 deletions(-)
+ create mode 100644 obnamlib/plugins/swift_plugin.py
+ create mode 100755 test-swift
+
+diff --git a/obnamlib/plugins/swift_plugin.py b/obnamlib/plugins/swift_plugin.py
+new file mode 100644
+index 0000000..ef51ad2
+--- /dev/null
++++ b/obnamlib/plugins/swift_plugin.py
+@@ -0,0 +1,437 @@
++# Copyright (C) 2009-2014 Lars Wirzenius <liw@liw.fi>
++#
++# This program 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 2 of the License, or
++# (at your option) any later version.
++#
++# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++
++
++import errno
++import hashlib
++import logging
++import os
++import pwd
++import random
++import socket
++import stat
++import subprocess
++import time
++import traceback
++import tracing
++import urllib
++import urlparse
++import swiftclient
++
++import obnamlib
++
++def ioerror_to_oserror(method):
++ '''Decorator to convert an IOError exception to OSError.
++
++ Python's os.* raise OSError, mostly, but paramiko's corresponding
++ methods raise IOError. This decorator fixes that.
++
++ '''
++
++ def helper(self, filename, *args, **kwargs):
++ try:
++ return method(self, filename, *args, **kwargs)
++ except IOError, e:
++ raise OSError(e.errno, e.strerror or str(e), filename)
++
++ return helper
++
++class SwiftFile(object):
++ def __init__(self, swift, swift_container, filename, mode):
++ self._swift = swift
++ self._swift_container = swift_container
++
++ self.filename = filename
++ self.mode = mode
++ if 'r' in mode:
++ self._contents = self._swift.get_object(self._swift_container, filename)[1]
++ self._lines = self._contents.splitlines()
++ self._lineindex = 0
++
++ def readline(self):
++ if len(self._lines) <= self._lineindex:
++ return ''
++ return self._lines[self._lineindex] + '\n'
++ self._lineindex += 1
++
++ def close(self):
++ pass
++
++ #def _write_contents(self, contents):
++ #if 'w' in self.mode:
++ #self._swift.put_object(self._swift_container, swiftclient.client.quote(self.filename), contents, headers={'x-object-meta-obnam-mode': obnamlib.NEW_FILE_MODE})
++ #else:
++ #raise IOError('Tried to write to read only file!')
++
++class SwiftStat(object):
++ def __init__(self, pathname, headers):
++ if headers != None:
++ self.st_mode = int(headers['x-object-meta-obnam-mode']) if 'x-object-meta-obnam-mode' in headers else 0
++ if headers['content-type'] == 'application/directory':
++ self.st_mode |= stat.S_IFDIR
++ self.st_size = 0
++ else:
++ self.st_size = int(headers['content-length'])
++
++ self.st_mtime_sec = int(headers['x-object-meta-obnam-mtime-sec']) if 'x-object-meta-obnam-mtime-sec' in headers else 0
++ self.st_mtime_nsec = int(headers['x-object-meta-obnam-mtime-nsec']) if 'x-object-meta-obnam-mtime-nsec' in headers else 0
++ self.st_atime_sec = int(headers['x-object-meta-obnam-atime-sec']) if 'x-object-meta-obnam-atime-sec' in headers else 0
++ self.st_atime_nsec = int(headers['x-object-meta-obnam-atime-nsec']) if 'x-object-meta-obnam-atime-nsec' in headers else 0
++ else:
++ self.st_mode = 0700 | stat.S_IFDIR
++ self.st_mtime_sec = 0
++ self.st_mtime_nsec = 0
++ self.st_atime_sec = 0
++ self.st_atime_nsec = 0
++ self.st_size = 0
++
++ self.st_nlink = 1
++ self.st_uid = 0
++ self.st_gid = 0
++ self.st_blocks = (self.st_size / 512) + (1 if self.st_size % 512 else 0)
++ self.st_dev = 0
++ self.st_ino = int(hashlib.md5(pathname).hexdigest()[:8], 16)
++
++class SwiftFS(obnamlib.VirtualFileSystem):
++
++ '''A VFS implementation for Openstack Swift.
++
++
++
++ '''
++
++ def __init__(self, baseurl, create=False, settings=None):
++ tracing.trace('baseurl=%s', baseurl)
++ tracing.trace('create=%s', create)
++ obnamlib.VirtualFileSystem.__init__(self, baseurl)
++ self._roundtrips = 0
++ self._swift_token = settings['swift-token']
++ self.create_path_if_missing = create
++ self.reinit(baseurl, create=create)
++
++ def log_stats(self):
++ obnamlib.VirtualFileSystem.log_stats(self)
++ logging.info('VFS: baseurl=%s roundtrips=%s' %
++ (self.baseurl, self._roundtrips))
++
++ def _create_root_if_missing(self):
++ self._swift.put_container(self._swift_container)
++ self.create_path_if_missing = False # only create once
++
++ def connect(self):
++ tracing.trace('connect')
++ self._swift = swiftclient.client.Connection(preauthurl=self._swift_url,preauthtoken=self._swift_token)
++ if self.create_path_if_missing:
++ self._create_root_if_missing()
++
++ def close(self):
++ tracing.trace('close')
++ logging.debug('SwiftFS.close called')
++ obnamlib.VirtualFileSystem.close(self)
++
++ @ioerror_to_oserror
++ def reinit(self, baseurl, create=False):
++ tracing.trace('baseurl=%s', baseurl)
++ tracing.trace('create=%s', create)
++ if hasattr(self, 'path') and self._baseurl != baseurl:
++ raise NotImplementedError('Can\'t reinit yet')
++ self._baseurl = baseurl
++ scheme, netloc, path, query, fragment = urlparse.urlsplit(baseurl)
++
++ if scheme != 'swift':
++ raise WrongURLSchemeError(url=baseurl)
++ scheme = 'https'
++
++ (path, self._swift_container) = os.path.split(path)
++ self._swift_url = urlparse.urlunsplit((scheme, netloc, path, None, None))
++
++ self.path = '/'
++
++ def getcwd(self):
++ return self.path
++
++ @ioerror_to_oserror
++ def chdir(self, pathname):
++ tracing.trace('chdir %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ newpath = os.path.normpath(os.path.join(self.path, pathname))
++ # Can always change to /, and its treated differently in swift. Thus just shortcut it.
++ if newpath == '/':
++ self.path = '/'
++ return
++ try:
++ headers = self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise OSError('Path not found!', e)
++ if headers.get('content-type') != 'application/directory':
++ raise OSError('Not a directory!')
++ self.path = newpath
++
++ @ioerror_to_oserror
++ def listdir(self, pathname):
++ tracing.trace('listdir %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ try:
++ self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise OSError('Path not found!')
++ files = self._swift.get_object(self._swift_container, '', query_string="path="+swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])[1]
++ file_data = []
++ for filename in files.split('\n'):
++ if filename == '':
++ continue
++ file_data.append(os.path.basename(urllib.unquote(filename)))
++ return file_data
++
++ def listdir2(self, pathname):
++ tracing.trace('listdir2 %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ try:
++ self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise OSError('Path not found!')
++ files = self._swift.get_object(self._swift_container, '', query_string="path="+swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])[1]
++ file_data = []
++ for filename in files.split('\n'):
++ if filename == '':
++ continue
++ header = self._swift.head_object(self._swift_container, filename)
++ file_data.append((os.path.basename(urllib.unquote(filename)), SwiftStat(os.path.normpath(os.path.join(self.path, pathname, filename))[1:], header)))
++ return file_data
++
++ def lock(self, lockname, data):
++ try:
++ self.write_file(lockname, data)
++ except OSError, e:
++ raise obnamlib.LockFail(lock_name=lockname, reason=str(e))
++
++ def unlock(self, lockname):
++ self._remove_if_exists(lockname)
++
++ def exists(self, pathname):
++ try:
++ self.lstat(pathname)
++ except OSError:
++ return False
++ else:
++ return True
++
++ def isdir(self, pathname):
++ try:
++ st = self.lstat(pathname)
++ except OSError:
++ return False
++ else:
++ return stat.S_ISDIR(st.st_mode)
++
++ def mknod(self, pathname, mode):
++ # SFTP does not provide an mknod, so we can't do this. We
++ # raise an exception, so upper layers can handle this (we _could_
++ # just fail silently, but that would be silly.)
++ raise NotImplementedError('mknod on swift: %s' % pathname)
++
++ @ioerror_to_oserror
++ def mkdir(self, pathname, mode=obnamlib.NEW_DIR_MODE):
++ tracing.trace('mkdir: %s with mode %o' % (pathname, mode))
++ try:
++ headers = self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.dirname(os.path.normpath(os.path.join(self.path, pathname))))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise OSError('Parent doesn\'t exist')
++
++ try:
++ headers = self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ self._swift.put_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:], None, content_type='application/directory', headers={'x-object-meta-obnam-mode': mode})
++ return
++
++ raise OSError('Folder in a state of existance.')
++
++ @ioerror_to_oserror
++ def makedirs(self, pathname):
++ tracing.trace('makedirs: %s' % pathname)
++ parent = os.path.dirname(pathname)
++ if parent and parent != pathname and not self.exists(parent):
++ self.makedirs(parent)
++ self.mkdir(pathname, obnamlib.NEW_DIR_MODE)
++
++ @ioerror_to_oserror
++ def rmdir(self, pathname):
++ tracing.trace('rmdir %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ try:
++ (headers, data) = self._swift.get_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++ except swiftclient.ClientException as e:
++ if e.http_status == 404:
++ raise OSError('Path not found!', e)
++ if stat.S_ISDIR(SwiftStat(os.path.normpath(os.path.join(self.path, pathname)), headers).st_mode):
++ if len(self._swift.get_object(self._swift_container, '', query_string="path="+swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])[1]) != 0:
++ raise OSError('Directory not empty!')
++ else:
++ self._swift.delete_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++ else:
++ raise OSError('Not a directory!')
++
++ @ioerror_to_oserror
++ def remove(self, pathname):
++ tracing.trace('remove %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ data = self.lstat(pathname)
++ if stat.S_ISDIR(data.st_mode):
++ raise OSError('Tried to delete folder.')
++ else:
++ self._swift.delete_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++
++ def _remove_if_exists(self, pathname):
++ '''Like remove, but OK if file does not exist.'''
++ try:
++ self.remove(pathname)
++ except OSError, e:
++ if e.errno != errno.ENOENT:
++ raise
++
++ @ioerror_to_oserror
++ def rename(self, old, new):
++ tracing.trace('rename %s (%s) to %s (%s)' % (old, os.path.normpath(os.path.join(self.path, old)), new, os.path.normpath(os.path.join(self.path, new))))
++ try:
++ self._swift.put_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, new)))[1:], None, headers={'x-copy-from': self._swift_container + '/' + swiftclient.client.quote(os.path.normpath(os.path.join(self.path, old)))[1:]})
++ except swiftclient.ClientException as e:
++ if e.http_status == 404:
++ raise OSError('Path not found!', e)
++ self.remove(old)
++
++ @ioerror_to_oserror
++ def lstat(self, pathname):
++ tracing.trace('lstat %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ if os.path.normpath(os.path.join(self.path, pathname)) == '/':
++ return SwiftStat(os.path.normpath(os.path.join(self.path, pathname, pathname))[1:], None)
++ try:
++ headers = self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise OSError('Path not found!', e)
++ return SwiftStat(os.path.normpath(os.path.join(self.path, pathname, pathname))[1:], headers)
++
++ @ioerror_to_oserror
++ def lchown(self, pathname, uid, gid):
++ self._delay()
++ if stat.S_ISLNK(self.lstat(pathname).st_mode):
++ logging.warning('NOT changing ownership of symlink %s' % pathname)
++ else:
++ self.sftp.chown(pathname, uid, gid)
++
++ @ioerror_to_oserror
++ def chmod_symlink(self, pathname, mode):
++ tracing.trace('chmod_symlink %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ try:
++ headers = self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise OSError('Path not found!', e)
++ headers['x-object-meta-obnam-mode'] = mode
++ self._swift.post_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:], headers=headers)
++
++ @ioerror_to_oserror
++ def chmod_not_symlink(self, pathname, mode):
++ self.chmod_symlink(pathname, mode)
++
++ @ioerror_to_oserror
++ def lutimes(self, pathname, atime_sec, atime_nsec, mtime_sec, mtime_nsec):
++ # FIXME: This does not work for symlinks!
++ # Sftp does not have a way of doing that. This means if the restore
++ # target is over sftp, symlinks and their targets will have wrong
++ # mtimes.
++ try:
++ headers = self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise OSError('Path not found!', e)
++ headers['x-object-meta-obnam-mtime-sec'] = mtime_sec
++ headers['x-object-meta-obnam-mtime-nsec'] = mtime_nsec
++ headers['x-object-meta-obnam-atime-sec'] = atime_sec
++ headers['x-object-meta-obnam-atime-nsec'] = atime_nsec
++ self._swift.post_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:], headers=headers)
++
++ def link(self, existing_path, new_path):
++ raise HardlinkError()
++
++ def readlink(self, symlink):
++ (headers, contents) = self._swift.get_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, symlink)))[1:])
++ info = SwiftStat(os.path.normpath(os.path.join(self.path, symlink))[1:], headers)
++ if stat.S_ISLNK(info.st_mode):
++ raise IOError('Not a symlink!')
++ return contents
++
++ @ioerror_to_oserror
++ def symlink(self, source, destination):
++ tracing.trace('rename %s (%s) to %s (%s)' % (source, os.path.normpath(os.path.join(self.path, source)), destination, os.path.normpath(os.path.join(self.path, destination))))
++ try:
++ self._swift.head_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, destination)))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ self._swift.put_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, destination)))[1:], source, headers={'x-object-meta-obnam-is-symlink': 'true', 'x-object-meta-obnam-mode': 0777})
++ return
++ raise IOError('Path exists!')
++
++ def open(self, pathname, mode, bufsize=-1):
++ tracing.trace('open %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ if 'w' not in mode:
++ try:
++ self._swift.get_object(self._swift_container, os.path.normpath(os.path.join(self.path, pathname))[1:])[1]
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise IOError('Path not found!')
++ return SwiftFile(self._swift, self._swift_container, os.path.normpath(os.path.join(self.path, pathname))[1:], mode)
++
++ def cat(self, pathname):
++ tracing.trace('cat %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ try:
++ contents = self._swift.get_object(self._swift_container, os.path.normpath(os.path.join(self.path, pathname))[1:])[1]
++ self.bytes_read += len(contents)
++ return contents
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ raise IOError('Path not found!')
++
++ @ioerror_to_oserror
++ def write_file(self, pathname, contents):
++ tracing.trace('writefile %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ try:
++ self._swift.head_object(self._swift_container, os.path.normpath(os.path.join(self.path, pathname))[1:])
++ except swiftclient.ClientException, e:
++ if e.http_status == 404:
++ self._swift.put_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:], contents, headers={'x-object-meta-obnam-mode': obnamlib.NEW_FILE_MODE})
++ self.bytes_written += len(contents)
++ return
++ raise OSError('File in state of existance!')
++
++ @ioerror_to_oserror
++ def overwrite_file(self, pathname, contents):
++ tracing.trace('overwrite_file %s (%s)' % (pathname, os.path.normpath(os.path.join(self.path, pathname))))
++ self._swift.put_object(self._swift_container, swiftclient.client.quote(os.path.normpath(os.path.join(self.path, pathname)))[1:], contents, headers={'x-object-meta-obnam-mode': obnamlib.NEW_FILE_MODE})
++ self.bytes_written += len(contents)
++
++
++class SwiftPlugin(obnamlib.ObnamPlugin):
++
++ def enable(self):
++ swift_group = obnamlib.option_group['swift'] = 'Openstack Swift'
++
++ self.app.settings.string(
++ ['swift-token'],
++ 'Auth token to access swift.',
++ group=swift_group)
++
++ self.app.fsf.register('swift', SwiftFS, settings=self.app.settings)
+diff --git a/obnamlib/vfs.py b/obnamlib/vfs.py
+index a236ce2..129e004 100644
+--- a/obnamlib/vfs.py
++++ b/obnamlib/vfs.py
+@@ -446,13 +446,13 @@ class VfsTests(object): # pragma: no cover
+
+ def test_chdir_to_relative_works(self):
+ pathname = os.path.join(self.basepath, 'foo')
+- os.mkdir(pathname)
++ self.fs.mkdir(pathname)
+ self.fs.chdir('foo')
+ self.assertEqual(self.fs.getcwd(), pathname)
+
+ def test_chdir_to_dotdot_works(self):
+ pathname = os.path.join(self.basepath, 'foo')
+- os.mkdir(pathname)
++ self.fs.mkdir(pathname)
+ self.fs.chdir('foo')
+ self.fs.chdir('..')
+ self.assertEqual(self.fs.getcwd(), self.basepath)
+diff --git a/test-swift b/test-swift
+new file mode 100755
+index 0000000..1211bef
+--- /dev/null
++++ b/test-swift
+@@ -0,0 +1,85 @@
++#!/usr/bin/env python2
++# Copyright 2010-2014 Lars Wirzenius
++#
++# This program 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.
++#
++# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
++
++
++'''Test Swift.
++
++'''
++
++
++import logging
++import os
++import pwd
++import shutil
++import tempfile
++import unittest
++
++import obnamlib
++import obnamlib.plugins.swift_plugin
++
++
++class SwiftTests(unittest.TestCase, obnamlib.VfsTests):
++
++ def setUp(self):
++ self.basepath = '/'
++ baseurl = 'swift://'
++ settings = {
++ 'swift-token': '',
++ }
++ self.fs = obnamlib.plugins.swift_plugin.SwiftFS(baseurl,
++ create=True,
++ settings=settings)
++ self.fs.connect()
++ objs = self.fs._swift.get_container(self.fs._swift_container)[1]
++ for obj in objs:
++ self.fs._swift.delete_object(self.fs._swift_container, obj.get('name'))
++ self.fs.close()
++
++ def tearDown(self):
++ #objs = self.fs._swift.get_container(self.fs._swift_container)[1]
++ #for obj in objs:
++ #self.fs._swift.delete_object(self.fs._swift_container, obj.get('name'))
++ #self.fs.close()
++ pass
++
++ def test_sets_path_to_absolute_path(self):
++ self.assert_(self.fs.path.startswith('/'))
++
++ def test_initial_cwd_is_basepath(self):
++ self.assertEqual(self.fs.getcwd(), self.fs.path)
++
++ def test_link_creates_hard_link(self):
++ pass # sftp does not support hardlinking, so not testing it
++
++ def test_mknod_creates_fifo(self):
++ self.assertRaises(NotImplementedError, self.fs.mknod, 'foo', 0)
++
++ def test_get_username_returns_None_for_zero(self):
++ self.assertEqual(self.fs.get_username(0), None)
++
++ def test_get_groupname_returns_None_for_zero(self):
++ self.assertEqual(self.fs.get_groupname(0), None)
++
++ def test_reinit_creates_target_if_requested(self):
++ pass # Swift only does containers, and won't work otherwise. Don't bother with this.
++
++ def test_reinit_to_nonexistent_filename_raises_OSError(self):
++ pass # Swift only does containers, and won't work otherwise. Don't bother with this.
++
++
++if __name__ == '__main__':
++ logging.basicConfig(filename='/dev/null')
++ unittest.main()
+diff --git a/without-tests b/without-tests
+index faf164f..40adecb 100644
+--- a/without-tests
++++ b/without-tests
+@@ -17,6 +17,7 @@ obnamlib/plugins/fsck_plugin.py
+ obnamlib/plugins/fuse_plugin.py
+ obnamlib/plugins/restore_plugin.py
+ obnamlib/plugins/sftp_plugin.py
++obnamlib/plugins/swift_plugin.py
+ obnamlib/plugins/show_plugin.py
+ obnamlib/plugins/verify_plugin.py
+ obnamlib/plugins/vfs_local_plugin.py
+--
+2.0.4
+
+
+_______________________________________________
+obnam-dev mailing list
+obnam-dev@obnam.org
+http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999010.M898823P17339Q219.exolobe1 b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999010.M898823P17339Q219.exolobe1
new file mode 100644
index 0000000..74859fc
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/new/1455999010.M898823P17339Q219.exolobe1
@@ -0,0 +1,106 @@
+Return-Path: <obnam-dev-bounces@obnam.org>
+X-Original-To: distix@pieni.net
+Delivered-To: distix@pieni.net
+Received: from bagpuss.pepperfish.net (bagpuss.pepperfish.net [148.251.8.16])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by pieni.net (Postfix) with ESMTPS id 8456421B02
+ for <distix@pieni.net>; Mon, 1 Dec 2014 03:08:46 +0100 (CET)
+Received: from platypus.pepperfish.net (unknown [10.112.100.20])
+ by bagpuss.pepperfish.net (Postfix) with ESMTP id D1521348C;
+ Mon, 1 Dec 2014 02:08:45 +0000 (GMT)
+Received: from localhost ([::1] helo=platypus.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XvGPt-0002sf-OC; Mon, 01 Dec 2014 02:08:45 +0000
+Received: from inmail ([10.112.100.10] helo=mx0.pepperfish.net)
+ by platypus.pepperfish.net with esmtp (Exim 4.80 #2 (Debian))
+ id 1XvGPr-0002rG-PN
+ for <obnam-dev@obnam.org>; Mon, 01 Dec 2014 02:08:43 +0000
+Received: from scadrial.mjdsystems.ca ([198.100.154.185])
+ by mx0.pepperfish.net with esmtp (Exim 4.80)
+ (envelope-from <matthew@mjdsystems.ca>) id 1XvGPn-00057D-HA
+ for obnam-dev@obnam.org; Mon, 01 Dec 2014 02:08:43 +0000
+Received: from cwmtaff.housem.mjdsystems.ca
+ (CPE00045a5ba0db-CM602ad073c297.cpe.net.cable.rogers.com [99.229.22.8])
+ by scadrial.mjdsystems.ca (Postfix) with ESMTPSA id 73D3D185B2F;
+ Sun, 30 Nov 2014 21:08:36 -0500 (EST)
+From: Matthew Dawson <matthew@mjdsystems.ca>
+To: obnam-dev@obnam.org
+Date: Sun, 30 Nov 2014 21:08:29 -0500
+Message-Id: <1417399711-8672-1-git-send-email-matthew@mjdsystems.ca>
+X-Mailer: git-send-email 2.0.4
+X-Spam-Score: -1.9
+X-Spam-Score-int: -18
+X-Spam-Bar: -
+X-Scanned-By: pepperfish.net, Mon, 01 Dec 2014 02:08:42 +0000
+X-Spam-Report: Content analysis details: (-1.9 points)
+ pts rule name description
+ ---- ---------------------- --------------------------------------------------
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay
+ domain
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%
+ [score: 0.0000]
+Cc: Matthew Dawson <matthew@mjdsystems.ca>
+Subject: [PATCH 0/3] RFC: Add support for Openstack Swift as backup
+ repository
+X-BeenThere: obnam-dev@obnam.org
+X-Mailman-Version: 2.1.5
+Precedence: list
+List-Id: Obnam development discussions <obnam-dev-obnam.org>
+List-Unsubscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=unsubscribe>
+List-Archive: <http://listmaster.pepperfish.net/pipermail/obnam-dev-obnam.org>
+List-Post: <mailto:obnam-dev@obnam.org>
+List-Help: <mailto:obnam-dev-request@obnam.org?subject=help>
+List-Subscribe: <http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org>,
+ <mailto:obnam-dev-request@obnam.org?subject=subscribe>
+Sender: obnam-dev-bounces@obnam.org
+Errors-To: obnam-dev-bounces@obnam.org
+
+Hi all,
+
+This patch set contains an experimental work in progress Openstack Swift VFS for
+Obnam. I've only just got it working (thus it's not merge ready) but it does
+pass the VFS unit tests except for reinit support. I've done initial testing
+against hubiC's implementation, and the code has managed an initial backup +
+verify on some (real) test data.
+
+I'm posting it here for initial comments, and also to find out if such a backend
+is wanted in Obnam. If this is wanted, I'll continue improving the backend.
+
+Current issues:
+ - Filename quoting is inconsistent, requires research to understand what the
+Openstack library requires.
+ - Too many round trips, mostly caused due to extra checking carried out.
+Commits are especially expensive.
+ - Only supports token based authentication with Swift, as that is what hubiC
+uses.
+
+For easy pulling, the code is also available at
+https://gitlab.com/MJDSys/obnam.git , on the swift branch. Note that branch
+has some miscellaneous fixes as well, which I submit separately once I clean
+them up.
+
+Matthew Dawson (3):
+ Initial swift. Passes tests.
+ Handle parent directories correctly, instead of ignoring them.
+ Tracing for the win!
+
+ obnamlib/plugins/swift_plugin.py | 496 +++++++++++++++++++++++++++++++++++++++
+ obnamlib/vfs.py | 4 +-
+ test-swift | 85 +++++++
+ without-tests | 1 +
+ 4 files changed, 584 insertions(+), 2 deletions(-)
+ create mode 100644 obnamlib/plugins/swift_plugin.py
+ create mode 100755 test-swift
+
+--
+2.0.4
+
+
+_______________________________________________
+obnam-dev mailing list
+obnam-dev@obnam.org
+http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/obnam-dev-obnam.org
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/tmp/.this-dir-not-empty/.empty/empty-file b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/tmp/.this-dir-not-empty/.empty/empty-file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/Maildir/tmp/.this-dir-not-empty/.empty/empty-file
diff --git a/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/ticket.yaml b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/ticket.yaml
new file mode 100644
index 0000000..f8c1849
--- /dev/null
+++ b/tickets/10d72738d6ce4ab7b0fc3f21c15635bc/ticket.yaml
@@ -0,0 +1,4 @@
+ticket-id:
+- 10d72738d6ce4ab7b0fc3f21c15635bc
+title:
+- "Re: [PATCH 0/3] RFC: Add support for Openstack Swift as backup\n repository"