diff -Nru grive-0.2.0/CMakeLists.txt grive-0.3.0/CMakeLists.txt --- grive-0.2.0/CMakeLists.txt 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/CMakeLists.txt 2012-08-09 10:53:18.000000000 +0000 @@ -1,6 +1,11 @@ cmake_minimum_required(VERSION 2.8) -set( GRIVE_VERSION "0.2.0" ) +# Grive version. remember to update it for every new release! +set( GRIVE_VERSION "0.3.0-pre" ) + +# common compile options +add_definitions( -DVERSION="${GRIVE_VERSION}" ) +add_definitions( -D_FILE_OFFSET_BITS=64 ) add_subdirectory( libgrive ) add_subdirectory( grive ) diff -Nru grive-0.2.0/README grive-0.3.0/README --- grive-0.2.0/README 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/README 2012-08-09 10:53:18.000000000 +0000 @@ -1,22 +1,21 @@ -Grive 0.2.0 -9 June 2012 +Grive 0.3.0 +25 July 2012 http://www.lbreda.com/grive/ -Grive is still considered experimental. It just downloads all the files in your google drive -into the current directory. After you make some changes to the local files, run grive and -it will upload your changes back to your google drive. New files created in local or google -drive will be uploaded or downloaded respectively. Deleted files will also be "removed". +Grive can be considered still beta quality. It simply downloads all the files in your +Google Drive into the current directory. After you make some changes to the local files, run +grive again and it will upload your changes back to your Google Drive. New files created locally +or in Google Drive will be uploaded or downloaded respectively. Deleted files will also be "removed". Currently Grive will NOT destroy any of your files: it will only move the files to a -directory named .trash, or put it in the google drive trash. You can always recover them. +directory named .trash or put them in the Google Drive trash. You can always recover them. -There are a few things that grive does not do at the moment: -- wait for changes in file system to occur and upload. Grive only sync when you run it. +There are a few things that Grive does not do at the moment: +- wait for changes in file system to occur and upload. A sync is only performed when you run Grive. - symbolic links support - support for Google documents -- support for files >2GB -Of course these will be done in future, possibly the next release. +Of course these will be added in the future, possibly the next release. You need the following libraries: @@ -35,16 +34,29 @@ http://www.lbreda.com/grive/installation -for detailed procedures to compile Grive. +...for detailed procedures to compile Grive. -When grive is ran for the first time, you should use the "-a" argument to grant -permission to grive to access to your Google Drive. An URL should be printed. -Go to the link. You will need to login to your google account if you haven't -done so. After granting the permission to grive, the browser will show you -an authenication code. Copy-and-paste that to the standard input of grive. +When Grive is run for the first time, you should use the "-a" argument to grant +permission to Grive to access to your Google Drive. A URL should be printed. +Go to the link. You will need to login to your Google account if you haven't +done so. After granting the permission to Grive, the browser will show you +an authenication code. Copy-and-paste that to the standard input of Grive. -If everything works fine, grive will create a .grive and a .grive_state file in your +If everything works fine, Grive will create .grive and .grive_state files in your current directory. It will also start downloading files from your Google Drive to your current directory. Enjoy! + +Version History: + +Grive v0.3: Bug fix & minor feature release +Fixed bugs: + #93: missing reference count increment in one of the Json constructors + #82: retry for HTTP error 500 & 503 + #77: Fixed a bug where grive crashed on the first run. + +New features: + #87: support for revisions + #86: partial sync (contributed by justin at tierramedia.com) + \ No newline at end of file diff -Nru grive-0.2.0/debian/changelog grive-0.3.0/debian/changelog --- grive-0.2.0/debian/changelog 2012-09-13 15:16:41.000000000 +0000 +++ grive-0.3.0/debian/changelog 2013-01-28 10:04:39.000000000 +0000 @@ -1,5 +1,92 @@ -grive (0.2.0-1) unstable; urgency=low +grive (0.3.0-1+git20120806~webupd8~raring1) raring; urgency=medium + + * upload for Raring + + -- Alin Andrei Thu, 09 Aug 2012 14:09:13 +0300 - * First version for Debian (Closes: #675310) +grive (0.3.0-1+git20120806~webupd8~quantal1) quantal; urgency=medium + + * new git pull - build without bfd for quantal (commented out in libgrive/CMakeLists.txt) + + -- Alin Andrei Thu, 09 Aug 2012 14:09:13 +0300 + +grive (0.3.0-1+git20120806~webupd8~quantal) quantal; urgency=medium + + * new git pull - build without bfd for quantal (commented out in libgrive/CMakeLists.txt) + + -- Alin Andrei Thu, 09 Aug 2012 13:57:24 +0300 + +grive (0.3.0-1+git20120806~webupd8~lucid) lucid; urgency=medium + + * new git pull + + -- Alin Andrei Thu, 09 Aug 2012 13:55:14 +0300 + +grive (0.2.0-1+git20120720~webupd8~lucid) lucid; urgency=medium + + * new git pull + + -- Alin Andrei Fri, 20 Jul 2012 16:08:29 +0300 + +grive (0.2.0-1+git20120711~webupd8~lucid) lucid; urgency=medium + + * new git pull + + -- Alin Andrei Thu, 12 Jul 2012 13:07:05 +0300 + +grive (0.2.0-1+git20120627~webupd8~lucid) lucid; urgency=medium + + * new git pull + + -- Alin Andrei Thu, 28 Jun 2012 17:32:38 +0300 + +grive (0.2.0-1+git20120626~webupd8~lucid) lucid; urgency=medium + + * new git pull + + -- Alin Andrei Tue, 26 Jun 2012 12:13:02 +0300 + +grive (0.2.0-1+git20120623~webupd8~natty) natty; urgency=medium - -- José Luis Segura Lucas Mon, 09 Jul 2012 07:54:24 +0200 + * new git pull + + -- Alin Andrei Mon, 25 Jun 2012 14:45:25 +0200 + +grive (0.2.0-1+git20120617~webupd8~oneiric1) oneiric; urgency=medium + + * new git pull + * new dependency: libboost-program-options-dev + + -- Alin Andrei Mon, 18 Jun 2012 14:45:25 +0200 + +grive (0.2.0-1+git20120612~webupd8~precise1) precise; urgency=medium + + * new git pull (bug fixes) + + -- Alin Andrei Mon, 12 Jun 2012 14:45:25 +0200 + +grive (0.1.0-1+git20120607~webupd8~precise1) precise; urgency=medium + + * new git pull (bug fixes) + * new libgcrypt11-dev dependency + + -- Alin Andrei Thu, 07 Jun 2012 14:45:25 +0200 + +grive (0.1.0-1+git20120601~webupd8~precise1) precise; urgency=medium + + * new git pull + + -- Alin Andrei Sat, 01 Jun 2012 14:45:25 +0200 + +grive (0.1.0-1+git20120531~webupd8~precise1) precise; urgency=medium + + * new git pull + * added binutils-dev dependency + + -- Alin Andrei Sat, 31 May 2012 14:55:25 +0000 + +grive (0.1.0-1+git20120522~webupd8~lucid) lucid; urgency=medium + + * initial upload + + -- Alin Andrei Sat, 22 May 2012 14:55:25 +0000 diff -Nru grive-0.2.0/debian/compat grive-0.3.0/debian/compat --- grive-0.2.0/debian/compat 2012-08-27 16:33:38.000000000 +0000 +++ grive-0.3.0/debian/compat 2012-02-08 15:18:31.000000000 +0000 @@ -1 +1 @@ -9 +7 diff -Nru grive-0.2.0/debian/control grive-0.3.0/debian/control --- grive-0.2.0/debian/control 2012-10-08 17:58:55.000000000 +0000 +++ grive-0.3.0/debian/control 2012-07-12 10:04:27.000000000 +0000 @@ -1,39 +1,19 @@ Source: grive Section: net -Priority: extra -Maintainer: José Luis Segura Lucas -Uploaders: Cleto Martín -Build-Depends: binutils-dev, - cmake, - debhelper (>= 9), - libboost-filesystem-dev, - libboost-program-options-dev, - libboost-system-dev, - libcppunit-dev, - libcurl4-gnutls-dev | libcurl-dev, - libexpat-dev, - libgcrypt-dev, - libjson0-dev, - xsltproc, - docbook-xsl -Standards-Version: 3.9.3 +Priority: optional +Maintainer: Alin Andrei +Build-Depends: debhelper, cmake, libjson0-dev, libcurl4-gnutls-dev | libcurl-dev, libstdc++6-4.4-dev, libcppunit-dev, libboost-filesystem-dev, libboost-program-options-dev, libgdbm-dev, libexpat1-dev, binutils-dev, libgcrypt11-dev +Standards-Version: 3.8.4 Homepage: https://github.com/Grive/grive -Vcs-Git: git://github.com/JoseLSegura/Grive-Debian-packaging.git Package: grive Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} -Description: Google Drive client for GNU/Linux - Grive is a Google Drive (an online storage service) client. It - allows synchronize your Google Drive files with a directory on your - local storage from the command-line. - . - It automatically synchronizes your local copy of your Google Drive, - adding or removing files from the online storage. It allows add new - files on your local directory and them will be uploaded to Google - Drive when it synchronizes. - . - Grive is still in process of development. It will include support for - auto-detecting changes on the local storage to force a - synchronization and a daemon mode which will work on user space to - have your local files always synchronized with your online storage. +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Grive: an open source Linux client for Google Drive + For the first time running grive, you should use the "-a" argument to grant + permission to grive to access to your Google Drive. An URL should be printed. + Go to the page. You will need to login to your google account if you haven't + done so. After granting the permission to grive, the browser will show you + an authenication code. Copy-and-paste that to the standard input of grive. + If everything works fine, grive will create a .grive file in your home directory. + It will also start downloading files from your Google Drive to your current directory. diff -Nru grive-0.2.0/debian/copyright grive-0.3.0/debian/copyright --- grive-0.2.0/debian/copyright 2012-10-08 18:29:39.000000000 +0000 +++ grive-0.3.0/debian/copyright 2012-07-12 10:04:36.000000000 +0000 @@ -1,89 +1,25 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0 -Upstream-Name: grive -Upstream-Contact: me@nestal.net -Source: https://github.com/Grive/grive - -Files: * -Copyright: 2012 Nestal Wan Wai Ho -License: GPL-2 - 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, see . - . - On Debian GNU/Linux systems, the complete text of the GNU General Public - License version 2 can be found in `/usr/share/common-licenses/GPL-2'. - -Files: libgrive/src/bfd/SymbolInfo.* libgrive/src/bfd/Addr.hh libgrive/src/bfd/Debug.* -Copyright: 2006 Nestal Wan Wai Ho -License: GPL-2 - 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, see . - . - On Debian GNU/Linux systems, the complete text of the GNU General Public - License version 2 can be found in `/usr/share/common-licenses/GPL-2'. - -Files: cmake/Modules/FindLibGcrypt.cmake -Copyright: 2006 Brad Hards -License: BSD - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - . - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Files: debian/* -Copyright: 2012 José Luis Segura Lucas -License: GPL-2+ - This package 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 package 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 - . - On Debian systems, the complete text of the GNU General - Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". +This package was debianized by: + + Alin Andrei on Tue, 22 May 2012 12:22:36 +0300 + +It was downloaded from: + + https://github.com/Grive/grive + +Upstream Author(s): + + Matchman Green + +Copyright: + + Copyright (C) Matchman Green + +License: + + GPL 2.0+ + +The Debian packaging is: + + Copyright (C) 2012 Alin Andrei + +and is licensed under the GPL version 2.0+. diff -Nru grive-0.2.0/debian/docs grive-0.3.0/debian/docs --- grive-0.2.0/debian/docs 2012-09-13 15:16:41.000000000 +0000 +++ grive-0.3.0/debian/docs 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -README diff -Nru grive-0.2.0/debian/grive.lintian-overrides grive-0.3.0/debian/grive.lintian-overrides --- grive-0.2.0/debian/grive.lintian-overrides 2012-09-13 15:16:41.000000000 +0000 +++ grive-0.3.0/debian/grive.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -# Suspicius call to unprotected "read" -# Called from libgrive/src/util/StdioFile.cc:103 -# always using the "sizeof" of the buffer to call "read". -hardening-no-fortify-functions diff -Nru grive-0.2.0/debian/grive.xml grive-0.3.0/debian/grive.xml --- grive-0.2.0/debian/grive.xml 2012-10-08 17:15:30.000000000 +0000 +++ grive-0.3.0/debian/grive.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,180 +0,0 @@ - -.
will be generated. You may view the -manual page with: nroff -man .
| less'. A typical entry -in a Makefile or Makefile.am is: - -DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/manpages/docbook.xsl -XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" - -manpage.1: manpage.xml - $(XP) $(DB2MAN) $< - -The xsltproc binary is found in the xsltproc package. The XSL files are in -docbook-xsl. A description of the parameters you can use can be found in the -docbook-xsl-doc-* packages. Please remember that if you create the nroff -version in one of the debian/rules file targets (such as build), you will need -to include xsltproc and docbook-xsl in your Build-Depends control field. -Alternatively use the xmlto command/package. That will also automatically -pull in xsltproc and docbook-xsl. - -Notes for using docbook2x: docbook2x-man does not automatically create the -AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as - ... . - -To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections -read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be -found in the docbook-xsl-doc-html package. - -Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` - -General documentation about man-pages and man-page-formatting: -man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ - ---> - - - - - - - - - - - - - -]> - - - - &dhtitle; - &dhpackage; - - - &dhfirstname; - &dhsurname; - Wrote this manpage for the Debian system. -
- &dhemail; -
-
-
- - 2012 - &dhusername; - - - This manual page was written for the Debian system - (and may be used by others). - Permission is granted to copy, distribute and/or modify - this document under the terms of the GNU General Public License, - Version 2 or any later version published by the Free Software - Foundation. - On Debian systems, the complete text of the GNU General Public - License can be found in - /usr/share/common-licenses/GPL-2. - -
- - &dhucpackage; - &dhsection; - - - &dhpackage; - a Google Drive (online storage service) client. - - - - &dhpackage; - - - - - - DESCRIPTION - &dhpackage; allows the synchronization of - all your files on the cloud with a directory of your choice and - the upload of new files to Google Drive. - - This manual page was written for the Debian distribution - because the original program does not have a manual page. - Instead, it has documentation in the GNU - info - 1 - format; see below. - - - OPTIONS - - - - - - - Requests authorization token from Google and sync to - current directory. - - - - - - - - Enable debug level messages (implies -V). - - - - - - - Only detects which files are needed for download or - upload without doing it. - - - - - - - - Forces grive to always download a file from Google - Drive instead uploading it. - - - - - - - - Show the help message. - - - - - - - - set FILENAME as log output location instead standard - output. - - - - -
diff -Nru grive-0.2.0/debian/manpages grive-0.3.0/debian/manpages --- grive-0.2.0/debian/manpages 2012-08-27 16:33:38.000000000 +0000 +++ grive-0.3.0/debian/manpages 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -debian/grive.1 diff -Nru grive-0.2.0/debian/rules grive-0.3.0/debian/rules --- grive-0.2.0/debian/rules 2012-10-08 17:59:06.000000000 +0000 +++ grive-0.3.0/debian/rules 2012-05-22 21:52:33.000000000 +0000 @@ -1,19 +1,10 @@ #!/usr/bin/make -f -# -*- makefile -*- - -DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) -DB2MAN := /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl %: dh $@ -override_dh_clean: - dh_clean - $(RM) debian/grive.1 - -override_dh_auto_build: - dh_auto_build - xsltproc -o debian/grive.1 --param man.charmap.use.subset "0" --novalid --nonet $(DB2MAN) debian/grive.xml - -override_dh_auto_test: - ./obj-$(DEB_BUILD_GNU_TYPE)/libgrive/unittest +override_dh_auto_configure: + mkdir build + cd build + cmake . -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr diff -Nru grive-0.2.0/debian/source/format grive-0.3.0/debian/source/format --- grive-0.2.0/debian/source/format 2013-01-28 10:12:20.306465616 +0000 +++ grive-0.3.0/debian/source/format 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -3.0 (quilt) diff -Nru grive-0.2.0/debian/watch grive-0.3.0/debian/watch --- grive-0.2.0/debian/watch 2012-09-13 15:16:41.000000000 +0000 +++ grive-0.3.0/debian/watch 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -version=3 - -opts=filenamemangle=s/.*(\d[\d\.]+)/grive_$1\.tar\.gz/ \ - https://github.com/Grive/grive/tags .*/tarball/v?(\d[\d\.]+) \ No newline at end of file diff -Nru grive-0.2.0/grive/CMakeLists.txt grive-0.3.0/grive/CMakeLists.txt --- grive-0.2.0/grive/CMakeLists.txt 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/grive/CMakeLists.txt 2012-08-09 10:53:18.000000000 +0000 @@ -7,8 +7,6 @@ ${OPT_INCS} ) -add_definitions( -DVERSION="${GRIVE_VERSION}" ) - file (GLOB GRIVE_EXE_SRC ${grive_SOURCE_DIR}/src/*.cc ) diff -Nru grive-0.2.0/grive/src/Config.cc grive-0.3.0/grive/src/Config.cc --- grive-0.2.0/grive/src/Config.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/grive/src/Config.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -/* - grive: an GPL program to sync a local directory with Google Drive - Copyright (C) 2012 Wan Wai Ho - - 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 version 2 - of the License. - - 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. -*/ - -#include "Config.hh" - -#include "util/StdioFile.hh" - -#include - -namespace gr { - -const std::string& Config::Filename() -{ - static const char *env_cfg = ::getenv( "GR_CONFIG" ) ; - static const std::string filename = (env_cfg != 0) ? env_cfg : ".grive" ; - - return filename ; -} - -Config::Config() : - m_cfg( Read( Filename() ) ) -{ -} - -void Config::Save( ) -{ - StdioFile file( Filename(), 0600 ) ; - m_cfg.Write( file ) ; -} - -Json& Config::Get() -{ - return m_cfg ; -} - -Json Config::Read( const std::string& filename ) -{ - try - { - return Json::ParseFile( filename ) ; - } - catch ( Exception& e ) - { - return Json() ; - } -} - -} // end of namespace diff -Nru grive-0.2.0/grive/src/Config.hh grive-0.3.0/grive/src/Config.hh --- grive-0.2.0/grive/src/Config.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/grive/src/Config.hh 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* - grive: an GPL program to sync a local directory with Google Drive - Copyright (C) 2012 Wan Wai Ho - - 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 version 2 - of the License. - - 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. -*/ - -#pragma once - -#include "util/Exception.hh" -#include "protocol/Json.hh" - -namespace gr { - -class Config -{ -public : - struct Error : virtual Exception {} ; - typedef boost::error_info File ; - - static const std::string& Filename() ; - - Config() ; - - Json& Get() ; - void Save() ; - -private : - Json Read( const std::string& filename ) ; - -private : - Json m_cfg ; -} ; - -} // end of namespace diff -Nru grive-0.2.0/grive/src/main.cc grive-0.3.0/grive/src/main.cc --- grive-0.2.0/grive/src/main.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/grive/src/main.cc 2012-08-09 10:53:18.000000000 +0000 @@ -17,10 +17,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "Config.hh" +#include "util/Config.hh" #include "drive/Drive.hh" +#include "http/CurlAgent.hh" +#include "protocol/AuthAgent.hh" #include "protocol/OAuth2.hh" #include "protocol/Json.hh" @@ -46,6 +48,7 @@ const std::string client_secret = "bl4ufi89h-9MkFlypcI7R785" ; using namespace gr ; +namespace po = boost::program_options; // libgcrypt insist this to be done in application, not library void InitGCrypt() @@ -60,18 +63,44 @@ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } -int Main( int argc, char **argv ) +void InitLog( const po::variables_map& vm ) { - InitGCrypt() ; - - Config config ; - std::auto_ptr comp_log(new log::CompositeLog) ; LogBase* console_log = comp_log->Add( std::auto_ptr( new log::DefaultLog ) ) ; + + if ( vm.count( "log" ) ) + { + std::auto_ptr file_log(new log::DefaultLog( vm["log"].as() )) ; + file_log->Enable( log::debug ) ; + file_log->Enable( log::verbose ) ; + file_log->Enable( log::info ) ; + file_log->Enable( log::warning ) ; + file_log->Enable( log::error ) ; + file_log->Enable( log::critical ) ; + + // log grive version to log file + file_log->Log( log::Fmt("grive version " VERSION " " __DATE__ " " __TIME__), log::verbose ) ; + file_log->Log( log::Fmt("current time: %1%") % DateTime::Now(), log::verbose ) ; + + comp_log->Add( file_log ) ; + } - Json options ; + if ( vm.count( "verbose" ) ) + { + console_log->Enable( log::verbose ) ; + } - namespace po = boost::program_options; + if ( vm.count( "debug" ) ) + { + console_log->Enable( log::verbose ) ; + console_log->Enable( log::debug ) ; + } + LogBase::Inst( std::auto_ptr(comp_log.release()) ) ; +} + +int Main( int argc, char **argv ) +{ + InitGCrypt() ; // construct the program options po::options_description desc( "Grive options" ); @@ -79,7 +108,10 @@ ( "help,h", "Produce help message" ) ( "version,v", "Display Grive version" ) ( "auth,a", "Request authorization token" ) + ( "path,p", po::value(), "Path to sync") ( "verbose,V", "Verbose mode. Enable more messages than normal.") + ( "log-xml", "Log more HTTP responses as XML for debugging.") + ( "new-rev", "Create new revisions in server for updated files.") ( "debug,d", "Enable debug level messages. Implies -v.") ( "log,l", po::value(), "Set log output filename." ) ( "force,f", "Force grive to always download a file from Google Drive " @@ -92,11 +124,26 @@ po::store(po::parse_command_line( argc, argv, desc), vm ); po::notify(vm); + // simple commands that doesn't require log or config if ( vm.count("help") ) { std::cout << desc << std::endl ; return 0 ; } + else if ( vm.count( "version" ) ) + { + std::cout + << "grive version " << VERSION << ' ' << __DATE__ << ' ' << __TIME__ << std::endl ; + return 0 ; + } + + // initialize logging + InitLog(vm) ; + + Config config(vm) ; + + Log( "config file name %1%", config.Filename(), log::verbose ); + if ( vm.count( "auth" ) ) { std::cout @@ -115,51 +162,14 @@ token.Auth( code ) ; // save to config - config.Get().Add( "refresh_token", Json( token.RefreshToken() ) ) ; + config.Set( "refresh_token", Json( token.RefreshToken() ) ) ; config.Save() ; } - if ( vm.count( "log" ) ) - { - std::auto_ptr file_log(new log::DefaultLog( vm["log"].as() )) ; - file_log->Enable( log::debug ) ; - file_log->Enable( log::verbose ) ; - file_log->Enable( log::info ) ; - file_log->Enable( log::warning ) ; - file_log->Enable( log::error ) ; - file_log->Enable( log::critical ) ; - - // log grive version to log file - file_log->Log( log::Fmt("grive version " VERSION " " __DATE__ " " __TIME__), log::verbose ) ; - file_log->Log( log::Fmt("current time: %1%") % DateTime::Now(), log::verbose ) ; - - comp_log->Add( file_log ) ; - } - if ( vm.count( "version" ) ) - { - std::cout - << "grive version " << VERSION << ' ' << __DATE__ << ' ' << __TIME__ << std::endl ; - return 0 ; - } - if ( vm.count( "verbose" ) ) - { - console_log->Enable( log::verbose ) ; - } - if ( vm.count( "debug" ) ) - { - console_log->Enable( log::verbose ) ; - console_log->Enable( log::debug ) ; - } - if ( vm.count( "force" ) ) - { - options.Add( "force", Json(true) ) ; - } - - LogBase::Inst( std::auto_ptr(comp_log.release()) ) ; std::string refresh_token ; try { - refresh_token = config.Get()["refresh_token"].Str() ; + refresh_token = config.Get("refresh_token").Str() ; } catch ( Exception& e ) { @@ -172,7 +182,9 @@ } OAuth2 token( refresh_token, client_id, client_secret ) ; - Drive drive( token, options ) ; + AuthAgent agent( token, std::auto_ptr( new http::CurlAgent ) ) ; + + Drive drive( &agent, config.GetAll() ) ; drive.DetectChanges() ; if ( vm.count( "dry-run" ) == 0 ) diff -Nru grive-0.2.0/libgrive/CMakeLists.txt grive-0.3.0/libgrive/CMakeLists.txt --- grive-0.2.0/libgrive/CMakeLists.txt 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/CMakeLists.txt 2012-08-09 10:56:20.000000000 +0000 @@ -6,8 +6,8 @@ find_package(JSONC REQUIRED) find_package(CURL REQUIRED) find_package(EXPAT REQUIRED) -find_package(Boost 1.40.0 COMPONENTS filesystem system REQUIRED) -find_package(BFD) +find_package(Boost 1.40.0 COMPONENTS program_options filesystem system REQUIRED) +#find_package(BFD) find_package(CppUnit) find_package(Iberty) find_package(ZLIB) @@ -29,6 +29,8 @@ if ( IBERTY_FOUND ) set( OPT_LIBS ${OPT_LIBS} ${IBERTY_LIBRARY} ) +else ( IBERTY_FOUND ) + set( IBERTY_LIBRARY "" ) endif ( IBERTY_FOUND ) if ( ZLIB_FOUND ) @@ -68,7 +70,6 @@ ) add_definitions( - -DVERSION="${GRIVE_VERSION}" -DTEST_DATA="${libgrive_SOURCE_DIR}/test/data/" -DSRC_DIR="${libgrive_SOURCE_DIR}/src" ) @@ -125,6 +126,7 @@ target_link_libraries( unittest grive ${CPPUNIT_LIBRARY} + ${Boost_LIBRARIES} ) ENDIF ( CPPUNIT_FOUND ) diff -Nru grive-0.2.0/libgrive/src/drive/Drive.cc grive-0.3.0/libgrive/src/drive/Drive.cc --- grive-0.2.0/libgrive/src/drive/Drive.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/Drive.cc 2012-08-09 10:53:18.000000000 +0000 @@ -23,11 +23,9 @@ #include "Entry.hh" #include "Feed.hh" -#include "http/CurlAgent.hh" +#include "http/Agent.hh" #include "http/ResponseLog.hh" #include "http/XmlResponse.hh" -#include "protocol/Json.hh" -#include "protocol/OAuth2.hh" #include "util/Destroy.hh" #include "util/log/Log.hh" #include "xml/Node.hh" @@ -53,12 +51,13 @@ const std::string state_file = ".grive_state" ; } -Drive::Drive( OAuth2& auth, const Json& options ) : - m_auth( auth ), - m_state( state_file, options ) +Drive::Drive( http::Agent *http, const Json& options ) : + m_http ( http ), + m_root ( options["path"].Str() ), + m_state ( m_root / state_file, options ), + m_options ( options ) { - m_http_hdr.Add( "Authorization: Bearer " + m_auth.AccessToken() ) ; - m_http_hdr.Add( "GData-Version: 3.0" ) ; + assert( m_http != 0 ) ; } void Drive::FromRemote( const Entry& entry ) @@ -93,14 +92,14 @@ m_state.Write( state_file ) ; } -void Drive::SyncFolders( http::Agent *http ) +void Drive::SyncFolders( ) { - assert( http != 0 ) ; + assert( m_http != 0 ) ; Log( "Synchronizing folders", log::info ) ; http::XmlResponse xml ; - http->Get( feed_base + "/-/folder?max-results=50&showroot=true", &xml, m_http_hdr ) ; + m_http->Get( feed_base + "/-/folder?max-results=50&showroot=true", &xml, http::Header() ) ; Feed feed( xml.Response() ) ; do @@ -121,7 +120,7 @@ m_state.FromRemote( e ) ; } } - } while ( feed.GetNext( http, m_http_hdr ) ) ; + } while ( feed.GetNext( m_http, http::Header() ) ) ; m_state.ResolveEntry() ; } @@ -129,63 +128,68 @@ void Drive::DetectChanges() { Log( "Reading local directories", log::info ) ; - m_state.FromLocal( "." ) ; + m_state.FromLocal( m_root ) ; - http::CurlAgent http ; - long prev_stamp = m_state.ChangeStamp() ; Trace( "previous change stamp is %1%", prev_stamp ) ; - SyncFolders( &http ) ; + SyncFolders( ) ; Log( "Reading remote server file list", log::info ) ; - http::XmlResponse xrsp ; - http.Get( feed_base + "?showfolders=true&showroot=true", &xrsp, m_http_hdr ) ; - xml::Node resp = xrsp.Response() ; - - m_resume_link = resp["link"]. + Feed feed ; + if ( m_options["log-xml"].Bool() ) + feed.EnableLog( "/tmp/file", ".xml" ) ; + + feed.Start( m_http, http::Header(), feed_base + "?showfolders=true&showroot=true" ) ; + + m_resume_link = feed.Root()["link"]. Find( "@rel", "http://schemas.google.com/g/2005#resumable-create-media" )["@href"] ; - - Feed feed( resp ) ; + do { - std::for_each( feed.begin(), feed.end(), boost::bind( &Drive::FromRemote, this, _1 ) ) ; - } while ( feed.GetNext( &http, m_http_hdr ) ) ; + std::for_each( + feed.begin(), feed.end(), + boost::bind( &Drive::FromRemote, this, _1 ) ) ; + + } while ( feed.GetNext( m_http, http::Header() ) ) ; // pull the changes feed if ( prev_stamp != -1 ) { - http::ResponseLog log( "/tmp/changes-", ".xml", &xrsp ) ; Log( "Detecting changes from last sync", log::info ) ; - http.Get( ChangesFeed(prev_stamp+1), &log, m_http_hdr ) ; + Feed changes ; + if ( m_options["log-xml"].Bool() ) + feed.EnableLog( "/tmp/changes", ".xml" ) ; + + feed.Start( m_http, http::Header(), ChangesFeed(prev_stamp+1) ) ; - Feed changes( xrsp.Response() ) ; - std::for_each( changes.begin(), changes.end(), boost::bind( &Drive::FromChange, this, _1 ) ) ; + std::for_each( + changes.begin(), changes.end(), + boost::bind( &Drive::FromChange, this, _1 ) ) ; } } void Drive::Update() { Log( "Synchronizing files", log::info ) ; - http::CurlAgent http ; - m_state.Sync( &http, m_http_hdr ) ; + m_state.Sync( m_http, m_options ) ; - UpdateChangeStamp( &http ) ; + UpdateChangeStamp( ) ; } void Drive::DryRun() { Log( "Synchronizing files (dry-run)", log::info ) ; - m_state.Sync( 0, m_http_hdr ) ; + m_state.Sync( 0, m_options ) ; } -void Drive::UpdateChangeStamp( http::Agent *http ) +void Drive::UpdateChangeStamp( ) { - assert( http != 0 ) ; + assert( m_http != 0 ) ; // get changed feed http::XmlResponse xrsp ; - http->Get( ChangesFeed(m_state.ChangeStamp()+1), &xrsp, m_http_hdr ) ; + m_http->Get( ChangesFeed(m_state.ChangeStamp()+1), &xrsp, http::Header() ) ; // we should go through the changes to see if it was really Grive to made that change // maybe by recording the updated timestamp and compare it? diff -Nru grive-0.2.0/libgrive/src/drive/Drive.hh grive-0.3.0/libgrive/src/drive/Drive.hh --- grive-0.2.0/libgrive/src/drive/Drive.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/Drive.hh 2012-08-09 10:53:18.000000000 +0000 @@ -22,6 +22,7 @@ #include "State.hh" #include "http/Header.hh" +#include "protocol/Json.hh" #include "util/Exception.hh" #include @@ -35,13 +36,11 @@ } class Entry ; -class OAuth2 ; -class Json ; class Drive { public : - Drive( OAuth2& auth, const Json& options ) ; + Drive( http::Agent *http, const Json& options ) ; void DetectChanges() ; void Update() ; @@ -51,18 +50,18 @@ struct Error : virtual Exception {} ; private : - void SyncFolders( http::Agent *http ) ; + void SyncFolders( ) ; void file(); void FromRemote( const Entry& entry ) ; void FromChange( const Entry& entry ) ; - void UpdateChangeStamp( http::Agent *http ) ; + void UpdateChangeStamp( ) ; private : - OAuth2& m_auth ; - http::Header m_http_hdr ; - + http::Agent *m_http ; std::string m_resume_link ; + fs::path m_root ; State m_state ; + Json m_options ; } ; } // end of namespace diff -Nru grive-0.2.0/libgrive/src/drive/Entry.cc grive-0.3.0/libgrive/src/drive/Entry.cc --- grive-0.2.0/libgrive/src/drive/Entry.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/Entry.cc 2012-08-09 10:53:18.000000000 +0000 @@ -192,7 +192,7 @@ std::string Entry::Name() const { - return m_kind == "file" ? m_filename : m_title ; + return (m_kind == "file" || m_kind == "pdf") ? m_filename : m_title ; } } // end of namespace diff -Nru grive-0.2.0/libgrive/src/drive/Feed.cc grive-0.3.0/libgrive/src/drive/Feed.cc --- grive-0.2.0/libgrive/src/drive/Feed.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/Feed.cc 2012-08-09 10:53:18.000000000 +0000 @@ -20,13 +20,20 @@ #include "Feed.hh" #include "http/Agent.hh" +#include "http/ResponseLog.hh" #include "http/XmlResponse.hh" #include "xml/NodeSet.hh" +#include + #include namespace gr { +Feed::Feed( ) +{ +} + Feed::Feed( const xml::Node& root ) : m_root ( root ), m_entries ( m_root["entry"] ) @@ -55,6 +62,23 @@ return nss.empty() ? "" : std::string(nss["@href"]) ; } +void Feed::Start( http::Agent *http, const http::Header& auth, const std::string& url ) +{ + http::XmlResponse xrsp ; + http::ResponseLog log( &xrsp ) ; + + if ( m_log.get() != 0 ) + log.Reset( + m_log->prefix, + (boost::format( "-#%1%%2%" ) % m_log->sequence++ % m_log->suffix ).str(), + &xrsp ) ; + + http->Get( url, &log, auth ) ; + + m_root = xrsp.Response() ; + m_entries = m_root["entry"] ; +} + bool Feed::GetNext( http::Agent *http, const http::Header& auth ) { assert( http != 0 ) ; @@ -62,12 +86,7 @@ xml::NodeSet nss = m_root["link"].Find( "@rel", "next" ) ; if ( !nss.empty() ) { - http::XmlResponse xrsp ; - http->Get( nss["@href"], &xrsp, auth ) ; - - m_root = xrsp.Response() ; - m_entries = m_root["entry"] ; - + Start( http, auth, nss["@href"] ) ; return true ; } else @@ -90,4 +109,17 @@ return Entry( *base_reference() ) ; } +void Feed::EnableLog( const std::string& prefix, const std::string& suffix ) +{ + m_log.reset( new LogInfo ) ; + m_log->prefix = prefix ; + m_log->suffix = suffix ; + m_log->sequence = 0 ; +} + +const xml::Node& Feed::Root() const +{ + return m_root ; +} + } // end of namespace diff -Nru grive-0.2.0/libgrive/src/drive/Feed.hh grive-0.3.0/libgrive/src/drive/Feed.hh --- grive-0.2.0/libgrive/src/drive/Feed.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/Feed.hh 2012-08-09 10:53:18.000000000 +0000 @@ -43,15 +43,29 @@ public : explicit Feed( const xml::Node& root ) ; + Feed( ) ; + void Start( http::Agent *http, const http::Header& auth, const std::string& url ) ; + void Assign( const xml::Node& root ) ; + const xml::Node& Root() const ; iterator begin() const ; iterator end() const ; std::string Next() const ; bool GetNext( http::Agent *http, const http::Header& auth ) ; - + + void EnableLog( const std::string& prefix, const std::string& suffix ) ; + private : + struct LogInfo + { + std::string prefix ; + std::string suffix ; + std::size_t sequence ; + } ; + std::auto_ptr m_log ; + xml::Node m_root ; xml::NodeSet m_entries ; } ; diff -Nru grive-0.2.0/libgrive/src/drive/Resource.cc grive-0.3.0/libgrive/src/drive/Resource.cc --- grive-0.2.0/libgrive/src/drive/Resource.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/Resource.cc 2012-08-09 10:53:18.000000000 +0000 @@ -58,8 +58,8 @@ /// default constructor creates the root folder -Resource::Resource() : - m_name ( "." ), +Resource::Resource(const fs::path& root_folder) : + m_name ( root_folder.string() ), m_kind ( "folder" ), m_id ( "folder:root" ), m_href ( root_href ), @@ -209,6 +209,14 @@ } } + // remote checksum unknown, assume the file is not changed in remote + else if ( remote.MD5().empty() ) + { + Log( "file %1% has unknown checksum in remote. assuned in sync", + Path(), log::verbose ) ; + m_state = sync ; + } + // if checksum is equal, no need to compare the mtime else if ( remote.MD5() == m_md5 ) { @@ -357,20 +365,24 @@ } // try to change the state to "sync" -void Resource::Sync( http::Agent *http, const http::Header& auth ) +void Resource::Sync( http::Agent *http, DateTime& sync_time, const Json& options ) { assert( m_state != unknown ) ; assert( !IsRoot() || m_state == sync ) ; // root folder is already synced - SyncSelf( http, auth ) ; + SyncSelf( http, options ) ; + + // we want the server sync time, so we will take the server time of the last file uploaded to store as the sync time + // m_mtime is updated to server modified time when the file is uploaded + sync_time = std::max(sync_time, m_mtime); // if myself is deleted, no need to do the childrens if ( m_state != local_deleted && m_state != remote_deleted ) std::for_each( m_child.begin(), m_child.end(), - boost::bind( &Resource::Sync, _1, http, auth ) ) ; + boost::bind( &Resource::Sync, _1, http, boost::ref(sync_time), options ) ) ; } -void Resource::SyncSelf( http::Agent* http, const http::Header& auth ) +void Resource::SyncSelf( http::Agent* http, const Json& options ) { assert( !IsRoot() || m_state == sync ) ; // root is always sync assert( IsRoot() || http == 0 || fs::is_directory( m_parent->Path() ) ) ; @@ -384,19 +396,19 @@ case local_new : Log( "sync %1% doesn't exist in server, uploading", path, log::info ) ; - if ( http != 0 && Create( http, auth ) ) + if ( http != 0 && Create( http ) ) m_state = sync ; break ; case local_deleted : Log( "sync %1% deleted in local. deleting remote", path, log::info ) ; if ( http != 0 ) - DeleteRemote( http, auth ) ; + DeleteRemote( http ) ; break ; case local_changed : Log( "sync %1% changed in local. uploading", path, log::info ) ; - if ( http != 0 && EditContent( http, auth ) ) + if ( http != 0 && EditContent( http, options["new-rev"].Bool() ) ) m_state = sync ; break ; @@ -407,7 +419,7 @@ if ( IsFolder() ) fs::create_directories( path ) ; else - Download( http, path, auth ) ; + Download( http, path ) ; m_state = sync ; } @@ -418,7 +430,7 @@ Log( "sync %1% changed in remote. downloading", path, log::info ) ; if ( http != 0 ) { - Download( http, path, auth ) ; + Download( http, path ) ; m_state = sync ; } break ; @@ -466,14 +478,14 @@ } } -void Resource::DeleteRemote( http::Agent *http, const http::Header& auth ) +void Resource::DeleteRemote( http::Agent *http ) { assert( http != 0 ) ; http::StringResponse str ; try { - http::Header hdr( auth ) ; + http::Header hdr ; hdr.Add( "If-Match: " + m_etag ) ; // doesn't know why, but an update before deleting seems to work always @@ -494,12 +506,12 @@ } -void Resource::Download( http::Agent* http, const fs::path& file, const http::Header& auth ) const +void Resource::Download( http::Agent* http, const fs::path& file ) const { assert( http != 0 ) ; http::Download dl( file.string(), http::Download::NoChecksum() ) ; - long r = http->Get( m_content, &dl, auth ) ; + long r = http->Get( m_content, &dl, http::Header() ) ; if ( r <= 400 ) { if ( m_mtime != DateTime() ) @@ -509,7 +521,7 @@ } } -bool Resource::EditContent( http::Agent* http, const http::Header& auth ) +bool Resource::EditContent( http::Agent* http, bool new_rev ) { assert( http != 0 ) ; assert( m_parent != 0 ) ; @@ -522,10 +534,10 @@ return false ; } - return Upload( http, m_edit, auth, false ) ; + return Upload( http, m_edit + (new_rev ? "?new-revision=true" : ""), false ) ; } -bool Resource::Create( http::Agent* http, const http::Header& auth ) +bool Resource::Create( http::Agent* http ) { assert( http != 0 ) ; assert( m_parent != 0 ) ; @@ -543,7 +555,7 @@ % xml::Escape(m_name) ).str() ; - http::Header hdr( auth ) ; + http::Header hdr ; hdr.Add( "Content-Type: application/atom+xml" ) ; http::XmlResponse xml ; @@ -555,7 +567,7 @@ } else if ( !m_parent->m_create.empty() ) { - return Upload( http, m_parent->m_create + "?convert=false", auth, true ) ; + return Upload( http, m_parent->m_create + "?convert=false", true ) ; } else { @@ -564,23 +576,18 @@ } } -bool Resource::Upload( http::Agent* http, const std::string& link, const http::Header& auth, bool post ) +bool Resource::Upload( + http::Agent* http, + const std::string& link, + bool post) { assert( http != 0 ) ; StdioFile file( Path() ) ; - - // TODO: upload in chunks - std::string data ; - char buf[4096] ; - std::size_t count = 0 ; - while ( (count = file.Read( buf, sizeof(buf) )) > 0 ) - data.append( buf, count ) ; - std::ostringstream xcontent_len ; - xcontent_len << "X-Upload-Content-Length: " << data.size() ; + xcontent_len << "X-Upload-Content-Length: " << file.Size() ; - http::Header hdr( auth ) ; + http::Header hdr ; hdr.Add( "Content-Type: application/atom+xml" ) ; hdr.Add( "X-Upload-Content-Type: application/octet-stream" ) ; hdr.Add( xcontent_len.str() ) ; @@ -606,8 +613,9 @@ std::string uplink = http->RedirLocation() ; http::XmlResponse xml ; - http->Put( uplink, data, &xml, uphdr ) ; + http->Put( uplink, file, &xml, uphdr ) ; AssignIDs( Entry( xml.Response() ) ) ; + m_mtime = Entry(xml.Response()).MTime(); return true ; } diff -Nru grive-0.2.0/libgrive/src/drive/Resource.hh grive-0.3.0/libgrive/src/drive/Resource.hh --- grive-0.2.0/libgrive/src/drive/Resource.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/Resource.hh 2012-08-09 10:53:18.000000000 +0000 @@ -32,10 +32,10 @@ namespace http { class Agent ; - class Header ; } class Entry ; +class Json ; /*! \brief A resource can be a file or a folder in the google drive @@ -51,7 +51,7 @@ typedef Children::const_iterator iterator ; public : - Resource() ; + Resource(const fs::path& root_folder) ; Resource( const std::string& name, const std::string& kind ) ; // default copy ctor & op= are fine @@ -77,7 +77,7 @@ void FromRemote( const Entry& remote, const DateTime& last_sync ) ; void FromLocal( const DateTime& last_sync ) ; - void Sync( http::Agent* http, const http::Header& auth ) ; + void Sync( http::Agent* http, DateTime& sync_time, const Json& options ) ; // children access iterator begin() const ; @@ -124,19 +124,19 @@ private : void SetState( State new_state ) ; - void Download( http::Agent* http, const fs::path& file, const http::Header& auth ) const ; - bool EditContent( http::Agent* http, const http::Header& auth ) ; - bool Create( http::Agent* http, const http::Header& auth ) ; - bool Upload( http::Agent* http, const std::string& link, const http::Header& auth, bool post ) ; + void Download( http::Agent* http, const fs::path& file ) const ; + bool EditContent( http::Agent* http, bool new_rev ) ; + bool Create( http::Agent* http ) ; + bool Upload( http::Agent* http, const std::string& link, bool post ) ; void FromRemoteFolder( const Entry& remote, const DateTime& last_sync ) ; void FromRemoteFile( const Entry& remote, const DateTime& last_sync ) ; void DeleteLocal() ; - void DeleteRemote( http::Agent* http, const http::Header& auth ) ; + void DeleteRemote( http::Agent* http ) ; void AssignIDs( const Entry& remote ) ; - void SyncSelf( http::Agent* http, const http::Header& auth ) ; + void SyncSelf( http::Agent* http, const Json& options ) ; private : std::string m_name ; diff -Nru grive-0.2.0/libgrive/src/drive/ResourceTree.cc grive-0.3.0/libgrive/src/drive/ResourceTree.cc --- grive-0.2.0/libgrive/src/drive/ResourceTree.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/ResourceTree.cc 2012-08-09 10:53:18.000000000 +0000 @@ -31,8 +31,8 @@ using namespace details ; -ResourceTree::ResourceTree( ) : - m_root( new Resource ) +ResourceTree::ResourceTree( const fs::path& rootFolder ) : + m_root(new Resource(rootFolder)) { m_set.insert( m_root ) ; } @@ -111,29 +111,6 @@ return i != map.end() ? *i : 0 ; } -/// Unlike other search functions, this one does not depend on the multi-index -/// container. It traverses the tree instead. -Resource* ResourceTree::FindByPath( const fs::path& path ) -{ - Resource *current = m_root ; - for ( fs::path::iterator i = path.begin() ; i != path.end() && current != 0 ; ++i ) - { - Trace( "path it = %1%", *i ) ; - - // current directory - if ( *i == "." ) - continue ; - - else if ( *i == ".." ) - current = current->Parent() ; - - else - current = current->FindChild( Path2Str(*i) ) ; - } - - return current ; -} - /// Reinsert should be called when the ID/HREF were updated bool ResourceTree::ReInsert( Resource *coll ) { diff -Nru grive-0.2.0/libgrive/src/drive/ResourceTree.hh grive-0.3.0/libgrive/src/drive/ResourceTree.hh --- grive-0.2.0/libgrive/src/drive/ResourceTree.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/ResourceTree.hh 2012-08-09 10:53:18.000000000 +0000 @@ -64,7 +64,7 @@ typedef details::Set::iterator iterator ; public : - ResourceTree( ) ; + ResourceTree( const fs::path& rootFolder ) ; ResourceTree( const ResourceTree& fs ) ; ~ResourceTree( ) ; @@ -74,7 +74,6 @@ Resource* FindByHref( const std::string& href ) ; const Resource* FindByHref( const std::string& href ) const ; - Resource* FindByPath( const fs::path& path ) ; Resource* FindByID( const std::string& id ) ; bool ReInsert( Resource *coll ) ; diff -Nru grive-0.2.0/libgrive/src/drive/State.cc grive-0.3.0/libgrive/src/drive/State.cc --- grive-0.2.0/libgrive/src/drive/State.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/State.cc 2012-08-09 10:53:18.000000000 +0000 @@ -24,7 +24,6 @@ #include "CommonUri.hh" #include "http/Agent.hh" -#include "http/Header.hh" #include "util/Crypt.hh" #include "util/log/Log.hh" #include "protocol/Json.hh" @@ -33,8 +32,9 @@ namespace gr { -State::State( const fs::path& filename, const Json& options ) : - m_cstamp( -1 ) +State::State( const fs::path& filename, const Json& options ) : + m_res ( options["path"].Str() ), + m_cstamp ( -1 ) { Read( filename ) ; @@ -73,7 +73,6 @@ for ( fs::directory_iterator i( p ) ; i != fs::directory_iterator() ; ++i ) { std::string fname = Path2Str(i->path().filename()) ; -// Trace( "found file %1%", i->path() ) ; if ( IsIgnore(fname) ) Log( "file %1% is ignored by grive", fname, log::verbose ) ; @@ -215,11 +214,6 @@ return m_res.FindByHref( href ) ; } -Resource* State::Find( const fs::path& path ) -{ - return m_res.FindByPath( path ) ; -} - State::iterator State::begin() { return m_res.begin() ; @@ -263,10 +257,28 @@ fs << result ; } -void State::Sync( http::Agent *http, const http::Header& auth ) +void State::Sync( http::Agent *http, const Json& options ) { - m_res.Root()->Sync( http, auth ) ; - m_last_sync = DateTime::Now() ; + // set the last sync time from the time returned by the server for the last file synced + // if the sync time hasn't changed (i.e. now files have been uploaded) + // set the last sync time to the time on the client + // ideally because we compare server file times to the last sync time + // the last sync time would always be a server time rather than a client time + // TODO - WARNING - do we use the last sync time to compare to client file times + // need to check if this introduces a new problem + DateTime last_sync_time = m_last_sync; + m_res.Root()->Sync( http, last_sync_time, options ) ; + + if ( last_sync_time == m_last_sync ) + { + Trace( "nothing changed? %1%", m_last_sync ) ; + m_last_sync = DateTime::Now(); + } + else + { + Trace( "updating last sync? %1%", last_sync_time ) ; + m_last_sync = last_sync_time; + } } long State::ChangeStamp() const diff -Nru grive-0.2.0/libgrive/src/drive/State.hh grive-0.3.0/libgrive/src/drive/State.hh --- grive-0.2.0/libgrive/src/drive/State.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/drive/State.hh 2012-08-09 10:53:18.000000000 +0000 @@ -31,7 +31,6 @@ namespace http { class Agent ; - class Header ; } class Json ; @@ -56,9 +55,8 @@ Resource* FindByHref( const std::string& href ) ; Resource* FindByID( const std::string& id ) ; - Resource* Find( const fs::path& path ) ; - void Sync( http::Agent *http, const http::Header& auth ) ; + void Sync( http::Agent *http, const Json& options ) ; iterator begin() ; iterator end() ; diff -Nru grive-0.2.0/libgrive/src/http/Agent.hh grive-0.3.0/libgrive/src/http/Agent.hh --- grive-0.2.0/libgrive/src/http/Agent.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/http/Agent.hh 2012-08-09 10:53:18.000000000 +0000 @@ -21,7 +21,11 @@ #include -namespace gr { namespace http { +namespace gr { + +class StdioFile ; + +namespace http { class Header ; class Receivable ; @@ -35,6 +39,12 @@ Receivable *dest, const Header& hdr ) = 0 ; + virtual long Put( + const std::string& url, + StdioFile& file, + Receivable *dest, + const Header& hdr ) = 0 ; + virtual long Get( const std::string& url, Receivable *dest, diff -Nru grive-0.2.0/libgrive/src/http/CurlAgent.cc grive-0.3.0/libgrive/src/http/CurlAgent.cc --- grive-0.2.0/libgrive/src/http/CurlAgent.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/http/CurlAgent.cc 2012-08-09 10:53:18.000000000 +0000 @@ -25,6 +25,7 @@ #include "Receivable.hh" #include "util/log/Log.hh" +#include "util/StdioFile.hh" #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -43,8 +45,9 @@ namespace { using namespace gr::http ; +using namespace gr ; -size_t ReadCallback( void *ptr, std::size_t size, std::size_t nmemb, std::string *data ) +size_t ReadStringCallback( void *ptr, std::size_t size, std::size_t nmemb, std::string *data ) { assert( ptr != 0 ) ; assert( data != 0 ) ; @@ -59,6 +62,22 @@ return count ; } +size_t ReadFileCallback( void *ptr, std::size_t size, std::size_t nmemb, StdioFile *file ) +{ + assert( ptr != 0 ) ; + assert( file != 0 ) ; + + u64_t count = std::min( + static_cast(size * nmemb), + static_cast(file->Size() - file->Tell()) ) ; + assert( count <= std::numeric_limits::max() ) ; + + if ( count > 0 ) + file->Read( ptr, static_cast(count) ) ; + + return count ; +} + } // end of local namespace namespace gr { namespace http { @@ -131,18 +150,20 @@ dest->Clear() ; CURLcode curl_code = ::curl_easy_perform(curl); + // get the HTTTP response code long http_code = 0; - ::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); - + ::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); Trace( "HTTP response %1%", http_code ) ; - ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, 0 ) ; - if ( curl_code != CURLE_OK || http_code >= 400 ) + // reset the curl buffer to prevent it from touch our "error" buffer + ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, 0 ) ; + + // only throw for libcurl errors + if ( curl_code != CURLE_OK ) { BOOST_THROW_EXCEPTION( Error() << CurlCode( curl_code ) - << HttpResponse( http_code ) << Url( url ) << expt::ErrMsg( error ) << HttpHeader( hdr ) @@ -167,13 +188,33 @@ // set common options ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L ) ; - ::curl_easy_setopt(curl, CURLOPT_READFUNCTION, &ReadCallback ) ; + ::curl_easy_setopt(curl, CURLOPT_READFUNCTION, &ReadStringCallback ) ; ::curl_easy_setopt(curl, CURLOPT_READDATA , &put_data ) ; ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, put_data.size() ) ; return ExecCurl( url, dest, hdr ) ; } +long CurlAgent::Put( + const std::string& url, + StdioFile& file, + Receivable *dest, + const Header& hdr ) +{ + Trace("HTTP PUT \"%1%\"", url ) ; + + Init() ; + CURL *curl = m_pimpl->curl ; + + // set common options + ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L ) ; + ::curl_easy_setopt(curl, CURLOPT_READFUNCTION, &ReadFileCallback ) ; + ::curl_easy_setopt(curl, CURLOPT_READDATA , &file ) ; + ::curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, static_cast(file.Size()) ) ; + + return ExecCurl( url, dest, hdr ) ; +} + long CurlAgent::Get( const std::string& url, Receivable *dest, diff -Nru grive-0.2.0/libgrive/src/http/CurlAgent.hh grive-0.3.0/libgrive/src/http/CurlAgent.hh --- grive-0.2.0/libgrive/src/http/CurlAgent.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/http/CurlAgent.hh 2012-08-09 10:53:18.000000000 +0000 @@ -44,6 +44,12 @@ const std::string& data, Receivable *dest, const Header& hdr ) ; + + long Put( + const std::string& url, + StdioFile& file, + Receivable *dest, + const Header& hdr ) ; long Get( const std::string& url, diff -Nru grive-0.2.0/libgrive/src/http/Error.hh grive-0.3.0/libgrive/src/http/Error.hh --- grive-0.2.0/libgrive/src/http/Error.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/http/Error.hh 2012-08-09 10:53:18.000000000 +0000 @@ -29,16 +29,16 @@ // CURL error code typedef boost::error_info CurlCode ; -// HTTP response code -typedef boost::error_info HttpResponse ; - -// HTTP response body -typedef boost::error_info HttpResponseText ; - // URL typedef boost::error_info Url ; // HTTP headers typedef boost::error_info HttpHeader ; +// HTTP response code +typedef boost::error_info HttpResponse ; + +// HTTP response body +typedef boost::error_info HttpResponseText ; + } } // end of namespace diff -Nru grive-0.2.0/libgrive/src/http/Header.cc grive-0.3.0/libgrive/src/http/Header.cc --- grive-0.2.0/libgrive/src/http/Header.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/http/Header.cc 2012-08-09 10:53:18.000000000 +0000 @@ -50,4 +50,11 @@ return os ; } +Header operator+( const Header& header, const std::string& str ) +{ + Header h( header ) ; + h.Add( str ) ; + return h ; +} + } } // end of namespace diff -Nru grive-0.2.0/libgrive/src/http/Header.hh grive-0.3.0/libgrive/src/http/Header.hh --- grive-0.2.0/libgrive/src/http/Header.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/http/Header.hh 2012-08-09 10:53:18.000000000 +0000 @@ -46,5 +46,6 @@ } ; std::ostream& operator<<( std::ostream& os, const Header& h ) ; +Header operator+( const Header& header, const std::string& str ) ; }} // end of namespace diff -Nru grive-0.2.0/libgrive/src/http/ResponseLog.cc grive-0.3.0/libgrive/src/http/ResponseLog.cc --- grive-0.2.0/libgrive/src/http/ResponseLog.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/http/ResponseLog.cc 2012-08-09 10:53:18.000000000 +0000 @@ -19,6 +19,7 @@ #include "ResponseLog.hh" +#include "util/log/Log.hh" #include "util/DateTime.hh" #include @@ -29,14 +30,27 @@ const std::string& prefix, const std::string& suffix, Receivable *next ) : - m_log( Filename(prefix, suffix).c_str() ), - m_next( next ) + m_enabled ( true ), + m_next ( next ) { + Reset( prefix, suffix, next ) ; +} + +ResponseLog::ResponseLog( Receivable *next ) : + m_enabled ( false ), + m_next ( next ) +{ + assert( m_next != 0 ) ; } std::size_t ResponseLog::OnData( void *data, std::size_t count ) { - m_log.rdbuf()->sputn( reinterpret_cast(data), count ) ; + if ( m_enabled ) + { + assert( m_log.rdbuf() != 0 ) ; + m_log.rdbuf()->sputn( reinterpret_cast(data), count ) ; + } + return m_next->OnData( data, count ) ; } @@ -48,7 +62,38 @@ std::string ResponseLog::Filename( const std::string& prefix, const std::string& suffix ) { - return prefix + DateTime::Now().Format( "%H%M%S" ) + suffix ; + return prefix + DateTime::Now().Format( "%F.%H%M%S" ) + suffix ; +} + +void ResponseLog::Enable( bool enable ) +{ + m_enabled = enable ; +} + +void ResponseLog::Reset( const std::string& prefix, const std::string& suffix, Receivable *next ) +{ + assert( next != 0 ) ; + + if ( m_log.is_open() ) + m_log.close() ; + + const std::string fname = Filename(prefix, suffix) ; + + // reset previous stream state. don't care if file can be opened + // successfully previously + m_log.clear() ; + + // re-open the file + m_log.open( fname.c_str() ) ; + if ( m_log ) + { + Trace( "logging HTTP response: %1%", fname ) ; + m_enabled = true ; + } + else + Trace( "cannot open log file %1%", fname ) ; + + m_next = next ; } }} // end of namespace diff -Nru grive-0.2.0/libgrive/src/http/ResponseLog.hh grive-0.3.0/libgrive/src/http/ResponseLog.hh --- grive-0.2.0/libgrive/src/http/ResponseLog.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/http/ResponseLog.hh 2012-08-09 10:53:18.000000000 +0000 @@ -33,14 +33,19 @@ const std::string& prefix, const std::string& suffix, Receivable *next ) ; - + ResponseLog( Receivable *next ) ; + std::size_t OnData( void *data, std::size_t count ) ; void Clear() ; + void Enable( bool enable = true ) ; + void Reset( const std::string& prefix, const std::string& suffix, Receivable *next ) ; + private : static std::string Filename( const std::string& prefix, const std::string& suffix ) ; private : + bool m_enabled ; std::ofstream m_log ; Receivable *m_next ; } ; diff -Nru grive-0.2.0/libgrive/src/protocol/AuthAgent.cc grive-0.3.0/libgrive/src/protocol/AuthAgent.cc --- grive-0.2.0/libgrive/src/protocol/AuthAgent.cc 1970-01-01 00:00:00.000000000 +0000 +++ grive-0.3.0/libgrive/src/protocol/AuthAgent.cc 2012-08-09 10:53:18.000000000 +0000 @@ -0,0 +1,180 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + 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 version 2 + of the License. + + 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. +*/ + +#include "AuthAgent.hh" + +#include "http/Error.hh" +#include "http/Header.hh" +#include "util/log/Log.hh" +#include "util/OS.hh" + +#include + +namespace gr { + +using namespace http ; + +AuthAgent::AuthAgent( const OAuth2& auth, std::auto_ptr real_agent ) : + m_auth ( auth ), + m_agent ( real_agent ) +{ + assert( m_agent.get() != 0 ) ; +} + +Header AuthAgent::AppendHeader( const Header& hdr ) const +{ + Header h(hdr) ; + h.Add( "Authorization: Bearer " + m_auth.AccessToken() ) ; + h.Add( "GData-Version: 3.0" ) ; + return h ; +} + +long AuthAgent::Put( + const std::string& url, + const std::string& data, + Receivable *dest, + const Header& hdr ) +{ + Header auth = AppendHeader(hdr) ; + + long response ; + while ( CheckRetry( + response = m_agent->Put(url, data, dest, auth) ) ) ; + + return CheckHttpResponse(response, url, auth) ; +} + +long AuthAgent::Put( + const std::string& url, + StdioFile& file, + Receivable *dest, + const Header& hdr ) +{ + Header auth = AppendHeader(hdr) ; + + long response ; + while ( CheckRetry( + response = m_agent->Put( url, file, dest, AppendHeader(hdr) ) ) ) ; + + return CheckHttpResponse(response, url, auth) ; +} + +long AuthAgent::Get( + const std::string& url, + Receivable *dest, + const Header& hdr ) +{ + Header auth = AppendHeader(hdr) ; + + long response ; + while ( CheckRetry( + response = m_agent->Get( url, dest, AppendHeader(hdr) ) ) ) ; + + return CheckHttpResponse(response, url, auth) ; +} + +long AuthAgent::Post( + const std::string& url, + const std::string& data, + Receivable *dest, + const Header& hdr ) +{ + Header auth = AppendHeader(hdr) ; + + long response ; + while ( CheckRetry( + response = m_agent->Post( url, data, dest, AppendHeader(hdr) ) ) ) ; + + return CheckHttpResponse(response, url, auth) ; +} + +long AuthAgent::Custom( + const std::string& method, + const std::string& url, + Receivable *dest, + const Header& hdr ) +{ + Header auth = AppendHeader(hdr) ; + + long response ; + while ( CheckRetry( + response = m_agent->Custom( method, url, dest, AppendHeader(hdr) ) ) ) ; + + return CheckHttpResponse(response, url, auth) ; +} + +std::string AuthAgent::RedirLocation() const +{ + return m_agent->RedirLocation() ; +} + +std::string AuthAgent::Escape( const std::string& str ) +{ + return m_agent->Escape( str ) ; +} + +std::string AuthAgent::Unescape( const std::string& str ) +{ + return m_agent->Unescape( str ) ; +} + +bool AuthAgent::CheckRetry( long response ) +{ + // HTTP 500 and 503 should be temperory. just wait a bit and retry + if ( response == 500 || response == 503 ) + { + Log( "resquest failed due to temperory error: %1%. retrying in 5 seconds", + response, log::warning ) ; + + os::Sleep( 5 ) ; + return true ; + } + + // HTTP 401 Unauthorized. the auth token has been expired. refresh it + else if ( response == 401 ) + { + Log( "resquest failed due to auth token expired: %1%. refreshing token", + response, log::warning ) ; + + m_auth.Refresh() ; + return true ; + } + else + return false ; +} + +long AuthAgent::CheckHttpResponse( + long response, + const std::string& url, + const http::Header& hdr ) +{ + // throw for other HTTP errors + if ( response >= 400 && response < 500 ) + { + BOOST_THROW_EXCEPTION( + Error() + << HttpResponse( response ) + << Url( url ) + << HttpHeader( hdr ) ) ; + } + + return response ; +} + +} // end of namespace diff -Nru grive-0.2.0/libgrive/src/protocol/AuthAgent.hh grive-0.3.0/libgrive/src/protocol/AuthAgent.hh --- grive-0.2.0/libgrive/src/protocol/AuthAgent.hh 1970-01-01 00:00:00.000000000 +0000 +++ grive-0.3.0/libgrive/src/protocol/AuthAgent.hh 2012-08-09 10:53:18.000000000 +0000 @@ -0,0 +1,86 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + 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 version 2 + of the License. + + 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. +*/ + +#pragma once + +#include "http/Agent.hh" +#include "OAuth2.hh" + +#include + +namespace gr { + +/*! \brief An HTTP agent with support OAuth2 + + This is a HTTP agent that provide support for OAuth2. It will also perform retries on + certain HTTP errors. +*/ +class AuthAgent : public http::Agent +{ +public : + AuthAgent( const OAuth2& auth, std::auto_ptr real_agent ) ; + + long Put( + const std::string& url, + const std::string& data, + http::Receivable *dest, + const http::Header& hdr ) ; + + long Put( + const std::string& url, + StdioFile& file, + http::Receivable *dest, + const http::Header& hdr ) ; + + long Get( + const std::string& url, + http::Receivable *dest, + const http::Header& hdr ) ; + + long Post( + const std::string& url, + const std::string& data, + http::Receivable *dest, + const http::Header& hdr ) ; + + long Custom( + const std::string& method, + const std::string& url, + http::Receivable *dest, + const http::Header& hdr ) ; + + std::string RedirLocation() const ; + + std::string Escape( const std::string& str ) ; + std::string Unescape( const std::string& str ) ; + +private : + http::Header AppendHeader( const http::Header& hdr ) const ; + bool CheckRetry( long response ) ; + long CheckHttpResponse( + long response, + const std::string& url, + const http::Header& hdr ) ; + +private : + OAuth2 m_auth ; + const std::auto_ptr m_agent ; +} ; + +} // end of namespace diff -Nru grive-0.2.0/libgrive/src/protocol/Json.cc grive-0.3.0/libgrive/src/protocol/Json.cc --- grive-0.2.0/libgrive/src/protocol/Json.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/protocol/Json.cc 2012-08-09 10:53:18.000000000 +0000 @@ -101,6 +101,17 @@ BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json bool" ) ) ; } +template <> +Json::Json( const Object& obj ) : + m_json( ::json_object_new_object() ) +{ + if ( m_json == 0 ) + BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json object" ) ) ; + + for ( Object::const_iterator i = obj.begin() ; i != obj.end() ; ++i ) + Add( i->first, i->second ) ; +} + Json::Json( struct json_object *json, NotOwned ) : m_json( json ) { @@ -186,7 +197,7 @@ struct json_object *j = ::json_object_object_get( m_json, key.c_str() ) ; if ( j != 0 ) { - Json tmp( j, NotOwned() ) ; + Json tmp( j ) ; json.Swap( tmp ) ; return true ; } @@ -198,7 +209,7 @@ { assert( m_json != 0 ) ; assert( json.m_json != 0 ) ; - + ::json_object_get( json.m_json ) ; ::json_object_object_add( m_json, key.c_str(), json.m_json ) ; } diff -Nru grive-0.2.0/libgrive/src/util/Config.cc grive-0.3.0/libgrive/src/util/Config.cc --- grive-0.2.0/libgrive/src/util/Config.cc 1970-01-01 00:00:00.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/Config.cc 2012-08-09 10:53:18.000000000 +0000 @@ -0,0 +1,104 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + 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 version 2 + of the License. + + 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. +*/ + +#include "Config.hh" + +#include "util/StdioFile.hh" + +#include + +#include +#include + +namespace po = boost::program_options; + +namespace gr { + +const std::string default_filename = ".grive"; +const char *env_name = "GR_CONFIG"; +const std::string default_root_folder = "."; + +Config::Config( const po::variables_map& vm ) +{ + m_cmd.Add( "log-xml", Json(vm.count("log-xml") > 0) ) ; + m_cmd.Add( "new-rev", Json(vm.count("new-rev") > 0) ) ; + m_cmd.Add( "force", Json(vm.count("force") > 0 ) ) ; + m_cmd.Add( "path", Json(vm.count("path") > 0 + ? vm["path"].as() + : default_root_folder ) ) ; + + m_path = GetPath( fs::path(m_cmd["path"].Str()) ) ; + m_file = Read( ) ; +} + +fs::path Config::GetPath( const fs::path& root_path ) +{ + // config file will be (in order of preference) + // value specified in environment string + // value specified in defaultConfigFileName in path from commandline --path + // value specified in defaultConfigFileName in current directory + const char *env = ::getenv( env_name ) ; + return root_path / (env ? env : default_filename) ; +} + +const fs::path Config::Filename() const +{ + return m_path ; +} + +void Config::Save( ) +{ + StdioFile file( m_path.string(), 0600 ) ; + m_file.Write( file ) ; +} + +void Config::Set( const std::string& key, const Json& value ) +{ + m_file.Add( key, value ) ; +} + +Json Config::Get( const std::string& key ) const +{ + return m_cmd.Has(key) ? m_cmd[key] : m_file[key] ; +} + +Json Config::GetAll() const +{ + Json::Object obj = m_file.AsObject() ; + Json::Object cmd_obj = m_cmd.AsObject() ; + + for ( Json::Object::iterator i = cmd_obj.begin() ; i != cmd_obj.end() ; ++i ) + obj[i->first] = i->second ; + + return Json( obj ) ; +} + +Json Config::Read() +{ + try + { + return Json::ParseFile( m_path.string() ) ; + } + catch ( Exception& e ) + { + return Json() ; + } +} + +} // end of namespace diff -Nru grive-0.2.0/libgrive/src/util/Config.hh grive-0.3.0/libgrive/src/util/Config.hh --- grive-0.2.0/libgrive/src/util/Config.hh 1970-01-01 00:00:00.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/Config.hh 2012-08-09 10:53:18.000000000 +0000 @@ -0,0 +1,67 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + 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 version 2 + of the License. + + 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. +*/ + +#pragma once + +#include "Exception.hh" +#include "FileSystem.hh" +#include "protocol/Json.hh" + +namespace boost +{ + namespace program_options + { + class variables_map ; + } +} + +namespace gr { + +class Config +{ +public : + struct Error : virtual Exception {} ; + typedef boost::error_info File ; + + Config( const boost::program_options::variables_map& vm ) ; + + const fs::path Filename() const ; + + void Set( const std::string& key, const Json& value ) ; + Json Get( const std::string& key ) const ; + + Json GetAll() const ; + void Save() ; + +private : + Json Read( ) ; + static fs::path GetPath( const fs::path& root_path ) ; + +private : + //! config file path + fs::path m_path; + + //! config values loaded from config file + Json m_file ; + + //! config values from command line + Json m_cmd ; +} ; + +} // end of namespace diff -Nru grive-0.2.0/libgrive/src/util/Crypt.cc grive-0.3.0/libgrive/src/util/Crypt.cc --- grive-0.2.0/libgrive/src/util/Crypt.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/Crypt.cc 2012-08-09 10:53:18.000000000 +0000 @@ -21,6 +21,7 @@ #include "StdioFile.hh" #include "Exception.hh" +#include "MemMap.hh" #include #include @@ -31,7 +32,8 @@ namespace gr { namespace crypt { -const std::size_t read_size = 8 * 1024 ; +// map 4MB of data at a time +const u64_t read_size = 1024 * 4096 ; struct MD5::Impl { @@ -85,13 +87,14 @@ std::string MD5::Get( StdioFile& file ) { - char buf[read_size] ; - MD5 crypt ; - std::size_t count = 0 ; - while ( (count = file.Read( buf, sizeof(buf) )) > 0 ) - crypt.Write( buf, count ) ; + u64_t size = file.Size() ; + for ( u64_t i = 0 ; i < size ; i += read_size ) + { + MemMap map( file, i, static_cast(std::min(read_size, size-i)) ) ; + crypt.Write( map.Addr(), map.Length() ) ; + } return crypt.Get() ; } diff -Nru grive-0.2.0/libgrive/src/util/MemMap.cc grive-0.3.0/libgrive/src/util/MemMap.cc --- grive-0.2.0/libgrive/src/util/MemMap.cc 1970-01-01 00:00:00.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/MemMap.cc 2012-08-09 10:53:18.000000000 +0000 @@ -0,0 +1,46 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + 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 version 2 + of the License. + + 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. +*/ + +#include "MemMap.hh" +#include "StdioFile.hh" + +namespace gr { + +MemMap::MemMap( StdioFile& file, off_t offset, std::size_t length ) : + m_addr ( file.Map( offset, length ) ), + m_length( length ) +{ +} + +MemMap::~MemMap() +{ + StdioFile::UnMap( m_addr, m_length ) ; +} + +void* MemMap::Addr() const +{ + return m_addr ; +} + +std::size_t MemMap::Length() const +{ + return m_length ; +} + +} // end of namespace diff -Nru grive-0.2.0/libgrive/src/util/MemMap.hh grive-0.3.0/libgrive/src/util/MemMap.hh --- grive-0.2.0/libgrive/src/util/MemMap.hh 1970-01-01 00:00:00.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/MemMap.hh 2012-08-09 10:53:18.000000000 +0000 @@ -0,0 +1,47 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + 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 version 2 + of the License. + + 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. +*/ + +#pragma once + +#include "Exception.hh" +#include "Types.hh" +#include + +namespace gr { + +class StdioFile ; + +class MemMap +{ +public : + struct Error : virtual Exception {} ; + +public : + MemMap( StdioFile& file, off_t offset, std::size_t length ) ; + ~MemMap() ; + + void* Addr() const ; + std::size_t Length() const ; + +private : + void *m_addr ; + std::size_t m_length ; +} ; + +} // end of namespace diff -Nru grive-0.2.0/libgrive/src/util/OS.cc grive-0.3.0/libgrive/src/util/OS.cc --- grive-0.2.0/libgrive/src/util/OS.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/OS.cc 2012-08-09 10:53:18.000000000 +0000 @@ -81,4 +81,17 @@ ) ; } +void Sleep( unsigned int sec ) +{ + struct timespec ts = { sec, 0 } ; + + int result = 0 ; + do + { + struct timespec rem ; + nanosleep( &ts, &rem ) ; + ts = rem ; + } while ( result == -1 && errno == EINTR ) ; +} + } } // end of namespaces diff -Nru grive-0.2.0/libgrive/src/util/OS.hh grive-0.3.0/libgrive/src/util/OS.hh --- grive-0.2.0/libgrive/src/util/OS.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/OS.hh 2012-08-09 10:53:18.000000000 +0000 @@ -38,6 +38,8 @@ void SetFileTime( const std::string& filename, const DateTime& t ) ; void SetFileTime( const fs::path& filename, const DateTime& t ) ; + + void Sleep( unsigned int sec ) ; } } // end of namespaces diff -Nru grive-0.2.0/libgrive/src/util/StdioFile.cc grive-0.3.0/libgrive/src/util/StdioFile.cc --- grive-0.2.0/libgrive/src/util/StdioFile.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/StdioFile.cc 2012-08-09 10:53:18.000000000 +0000 @@ -30,10 +30,47 @@ #include #include +#include #include #include #include +// local functions +namespace { + +off_t LSeek( int fd, off_t offset, int whence ) +{ + assert( fd >= 0 ) ; + + off_t r = ::lseek( fd, offset, whence ) ; + if ( r == static_cast(-1) ) + { + BOOST_THROW_EXCEPTION( + gr::StdioFile::Error() + << boost::errinfo_api_function("lseek") + << boost::errinfo_errno(errno) + ) ; + } + + return r ; +} + +struct stat FStat( int fd ) +{ + struct stat s = {} ; + if ( ::fstat( fd, &s ) != 0 ) + { + BOOST_THROW_EXCEPTION( + gr::StdioFile::Error() + << boost::errinfo_api_function("fstat") + << boost::errinfo_errno(errno) + ) ; + } + return s ; +} + +} // end of local functions + namespace gr { StdioFile::StdioFile( ) : m_fd( -1 ) @@ -127,16 +164,26 @@ return count ; } -long StdioFile::Seek( long offset, int whence ) +off_t StdioFile::Seek( off_t offset, int whence ) +{ + assert( IsOpened() ) ; + return LSeek( m_fd, offset, whence ) ; +} + +off_t StdioFile::Tell() const { assert( IsOpened() ) ; - return ::lseek( m_fd, offset, whence ) ; + return LSeek( m_fd, 0, SEEK_CUR ) ; } -long StdioFile::Tell() const +u64_t StdioFile::Size() const { assert( IsOpened() ) ; - return ::lseek( m_fd, 0, SEEK_CUR ) ; + + struct stat s = FStat(m_fd) ; + + assert( s.st_size >= 0 ) ; + return static_cast( s.st_size ) ; } void StdioFile::Chmod( int mode ) @@ -153,4 +200,32 @@ } } +void* StdioFile::Map( off_t offset, std::size_t length ) +{ + assert( IsOpened() ) ; + + void *addr = ::mmap( 0, length, PROT_READ, MAP_PRIVATE, m_fd, offset ) ; + if ( addr == reinterpret_cast( -1 ) ) + { + BOOST_THROW_EXCEPTION( + Error() + << boost::errinfo_api_function("mmap") + << boost::errinfo_errno(errno) + ) ; + } + return addr ; +} + +void StdioFile::UnMap( void *addr, std::size_t length ) +{ + if ( ::munmap( addr, length ) != 0 ) + { + BOOST_THROW_EXCEPTION( + Error() + << boost::errinfo_api_function("munmap") + << boost::errinfo_errno(errno) + ) ; + } +} + } // end of namespace diff -Nru grive-0.2.0/libgrive/src/util/StdioFile.hh grive-0.3.0/libgrive/src/util/StdioFile.hh --- grive-0.2.0/libgrive/src/util/StdioFile.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/StdioFile.hh 2012-08-09 10:53:18.000000000 +0000 @@ -21,6 +21,7 @@ #include "Exception.hh" #include "FileSystem.hh" +#include "Types.hh" #include @@ -45,11 +46,15 @@ std::size_t Read( void *ptr, std::size_t size ) ; std::size_t Write( const void *ptr, std::size_t size ) ; - long Seek( long offset, int whence ) ; - long Tell() const ; + off_t Seek( off_t offset, int whence ) ; + off_t Tell() const ; + u64_t Size() const ; void Chmod( int mode ) ; + void* Map( off_t offset, std::size_t length ) ; + static void UnMap( void *addr, std::size_t length ) ; + private : void Open( const fs::path& path, int flags, int mode ) ; diff -Nru grive-0.2.0/libgrive/src/util/Types.hh grive-0.3.0/libgrive/src/util/Types.hh --- grive-0.2.0/libgrive/src/util/Types.hh 1970-01-01 00:00:00.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/Types.hh 2012-08-09 10:53:18.000000000 +0000 @@ -0,0 +1,31 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + 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 version 2 + of the License. + + 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. +*/ + +#pragma once + +#include + +// import types into the Grive namespace +namespace gr +{ + using ::off_t ; + + // should use boost/cstdint + typedef unsigned long long u64_t ; +} diff -Nru grive-0.2.0/libgrive/src/util/log/Log.hh grive-0.3.0/libgrive/src/util/log/Log.hh --- grive-0.2.0/libgrive/src/util/log/Log.hh 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/src/util/log/Log.hh 2012-08-09 10:53:18.000000000 +0000 @@ -135,4 +135,10 @@ LogBase::Inst()->Log( log::Fmt(fmt) % p1 % p2 % p3, log::debug ) ; } +template +void Trace( const std::string& fmt, const P1& p1, const P2& p2, const P3& p3, const P4& p4 ) +{ + LogBase::Inst()->Log( log::Fmt(fmt) % p1 % p2 % p3 % p4, log::debug ) ; +} + } // end of namespace diff -Nru grive-0.2.0/libgrive/test/UnitTest.cc grive-0.3.0/libgrive/test/UnitTest.cc --- grive-0.2.0/libgrive/test/UnitTest.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/test/UnitTest.cc 2012-08-09 10:53:18.000000000 +0000 @@ -27,6 +27,7 @@ #include "drive/StateTest.hh" #include "util/DateTimeTest.hh" #include "util/FunctionTest.hh" +#include "util/ConfigTest.hh" #include "util/SignalHandlerTest.hh" #include "xml/NodeTest.hh" @@ -43,6 +44,7 @@ runner.addTest( ResourceTreeTest::suite( ) ) ; runner.addTest( DateTimeTest::suite( ) ) ; runner.addTest( FunctionTest::suite( ) ) ; + runner.addTest( ConfigTest::suite( ) ) ; runner.addTest( SignalHandlerTest::suite( ) ) ; runner.addTest( NodeTest::suite( ) ) ; runner.run(); diff -Nru grive-0.2.0/libgrive/test/drive/ResourceTest.cc grive-0.3.0/libgrive/test/drive/ResourceTest.cc --- grive-0.2.0/libgrive/test/drive/ResourceTest.cc 2012-07-07 15:43:18.000000000 +0000 +++ grive-0.3.0/libgrive/test/drive/ResourceTest.cc 2012-08-09 10:53:18.000000000 +0000 @@ -38,9 +38,10 @@ void ResourceTest::TestRootPath() { - Resource root ; + std::string rootFolder = "/home/usr/grive/grive"; + Resource root(rootFolder) ; CPPUNIT_ASSERT( root.IsRoot() ) ; - GRUT_ASSERT_EQUAL( root.Path(), fs::path( "." ) ) ; + GRUT_ASSERT_EQUAL( root.Path(), fs::path( rootFolder ) ) ; } void ResourceTest::TestNormal( ) @@ -60,7 +61,7 @@ Entry remote( entry ) ; subject.FromRemote( remote, DateTime() ) ; - GRUT_ASSERT_EQUAL( subject.StateStr(), "local_changed" ) ; + GRUT_ASSERT_EQUAL( "local_changed", subject.StateStr() ) ; } diff -Nru grive-0.2.0/libgrive/test/util/ConfigTest.cc grive-0.3.0/libgrive/test/util/ConfigTest.cc --- grive-0.2.0/libgrive/test/util/ConfigTest.cc 1970-01-01 00:00:00.000000000 +0000 +++ grive-0.3.0/libgrive/test/util/ConfigTest.cc 2012-08-09 10:53:18.000000000 +0000 @@ -0,0 +1,65 @@ +/* +grive: an GPL program to sync a local directory with Google Drive +Copyright (C) 2012 Wan Wai Ho + +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 version 2 +of the License. + +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. +*/ + +#include "ConfigTest.hh" + +#include "Assert.hh" + +#include "util/Config.hh" +#include "protocol/Json.hh" +#include "util/log/Log.hh" + +#include +#include + +using namespace grut; +using namespace gr ; +namespace po = boost::program_options; + +ConfigTest::ConfigTest( ) +{ +} + +void ConfigTest::TestInitialiseWithNoPath( ) +{ + po::variables_map vm; + po::notify(vm); + + Config config(vm); + GRUT_ASSERT_EQUAL( "./.grive", config.Filename().string()) ; +} + +void ConfigTest::TestInitialiseWithPath( ) +{ + char const *argv[] = { "Program", "-p", "/home/grive" }; + int argc = 3; + + po::options_description desc( "Grive options" ); + desc.add_options() + ( "path,p", po::value(), "Path to sync") + ; + + po::variables_map vm; + po::store(po::parse_command_line( argc, argv, desc), vm ); + po::notify(vm); + + Config config(vm); + GRUT_ASSERT_EQUAL( "/home/grive/.grive", config.Filename().string()) ; +} + diff -Nru grive-0.2.0/libgrive/test/util/ConfigTest.hh grive-0.3.0/libgrive/test/util/ConfigTest.hh --- grive-0.2.0/libgrive/test/util/ConfigTest.hh 1970-01-01 00:00:00.000000000 +0000 +++ grive-0.3.0/libgrive/test/util/ConfigTest.hh 2012-08-09 11:08:57.000000000 +0000 @@ -0,0 +1,44 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 Wan Wai Ho + + 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 version 2 + of the License. + + 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. +*/ + +#pragma once + +#include "util/Config.hh" +#include +#include + +namespace grut { + +class ConfigTest : public CppUnit::TestFixture +{ +public : + ConfigTest( ) ; + + CPPUNIT_TEST_SUITE( ConfigTest ) ; + CPPUNIT_TEST( TestInitialiseWithNoPath ) ; + CPPUNIT_TEST( TestInitialiseWithPath ) ; + CPPUNIT_TEST_SUITE_END(); + +private : + void TestInitialiseWithNoPath ( ); + void TestInitialiseWithPath ( ); +} ; + +} // end of namespace +