diff --git a/.gitignore b/.gitignore index da71e17a..a7a94cd9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,17 @@ grive.kdev4 .project .cproject build/ +CMakeCache.txt +CMakeFiles/ +Makefile +cmake_install.cmake +grive/CMakeFiles/ +grive/Makefile +grive/cmake_install.cmake +grive/grive +libgrive/CMakeFiles/ +libgrive/Makefile +libgrive/btest +libgrive/cmake_install.cmake +libgrive/libgrive.a +install_manifest.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 48f1460b..45c80093 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,14 @@ set( GRIVE_VERSION "0.3.0-pre" ) # common compile options add_definitions( -DVERSION="${GRIVE_VERSION}" ) +add_definitions( -DPACKAGE="grive" ) +add_definitions( -DPACKAGE_VERSION="${GRIVE_VERSION}" ) add_definitions( -D_FILE_OFFSET_BITS=64 ) +# Package name and version for libraries depending on autotools +add_definitions( -DPACKAGE="grive" ) +add_definitions( -DPACKAGE_VERSION="${GRIVE_VERSION}" ) + add_subdirectory( libgrive ) add_subdirectory( grive ) -add_subdirectory( bgrive ) + diff --git a/README b/README index a713a75c..fd1f67f0 100644 --- a/README +++ b/README @@ -1,5 +1,7 @@ Grive 0.3.0 -25 July 2012 +13 October 2014 + +Command line Google Drive Sync http://www.lbreda.com/grive/ @@ -24,6 +26,7 @@ You need the following libraries: - libstdc++ - libgcrypt - Boost (Boost filesystem and program_option are required) +- yajl There are also some optional dependencies: - CppUnit (for unit tests) @@ -50,6 +53,11 @@ Enjoy! Version History: +Grive v0.3.1: +Merge Many forks (bug fixes and features) into linwiz/grive. +Remove useless code: bgrive and qgrive. + + Grive v0.3: Bug fix & minor feature release Fixed bugs: #93: missing reference count increment in one of the Json constructors @@ -59,4 +67,4 @@ Fixed bugs: New features: #87: support for revisions #86: partial sync (contributed by justin at tierramedia.com) - \ No newline at end of file + diff --git a/bgrive/CMakeLists.txt b/bgrive/CMakeLists.txt deleted file mode 100644 index 074ab383..00000000 --- a/bgrive/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -project( bgrive ) - -find_package(Qt4 REQUIRED) -find_package(Boost REQUIRED) -INCLUDE(${QT_USE_FILE}) - -include_directories( - ${bgrive_SOURCE_DIR}/../libgrive/src - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} -) - -file (GLOB BGRIVE_EXE_SRC - ${bgrive_SOURCE_DIR}/src/*.cc -) - -file (GLOB BGRIVE_UI - ${bgrive_SOURCE_DIR}/ui/*.ui -) - -QT4_WRAP_UI(BGRIVE_UI_SRCS ${BGRIVE_UI}) -QT4_WRAP_CPP(BGRIVE_MOC_SRCS - src/MainWnd.hh ) - -add_executable( bgrive_executable - ${BGRIVE_EXE_SRC} - ${BGRIVE_UI_SRCS} - ${BGRIVE_MOC_SRCS} -) - -target_link_libraries( bgrive_executable - ${Boost_LIBRARIES} - ${QT_QTMAIN_LIBRARY} - ${QT_LIBRARIES} - grive -) - -set_target_properties( bgrive_executable - PROPERTIES OUTPUT_NAME bgrive -) - -install(TARGETS bgrive_executable RUNTIME DESTINATION bin) -install(FILES doc/grive.1 DESTINATION share/man/man1 ) diff --git a/bgrive/src/DriveModel.cc b/bgrive/src/DriveModel.cc deleted file mode 100644 index bc3bcf43..00000000 --- a/bgrive/src/DriveModel.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* - grive: an GPL program to sync a local directory with Google Drive - Copyright (C) 2013 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 "DriveModel.hh" - -#include "drive2/Resource.hh" - -#include - -namespace gr { - -using namespace v2; - -DriveModel::DriveModel( http::Agent *agent ) -{ - m_drv.Refresh( agent ) ; -} - -Qt::ItemFlags DriveModel::flags( const QModelIndex& ) const -{ - return Qt::ItemIsEnabled | Qt::ItemIsSelectable ; -} - -QVariant DriveModel::data( const QModelIndex& index, int role ) const -{ - const Resource *res = Res(index) ; - if ( role == Qt::DisplayRole && res != 0 ) - { - switch ( index.column() ) - { - case 0: return QString::fromUtf8(res->Title().c_str()) ; - default: break ; - } - } - - return QVariant() ; -} - -QVariant DriveModel::headerData( int section, Qt::Orientation orientation, int role ) const -{ - return role == Qt::DisplayRole ? QString("header") : QVariant() ; -} - -int DriveModel::rowCount( const QModelIndex& parent ) const -{ - return Res(parent)->ChildCount() ; -} - -int DriveModel::columnCount( const QModelIndex& parent ) const -{ - return 1 ; -} - -bool DriveModel::hasChildren( const QModelIndex& parent ) const -{ - return Res(parent)->ChildCount() > 0 ; -} - -QModelIndex DriveModel::index( int row, int column, const QModelIndex& parent_idx ) const -{ - const Resource *parent = Res(parent_idx) ; - - // check out-of-bound - if ( parent != 0 && static_cast(row) >= parent->ChildCount() ) - BOOST_THROW_EXCEPTION( - Exception() - << InvalidRow_( row ) - << ResourceName_( parent->Title() ) - ) ; - - - return createIndex( row, column, const_cast(m_drv.Child(parent, row)) ) ; -} - -const Resource* DriveModel::Res( const QModelIndex& idx ) const -{ - return idx.isValid() - ? reinterpret_cast(idx.internalPointer()) - : m_drv.Root() ; -} - -QModelIndex DriveModel::parent( const QModelIndex& idx ) const -{ - // if I am root, my parent is myself - const Resource *res = Res(idx) ; - if ( res == m_drv.Root() ) - return QModelIndex() ; - - // if my parent is root, return model index of root (i.e. QModelIndex()) - const Resource *parent = m_drv.Parent(res) ; - if ( parent == 0 || parent == m_drv.Root() || idx.column() != 0 ) - return QModelIndex() ; - - // check grand-parent to know the row() of my parent - const Resource *grand = m_drv.Parent(parent) ; - return createIndex( grand->Index(parent->ID()), 0, const_cast(parent) ) ; -} - -} // end of namespace diff --git a/bgrive/src/DriveModel.hh b/bgrive/src/DriveModel.hh deleted file mode 100644 index f39847f4..00000000 --- a/bgrive/src/DriveModel.hh +++ /dev/null @@ -1,61 +0,0 @@ -/* - grive: an GPL program to sync a local directory with Google Drive - Copyright (C) 2013 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 - -#include "drive2/Drive.hh" -#include "util/Exception.hh" - -namespace gr { - -namespace http -{ - class Agent ; -} - -class DriveModel : public QAbstractItemModel -{ -public : - typedef boost::error_info InvalidRow_ ; - typedef boost::error_info ResourceName_ ; - -public : - DriveModel( http::Agent *agent ) ; - - // QAbstractItemModel overrides - Qt::ItemFlags flags( const QModelIndex & index ) const ; - QVariant data( const QModelIndex& index, int role ) const ; - QVariant headerData( int section, Qt::Orientation orientation, int role ) const ; - int rowCount( const QModelIndex& parent ) const ; - int columnCount( const QModelIndex& parent ) const ; - bool hasChildren ( const QModelIndex& parent ) const ; - QModelIndex index( int row, int column, const QModelIndex& parent ) const ; - QModelIndex parent( const QModelIndex& idx ) const ; - - const v2::Resource* Res( const QModelIndex& idx ) const ; - -private : - v2::Drive m_drv ; -} ; - -} // end of namespace - diff --git a/bgrive/src/MainWnd.cc b/bgrive/src/MainWnd.cc deleted file mode 100644 index 28d4e088..00000000 --- a/bgrive/src/MainWnd.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - grive: an GPL program to sync a local directory with Google Drive - Copyright (C) 2013 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 "MainWnd.hh" - -#include "drive2/Resource.hh" - -#include - -#include - -namespace gr { - -using namespace v2 ; - -MainWnd::MainWnd( http::Agent *agent ) : - m_drive( agent ) -{ - m_ui.setupUi(this) ; - m_ui.m_dir->setModel( &m_drive ) ; - - connect( - m_ui.m_dir, SIGNAL(activated(const QModelIndex&)), - this, SLOT(OnClick(const QModelIndex&)) - ) ; -} - -void MainWnd::OnClick( const QModelIndex& index ) -{ - const Resource *res = m_drive.Res(index) ; - if ( res != 0 ) - ShowResource( res ) ; -} - -void MainWnd::ShowResource( const v2::Resource *res ) -{ - m_ui.m_title->setText( QString::fromUtf8(res->Title().c_str()) ) ; - m_ui.m_mime_type->setText( QString::fromUtf8(res->Mime().c_str()) ) ; -} - -} // end of namespace diff --git a/bgrive/src/MainWnd.hh b/bgrive/src/MainWnd.hh deleted file mode 100644 index fe9401b6..00000000 --- a/bgrive/src/MainWnd.hh +++ /dev/null @@ -1,56 +0,0 @@ -/* - grive: an GPL program to sync a local directory with Google Drive - Copyright (C) 2013 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 -#include "ui_MainWindow.h" - -#include "DriveModel.hh" - -class QModelIndex ; - -namespace gr { - -namespace http -{ - class Agent ; -} - -class MainWnd : public QMainWindow -{ - Q_OBJECT - -public : - MainWnd( http::Agent *agent ) ; - -private : - void ShowResource( const v2::Resource *res ) ; - -public slots : - void OnClick( const QModelIndex& index ) ; - -private : - Ui::MainWindow m_ui ; - DriveModel m_drive ; -} ; - -} // end of namespace - diff --git a/bgrive/src/main.cc b/bgrive/src/main.cc deleted file mode 100644 index ea578ec9..00000000 --- a/bgrive/src/main.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - grive: an GPL program to sync a local directory with Google Drive - Copyright (C) 2013 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 "MainWnd.hh" - -#include -#include - -#include "drive2/Drive.hh" - -#include "http/CurlAgent.hh" -#include "http/Header.hh" -#include "protocol/JsonResponse.hh" - -#include "protocol/Json.hh" -#include "protocol/OAuth2.hh" -#include "protocol/AuthAgent.hh" - -#include "util/File.hh" - -#include -#include - -const std::string client_id = "22314510474.apps.googleusercontent.com" ; -const std::string client_secret = "bl4ufi89h-9MkFlypcI7R785" ; - -using namespace gr ; -using namespace gr::v2 ; - -int main( int argc, char **argv ) -{ - File file( ".grive" ) ; - Json cfg = Json::Parse( &file ) ; - - std::string refresh_token = cfg["refresh_token"].Str() ; - OAuth2 token( refresh_token, client_id, client_secret ) ; - - AuthAgent agent( token, std::auto_ptr( new http::CurlAgent ) ) ; - - QApplication app( argc, argv ) ; - MainWnd wnd( &agent ) ; - wnd.show(); - - return app.exec() ; -} diff --git a/bgrive/ui/MainWindow.ui b/bgrive/ui/MainWindow.ui deleted file mode 100644 index 61c99206..00000000 --- a/bgrive/ui/MainWindow.ui +++ /dev/null @@ -1,132 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 800 - 600 - - - - Grive - - - - - - - Qt::Horizontal - - - - - 0 - 0 - - - - - - - - - Title: - - - - - - - - - - - - - - - - - Filename: - - - - - - - - - - Mime type: - - - - - - - - - - Last Updated: - - - - - - - - - - - - - - - - - - - 0 - 0 - 800 - 23 - - - - - &File - - - - - - - - - E&xit - - - - - - - m_action_exit - activated() - MainWindow - close() - - - -1 - -1 - - - 399 - 299 - - - - - diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..cf0c49b9 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_EXE_LINKER_FLAGS=-ljson-c diff --git a/cmake/Modules/FindBFD.cmake b/cmake/Modules/FindBFD.cmake index 785e29b6..5fe43c14 100644 --- a/cmake/Modules/FindBFD.cmake +++ b/cmake/Modules/FindBFD.cmake @@ -1,9 +1,15 @@ find_library( DL_LIBRARY NAMES dl PATH /usr/lib /usr/lib64 ) find_library( BFD_LIBRARY NAMES bfd PATH /usr/lib /usr/lib64 ) -if ( DL_LIBRARY AND BFD_LIBRARY ) +include(CheckCSourceCompiles) +check_c_source_compiles( + "#include + int main(void) { + return 0; + }" BFD_WORKS) +if ( DL_LIBRARY AND BFD_LIBRARY AND BFD_WORKS) set( BFD_FOUND TRUE ) -endif (DL_LIBRARY AND BFD_LIBRARY) +endif (DL_LIBRARY AND BFD_LIBRARY AND BFD_WORKS) if ( BFD_FOUND ) diff --git a/cmake/Modules/FindJSONC.cmake b/cmake/Modules/FindJSONC.cmake index f72e8ea1..15a09b78 100644 --- a/cmake/Modules/FindJSONC.cmake +++ b/cmake/Modules/FindJSONC.cmake @@ -6,8 +6,12 @@ # JSONC_INCLUDE_DIR - The JSON-C include directory. # JSONC_LIBRARY - The JSON-C library to link against. -FIND_PATH(JSONC_INCLUDE_DIR json/json.h) -FIND_LIBRARY(JSONC_LIBRARY NAMES json) +find_package(PkgConfig) + +pkg_check_modules(PC_JSONC json-c) + +FIND_PATH(JSONC_INCLUDE_DIR json/json.h json-c/json.h HINTS ${PC_JSONC_INCLUDE_DIRS} ) +FIND_LIBRARY(JSONC_LIBRARY NAMES json json-c HINTS ${PC_JSONC_LIBRARY_DIRS} ) IF (JSONC_INCLUDE_DIR AND JSONC_LIBRARY) SET(JSONC_FOUND TRUE) diff --git a/cmake/Modules/FindYAJL.cmake b/cmake/Modules/FindYAJL.cmake new file mode 100644 index 00000000..0dc425c0 --- /dev/null +++ b/cmake/Modules/FindYAJL.cmake @@ -0,0 +1,30 @@ +# - Find YAJL +# This module finds an installed YAJL package. +# +# It sets the following variables: +# YAJL_FOUND - Set to false, or undefined, if YAJL isn't found. +# YAJL_INCLUDE_DIR - The YAJL include directory. +# YAJL_LIBRARY - The YAJL library to link against. + +FIND_PATH(YAJL_INCLUDE_DIR yajl/yajl_gen.h) +FIND_LIBRARY(YAJL_LIBRARY NAMES yajl) + +IF (YAJL_INCLUDE_DIR AND YAJL_LIBRARY) + SET(YAJL_FOUND TRUE) +ENDIF (YAJL_INCLUDE_DIR AND YAJL_LIBRARY) + +IF (YAJL_FOUND) + + # show which YAJL was found only if not quiet + IF (NOT YAJL_FIND_QUIETLY) + MESSAGE(STATUS "Found YAJL: ${YAJL_LIBRARY}") + ENDIF (NOT YAJL_FIND_QUIETLY) + +ELSE (YAJL_FOUND) + + # fatal error if YAJL is required but not found + IF (YAJL_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find YAJL") + ENDIF (YAJL_FIND_REQUIRED) + +ENDIF (YAJL_FOUND) diff --git a/grive.spec b/grive.spec new file mode 100644 index 00000000..3cec116c --- /dev/null +++ b/grive.spec @@ -0,0 +1,50 @@ +%define rev %(git ls-remote https://github.com/linwiz/grive.git refs/heads/master|awk '{print $1}') + +Name: grive +Version: 0.3.0pre_git%{rev} +Release: 1%{?dist} + +Summary: An open source Linux client for Google Drive + +License: GPLv2 +URL: http://grive.github.com/grive/ + +BuildRequires: git +BuildRequires: gawk +BuildRequires: cmake +BuildRequires: libstdc++-devel +BuildRequires: libcurl-devel +BuildRequires: json-c-devel +BuildRequires: expat-devel +BuildRequires: openssl-devel +BuildRequires: boost-devel +BuildRequires: binutils-devel +BuildRequires: yajl-devel +BuildRequires: libgcrypt-devel + +%description +The purpose of this project is to provide an independent implementation +of Google Drive client. It uses the Google Document List API to talk to +the servers in Google. The code is written in standard C++. + +%prep +rm -rf grive-%{version} +git clone https://github.com/linwiz/grive.git -b master grive-%{version} +cd grive-%{version} + +%build +cd grive-%{version} +%cmake . +make %{?_smp_mflags} + +%install +cd grive-%{version} +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT +rm -rf $RPM_BUILD_ROOT/%{_bindir}/bgrive + +%files +%{_docdir}/%{name}/COPYING +%{_docdir}/%{name}/README +%{_bindir}/%{name} +%{_mandir}/man1/%{name}.1.gz diff --git a/grive/doc/grive.1 b/grive/doc/grive.1 index 57b2e9cc..017cef14 100644 --- a/grive/doc/grive.1 +++ b/grive/doc/grive.1 @@ -33,6 +33,11 @@ Forces .I grive to always download a file from Google Drive instead uploading it .TP +\fB\-u, \-\-upload\fR +Forces +.I grive +to only upload a file from Google Drive instead downloading it +.TP \fB\-h\fR, \fB\-\-help\fR Produces help message .TP diff --git a/grive/src/main.cc b/grive/src/main.cc index 5209c941..8feb38d6 100644 --- a/grive/src/main.cc +++ b/grive/src/main.cc @@ -78,19 +78,19 @@ void InitLog( const po::variables_map& vm ) 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( "verbose" ) ) { console_log->Enable( log::verbose ) ; } - + if ( vm.count( "debug" ) ) { console_log->Enable( log::verbose ) ; @@ -102,7 +102,7 @@ void InitLog( const po::variables_map& vm ) int Main( int argc, char **argv ) { InitGCrypt() ; - + // construct the program options po::options_description desc( "Grive options" ); desc.add_options() @@ -110,6 +110,7 @@ int Main( int argc, char **argv ) ( "version,v", "Display Grive version" ) ( "auth,a", "Request authorization token" ) ( "path,p", po::value(), "Path to sync") + ( "dir,s", po::value(), "Subdirectory 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.") @@ -117,14 +118,17 @@ int Main( int argc, char **argv ) ( "log,l", po::value(), "Set log output filename." ) ( "force,f", "Force grive to always download a file from Google Drive " "instead of uploading it." ) + ( "uploadonly,u", "Force grive to always upload a file from Google Drive " + "instead of downloading it." ) ( "dry-run", "Only detect which files need to be uploaded/downloaded, " "without actually performing them." ) + ("docs,g", "Synchronises Google Docs, Sheets and Slides.") ; - + po::variables_map vm; 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") ) { @@ -140,9 +144,9 @@ int Main( int argc, char **argv ) // initialize logging InitLog(vm) ; - + Config config(vm) ; - + Log( "config file name %1%", config.Filename(), log::verbose ); if ( vm.count( "auth" ) ) @@ -152,21 +156,21 @@ int Main( int argc, char **argv ) << "Please go to this URL and get an authentication code:\n\n" << OAuth2::MakeAuthURL( client_id ) << std::endl ; - + std::cout << "\n-----------------------\n" << "Please input the authentication code here: " << std::endl ; std::string code ; std::cin >> code ; - + OAuth2 token( client_id, client_secret ) ; token.Auth( code ) ; - + // save to config config.Set( "refresh_token", Json( token.RefreshToken() ) ) ; config.Save() ; } - + std::string refresh_token ; try { @@ -178,10 +182,10 @@ int Main( int argc, char **argv ) "Please run grive with the \"-a\" option if this is the " "first time you're accessing your Google Drive!", log::critical ) ; - + return -1; } - + OAuth2 token( refresh_token, client_id, client_secret ) ; AuthAgent agent( token, std::auto_ptr( new http::CurlAgent ) ) ; @@ -195,7 +199,7 @@ int Main( int argc, char **argv ) } else drive.DryRun() ; - + config.Save() ; Log( "Finished!", log::info ) ; return 0 ; diff --git a/icon/128x128/128x128.png b/icon/128x128/128x128.png deleted file mode 100644 index 5914ad64..00000000 Binary files a/icon/128x128/128x128.png and /dev/null differ diff --git a/icon/16x16/16x16.png b/icon/16x16/16x16.png deleted file mode 100644 index 2e6949b3..00000000 Binary files a/icon/16x16/16x16.png and /dev/null differ diff --git a/icon/22x22/22x22.png b/icon/22x22/22x22.png deleted file mode 100644 index d005088a..00000000 Binary files a/icon/22x22/22x22.png and /dev/null differ diff --git a/icon/256x256/256x256.png b/icon/256x256/256x256.png deleted file mode 100644 index c6a6b5fd..00000000 Binary files a/icon/256x256/256x256.png and /dev/null differ diff --git a/icon/32x32/32x32.png b/icon/32x32/32x32.png deleted file mode 100644 index 8d145aac..00000000 Binary files a/icon/32x32/32x32.png and /dev/null differ diff --git a/icon/48x48/48x48.png b/icon/48x48/48x48.png deleted file mode 100644 index eabdd919..00000000 Binary files a/icon/48x48/48x48.png and /dev/null differ diff --git a/icon/64x64/64x64.png b/icon/64x64/64x64.png deleted file mode 100644 index d7677a52..00000000 Binary files a/icon/64x64/64x64.png and /dev/null differ diff --git a/libgrive/CMakeLists.txt b/libgrive/CMakeLists.txt index 3cc15742..d75e4e66 100644 --- a/libgrive/CMakeLists.txt +++ b/libgrive/CMakeLists.txt @@ -4,14 +4,20 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") find_package(LibGcrypt REQUIRED) find_package(JSONC REQUIRED) +include_directories(${JSONC_INCLUDE_DIR}) find_package(CURL REQUIRED) find_package(EXPAT REQUIRED) +find_package(YAJL REQUIRED) find_package(Boost 1.40.0 COMPONENTS program_options filesystem unit_test_framework system REQUIRED) +find_package(YAJL REQUIRED) find_package(BFD) find_package(CppUnit) find_package(Iberty) find_package(ZLIB) +include(FindPkgConfig) +pkg_search_module(YAJL REQUIRED yajl) + # additional headers if build unit tests IF ( CPPUNIT_FOUND ) set( OPT_INCS ${CPPUNIT_INCLUDE_DIR} ) @@ -41,7 +47,9 @@ include_directories( ${libgrive_SOURCE_DIR}/src ${libgrive_SOURCE_DIR}/test ${GDBM_INCLUDE_DIR} + ${YAJL_INCLUDE_DIR} ${OPT_INCS} + ${YAJL_INCLUDE_DIRS} ) file(GLOB DRIVE_HEADERS @@ -80,7 +88,7 @@ add_definitions( add_library( grive STATIC ${LIBGRIVE_SRC} ${OPT_SRC} ) target_link_libraries( grive - yajl + ${YAJL_LIBRARIES} ${CURL_LIBRARIES} ${JSONC_LIBRARY} ${LIBGCRYPT_LIBRARIES} @@ -89,6 +97,7 @@ target_link_libraries( grive ${IBERTY_LIBRARY} ${EXPAT_LIBRARY} ${OPT_LIBS} + ${YAJL_LIBRARIES} ) #set_target_properties(grive PROPERTIES diff --git a/libgrive/src/bfd/Backtrace.hh b/libgrive/src/bfd/Backtrace.hh index aab906d9..8673a388 100644 --- a/libgrive/src/bfd/Backtrace.hh +++ b/libgrive/src/bfd/Backtrace.hh @@ -30,11 +30,11 @@ namespace gr { /** \internal The sole reason for this class to exists is to provide the operator<< overload to allow: - + \code std::cout << Backtrace() << std::endl ; \endcode - + \sa SymbolInfo */ class Backtrace @@ -42,7 +42,7 @@ class Backtrace public : explicit Backtrace( std::size_t skip = 2 ) ; Backtrace( const Backtrace& bt ) ; - + friend std::ostream& operator<<( std::ostream& os, const gr::Backtrace& bt ) ; diff --git a/libgrive/src/bfd/Debug.cc b/libgrive/src/bfd/Debug.cc index f00c4829..0225cc27 100644 --- a/libgrive/src/bfd/Debug.cc +++ b/libgrive/src/bfd/Debug.cc @@ -52,16 +52,16 @@ std::string Demangle( const char *name ) std::ostream& PrintHex( std::ostream& os, const void *buf, std::size_t size ) { const unsigned char *raw = static_cast( buf ) ; - + for ( std::size_t i = 0 ; i < size ; i++ ) { if ( i % 8 == 0 && i > 0 ) os << std::endl ; - + if ( i % 8 == 0 ) os << std::hex << std::setw(8) << std::setfill('0') << i << " " ; - - os << "0x" << std::hex << std::setw(2) << std::setfill('0') + + os << "0x" << std::hex << std::setw(2) << std::setfill('0') << (int)raw[i] << ", " ; } os << std::endl ; diff --git a/libgrive/src/bfd/SymbolInfo.cc b/libgrive/src/bfd/SymbolInfo.cc index afd3ba14..568c0b04 100644 --- a/libgrive/src/bfd/SymbolInfo.cc +++ b/libgrive/src/bfd/SymbolInfo.cc @@ -48,9 +48,9 @@ SymbolInfo::SymbolInfo( ) m_impl->m_bfd = 0 ; m_impl->m_symbols = 0 ; m_impl->m_symbol_count = 0 ; - + bfd_init( ) ; - + // opening itself bfd *b = bfd_openr( "/proc/self/exe", 0 ) ; if ( b == NULL ) @@ -59,13 +59,13 @@ SymbolInfo::SymbolInfo( ) << bfd_errmsg( bfd_get_error() ) << std::endl ; return ; } - + if ( bfd_check_format( b, bfd_archive ) ) { bfd_close( b ) ; return ; } - + char **matching ; if ( !bfd_check_format_matches( b, bfd_object, &matching ) ) { @@ -77,7 +77,7 @@ SymbolInfo::SymbolInfo( ) std::cerr << bfd_get_filename( b ) << ": Matching formats: " ; for ( char **p = matching ; *p != 0 ; p++ ) std::cerr << " " << *p ; - + std::cerr << std::endl ; std::free( matching ) ; } @@ -106,7 +106,7 @@ struct SymbolInfo::BacktraceInfo const char *m_func_name ; unsigned int m_lineno ; unsigned int m_is_found ; - + static void Callback( bfd *abfd, asection *section, void* addr ) ; } ; @@ -116,17 +116,17 @@ void SymbolInfo::BacktraceInfo::Callback( bfd *abfd, asection *section, BacktraceInfo *info = (BacktraceInfo *)data ; if ((section->flags & SEC_ALLOC) == 0) return ; - + bfd_vma vma = bfd_get_section_vma(abfd, section); - + unsigned long address = (unsigned long)(info->m_addr); if ( address < vma ) return; - + bfd_size_type size = bfd_section_size(abfd, section); if ( address > (vma + size)) return ; - + const SymbolInfo *pthis = info->m_pthis ; info->m_is_found = bfd_find_nearest_line( abfd, section, pthis->m_impl->m_symbols, @@ -148,7 +148,7 @@ void SymbolInfo::PrintTrace( void *addr, std::ostream& os, std::size_t idx ) { this, addr, 0, 0, 0, false } ; - + Dl_info sym ; bfd_map_over_sections( m_impl->m_bfd, &SymbolInfo::BacktraceInfo::Callback, @@ -164,7 +164,7 @@ if ( btinfo.m_is_found ) filename.erase( pos, std::strlen( SRC_DIR ) ) ; #endif os << "#" << idx << " " << addr << " " - << filename << ":" << btinfo.m_lineno + << filename << ":" << btinfo.m_lineno << " " << (btinfo.m_func_name != 0 ? Demangle(btinfo.m_func_name) : "" ) << std::endl ; diff --git a/libgrive/src/bfd/SymbolInfo.hh b/libgrive/src/bfd/SymbolInfo.hh index bcbc3b14..8854691d 100644 --- a/libgrive/src/bfd/SymbolInfo.hh +++ b/libgrive/src/bfd/SymbolInfo.hh @@ -28,7 +28,7 @@ namespace gr { /// ource code symbolic information /** \internal - + This class represents symbolic information about the source code, e.g. function names and line numbers. It provides an interface to lookup these informations by address. @@ -41,7 +41,7 @@ public : /*! \brief singleton function \internal - + Returns the SymbolInfo singleton. Normally only one object of SymbolInfo is enough for one application, so a singleton is enough. This function will create the SymbolInfo object @@ -51,11 +51,11 @@ public : std::size_t Backtrace( addr_t *stack, std::size_t count ) ; void PrintTrace( addr_t addr, std::ostream& os, std::size_t idx = 0 ) ; - + private : struct Impl ; const std::auto_ptr m_impl ; - + struct BacktraceInfo ; friend struct BacktraceInfo ; } ; diff --git a/libgrive/src/drive/CommonUri.hh b/libgrive/src/drive/CommonUri.hh index b0e06f7f..4a06e299 100644 --- a/libgrive/src/drive/CommonUri.hh +++ b/libgrive/src/drive/CommonUri.hh @@ -26,11 +26,11 @@ namespace gr { namespace v1 const std::string feed_base = "https://docs.google.com/feeds/default/private/full" ; const std::string feed_changes = "https://docs.google.com/feeds/default/private/changes" ; const std::string feed_metadata = "https://docs.google.com/feeds/metadata/default" ; - + const std::string root_href = "https://docs.google.com/feeds/default/private/full/folder%3Aroot" ; const std::string root_create = "https://docs.google.com/feeds/upload/create-session/default/private/full" ; - + std::string ChangesFeed( int changestamp ) ; } } diff --git a/libgrive/src/drive/Drive.cc b/libgrive/src/drive/Drive.cc index 39354484..d2f20f71 100644 --- a/libgrive/src/drive/Drive.cc +++ b/libgrive/src/drive/Drive.cc @@ -65,14 +65,14 @@ void Drive::FromRemote( const Entry& entry ) // entries from change feed does not have the parent HREF, // so these checkings are done in normal entries only Resource *parent = m_state.FindByHref( entry.ParentHref() ) ; - + if ( parent != 0 && !parent->IsFolder() ) Log( "warning: entry %1% has parent %2% which is not a folder, ignored", entry.Title(), parent->Name(), log::verbose ) ; - + else if ( parent == 0 || !parent->IsInRootTree() ) Log( "file \"%1%\" parent doesn't exist, ignored", entry.Title(), log::verbose ) ; - + else m_state.FromRemote( entry ) ; } @@ -81,7 +81,7 @@ void Drive::FromChange( const Entry& entry ) { if ( entry.IsRemoved() ) Log( "file \"%1%\" represents a deletion, ignored", entry.Title(), log::verbose ) ; - + // folders go directly else m_state.FromRemote( entry ) ; @@ -100,7 +100,7 @@ void Drive::SyncFolders( ) http::XmlResponse xml ; m_http->Get( feed_base + "/-/folder?max-results=50&showroot=true", &xml, http::Header() ) ; - + Feed feed( xml.Response() ) ; do { @@ -112,10 +112,10 @@ void Drive::SyncFolders( ) { if ( e.ParentHrefs().size() != 1 ) Log( "folder \"%1%\" has multiple parents, ignored", e.Title(), log::verbose ) ; - + else if ( e.Title().find('/') != std::string::npos ) Log( "folder \"%1%\" contains a slash in its name, ignored", e.Title(), log::verbose ) ; - + else m_state.FromRemote( e ) ; } @@ -129,30 +129,30 @@ void Drive::DetectChanges() { Log( "Reading local directories", log::info ) ; m_state.FromLocal( m_root ) ; - + long prev_stamp = m_state.ChangeStamp() ; Trace( "previous change stamp is %1%", prev_stamp ) ; - + SyncFolders( ) ; Log( "Reading remote server file list", log::info ) ; Feed feed ; if ( m_options["log-xml"].Bool() ) feed.EnableLog( "/tmp/file", ".xml" ) ; - + feed.Start( m_http, feed_base + "?showfolders=true&showroot=true" ) ; - + m_resume_link = feed.Root()["link"]. Find( "@rel", "http://schemas.google.com/g/2005#resumable-create-media" )["@href"] ; - + do { std::for_each( feed.begin(), feed.end(), boost::bind( &Drive::FromRemote, this, _1 ) ) ; - + } while ( feed.GetNext( m_http ) ) ; - + // pull the changes feed if ( prev_stamp != -1 ) { @@ -160,9 +160,9 @@ void Drive::DetectChanges() Feed changes ; if ( m_options["log-xml"].Bool() ) feed.EnableLog( "/tmp/changes", ".xml" ) ; - + feed.Start( m_http, ChangesFeed(prev_stamp+1) ) ; - + std::for_each( changes.begin(), changes.end(), boost::bind( &Drive::FromChange, this, _1 ) ) ; @@ -173,7 +173,7 @@ void Drive::Update() { Log( "Synchronizing files", log::info ) ; m_state.Sync( m_http, m_options ) ; - + UpdateChangeStamp( ) ; } @@ -190,10 +190,10 @@ void Drive::UpdateChangeStamp( ) // get changed feed http::XmlResponse xrsp ; 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? - m_state.ChangeStamp( + m_state.ChangeStamp( std::atoi(xrsp.Response()["docs:largestChangestamp"]["@value"].front().Value().c_str()) ) ; } diff --git a/libgrive/src/drive/Drive.hh b/libgrive/src/drive/Drive.hh index 0490d5c1..32797ff9 100644 --- a/libgrive/src/drive/Drive.hh +++ b/libgrive/src/drive/Drive.hh @@ -48,16 +48,16 @@ public : void Update() ; void DryRun() ; void SaveState() ; - + struct Error : virtual Exception {} ; - + private : void SyncFolders( ) ; void file(); void FromRemote( const Entry& entry ) ; void FromChange( const Entry& entry ) ; void UpdateChangeStamp( ) ; - + private : http::Agent *m_http ; std::string m_resume_link ; diff --git a/libgrive/src/drive/Entry.hh b/libgrive/src/drive/Entry.hh index b7e9293a..4c5e2449 100644 --- a/libgrive/src/drive/Entry.hh +++ b/libgrive/src/drive/Entry.hh @@ -46,18 +46,18 @@ class Entry public : Entry( ) ; explicit Entry( const xml::Node& n ) ; - + std::string Title() const ; std::string Filename() const ; std::string Kind() const ; std::string MD5() const ; DateTime MTime() const ; - + std::string Name() const ; - + std::string ResourceID() const ; std::string ETag() const ; - + std::string SelfHref() const ; std::string AltSelf() const ; std::string ParentHref() const ; @@ -65,16 +65,16 @@ public : std::string EditLink() const ; std::string CreateLink() const ; long ChangeStamp() const ; - + bool IsChange() const ; bool IsRemoved() const ; - + const std::vector& ParentHrefs() const ; - + void Swap( Entry& e ) ; - + void Update( const xml::Node& entry ) ; - + private : std::string m_title ; std::string m_filename ; @@ -84,7 +84,7 @@ private : std::string m_resource_id ; std::vector m_parent_hrefs ; - + std::string m_self_href ; std::string m_alt_self ; std::string m_content_src ; @@ -92,7 +92,7 @@ private : std::string m_create_link ; long m_change_stamp ; - + DateTime m_mtime ; bool m_is_removed ; } ; diff --git a/libgrive/src/drive/Feed.cc b/libgrive/src/drive/Feed.cc index b227e520..6c7fb8bf 100644 --- a/libgrive/src/drive/Feed.cc +++ b/libgrive/src/drive/Feed.cc @@ -67,15 +67,15 @@ void Feed::Start( http::Agent *http, 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, http::Header() ) ; - + m_root = xrsp.Response() ; m_entries = m_root["entry"] ; } diff --git a/libgrive/src/drive/Feed.hh b/libgrive/src/drive/Feed.hh index 92e62345..8772a051 100644 --- a/libgrive/src/drive/Feed.hh +++ b/libgrive/src/drive/Feed.hh @@ -47,18 +47,18 @@ public : explicit Feed( const xml::Node& root ) ; Feed( ) ; void Start( http::Agent *http, 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 ) ; - + void EnableLog( const std::string& prefix, const std::string& suffix ) ; - + private : struct LogInfo { @@ -82,11 +82,11 @@ class Feed::iterator : public boost::iterator_adaptor< { public : iterator() ; - explicit iterator( xml::Node::iterator i ) ; + explicit iterator( xml::Node::iterator i ) ; private : friend class boost::iterator_core_access; - + reference dereference() const ; } ; diff --git a/libgrive/src/drive/Resource.cc b/libgrive/src/drive/Resource.cc index 4010cab2..d0a8eb64 100644 --- a/libgrive/src/drive/Resource.cc +++ b/libgrive/src/drive/Resource.cc @@ -36,6 +36,7 @@ #include "xml/Node.hh" #include "xml/NodeSet.hh" #include "xml/String.hh" +#include "xml/TreeBuilder.hh" #include #include @@ -84,7 +85,7 @@ void Resource::SetState( State new_state ) new_state == remote_new || new_state == remote_deleted || new_state == local_new || new_state == local_deleted ) ; - + m_state = new_state ; std::for_each( m_child.begin(), m_child.end(), boost::bind( &Resource::SetState, _1, new_state ) ) ; @@ -93,17 +94,17 @@ void Resource::SetState( State new_state ) void Resource::FromRemoteFolder( const Entry& remote, const DateTime& last_sync ) { fs::path path = Path() ; - + if ( remote.CreateLink().empty() ) Log( "folder %1% is read-only", path, log::verbose ) ; - + // already sync if ( fs::is_directory( path ) ) { Log( "folder %1% is in sync", path, log::verbose ) ; m_state = sync ; } - + // remote file created after last sync, so remote is newer else if ( remote.MTime() > last_sync ) { @@ -146,11 +147,11 @@ void Resource::FromRemote( const Entry& remote, const DateTime& last_sync ) FromRemoteFolder( remote, last_sync ) ; else FromRemoteFile( remote, last_sync ) ; - + AssignIDs( remote ) ; - + assert( m_state != unknown ) ; - + if ( m_state == remote_new || m_state == remote_changed ) { m_md5 = remote.MD5() ; @@ -175,7 +176,7 @@ void Resource::AssignIDs( const Entry& remote ) void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) { assert( m_parent != 0 ) ; - + fs::path path = Path() ; // recursively create/delete folder @@ -186,7 +187,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) ( m_parent->m_state == remote_new || m_parent->m_state == local_new ) ? "created" : "deleted", ( m_parent->m_state == remote_new || m_parent->m_state == remote_deleted ) ? "remote" : "local", m_parent->m_state, log::verbose ) ; - + m_state = m_parent->m_state ; } @@ -194,12 +195,12 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) else if ( !fs::exists( path ) ) { Trace( "file %1% change stamp = %2%", Path(), remote.ChangeStamp() ) ; - + if ( remote.MTime() > last_sync || remote.ChangeStamp() > 0 ) { Log( "file %1% is created in remote (change %2%)", path, remote.ChangeStamp(), log::verbose ) ; - + m_state = remote_new ; } else @@ -208,7 +209,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) m_state = local_deleted ; } } - + // remote checksum unknown, assume the file is not changed in remote else if ( remote.MD5().empty() ) { @@ -216,7 +217,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) Path(), log::verbose ) ; m_state = sync ; } - + // if checksum is equal, no need to compare the mtime else if ( remote.MD5() == m_md5 ) { @@ -235,7 +236,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) Log( "file %1% is changed in remote", path, log::verbose ) ; m_state = remote_changed ; } - + // remote also has the file, so it's not new in local else if ( m_state == local_new || m_state == remote_deleted ) { @@ -252,7 +253,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) void Resource::FromLocal( const DateTime& last_sync ) { fs::path path = Path() ; - assert( fs::exists( path ) ) ; + //assert( fs::exists( path ) ) ; // root folder is always in sync if ( !IsRoot() ) @@ -262,18 +263,18 @@ void Resource::FromLocal( const DateTime& last_sync ) // follow parent recursively if ( m_parent->m_state == local_new || m_parent->m_state == local_deleted ) m_state = local_new ; - + // if the file is not created after last sync, assume file is // remote_deleted first, it will be updated to sync/remote_changed // in FromRemote() else m_state = ( m_mtime > last_sync ? local_new : remote_deleted ) ; - + m_name = path.filename().string() ; - m_kind = fs::is_directory(path) ? "folder" : "file" ; - m_md5 = fs::is_directory(path) ? "" : crypt::MD5::Get( path ) ; + //m_kind = fs::is_directory(path) ? "folder" : "file" ; + m_md5 = IsFolder() ? "" : crypt::MD5::Get( path ) ; } - + assert( m_state != unknown ) ; } @@ -323,12 +324,12 @@ void Resource::Swap( Resource& coll ) m_id.swap( coll.m_id ) ; m_href.swap( coll.m_href ) ; - m_content.swap( coll.m_content ) ; + m_content.swap( coll.m_content ) ; m_edit.swap( coll.m_edit ) ; m_create.swap( coll.m_create ) ; - + m_mtime.Swap( coll.m_mtime ) ; - + std::swap( m_parent, coll.m_parent ) ; m_child.swap( coll.m_child ) ; std::swap( m_state, coll.m_state ) ; @@ -369,13 +370,13 @@ 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, 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(), @@ -391,28 +392,33 @@ void Resource::SyncSelf( http::Agent* http, const Json& options ) const fs::path path = Path() ; + Json uploadonly ; + switch ( m_state ) { case local_new : Log( "sync %1% doesn't exist in server, uploading", path, log::info ) ; - if ( http != 0 && Create( http ) ) m_state = sync ; break ; - + case local_deleted : + if ( options.Get("uploadonly", uploadonly) && uploadonly.Bool() ) + break ; Log( "sync %1% deleted in local. deleting remote", path, log::info ) ; if ( http != 0 ) DeleteRemote( http ) ; break ; - + case local_changed : Log( "sync %1% changed in local. uploading", path, log::info ) ; if ( http != 0 && EditContent( http, options["new-rev"].Bool() ) ) m_state = sync ; break ; - + case remote_new : + if ( options.Get("uploadonly", uploadonly) && uploadonly.Bool() ) + break ; Log( "sync %1% created in remote. creating local", path, log::info ) ; if ( http != 0 ) { @@ -420,12 +426,14 @@ void Resource::SyncSelf( http::Agent* http, const Json& options ) fs::create_directories( path ) ; else Download( http, path ) ; - + m_state = sync ; } break ; - + case remote_changed : + if ( options.Get("uploadonly", uploadonly) && uploadonly.Bool() ) + break ; assert( !IsFolder() ) ; Log( "sync %1% changed in remote. downloading", path, log::info ) ; if ( http != 0 ) @@ -434,13 +442,15 @@ void Resource::SyncSelf( http::Agent* http, const Json& options ) m_state = sync ; } break ; - + case remote_deleted : + if ( options.Get("uploadonly", uploadonly) && uploadonly.Bool() ) + break ; Log( "sync %1% deleted in remote. deleting local", path, log::info ) ; if ( http != 0 ) DeleteLocal() ; break ; - + case sync : Log( "sync %1% already in sync", path, log::verbose ) ; break ; @@ -449,7 +459,7 @@ void Resource::SyncSelf( http::Agent* http, const Json& options ) case unknown : assert( false ) ; break ; - + default : break ; } @@ -463,11 +473,11 @@ void Resource::DeleteLocal() assert( m_parent != 0 ) ; fs::path parent = m_parent->Path() ; fs::path dest = ".trash" / parent / Name() ; - + std::size_t idx = 1 ; while ( fs::exists( dest ) && idx != 0 ) dest = ".trash" / parent / (boost::format(trash_file) % Name() % idx++).str() ; - + // wrap around! just remove the file if ( idx == 0 ) fs::remove_all( Path() ) ; @@ -482,17 +492,17 @@ void Resource::DeleteRemote( http::Agent *http ) { assert( http != 0 ) ; http::StringResponse str ; - + try { http::Header hdr ; hdr.Add( "If-Match: " + m_etag ) ; - + // doesn't know why, but an update before deleting seems to work always http::XmlResponse xml ; http->Get( m_href, &xml, hdr ) ; AssignIDs( Entry( xml.Response() ) ) ; - + http->Custom( "DELETE", m_href, &str, hdr ) ; } catch ( Exception& e ) @@ -509,7 +519,7 @@ void Resource::DeleteRemote( http::Agent *http ) 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, http::Header() ) ; if ( r <= 400 ) @@ -533,7 +543,7 @@ bool Resource::EditContent( http::Agent* http, bool new_rev ) Log( "Cannot upload %1%: file read-only. %2%", m_name, m_state, log::warning ) ; return false ; } - + return Upload( http, m_edit + (new_rev ? "?new-revision=true" : ""), false ) ; } @@ -543,13 +553,13 @@ bool Resource::Create( http::Agent* http ) assert( m_parent != 0 ) ; assert( m_parent->IsFolder() ) ; assert( m_parent->m_state == sync ) ; - + if ( IsFolder() ) { std::string uri = feed_base ; if ( !m_parent->IsRoot() ) uri += ("/" + http->Escape(m_parent->m_id) + "/contents") ; - + std::string meta = (boost::format( xml_meta ) % "folder" % xml::Escape(m_name) @@ -557,7 +567,7 @@ bool Resource::Create( http::Agent* http ) http::Header hdr ; hdr.Add( "Content-Type: application/atom+xml" ) ; - + http::XmlResponse xml ; // http::ResponseLog log( "create", ".xml", &xml ) ; http->Post( uri, meta, &xml, hdr ) ; @@ -582,41 +592,85 @@ bool Resource::Upload( bool post) { assert( http != 0 ) ; - + File file( Path() ) ; std::ostringstream xcontent_len ; xcontent_len << "X-Upload-Content-Length: " << file.Size() ; - + http::Header hdr ; hdr.Add( "Content-Type: application/atom+xml" ) ; hdr.Add( "X-Upload-Content-Type: application/octet-stream" ) ; hdr.Add( xcontent_len.str() ) ; hdr.Add( "If-Match: " + m_etag ) ; hdr.Add( "Expect:" ) ; - + std::string meta = (boost::format( xml_meta ) % m_kind % xml::Escape(m_name) ).str() ; - - http::StringResponse str ; - if ( post ) - http->Post( link, meta, &str, hdr ) ; - else - http->Put( link, meta, &str, hdr ) ; - - http::Header uphdr ; - uphdr.Add( "Expect:" ) ; - uphdr.Add( "Accept:" ) ; - - // the content upload URL is in the "Location" HTTP header - std::string uplink = http->RedirLocation() ; - http::XmlResponse xml ; - - http->Put( uplink, &file, &xml, uphdr ) ; - AssignIDs( Entry( xml.Response() ) ) ; - m_mtime = Entry(xml.Response()).MTime(); - + + bool retrying=false; + while ( true ) { + if ( retrying ) { + file.Seek( 0, SEEK_SET ); + os::Sleep( 5 ); + } + + try { + http::StringResponse str ; + if ( post ) + http->Post( link, meta, &str, hdr ) ; + else + http->Put( link, meta, &str, hdr ) ; + } catch ( Error &e ) { + std::string const *info = boost::get_error_info(e); + if ( info && (*info == "XML_Parse") ) { + Log( "Error parsing pre-upload response XML, retrying whole upload in 5s", + log::warning ); + retrying = true; + continue; + } else { + throw e; + } + } + + http::Header uphdr ; + uphdr.Add( "Expect:" ) ; + uphdr.Add( "Accept:" ) ; + + // the content upload URL is in the "Location" HTTP header + std::string uplink = http->RedirLocation() ; + http::XmlResponse xml ; + + long http_code = 0; + try { + http_code = http->Put( uplink, &file, &xml, uphdr ) ; + } catch ( Error &e ) { + std::string const *info = boost::get_error_info(e); + if ( info && (*info == "XML_Parse") ) { + Log( "Error parsing response XML, retrying whole upload in 5s", + log::warning ); + retrying = true; + continue; + } else { + throw e; + } + } + + if ( http_code == 410 || http_code == 412 ) { + Log( "request failed with %1%, retrying whole upload in 5s", http_code, + log::warning ) ; + retrying = true; + continue; + } + + if ( retrying ) + Log( "upload succeeded on retry", log::warning ); + Entry responseEntry = Entry( xml.Response() ); + AssignIDs( responseEntry ) ; + m_mtime = responseEntry.MTime(); + break; + } return true ; } diff --git a/libgrive/src/drive/Resource.hh b/libgrive/src/drive/Resource.hh index 46096807..775884f8 100644 --- a/libgrive/src/drive/Resource.hh +++ b/libgrive/src/drive/Resource.hh @@ -52,11 +52,11 @@ public : typedef std::vector Children ; typedef Children::const_iterator iterator ; - + public : Resource(const fs::path& root_folder) ; Resource( const std::string& name, const std::string& kind ) ; - + // default copy ctor & op= are fine void Swap( Resource& coll ) ; @@ -65,12 +65,12 @@ public : std::string Name() const ; std::string SelfHref() const ; std::string ResourceID() const ; - + const Resource* Parent() const ; Resource* Parent() ; void AddChild( Resource *child ) ; Resource* FindChild( const std::string& title ) ; - + fs::path Path() const ; bool IsInRootTree() const ; bool IsRoot() const ; @@ -79,51 +79,51 @@ public : void FromRemote( const Entry& remote, const DateTime& last_sync ) ; void FromLocal( const DateTime& last_sync ) ; - + void Sync( http::Agent* http, DateTime& sync_time, const Json& options ) ; // children access iterator begin() const ; iterator end() const ; std::size_t size() const ; - + std::string StateStr() const ; - + private : /// State of the resource. indicating what to do with the resource enum State { /// The best state: the file is the same in remote and in local. sync, - + /// Resource created in local, but remote does not have it. /// We should create the resource in google drive and upload new content local_new, - + /// Resource exists in both local & remote, but changes in local is newer /// than remote. We should upload local copy to overwrite remote. local_changed, - + /// Resource deleted from local since last time grive has checked. local_deleted, - + /// Resource created in google drive, but not exist in local. /// We should download the file. remote_new, - - /// Resource exists in both local & remote, but remote is newer. + + /// Resource exists in both local & remote, but remote is newer. remote_changed, - + /// Resource delete in remote, need to delete in local remote_deleted, - - + + /// invalid value unknown } ; friend std::ostream& operator<<( std::ostream& os, State s ) ; - + private : void SetState( State new_state ) ; @@ -131,22 +131,22 @@ private : 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 ) ; - + void AssignIDs( const Entry& remote ) ; void SyncSelf( http::Agent* http, const Json& options ) ; - + private : std::string m_name ; std::string m_kind ; std::string m_md5 ; DateTime m_mtime ; - + std::string m_id ; std::string m_href ; std::string m_edit ; @@ -157,7 +157,7 @@ private : // not owned Resource *m_parent ; std::vector m_child ; - + State m_state ; } ; diff --git a/libgrive/src/drive/ResourceTree.cc b/libgrive/src/drive/ResourceTree.cc index 4a8a6daf..e3933c97 100644 --- a/libgrive/src/drive/ResourceTree.cc +++ b/libgrive/src/drive/ResourceTree.cc @@ -46,10 +46,10 @@ ResourceTree::ResourceTree( const ResourceTree& fs ) : Resource *c = new Resource( **i ) ; if ( c->SelfHref() == root_href ) m_root = c ; - + m_set.insert( c ) ; } - + assert( m_root != 0 ) ; } @@ -63,7 +63,7 @@ void ResourceTree::Clear() // delete all pointers const Set& s = m_set.get() ; std::for_each( s.begin(), s.end(), Destroy() ) ; - + m_set.clear() ; m_root = 0 ; } diff --git a/libgrive/src/drive/ResourceTree.hh b/libgrive/src/drive/ResourceTree.hh index 212141a8..b9673e91 100644 --- a/libgrive/src/drive/ResourceTree.hh +++ b/libgrive/src/drive/ResourceTree.hh @@ -49,7 +49,7 @@ namespace details hashed_unique, identity > > > Folders ; - + typedef Folders::index::type IDMap ; typedef Folders::index::type HrefMap ; typedef Folders::index::type Set ; @@ -69,24 +69,24 @@ public : ResourceTree( const fs::path& rootFolder ) ; ResourceTree( const ResourceTree& fs ) ; ~ResourceTree( ) ; - + void Swap( ResourceTree& fs ) ; ResourceTree& operator=( const ResourceTree& fs ) ; - + Resource* FindByHref( const std::string& href ) ; const Resource* FindByHref( const std::string& href ) const ; Resource* FindByID( const std::string& id ) ; - + bool ReInsert( Resource *coll ) ; - + void Insert( Resource *coll ) ; void Erase( Resource *coll ) ; void Update( Resource *coll, const Entry& e, const DateTime& last_sync ) ; - + Resource* Root() ; const Resource* Root() const ; - + iterator begin() ; iterator end() ; diff --git a/libgrive/src/drive/State.cc b/libgrive/src/drive/State.cc index 2d1dc943..7a7681af 100644 --- a/libgrive/src/drive/State.cc +++ b/libgrive/src/drive/State.cc @@ -35,15 +35,16 @@ namespace gr { namespace v1 { State::State( const fs::path& filename, const Json& options ) : m_res ( options["path"].Str() ), + m_dir ( options["dir"].Str() ), m_cstamp ( -1 ) { Read( filename ) ; - + // the "-f" option will make grive always thinks remote is newer Json force ; if ( options.Get("force", force) && force.Bool() ) m_last_sync = DateTime() ; - + Log( "last sync time: %1%", m_last_sync, log::verbose ) ; } @@ -60,43 +61,48 @@ void State::FromLocal( const fs::path& p ) bool State::IsIgnore( const std::string& filename ) { - return filename[0] == '.' ; + return filename == ".grive" || filename == ".grive_state" || filename == ".trash"; } void State::FromLocal( const fs::path& p, Resource* folder ) { assert( folder != 0 ) ; assert( folder->IsFolder() ) ; - + // sync the folder itself folder->FromLocal( m_last_sync ) ; for ( fs::directory_iterator i( p ) ; i != fs::directory_iterator() ; ++i ) { std::string fname = i->path().filename().string() ; - + if ( IsIgnore(fname) ) Log( "file %1% is ignored by grive", fname, log::verbose ) ; - + + // check if it is ignored + else if ( folder == m_res.Root() && m_dir != "" && fname != m_dir ) + Log( "%1% %2% is ignored", fs::is_directory(i->path()) ? "folder" : "file", fname, log::verbose ); + // check for broken symblic links else if ( !fs::exists( i->path() ) ) Log( "file %1% doesn't exist (broken link?), ignored", i->path(), log::verbose ) ; - + else { + bool is_dir = fs::is_directory(i->path()); // if the Resource object of the child already exists, it should // have been so no need to do anything here Resource *c = folder->FindChild( fname ) ; if ( c == 0 ) { - c = new Resource( fname, fs::is_directory(i->path()) ? "folder" : "file" ) ; + c = new Resource( fname, is_dir ? "folder" : "file" ) ; folder->AddChild( c ) ; m_res.Insert( c ) ; } - - c->FromLocal( m_last_sync ) ; - - if ( fs::is_directory( i->path() ) ) + + c->FromLocal( m_last_sync ) ; + + if ( is_dir ) FromLocal( *i, c ) ; } } @@ -104,18 +110,22 @@ void State::FromLocal( const fs::path& p, Resource* folder ) void State::FromRemote( const Entry& e ) { - std::string fn = e.Filename() ; + std::string fn = e.Filename() ; if ( IsIgnore( e.Name() ) ) Log( "%1% %2% is ignored by grive", e.Kind(), e.Name(), log::verbose ) ; + // check if it is ignored + else if ( e.ParentHref() == m_res.Root()->SelfHref() && m_dir != "" && e.Name() != m_dir ) + Log( "%1% %2% is ignored", e.Kind(), e.Name(), log::verbose ); + // common checkings else if ( e.Kind() != "folder" && (fn.empty() || e.ContentSrc().empty()) ) Log( "%1% \"%2%\" is a google document, ignored", e.Kind(), e.Name(), log::verbose ) ; - + else if ( fn.find('/') != fn.npos ) Log( "%1% \"%2%\" contains a slash in its name, ignored", e.Kind(), e.Name(), log::verbose ) ; - + else if ( !e.IsChange() && e.ParentHrefs().size() != 1 ) Log( "%1% \"%2%\" has multiple parents, ignored", e.Kind(), e.Name(), log::verbose ) ; @@ -143,7 +153,7 @@ std::size_t State::TryResolveEntry() std::size_t count = 0 ; std::vector& en = m_unresolved ; - + for ( std::vector::iterator i = en.begin() ; i != en.end() ; ) { if ( Update( *i ) ) @@ -161,7 +171,7 @@ void State::FromChange( const Entry& e ) { assert( e.IsChange() ) ; assert( !IsIgnore( e.Name() ) ) ; - + // entries in the change feed is always treated as newer in remote, // so we override the last sync time to 0 if ( Resource *res = m_res.FindByHref( e.AltSelf() ) ) @@ -190,7 +200,7 @@ bool State::Update( const Entry& e ) // since we are updating the ID and Href, we need to remove it and re-add it. m_res.Update( child, e, m_last_sync ) ; } - + // folder entry exist in google drive, but not local. we should create // the directory else if ( e.Kind() == "folder" || !e.Filename().empty() ) @@ -199,11 +209,11 @@ bool State::Update( const Entry& e ) child = new Resource( name, e.Kind() ) ; parent->AddChild( child ) ; m_res.Insert( child ) ; - + // update the state of the resource m_res.Update( child, e, m_last_sync ) ; } - + return true ; } else @@ -231,12 +241,12 @@ void State::Read( const fs::path& filename ) { File file( filename ) ; Json json = Json::Parse( &file ) ; - + Json last_sync = json["last_sync"] ; m_last_sync.Assign( last_sync["sec"].Int(), last_sync["nsec"].Int() ) ; - + m_cstamp = json["change_stamp"].Int() ; } catch ( Exception& ) @@ -248,13 +258,13 @@ void State::Read( const fs::path& filename ) void State::Write( const fs::path& filename ) const { Json last_sync ; - last_sync.Add( "sec", Json(m_last_sync.Sec() ) ); - last_sync.Add( "nsec", Json(m_last_sync.NanoSec() ) ); - + last_sync.Add( "sec", Json((boost::uint64_t) m_last_sync.Sec() ) ); + last_sync.Add( "nsec", Json((boost::uint64_t) m_last_sync.NanoSec() ) ); + Json result ; result.Add( "last_sync", last_sync ) ; - result.Add( "change_stamp", Json(m_cstamp) ) ; - + result.Add( "change_stamp", Json((boost::uint64_t) m_cstamp) ) ; + std::ofstream fs( filename.string().c_str() ) ; fs << result ; } @@ -270,7 +280,7 @@ void State::Sync( http::Agent *http, const Json& options ) // 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 ) ; diff --git a/libgrive/src/drive/State.hh b/libgrive/src/drive/State.hh index 8c641892..dd3da552 100644 --- a/libgrive/src/drive/State.hh +++ b/libgrive/src/drive/State.hh @@ -48,11 +48,11 @@ public : public : explicit State( const fs::path& filename, const Json& options ) ; ~State() ; - + void FromLocal( const fs::path& p ) ; void FromRemote( const Entry& e ) ; void ResolveEntry() ; - + void Read( const fs::path& filename ) ; void Write( const fs::path& filename ) const ; @@ -60,13 +60,13 @@ public : Resource* FindByID( const std::string& id ) ; void Sync( http::Agent *http, const Json& options ) ; - + iterator begin() ; iterator end() ; - + long ChangeStamp() const ; void ChangeStamp( long cstamp ) ; - + private : void FromLocal( const fs::path& p, Resource *folder ) ; void FromChange( const Entry& e ) ; @@ -74,12 +74,12 @@ private : std::size_t TryResolveEntry() ; static bool IsIgnore( const std::string& filename ) ; - + private : ResourceTree m_res ; DateTime m_last_sync ; - long m_cstamp ; - + int m_cstamp ; + std::string m_dir ; std::vector m_unresolved ; } ; diff --git a/libgrive/src/drive2/Drive.cc b/libgrive/src/drive2/Drive.cc index feaa84be..761a772f 100644 --- a/libgrive/src/drive2/Drive.cc +++ b/libgrive/src/drive2/Drive.cc @@ -46,12 +46,12 @@ void Drive::Refresh( http::Agent *agent ) // find root node ID assert( m_root == 0 ) ; m_root = NewResource( agent, "root" ) ; - + // get all folders first Feed folders( feeds::files ) ; folders.Query( "mimeType", mime_types::folder ) ; NewResource( agent, folders ) ; - + // get all files Feed files( feeds::files ) ; NewResource( agent, files ) ; @@ -61,7 +61,7 @@ void Drive::Refresh( http::Agent *agent ) { Resource *parent = Find( (*i)->Parent() ), *child = *i ; assert( child != 0 ) ; - + if ( parent != 0 ) { // initialize parent IDs @@ -74,7 +74,7 @@ void Drive::Refresh( http::Agent *agent ) void Drive::NewResource( http::Agent *agent, Feed& items ) { assert( agent != 0 ) ; - + while ( items.Next( agent ) ) { std::vector item_json = items.Content()["items"].AsArray() ; @@ -88,7 +88,7 @@ Resource* Drive::NewResource( http::Agent *agent, const std::string& id ) { Feed feed( feeds::files + "/" + id ) ; feed.Next( agent ) ; - + return NewResource( feed.Content() ) ; } @@ -96,7 +96,7 @@ Resource* Drive::NewResource( const Val& item ) { // assume resource is directly under root std::string parent_id = m_root != 0 ? m_root->ID() : "" ; - + Val parents ; if ( item.Get( "parents", parents ) ) { @@ -116,10 +116,10 @@ Resource* Drive::NewResource( const Val& item ) item["mimeType"].Str(), item["title"].Str(), parent_id ) ; - + m_db.insert(r) ; assert( Find(r->ID()) == r ) ; - + return r ; } @@ -151,7 +151,7 @@ const Resource* Drive::Child( const Resource *parent, std::size_t idx ) const BOOST_THROW_EXCEPTION( Exception() ) ; - + return Find( parent->At(idx) ) ; } diff --git a/libgrive/src/drive2/Drive.hh b/libgrive/src/drive2/Drive.hh index 33014b03..f858ecf0 100644 --- a/libgrive/src/drive2/Drive.hh +++ b/libgrive/src/drive2/Drive.hh @@ -52,7 +52,7 @@ namespace details hashed_non_unique, const_mem_fun > > > DB ; - + typedef DB::index::type ID ; typedef DB::index::type Set ; } @@ -63,7 +63,7 @@ class Drive { public : Drive( ) ; - + void Refresh( http::Agent *agent ) ; Resource* Find( const std::string& id ) ; @@ -71,7 +71,7 @@ public : Resource* Root() ; const Resource* Root() const ; - + const Resource* Child( const Resource *parent, std::size_t idx ) const ; const Resource* Parent( const Resource *child ) const ; @@ -79,10 +79,10 @@ private : Resource* NewResource( const Val& item ) ; Resource* NewResource( http::Agent *agent, const std::string& id ) ; void NewResource( http::Agent *agent, Feed& items ) ; - + private : details::DB m_db ; - + Resource *m_root ; } ; diff --git a/libgrive/src/drive2/Feed.cc b/libgrive/src/drive2/Feed.cc index 78f67f06..8d07b1c4 100644 --- a/libgrive/src/drive2/Feed.cc +++ b/libgrive/src/drive2/Feed.cc @@ -45,7 +45,7 @@ bool Feed::Next( http::Agent *agent ) Val url ; if ( !m_content.Get("nextLink", url) ) return false ; - + http::ValResponse out ; try { @@ -57,7 +57,7 @@ bool Feed::Next( http::Agent *agent ) throw ; } m_content = out.Response() ; - + return true ; } diff --git a/libgrive/src/drive2/Feed.hh b/libgrive/src/drive2/Feed.hh index ad1f294a..d46e7bd2 100644 --- a/libgrive/src/drive2/Feed.hh +++ b/libgrive/src/drive2/Feed.hh @@ -45,8 +45,8 @@ public : public : Feed( const std::string& base ) ; void Query( const std::string& field, const std::string& value ) ; - - + + bool Next( http::Agent *agent ) ; Val Content() const ; diff --git a/libgrive/src/drive2/Resource.hh b/libgrive/src/drive2/Resource.hh index 8513c604..d5acf5cf 100644 --- a/libgrive/src/drive2/Resource.hh +++ b/libgrive/src/drive2/Resource.hh @@ -38,7 +38,7 @@ public : std::string ID() const ; std::string Mime() const ; std::string Title() const ; - + bool IsFolder() const ; void AddChild( const std::string& child ) ; @@ -53,9 +53,9 @@ private : std::string m_id ; std::string m_mime ; std::string m_title ; - + std::vector m_children ; - + std::string m_parent ; } ; diff --git a/libgrive/src/http/Agent.hh b/libgrive/src/http/Agent.hh index a1903ce9..20ed9b31 100644 --- a/libgrive/src/http/Agent.hh +++ b/libgrive/src/http/Agent.hh @@ -46,26 +46,26 @@ public : File *file, DataStream *dest, const Header& hdr ) = 0 ; - + virtual long Get( const std::string& url, DataStream *dest, const Header& hdr ) = 0 ; - + virtual long Post( const std::string& url, const std::string& data, DataStream *dest, const Header& hdr ) = 0 ; - + virtual long Custom( const std::string& method, const std::string& url, DataStream *dest, const Header& hdr ) = 0 ; - + virtual std::string RedirLocation() const = 0 ; - + virtual std::string Escape( const std::string& str ) = 0 ; virtual std::string Unescape( const std::string& str ) = 0 ; } ; diff --git a/libgrive/src/http/CurlAgent.cc b/libgrive/src/http/CurlAgent.cc index d725e86c..7a1dee54 100644 --- a/libgrive/src/http/CurlAgent.cc +++ b/libgrive/src/http/CurlAgent.cc @@ -57,7 +57,7 @@ std::size_t ReadStringCallback( void *ptr, std::size_t size, std::size_t nmemb, std::memcpy( ptr, &(*data)[0], count ) ; data->erase( 0, count ) ; } - + return count ; } @@ -70,10 +70,10 @@ std::size_t ReadFileCallback( void *ptr, std::size_t size, std::size_t nmemb, Fi static_cast(size * nmemb), static_cast(file->Size() - file->Tell()) ) ; assert( count <= std::numeric_limits::max() ) ; - + if ( count > 0 ) file->Read( static_cast(ptr), static_cast(count) ) ; - + return count ; } @@ -96,7 +96,7 @@ CurlAgent::CurlAgent() : void CurlAgent::Init() { ::curl_easy_reset( m_pimpl->curl ) ; - ::curl_easy_setopt( m_pimpl->curl, CURLOPT_SSL_VERIFYPEER, 0L ) ; + ::curl_easy_setopt( m_pimpl->curl, CURLOPT_SSL_VERIFYPEER, 0L ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_SSL_VERIFYHOST, 0L ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_HEADERFUNCTION, &CurlAgent::HeaderCallback ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_WRITEHEADER , this ) ; @@ -112,7 +112,7 @@ std::size_t CurlAgent::HeaderCallback( void *ptr, size_t size, size_t nmemb, Cur { char *str = reinterpret_cast(ptr) ; std::string line( str, str + size*nmemb ) ; - + static const std::string loc = "Location: " ; std::size_t pos = line.find( loc ) ; if ( pos != line.npos ) @@ -120,7 +120,7 @@ std::size_t CurlAgent::HeaderCallback( void *ptr, size_t size, size_t nmemb, Cur std::size_t end_pos = line.find( "\r\n", pos ) ; pthis->m_pimpl->location = line.substr( loc.size(), end_pos - loc.size() ) ; } - + return size*nmemb ; } @@ -153,10 +153,10 @@ long CurlAgent::ExecCurl( long http_code = 0; ::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); Trace( "HTTP response %1%", http_code ) ; - + // 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 ) { @@ -179,7 +179,7 @@ long CurlAgent::Put( const Header& hdr ) { Trace("HTTP PUT \"%1%\"", url ) ; - + Init() ; CURL *curl = m_pimpl->curl ; @@ -190,7 +190,7 @@ long CurlAgent::Put( ::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 ) ; } @@ -200,10 +200,10 @@ long CurlAgent::Put( DataStream *dest, const Header& hdr ) { - assert( file != 0 ) ; + assert( file != 0 ) ; Trace("HTTP PUT \"%1%\"", url ) ; - + Init() ; CURL *curl = m_pimpl->curl ; @@ -212,7 +212,7 @@ long CurlAgent::Put( ::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 ) ; } @@ -243,7 +243,7 @@ long CurlAgent::Post( // make a copy because the parameter is const std::string post_data = data ; - + // set post specific options ::curl_easy_setopt(curl, CURLOPT_POST, 1L); ::curl_easy_setopt(curl, CURLOPT_POSTFIELDS, &post_data[0] ) ; @@ -274,7 +274,7 @@ void CurlAgent::SetHeader( const Header& hdr ) struct curl_slist *curl_hdr = 0 ; for ( Header::iterator i = hdr.begin() ; i != hdr.end() ; ++i ) curl_hdr = curl_slist_append( curl_hdr, i->c_str() ) ; - + ::curl_easy_setopt( m_pimpl->curl, CURLOPT_HTTPHEADER, curl_hdr ) ; } @@ -286,23 +286,23 @@ std::string CurlAgent::RedirLocation() const std::string CurlAgent::Escape( const std::string& str ) { CURL *curl = m_pimpl->curl ; - + char *tmp = curl_easy_escape( curl, str.c_str(), str.size() ) ; std::string result = tmp ; curl_free( tmp ) ; - + return result ; } std::string CurlAgent::Unescape( const std::string& str ) { CURL *curl = m_pimpl->curl ; - + int r ; char *tmp = curl_easy_unescape( curl, str.c_str(), str.size(), &r ) ; std::string result = tmp ; curl_free( tmp ) ; - + return result ; } diff --git a/libgrive/src/http/CurlAgent.hh b/libgrive/src/http/CurlAgent.hh index c142c3b1..e85838d4 100644 --- a/libgrive/src/http/CurlAgent.hh +++ b/libgrive/src/http/CurlAgent.hh @@ -31,7 +31,7 @@ class DataStream ; namespace http { /*! \brief agent to provide HTTP access - + This class provides functions to send HTTP request in many methods (e.g. get, post and put). Normally the HTTP response is returned in a Receivable. */ @@ -40,13 +40,13 @@ class CurlAgent : public Agent public : CurlAgent() ; ~CurlAgent() ; - + long Put( const std::string& url, const std::string& data, DataStream *dest, const Header& hdr ) ; - + long Put( const std::string& url, File *file, @@ -57,28 +57,28 @@ public : const std::string& url, DataStream *dest, const Header& hdr ) ; - + long Post( const std::string& url, const std::string& data, DataStream *dest, const Header& hdr ) ; - + long Custom( const std::string& method, const std::string& url, DataStream *dest, const Header& hdr ) ; - + std::string RedirLocation() const ; - + std::string Escape( const std::string& str ) ; std::string Unescape( const std::string& str ) ; private : static std::size_t HeaderCallback( void *ptr, size_t size, size_t nmemb, CurlAgent *pthis ) ; static std::size_t Receive( void* ptr, size_t size, size_t nmemb, DataStream *recv ) ; - + void SetHeader( const Header& hdr ) ; long ExecCurl( const std::string& url, @@ -86,7 +86,7 @@ private : const Header& hdr ) ; void Init() ; - + private : struct Impl ; std::auto_ptr m_pimpl ; diff --git a/libgrive/src/http/Download.cc b/libgrive/src/http/Download.cc index 885187ef..e74fe34d 100644 --- a/libgrive/src/http/Download.cc +++ b/libgrive/src/http/Download.cc @@ -68,10 +68,10 @@ std::string Download::Finish() const std::size_t Download::Write( const char *data, std::size_t count ) { assert( data != 0 ) ; - + if ( m_crypt.get() != 0 ) m_crypt->Write( data, count ) ; - + return m_file.Write( data, count ) ; } diff --git a/libgrive/src/http/Download.hh b/libgrive/src/http/Download.hh index 77cc1ae8..e556538f 100644 --- a/libgrive/src/http/Download.hh +++ b/libgrive/src/http/Download.hh @@ -39,13 +39,13 @@ public : Download( const std::string& filename ) ; Download( const std::string& filename, NoChecksum ) ; ~Download() ; - + std::string Finish() const ; - + void Clear() ; std::size_t Write( const char *data, std::size_t count ) ; - std::size_t Read( char *, std::size_t ) ; - + std::size_t Read( char *, std::size_t ) ; + private : File m_file ; std::auto_ptr m_crypt ; diff --git a/libgrive/src/http/Header.hh b/libgrive/src/http/Header.hh index 2486cd0c..d0e16035 100644 --- a/libgrive/src/http/Header.hh +++ b/libgrive/src/http/Header.hh @@ -35,9 +35,9 @@ public : public : Header() ; - + void Add( const std::string& str ) ; - + iterator begin() const ; iterator end() const ; diff --git a/libgrive/src/http/ResponseLog.cc b/libgrive/src/http/ResponseLog.cc index 9de4ac04..a9bfb982 100644 --- a/libgrive/src/http/ResponseLog.cc +++ b/libgrive/src/http/ResponseLog.cc @@ -50,7 +50,7 @@ std::size_t ResponseLog::Write( const char *data, std::size_t count ) assert( m_log.rdbuf() != 0 ) ; m_log.rdbuf()->sputn( data, count ) ; } - + return m_next->Write( data, count ) ; } @@ -73,16 +73,16 @@ void ResponseLog::Enable( bool enable ) void ResponseLog::Reset( const std::string& prefix, const std::string& suffix, DataStream *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 ) @@ -92,7 +92,7 @@ void ResponseLog::Reset( const std::string& prefix, const std::string& suffix, D } else Trace( "cannot open log file %1%", fname ) ; - + m_next = next ; } diff --git a/libgrive/src/http/ResponseLog.hh b/libgrive/src/http/ResponseLog.hh index 046b5c97..b37cb2fe 100644 --- a/libgrive/src/http/ResponseLog.hh +++ b/libgrive/src/http/ResponseLog.hh @@ -34,16 +34,16 @@ public : const std::string& suffix, DataStream *next ) ; ResponseLog( DataStream *next ) ; - + std::size_t Write( const char *data, std::size_t count ) ; std::size_t Read( char *data, std::size_t count ) ; - + void Enable( bool enable = true ) ; void Reset( const std::string& prefix, const std::string& suffix, DataStream *next ) ; - + private : static std::string Filename( const std::string& prefix, const std::string& suffix ) ; - + private : bool m_enabled ; std::ofstream m_log ; diff --git a/libgrive/src/http/StringResponse.hh b/libgrive/src/http/StringResponse.hh index 3f262a94..0b1d2ede 100644 --- a/libgrive/src/http/StringResponse.hh +++ b/libgrive/src/http/StringResponse.hh @@ -35,7 +35,7 @@ public : void Clear() ; const std::string& Response() const ; - + private : std::string m_resp ; } ; diff --git a/libgrive/src/http/XmlResponse.cc b/libgrive/src/http/XmlResponse.cc index b25f1c4d..3df42f94 100644 --- a/libgrive/src/http/XmlResponse.cc +++ b/libgrive/src/http/XmlResponse.cc @@ -28,6 +28,11 @@ XmlResponse::XmlResponse() : m_tb( new xml::TreeBuilder ) { } +void XmlResponse::Clear() +{ + m_tb.reset(new xml::TreeBuilder); +} + std::size_t XmlResponse::Write( const char *data, std::size_t count ) { m_tb->ParseData( data, count ) ; diff --git a/libgrive/src/http/XmlResponse.hh b/libgrive/src/http/XmlResponse.hh index b1505097..80f93a21 100644 --- a/libgrive/src/http/XmlResponse.hh +++ b/libgrive/src/http/XmlResponse.hh @@ -42,7 +42,7 @@ public : void Finish() ; xml::Node Response() const ; - + private : std::auto_ptr m_tb ; } ; diff --git a/libgrive/src/json/JsonParser.cc b/libgrive/src/json/JsonParser.cc index 9ae63f48..78fa07ee 100644 --- a/libgrive/src/json/JsonParser.cc +++ b/libgrive/src/json/JsonParser.cc @@ -35,63 +35,63 @@ namespace b->VisitNull() ; return true ; } - + int OnBool( void *ctx, int value ) { ValVisitor *b = reinterpret_cast(ctx) ; b->Visit( static_cast(value) ) ; return true ; } - + int OnInt( void *ctx, long long value ) { ValVisitor *b = reinterpret_cast(ctx) ; b->Visit(value) ; return true ; } - + int OnDouble( void *ctx, double value ) { ValVisitor *b = reinterpret_cast(ctx) ; b->Visit(value) ; return true ; } - + int OnStr( void *ctx, const unsigned char *str, std::size_t len ) { ValVisitor *b = reinterpret_cast(ctx) ; b->Visit( std::string(reinterpret_cast(str), len) ) ; return true ; } - + int StartMap( void *ctx ) { ValVisitor *b = reinterpret_cast(ctx) ; b->StartObject() ; return true ; } - + int OnMapKey( void *ctx, const unsigned char *str, std::size_t len ) { ValVisitor *b = reinterpret_cast(ctx) ; b->VisitKey( std::string(reinterpret_cast(str), len) ) ; return true ; } - + int EndMap( void *ctx ) { ValVisitor *b = reinterpret_cast(ctx) ; b->EndObject() ; return true ; } - + int StartArray( void *ctx ) { ValVisitor *b = reinterpret_cast(ctx) ; b->StartArray() ; return true ; } - + int EndArray( void *ctx ) { ValVisitor *b = reinterpret_cast(ctx) ; @@ -99,19 +99,19 @@ namespace return true ; } - const yajl_callbacks callbacks = { - OnNull, - OnBool, - OnInt, - OnDouble, - 0, - OnStr, - StartMap, - OnMapKey, - EndMap, - StartArray, - EndArray, - }; + const yajl_callbacks callbacks = { + OnNull, + OnBool, + OnInt, + OnDouble, + 0, + OnStr, + StartMap, + OnMapKey, + EndMap, + StartArray, + EndArray, + }; } void JsonParser::Parse( const std::string& json, ValVisitor *callback ) @@ -142,15 +142,15 @@ JsonParser::~JsonParser() void JsonParser::Parse( const char *str, std::size_t size ) { const unsigned char *ustr = reinterpret_cast(str) ; - + yajl_status r = yajl_parse( m_impl->hand, ustr, size ) ; - + if ( r != yajl_status_ok ) { unsigned char *msg = yajl_get_error( m_impl->hand, true, ustr, size ) ; std::string msg_str(reinterpret_cast(msg)) ; yajl_free_error(m_impl->hand, msg) ; - + BOOST_THROW_EXCEPTION( Error() << ParseErr_(msg_str) @@ -166,7 +166,7 @@ void JsonParser::Finish() unsigned char *msg = yajl_get_error( m_impl->hand, false, 0, 0 ) ; std::string msg_str(reinterpret_cast(msg)) ; yajl_free_error(m_impl->hand, msg) ; - + BOOST_THROW_EXCEPTION( Error() << ParseErr_(msg_str) ) ; } } diff --git a/libgrive/src/json/JsonParser.hh b/libgrive/src/json/JsonParser.hh index 27d6a4c8..37250cf9 100644 --- a/libgrive/src/json/JsonParser.hh +++ b/libgrive/src/json/JsonParser.hh @@ -37,13 +37,13 @@ public : typedef boost::error_info JsonText_ ; static void Parse( const std::string& json, ValVisitor *callback ) ; - + explicit JsonParser( ValVisitor *callback ) ; ~JsonParser() ; - + void Parse( const char *str, std::size_t size ) ; void Finish() ; - + private : struct Impl ; std::auto_ptr m_impl ; diff --git a/libgrive/src/json/JsonWriter.cc b/libgrive/src/json/JsonWriter.cc index 9fbcc2bb..3a3648b9 100644 --- a/libgrive/src/json/JsonWriter.cc +++ b/libgrive/src/json/JsonWriter.cc @@ -104,7 +104,7 @@ void JsonWriter::WriteCallback( void *ctx, const char *str, std::size_t size ) JsonWriter *pthis = reinterpret_cast(ctx) ; assert( pthis != 0 ) ; assert( pthis->m_impl->out != 0 ) ; - + pthis->m_impl->out->Write( str, size ) ; } diff --git a/libgrive/src/json/Val.cc b/libgrive/src/json/Val.cc index 79c0b5e1..f21e52ec 100644 --- a/libgrive/src/json/Val.cc +++ b/libgrive/src/json/Val.cc @@ -48,7 +48,7 @@ Val::Val( TypeEnum type ) case string_type: m_base.reset( new Impl ) ; break ; case array_type: m_base.reset( new Impl ) ; break ; case object_type: m_base.reset( new Impl ) ; break ; - case null_type: + case null_type: default: m_base.reset( new Impl ) ; break ; } } @@ -85,7 +85,7 @@ const Val& Val::operator[]( const std::string& key ) const Object::const_iterator i = obj.find(key) ; if ( i != obj.end() ) return i->second ; - + // shut off compiler warning BOOST_THROW_EXCEPTION(Error() << NoKey_(key)) ; throw ; @@ -96,7 +96,7 @@ const Val& Val::operator[]( std::size_t index ) const const Array& ar = As() ; if ( index < ar.size() ) return ar[index] ; - + // shut off compiler warning BOOST_THROW_EXCEPTION(Error() << OutOfRange_(index)) ; throw ; @@ -165,18 +165,18 @@ void Val::Visit( ValVisitor *visitor ) const case double_type: visitor->Visit( As() ) ; break ; case string_type: visitor->Visit( As() ) ; break ; case bool_type: visitor->Visit( As() ) ; break ; - + case object_type: { visitor->StartObject() ; - + const Object& obj = As() ; for ( Object::const_iterator i = obj.begin() ; i != obj.end() ; ++i ) { visitor->VisitKey( i->first ) ; i->second.Visit( visitor ) ; } - + visitor->EndObject() ; break ; } @@ -184,11 +184,11 @@ void Val::Visit( ValVisitor *visitor ) const case array_type: { visitor->StartArray() ; - + const Array& arr = As() ; for ( Array::const_iterator i = arr.begin() ; i != arr.end() ; ++i ) i->Visit( visitor ) ; - + visitor->EndArray() ; break ; } @@ -204,14 +204,14 @@ void Val::Select( const Object& obj, const std::string& key, std::vector& r /** If \a this is an array of objects, this function returns all values of the objects in the array with the key \a key. If \a this is an object, - just return the value with the key \a key. + just return the value with the key \a key. */ std::vector Val::Select( const std::string& key ) const { std::vector result ; if ( Is() ) Select( As(), key, result ) ; - + else if ( Is() ) { const Array& array = As() ; @@ -241,7 +241,7 @@ namespace std { v1.Swap( v2 ) ; } - + ostream& operator<<( ostream& os, gr::Val::TypeEnum t ) { return os << static_cast(t) ; diff --git a/libgrive/src/json/Val.hh b/libgrive/src/json/Val.hh index 25478860..3d791f2a 100644 --- a/libgrive/src/json/Val.hh +++ b/libgrive/src/json/Val.hh @@ -43,7 +43,7 @@ public : typedef boost::error_info DestType_ ; typedef boost::error_info NoKey_ ; typedef boost::error_info OutOfRange_ ; - + private : template struct Type2Enum ; @@ -71,10 +71,10 @@ public : template Val& Assign( const T& t ) ; - + void Swap( Val& val ) ; Val& operator=( const Val& val ) ; - + template Val& operator=( const T& t ) { @@ -108,14 +108,14 @@ public : bool Has( const std::string& key ) const ; bool Get( const std::string& key, Val& val ) const ; void Add( const std::string& key, const Val& val ) ; - + // shortcuts for array (and array of objects) void Add( const Val& json ) ; Val FindInArray( const std::string& key, const std::string& value ) const ; bool FindInArray( const std::string& key, const std::string& value, Val& result ) const ; - + std::vector Select( const std::string& key ) const ; - + friend std::ostream& operator<<( std::ostream& os, const Val& val ) ; void Visit( ValVisitor *visitor ) const ; @@ -124,7 +124,7 @@ private : template struct Impl ; - + std::auto_ptr m_base ; private : diff --git a/libgrive/src/json/ValBuilder.cc b/libgrive/src/json/ValBuilder.cc index c5658ff2..211f4701 100644 --- a/libgrive/src/json/ValBuilder.cc +++ b/libgrive/src/json/ValBuilder.cc @@ -64,7 +64,7 @@ void ValBuilder::Build( const Val& t ) Level l = { Val::Null(), t } ; m_ctx.push( l ) ; } - + else if ( m_ctx.top().val.Is() ) { Val::Array& ar = m_ctx.top().val.As() ; @@ -74,7 +74,7 @@ void ValBuilder::Build( const Val& t ) { if ( !m_ctx.top().key.Is() ) BOOST_THROW_EXCEPTION( Error() << NoKey_(t) ) ; - + else { Val::Object& obj = m_ctx.top().val.As() ; @@ -107,12 +107,12 @@ void ValBuilder::End( Val::TypeEnum type ) if ( m_ctx.top().val.Type() == type ) { assert( m_ctx.top().key.Is() ) ; - + // get top Val from stack Val current ; current.Swap( m_ctx.top().val ) ; m_ctx.pop() ; - + Build(current) ; } } diff --git a/libgrive/src/json/ValBuilder.hh b/libgrive/src/json/ValBuilder.hh index efbe5b2a..b9dd4f03 100644 --- a/libgrive/src/json/ValBuilder.hh +++ b/libgrive/src/json/ValBuilder.hh @@ -37,7 +37,7 @@ public : typedef boost::error_info Mismatch_ ; typedef boost::error_info Unexpected_ ; typedef boost::error_info NoKey_ ; - + public : ValBuilder( ) ; ~ValBuilder() ; diff --git a/libgrive/src/json/ValResponse.hh b/libgrive/src/json/ValResponse.hh index cdeca6af..a0881357 100644 --- a/libgrive/src/json/ValResponse.hh +++ b/libgrive/src/json/ValResponse.hh @@ -42,7 +42,7 @@ public : void Finish() ; Val Response() const ; - + private : ValBuilder m_val ; JsonParser m_parser ; diff --git a/libgrive/src/protocol/AuthAgent.cc b/libgrive/src/protocol/AuthAgent.cc index 745f274c..9e684655 100644 --- a/libgrive/src/protocol/AuthAgent.cc +++ b/libgrive/src/protocol/AuthAgent.cc @@ -21,8 +21,10 @@ #include "http/Error.hh" #include "http/Header.hh" +#include "http/XmlResponse.hh" #include "util/log/Log.hh" #include "util/OS.hh" +#include "util/File.hh" #include @@ -56,7 +58,7 @@ long AuthAgent::Put( long response ; while ( CheckRetry( response = m_agent->Put(url, data, dest, auth) ) ) ; - + return CheckHttpResponse(response, url, auth) ; } @@ -67,11 +69,24 @@ long AuthAgent::Put( const Header& hdr ) { Header auth = AppendHeader(hdr) ; - + long response ; - while ( CheckRetry( - response = m_agent->Put( url, file, dest, AppendHeader(hdr) ) ) ) ; - + bool keepTrying = true; + while ( keepTrying ) { + response = m_agent->Put( url, file, dest, auth ); + keepTrying = CheckRetry( response ); + if ( keepTrying ) { + file->Seek( 0, SEEK_SET ); + XmlResponse *xmlResponse = dynamic_cast(dest); + if( xmlResponse ) + xmlResponse->Clear(); + } + } + + // On 410 Gone or 412 Precondition failed, recovery may be possible so don't + // throw an exception + if ( response == 410 || response == 412 ) + return response; return CheckHttpResponse(response, url, auth) ; } @@ -85,7 +100,7 @@ long AuthAgent::Get( long response ; while ( CheckRetry( response = m_agent->Get( url, dest, AppendHeader(hdr) ) ) ) ; - + return CheckHttpResponse(response, url, auth) ; } @@ -96,11 +111,11 @@ long AuthAgent::Post( 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) ; } @@ -115,7 +130,7 @@ long AuthAgent::Custom( long response ; while ( CheckRetry( response = m_agent->Custom( method, url, dest, AppendHeader(hdr) ) ) ) ; - + return CheckHttpResponse(response, url, auth) ; } @@ -139,19 +154,19 @@ 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", + Log( "request 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", + Log( "request failed due to auth token expired: %1%. refreshing token", response, log::warning ) ; - + os::Sleep( 5 ) ; m_auth.Refresh() ; return true ; } @@ -173,7 +188,7 @@ long AuthAgent::CheckHttpResponse( << Url( url ) << HttpHeader( hdr ) ) ; } - + return response ; } diff --git a/libgrive/src/protocol/AuthAgent.hh b/libgrive/src/protocol/AuthAgent.hh index ec939a8d..bd41c63c 100644 --- a/libgrive/src/protocol/AuthAgent.hh +++ b/libgrive/src/protocol/AuthAgent.hh @@ -27,7 +27,7 @@ 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. */ @@ -41,7 +41,7 @@ public : const std::string& data, DataStream *dest, const http::Header& hdr ) ; - + long Put( const std::string& url, File* file, @@ -52,21 +52,21 @@ public : const std::string& url, DataStream *dest, const http::Header& hdr ) ; - + long Post( const std::string& url, const std::string& data, DataStream *dest, const http::Header& hdr ) ; - + long Custom( const std::string& method, const std::string& url, DataStream *dest, const http::Header& hdr ) ; - + std::string RedirLocation() const ; - + std::string Escape( const std::string& str ) ; std::string Unescape( const std::string& str ) ; @@ -77,7 +77,7 @@ private : long response, const std::string& url, const http::Header& hdr ) ; - + private : OAuth2 m_auth ; const std::auto_ptr m_agent ; diff --git a/libgrive/src/protocol/Json.cc b/libgrive/src/protocol/Json.cc index 4c115d6a..dfee446c 100644 --- a/libgrive/src/protocol/Json.cc +++ b/libgrive/src/protocol/Json.cc @@ -149,7 +149,7 @@ Json::Json( const std::vector& arr ) : { if ( m_json == 0 ) BOOST_THROW_EXCEPTION( Error() << JsonCApi_( "json_object_new_array" ) ) ; - + for ( std::vector::const_iterator i = arr.begin() ; i != arr.end() ; ++i ) Add( *i ) ; } @@ -221,7 +221,7 @@ void Json::Swap( Json& other ) Json Json::operator[]( const std::string& key ) const { assert( m_json != 0 ) ; - + struct json_object *j = 0 ; if ( !::json_object_object_get_ex( m_json, key.c_str(), &j ) ) BOOST_THROW_EXCEPTION( @@ -229,7 +229,7 @@ Json Json::operator[]( const std::string& key ) const << JsonCApi_( "json_object_object_get" ) << KeyNotFound_( key ) << Json_( ::json_object_to_json_string(m_json) ) ) ; - + assert( j != 0 ) ; return Json( j ) ; } @@ -247,7 +247,7 @@ Json Json::operator[]( const std::size_t& idx ) const << OutOfRange_( idx ) << Json_( ::json_object_to_json_string(m_json) ) ) ; } - + return Json( j ) ; } @@ -264,7 +264,7 @@ bool Json::Get( const std::string& key, Json& json ) const if ( ::json_object_object_get_ex( m_json, key.c_str(), &j ) ) { assert( j != 0 ) ; - + Json tmp( j ) ; json.Swap( tmp ) ; return true ; @@ -286,7 +286,7 @@ void Json::Add( const Json& json ) { assert( m_json != 0 ) ; assert( json.m_json != 0 ) ; - + ::json_object_get( json.m_json ) ; ::json_object_array_add( m_json, json.m_json ) ; } @@ -389,12 +389,12 @@ Json::Type Json::DataType() const Json::Object Json::AsObject() const { Object result ; - + json_object_object_foreach( m_json, key, val ) { result.insert( Object::value_type( key, Json( val ) ) ) ; } - + return result ; } @@ -415,10 +415,10 @@ Json::Array Json::AsArray() const { std::size_t count = ::json_object_array_length( m_json ) ; Array result ; - + for ( std::size_t i = 0 ; i < count ; ++i ) result.push_back( Json( ::json_object_array_get_idx( m_json, i ) ) ) ; - + return result ; } @@ -441,21 +441,21 @@ Json::Array Json::As() const Json Json::FindInArray( const std::string& key, const std::string& value ) const { std::size_t count = ::json_object_array_length( m_json ) ; - + for ( std::size_t i = 0 ; i < count ; ++i ) { Json item( ::json_object_array_get_idx( m_json, i ) ) ; if ( item.Has(key) && item[key].Str() == value ) return item ; } - + BOOST_THROW_EXCEPTION( Error() << JsonCApi_( "Json::FindInArray" ) << KeyNotFound_( key ) << Value_(value) ) ; - + // shut off compiler warnings return Json() ; } @@ -482,7 +482,7 @@ Json Json::Parse( const std::string& str ) << JsonCApi_( "json_tokener_parse" ) << ValueErr( str ) ) ; - + return Json( json, NotOwned() ) ; } @@ -495,23 +495,23 @@ Json Json::Parse( DataStream *in ) struct json_tokener *tok = ::json_tokener_new() ; struct json_object *json = 0 ; - + char buf[1024] ; std::size_t count = 0 ; while ( (count = in->Read( buf, sizeof(buf) ) ) > 0 ) { json = ::json_tokener_parse_ex( tok, buf, count ) ; - + // check for parse error if ( ::json_tokener_get_error(tok) == ::json_tokener_continue ) break ; } - + // save the error code and free the tokener before throwing exceptions ::json_tokener_error err = ::json_tokener_get_error(tok) ; ::json_tokener_free( tok ) ; tok = 0 ; - + if ( err != json_tokener_success || json == 0 ) { BOOST_THROW_EXCEPTION( @@ -520,7 +520,7 @@ Json Json::Parse( DataStream *in ) << ErrMsg_( ::json_tokener_error_desc(err) ) ) ; } - + return Json( json, NotOwned() ) ; } diff --git a/libgrive/src/protocol/Json.hh b/libgrive/src/protocol/Json.hh index 320f9d71..bf193863 100644 --- a/libgrive/src/protocol/Json.hh +++ b/libgrive/src/protocol/Json.hh @@ -59,25 +59,25 @@ public : public : template explicit Json( const T& val ) ; - + template explicit Json( const char (&str)[n] ) : m_json( InitStr( str, n ) ) { } - + Json() ; Json( const Json& rhs ) ; Json( const char *str ) ; ~Json() ; - + static Json Parse( const std::string& str ) ; static Json Parse( DataStream *in ) ; - + Json operator[]( const std::string& key ) const ; Json operator[]( const std::size_t& idx ) const ; Json& operator=( const Json& rhs ) ; - + void Swap( Json& other ) ; std::string Str() const ; @@ -89,17 +89,17 @@ public : template bool Is() const ; - + template T As() const ; - + bool Has( const std::string& key ) const ; bool Get( const std::string& key, Json& json ) const ; void Add( const std::string& key, const Json& json ) ; void Add( const Json& json ) ; Json FindInArray( const std::string& key, const std::string& value ) const ; bool FindInArray( const std::string& key, const std::string& value, Json& result ) const ; - + /** Expect *this is a JSON array of objects. Select all "key" values inside each objects in the array and copies them in the output iterator \a out. */ @@ -115,17 +115,17 @@ public : } return out ; } - + friend std::ostream& operator<<( std::ostream& os, const Json& json ) ; void Write( DataStream *out ) const ; enum Type { null_type, bool_type, double_type, int_type, object_type, array_type, string_type } ; - + Type DataType() const ; - + private : Json( struct json_object *json ) ; - + struct NotOwned {} ; Json( struct json_object *json, NotOwned ) ; diff --git a/libgrive/src/protocol/JsonResponse.hh b/libgrive/src/protocol/JsonResponse.hh index 2b6322f7..8768bb69 100644 --- a/libgrive/src/protocol/JsonResponse.hh +++ b/libgrive/src/protocol/JsonResponse.hh @@ -38,7 +38,7 @@ public : std::size_t Read( char *data, std::size_t count ) ; Json Response() const ; - + private : StringResponse m_resp ; } ; diff --git a/libgrive/src/protocol/OAuth2.cc b/libgrive/src/protocol/OAuth2.cc index 5d2c1727..bd738fee 100644 --- a/libgrive/src/protocol/OAuth2.cc +++ b/libgrive/src/protocol/OAuth2.cc @@ -80,10 +80,10 @@ std::string OAuth2::MakeAuthURL( return "https://accounts.google.com/o/oauth2/auth" "?scope=" + - h.Escape( "https://www.googleapis.com/auth/userinfo.email" ) + "+" + + h.Escape( "https://www.googleapis.com/auth/userinfo.email" ) + "+" + h.Escape( "https://www.googleapis.com/auth/userinfo.profile" ) + "+" + - h.Escape( "https://docs.google.com/feeds/" ) + "+" + - h.Escape( "https://docs.googleusercontent.com/" ) + "+" + + h.Escape( "https://docs.google.com/feeds/" ) + "+" + + h.Escape( "https://docs.googleusercontent.com/" ) + "+" + h.Escape( "https://spreadsheets.google.com/feeds/" ) + "&redirect_uri=urn:ietf:wg:oauth:2.0:oob" "&response_type=code" @@ -100,7 +100,7 @@ void OAuth2::Refresh( ) http::JsonResponse resp ; http::CurlAgent http ; - + DisableLog dlog( log::debug ) ; http.Post( token_url, post, &resp, http::Header() ) ; diff --git a/libgrive/src/protocol/OAuth2.hh b/libgrive/src/protocol/OAuth2.hh index e8713f3e..93bba9e6 100644 --- a/libgrive/src/protocol/OAuth2.hh +++ b/libgrive/src/protocol/OAuth2.hh @@ -35,26 +35,26 @@ public : const std::string& client_secret ) ; std::string Str() const ; - + static std::string MakeAuthURL( const std::string& client_id, const std::string& state = std::string() ) ; void Auth( const std::string& auth_code ) ; void Refresh( ) ; - + std::string RefreshToken( ) const ; std::string AccessToken( ) const ; - + // adding HTTP auth header std::string HttpHeader( ) const ; - + private : std::string m_access ; std::string m_refresh ; - + const std::string m_client_id ; const std::string m_client_secret ; } ; - + } // end of namespace diff --git a/libgrive/src/util/CArray.hh b/libgrive/src/util/CArray.hh index d48e89bf..baba9d30 100644 --- a/libgrive/src/util/CArray.hh +++ b/libgrive/src/util/CArray.hh @@ -25,10 +25,10 @@ namespace gr { /*! \brief get the begin iterator from an array \internal - + This function returns the begin "iterator" of an array. It is useful to treat an array like an STL container. - + For example: \code int array[10] = { 1, 2, 3, 4, 5 } ; @@ -48,10 +48,10 @@ T* Begin( T (&array)[n] ) /*! \brief get the end iterator from an array \internal - + This function returns the end "iterator" of an array. It is useful to treat an array like an STL container. - + \param array reference to the array \return the end iterator of the array. i.e. \a array+n \sa Begin(), Count() diff --git a/libgrive/src/util/Config.cc b/libgrive/src/util/Config.cc index b5a9f15b..dfdbd430 100644 --- a/libgrive/src/util/Config.cc +++ b/libgrive/src/util/Config.cc @@ -31,18 +31,21 @@ 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 = "."; +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 + m_cmd.Add( "force", Json(vm.count("force") > 0 ) ) ; + m_cmd.Add( "uploadonly",Json(vm.count("uploadonly") > 0 ) ) ; + m_cmd.Add( "path", Json(vm.count("path") > 0 ? vm["path"].as() : default_root_folder ) ) ; - + m_cmd.Add( "dir", Json(vm.count("dir") > 0 + ? vm["dir"].as() + : "" ) ) ; m_path = GetPath( fs::path(m_cmd["path"].Str()) ) ; m_file = Read( ) ; } @@ -82,10 +85,10 @@ 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 ) ; } diff --git a/libgrive/src/util/Config.hh b/libgrive/src/util/Config.hh index e2c0423f..b4e83e32 100644 --- a/libgrive/src/util/Config.hh +++ b/libgrive/src/util/Config.hh @@ -42,7 +42,7 @@ public : 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 ; @@ -56,12 +56,12 @@ private : 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 --git a/libgrive/src/util/Crypt.cc b/libgrive/src/util/Crypt.cc index 5fb8ebe8..66b496ba 100644 --- a/libgrive/src/util/Crypt.cc +++ b/libgrive/src/util/Crypt.cc @@ -66,7 +66,7 @@ std::string MD5::Get() const { unsigned char *md5 = ::gcry_md_read( m_impl->hd, GCRY_MD_MD5 ) ; unsigned int len = ::gcry_md_get_algo_dlen(GCRY_MD_MD5) ; - + // format the MD5 string std::ostringstream ss ; for ( unsigned int i = 0 ; i < len ; i++ ) @@ -91,7 +91,7 @@ std::string MD5::Get( const fs::path& file ) std::string MD5::Get( File& file ) { MD5 crypt ; - + u64_t size = file.Size() ; for ( u64_t i = 0 ; i < size ; i += read_size ) { diff --git a/libgrive/src/util/Crypt.hh b/libgrive/src/util/Crypt.hh index dcd8dd34..3db4637e 100644 --- a/libgrive/src/util/Crypt.hh +++ b/libgrive/src/util/Crypt.hh @@ -44,7 +44,7 @@ public : static std::string Get( File& file ) ; static std::string Get( const boost::filesystem::path& file ) ; - + void Write( const void *data, std::size_t size ) ; std::string Get() const ; diff --git a/libgrive/src/util/DataStream.hh b/libgrive/src/util/DataStream.hh index 819c8f8a..e6623b7a 100644 --- a/libgrive/src/util/DataStream.hh +++ b/libgrive/src/util/DataStream.hh @@ -30,7 +30,7 @@ class DataStream { protected : virtual ~DataStream() {} - + public : /** Reading from the stream. The caller indicates that it wants to read `size` bytes and must provide enough space pointed diff --git a/libgrive/src/util/DateTime.cc b/libgrive/src/util/DateTime.cc index ffb4ec57..a2803699 100644 --- a/libgrive/src/util/DateTime.cc +++ b/libgrive/src/util/DateTime.cc @@ -86,7 +86,7 @@ DateTime DateTime::Now() << boost::errinfo_errno(errno) ) ; } - + return DateTime( tv.tv_sec, tv.tv_usec * 1000 ) ; } @@ -96,7 +96,7 @@ std::string DateTime::Format( const std::string& format ) const char tmp[1024] ; std::size_t count = ::strftime( tmp, sizeof(tmp), format.c_str(), &tp ) ; - return count > 0 ? std::string( tmp, count ) : "" ; + return count > 0 ? std::string( tmp, count ) : "" ; } struct tm DateTime::Tm() const @@ -129,7 +129,7 @@ std::ostream& operator<<( std::ostream& os, const DateTime& dt ) struct timeval DateTime::Tv() const { assert( m_nsec < 1000000000 ) ; - + timeval result ; result.tv_sec = m_sec ; result.tv_usec = m_nsec / 1000 ; diff --git a/libgrive/src/util/DateTime.hh b/libgrive/src/util/DateTime.hh index eb19f318..d017e0b9 100644 --- a/libgrive/src/util/DateTime.hh +++ b/libgrive/src/util/DateTime.hh @@ -35,26 +35,26 @@ public : explicit DateTime( std::time_t sec, unsigned long nsec = 0 ) ; void Assign( std::time_t sec, unsigned long nsec = 0 ) ; - + static DateTime Now() ; - + std::time_t Sec( ) const ; unsigned long NanoSec( ) const ; std::string Format( const std::string& format ) const ; - + tm Tm() const ; timeval Tv() const ; - + bool operator==( const DateTime& dt ) const ; bool operator!=( const DateTime& dt ) const ; bool operator>( const DateTime& dt ) const ; bool operator>=( const DateTime& dt ) const ; bool operator<( const DateTime& dt ) const ; bool operator<=( const DateTime& dt ) const ; - + void Swap( DateTime& dt ) ; std::string ToString() const ; - + private : std::time_t m_sec ; unsigned long m_nsec ; diff --git a/libgrive/src/util/Exception.hh b/libgrive/src/util/Exception.hh index f1515841..803fd511 100644 --- a/libgrive/src/util/Exception.hh +++ b/libgrive/src/util/Exception.hh @@ -42,7 +42,7 @@ struct Exception : virtual public boost::exception { Exception( ) ; - + virtual const char* what() const throw() ; } ; diff --git a/libgrive/src/util/File.cc b/libgrive/src/util/File.cc index 375cd625..a2367a52 100644 --- a/libgrive/src/util/File.cc +++ b/libgrive/src/util/File.cc @@ -48,7 +48,7 @@ using namespace gr ; 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) ) { @@ -58,7 +58,7 @@ off_t LSeek( int fd, off_t offset, int whence ) << boost::errinfo_errno(errno) ) ; } - + return r ; } @@ -104,7 +104,7 @@ File::File( const fs::path& path, int mode ) : m_fd( -1 ) OpenForWrite( path, mode ) ; } -/** The destructor will close the file. +/** The destructor will close the file. */ File::~File( ) { @@ -115,7 +115,7 @@ void File::Open( const fs::path& path, int flags, int mode ) { if ( IsOpened() ) Close() ; - + assert( m_fd == -1 ) ; m_fd = ::open( path.string().c_str(), flags, mode ) ; if ( m_fd == -1 ) @@ -209,9 +209,9 @@ off_t File::Tell() const u64_t File::Size() const { assert( IsOpened() ) ; - + struct stat s = FStat(m_fd) ; - + assert( s.st_size >= 0 ) ; return static_cast( s.st_size ) ; } @@ -219,7 +219,7 @@ u64_t File::Size() const void File::Chmod( int mode ) { assert( IsOpened() ) ; -#ifndef WIN32 +#ifndef WIN32 if ( ::fchmod( m_fd, mode ) != 0 ) { BOOST_THROW_EXCEPTION( @@ -235,7 +235,7 @@ void File::Chmod( int mode ) void* File::Map( off_t offset, std::size_t length ) { assert( IsOpened() ) ; - + #ifdef WIN32 assert( false ) ; return 0 ; diff --git a/libgrive/src/util/File.hh b/libgrive/src/util/File.hh index 041c5998..355781b7 100644 --- a/libgrive/src/util/File.hh +++ b/libgrive/src/util/File.hh @@ -57,14 +57,14 @@ public : void OpenForWrite( const fs::path& path, int mode = 0600 ) ; void Close() ; bool IsOpened() const ; - + std::size_t Read( char *ptr, std::size_t size ) ; std::size_t Write( const char *ptr, std::size_t size ) ; 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 ) ; @@ -74,9 +74,9 @@ public : private : void Open( const fs::path& path, int flags, int mode ) ; - + private : int m_fd ; } ; - + } // end of namespace diff --git a/libgrive/src/util/Function.hh b/libgrive/src/util/Function.hh index 197418f0..3dcd02e3 100644 --- a/libgrive/src/util/Function.hh +++ b/libgrive/src/util/Function.hh @@ -27,7 +27,7 @@ namespace gr { namespace impl { template class FuncImpl ; - + template class FuncImpl { public : @@ -43,7 +43,7 @@ namespace impl virtual FuncImpl* Clone() const = 0 ; virtual ~FuncImpl() {} } ; - + template class FuncImpl { public : @@ -54,23 +54,23 @@ namespace impl template struct FuncTrait ; - + struct NullType {} ; - + template struct FuncTrait { typedef R ReturnType ; typedef NullType Param1Type ; typedef NullType Param2Type ; } ; - + template struct FuncTrait { typedef R ReturnType ; typedef P1 Param1Type ; typedef NullType Param2Type ; } ; - + template struct FuncTrait { typedef R ReturnType ; @@ -83,11 +83,11 @@ namespace impl public : explicit FuncHolder( const F& f ) : m_func( f ) { } FuncHolder* Clone() const { return new FuncHolder( *this ) ; } - + typedef typename FuncTrait::ReturnType ReturnType ; - + ReturnType operator()() { return m_func(); } - + ReturnType operator()( typename FuncTrait::Param1Type p1) { return m_func(p1); @@ -103,7 +103,7 @@ namespace impl private : F m_func ; } ; - + template struct NullFunc { @@ -123,7 +123,7 @@ namespace impl return ReturnType() ; } } ; - + template FuncHolder* MakeFuncHolder( F func ) { @@ -148,7 +148,7 @@ public : m_pimpl( impl::MakeFuncHolder( f ) ) { } - + Function& operator=( const Function& f ) { Function tmp( f ) ; @@ -160,17 +160,17 @@ public : } typedef typename impl::FuncTrait::ReturnType ReturnType ; - + ReturnType operator()( ) { return (*m_pimpl)() ; } - + template ReturnType operator()( P1 p1 ) { return (*m_pimpl)( p1 ) ; } - + template ReturnType operator()( P1 p1, P2 p2 ) { return (*m_pimpl)( p1, p2 ) ; diff --git a/libgrive/src/util/MemMap.cc b/libgrive/src/util/MemMap.cc index 12b1f780..005eeaa0 100644 --- a/libgrive/src/util/MemMap.cc +++ b/libgrive/src/util/MemMap.cc @@ -32,7 +32,7 @@ MemMap::~MemMap() { File::UnMap( m_addr, m_length ) ; } - + void* MemMap::Addr() const { return m_addr ; diff --git a/libgrive/src/util/MemMap.hh b/libgrive/src/util/MemMap.hh index b8ca5a26..143e710d 100644 --- a/libgrive/src/util/MemMap.hh +++ b/libgrive/src/util/MemMap.hh @@ -35,7 +35,7 @@ public : public : MemMap( File& file, off_t offset, std::size_t length ) ; ~MemMap() ; - + void* Addr() const ; std::size_t Length() const ; diff --git a/libgrive/src/util/OS.cc b/libgrive/src/util/OS.cc index 5bf2f663..ed1cb247 100644 --- a/libgrive/src/util/OS.cc +++ b/libgrive/src/util/OS.cc @@ -56,7 +56,7 @@ DateTime FileCTime( const std::string& filename ) << boost::errinfo_file_name(filename) ) ; } - + #if defined __APPLE__ && defined __DARWIN_64_BIT_INO_T return DateTime( s.st_ctimespec.tv_sec, s.st_ctimespec.tv_nsec ) ; #else @@ -84,7 +84,7 @@ void SetFileTime( const std::string& filename, const DateTime& t ) void Sleep( unsigned int sec ) { struct timespec ts = { sec, 0 } ; - + int result = 0 ; do { diff --git a/libgrive/src/util/OS.hh b/libgrive/src/util/OS.hh index 31ab51de..a91d72ec 100644 --- a/libgrive/src/util/OS.hh +++ b/libgrive/src/util/OS.hh @@ -32,13 +32,13 @@ class Path ; namespace os { struct Error : virtual Exception {} ; - + DateTime FileCTime( const std::string& filename ) ; DateTime FileCTime( const fs::path& filename ) ; - + void SetFileTime( const std::string& filename, const DateTime& t ) ; void SetFileTime( const fs::path& filename, const DateTime& t ) ; - + void Sleep( unsigned int sec ) ; } diff --git a/libgrive/src/util/SignalHandler.cc b/libgrive/src/util/SignalHandler.cc index 43328ee1..34745752 100644 --- a/libgrive/src/util/SignalHandler.cc +++ b/libgrive/src/util/SignalHandler.cc @@ -42,15 +42,6 @@ SignalHandler::SignalHandler() } -SignalHandler::SignalHandler( const SignalHandler& right ) -{ - -} - -SignalHandler& SignalHandler::operator ==( const SignalHandler& right ) -{ - return (*this); -} SignalHandler::~SignalHandler() { @@ -65,31 +56,25 @@ SignalHandler& SignalHandler::GetInstance() void SignalHandler::UnregisterSignal( unsigned int signumber ) { - m_signals[signumber] = 0 ; - - // Restore the old signal - signal( ( int ) signumber, m_signalsOld[signumber] ); + if ( m_signals.erase( signumber ) ) + { + signal( ( int ) signumber, m_signalsOld[signumber] ); + } } -void SignalHandler::RegisterSignal( unsigned int signumber, Callback callback ) +void SignalHandler::RegisterSignal( unsigned int signumber, Callback callback ) throw ( SignalError ) { - signals_t::const_iterator anIterator ; - for (anIterator = m_signals.begin(); anIterator != m_signals.end(); ++anIterator) + if ( m_signals.find( signumber ) != m_signals.end() ) { - if (anIterator->first == signumber) - { - if (anIterator->second != 0) - { - std::ostringstream oss; - oss << "Signal " << signumber << " already has a callback!"; - throw SignalError( oss.str() ); ; - } - } + std::ostringstream oss; + oss << "Signal " << signumber << " already has a callback!"; + throw SignalError( oss.str() ); ; } m_signals[signumber] = callback ; - if ( ( m_signalsOld[signumber] = signal( ( int ) signumber, m_signals[signumber] ) ) == SIG_ERR ) { + if ( ( m_signalsOld[signumber] = signal( ( int ) signumber, m_signals[signumber] ) ) == SIG_ERR ) + { throw SignalError( " Error while registering the signal! " ) ; } } diff --git a/libgrive/src/util/SignalHandler.hh b/libgrive/src/util/SignalHandler.hh index 2ef08675..19f0a97d 100644 --- a/libgrive/src/util/SignalHandler.hh +++ b/libgrive/src/util/SignalHandler.hh @@ -32,14 +32,6 @@ public : virtual ~SignalError() throw () ; }; -class SignalFunctor -{ -public : - SignalFunctor() ; - virtual ~SignalFunctor() ; - static void Callback( int signumber ) ; -}; - class SignalHandler { typedef void (*Callback)(int); @@ -47,13 +39,14 @@ class SignalHandler public : virtual ~SignalHandler() ; - void RegisterSignal ( unsigned int signumber, Callback callback ) ; + void RegisterSignal ( unsigned int signumber, Callback callback ) throw ( SignalError ); void UnregisterSignal( unsigned int signumber ); static SignalHandler& GetInstance() ; + private : SignalHandler() ; SignalHandler( const SignalHandler& right ) ; - SignalHandler& operator==( const SignalHandler& right ) ; + SignalHandler& operator=( const SignalHandler& right ) ; signals_t m_signals; signals_t m_signalsOld; diff --git a/libgrive/src/util/StringStream.hh b/libgrive/src/util/StringStream.hh index 600f24c3..a17a38f5 100644 --- a/libgrive/src/util/StringStream.hh +++ b/libgrive/src/util/StringStream.hh @@ -26,16 +26,16 @@ namespace gr { /** \brief DataStream base on `std::string`s - + StringStream is a DataStream back-end that uses std::string for storage. It is useful for unit tests and text parsing, especially when used with StreamParser. - + StringStream has a limit on the maximum number of byte it stores. This is to prevent DOS attacks in which the client sends a lot of bytes before the delimiter (e.g. new-line characters) and the server is forced to hold all of them in memory. - + The limit is current 1024 bytes. */ class StringStream : public DataStream @@ -48,7 +48,7 @@ public : const std::string& Str() const ; void Str( const std::string& str ) ; - + private : std::string m_str ; } ; diff --git a/libgrive/src/util/Types.hh b/libgrive/src/util/Types.hh index a981c6d3..b80fb138 100644 --- a/libgrive/src/util/Types.hh +++ b/libgrive/src/util/Types.hh @@ -25,7 +25,7 @@ namespace gr { using ::off_t ; - + // should use boost/cstdint typedef unsigned long long u64_t ; } diff --git a/libgrive/src/util/log/CommonLog.cc b/libgrive/src/util/log/CommonLog.cc index d9cab059..70ff90b1 100644 --- a/libgrive/src/util/log/CommonLog.cc +++ b/libgrive/src/util/log/CommonLog.cc @@ -34,10 +34,10 @@ CommonLog::CommonLog() bool CommonLog::Enable( log::Serverity s, bool enable ) { assert( s >= debug && s < serverity_count ) ; - + bool prev = m_enabled[s] ; m_enabled[s] = enable ; - + return prev ; } diff --git a/libgrive/src/util/log/CommonLog.hh b/libgrive/src/util/log/CommonLog.hh index a8e910e4..0bb2f359 100644 --- a/libgrive/src/util/log/CommonLog.hh +++ b/libgrive/src/util/log/CommonLog.hh @@ -29,10 +29,10 @@ class CommonLog : public LogBase { public : CommonLog() ; - + bool Enable( log::Serverity s, bool enable = true ) ; bool IsEnabled( log::Serverity s ) const ; - + private : std::bitset m_enabled ; } ; diff --git a/libgrive/src/util/log/CompositeLog.cc b/libgrive/src/util/log/CompositeLog.cc index 6c9140ab..306d6a7e 100644 --- a/libgrive/src/util/log/CompositeLog.cc +++ b/libgrive/src/util/log/CompositeLog.cc @@ -38,7 +38,7 @@ CompositeLog::~CompositeLog() { std::for_each( m_logs.begin(), m_logs.end(), Destroy() ) ; } - + LogBase* CompositeLog::Add( std::auto_ptr log ) { m_logs.push_back( log.get() ) ; diff --git a/libgrive/src/util/log/CompositeLog.hh b/libgrive/src/util/log/CompositeLog.hh index 6efe3be0..3a533849 100644 --- a/libgrive/src/util/log/CompositeLog.hh +++ b/libgrive/src/util/log/CompositeLog.hh @@ -31,7 +31,7 @@ class CompositeLog : public CommonLog public : CompositeLog() ; ~CompositeLog() ; - + LogBase* Add( std::auto_ptr log ) ; void Log( const log::Fmt& msg, log::Serverity s ) ; diff --git a/libgrive/src/util/log/DefaultLog.cc b/libgrive/src/util/log/DefaultLog.cc index 6f4c64d0..5c17387c 100644 --- a/libgrive/src/util/log/DefaultLog.cc +++ b/libgrive/src/util/log/DefaultLog.cc @@ -47,7 +47,7 @@ void DefaultLog::Log( const log::Fmt& msg, log::Serverity s ) case log::info: m_log << msg << std::endl ; break ; - + default: m_log << msg << std::endl ; break ; diff --git a/libgrive/src/util/log/DefaultLog.hh b/libgrive/src/util/log/DefaultLog.hh index 60e92e16..03917449 100644 --- a/libgrive/src/util/log/DefaultLog.hh +++ b/libgrive/src/util/log/DefaultLog.hh @@ -33,7 +33,7 @@ public : explicit DefaultLog( const std::string& filename ) ; void Log( const log::Fmt& msg, log::Serverity s ) ; - + private : std::ofstream m_file ; std::ostream& m_log ; diff --git a/libgrive/src/util/log/Log.cc b/libgrive/src/util/log/Log.cc index b93e1b7f..84a3d530 100644 --- a/libgrive/src/util/log/Log.cc +++ b/libgrive/src/util/log/Log.cc @@ -29,7 +29,7 @@ public : void Log( const log::Fmt&, log::Serverity ) { } - + bool Enable( log::Serverity, bool enable ) { return enable ; @@ -43,10 +43,10 @@ public : LogBase* LogBase::Inst( std::auto_ptr log ) { static std::auto_ptr inst( new MockLog ) ; - + if ( log.get() != 0 ) inst = log ; - + assert( inst.get() != 0 ) ; return inst.get() ; } diff --git a/libgrive/src/util/log/Log.hh b/libgrive/src/util/log/Log.hh index 0d43adbb..0480865e 100644 --- a/libgrive/src/util/log/Log.hh +++ b/libgrive/src/util/log/Log.hh @@ -31,28 +31,28 @@ namespace log { /// user unfriendly messages. only meant for developers. debug, - + /// enabled only if -V is specified. grive tries to tell you every /// single thing it tries to do. verbose, - + /// notification messages indicates nothing is going wrong info, - + /// potential error messages warning, - + /// an error has occurs but grive doesn't need to quit error, - + /// grive cannot proceed critical, - - + + /// must be put at the end, equal to number of serverities serverity_count } ; - + typedef boost::format Fmt ; } @@ -64,7 +64,7 @@ public : virtual void Log( const log::Fmt& msg, log::Serverity s = log::info ) = 0 ; virtual bool Enable( log::Serverity s, bool enable = true ) = 0 ; virtual bool IsEnabled( log::Serverity s ) const = 0 ; - + static LogBase* Inst( std::auto_ptr log = std::auto_ptr() ) ; ~LogBase() ; diff --git a/libgrive/src/xml/Node.cc b/libgrive/src/xml/Node.cc index abed0c4e..b7e4d925 100644 --- a/libgrive/src/xml/Node.cc +++ b/libgrive/src/xml/Node.cc @@ -45,7 +45,7 @@ public : Impl() : m_ref(1), m_type( element ) { } - + Impl( const std::string& str, Type type, const std::string& value = "" ) : m_ref(1), m_type( type ), @@ -53,7 +53,7 @@ public : m_value( value ) { } - + ~Impl() { std::for_each( m_children.begin(), m_children.end(), std::mem_fun( &Impl::Release ) ) ; @@ -64,13 +64,13 @@ public : ++m_ref ; return this ; } - + void Release() { if ( --m_ref == 0 ) delete this ; } - + std::size_t RefCount() const { assert( m_ref > 0 ) ; @@ -81,9 +81,9 @@ public : { assert( child != 0 ) ; assert( child->m_type >= element && child->m_type <= text ) ; - + ImplVec *map[] = { &m_element, &m_attr, 0 } ; - + if ( map[child->m_type] != 0 ) { ImplVec& vec = *map[child->m_type] ; @@ -93,10 +93,10 @@ public : // cannot allow duplicate attribute nodes if ( child->m_type == attr && p.first != p.second ) BOOST_THROW_EXCEPTION( Error() << DupAttr_( child->m_name ) ) ; - + vec.insert( p.second, child ) ; } - + m_children.push_back( child ) ; } @@ -105,67 +105,67 @@ public : assert( !name.empty() ) ; return name[0] == '@' - ? Find( m_attr, name.substr(1) ) + ? Find( m_attr, name.substr(1) ) : Find( m_element, name ) ; } - + Impl* FindAttr( const std::string& name ) { std::pair r = Find( m_attr, name ) ; return r.first != r.second ? *r.first : 0 ; } - + iterator Begin() { return m_children.begin() ; } - + iterator End() { return m_children.end() ; } - + const_iterator Begin() const { return m_children.begin() ; } - + const_iterator End() const { return m_children.end() ; } - + std::size_t Size() const { return m_children.size() ; } - + Range Attr() { return std::make_pair( m_attr.begin(), m_attr.end() ) ; } - + const std::string& Name() const { return m_name ; } - + std::string Value() const { assert( m_type != element || m_value.empty() ) ; - + std::string value = m_value ; for ( const_iterator i = Begin() ; i != End() ; ++i ) value += (*i)->Value() ; return value ; } - + void Value( const std::string& val ) { m_value = val ; } - + Type GetType() const { return m_type ; @@ -188,7 +188,7 @@ private : private : std::size_t m_ref ; - + Type m_type ; std::string m_name ; std::string m_value ; @@ -211,7 +211,7 @@ Node::iterator::reference Node::iterator::dereference() const { Impl *p = *base_reference() ; assert( p != 0 ) ; - + return Node( p->AddRef() ) ; } @@ -264,7 +264,7 @@ bool Node::IsCompatible( Type parent, Type child ) { false, false, true }, // attribute { false, false, false } // text } ; - + assert( parent >= element && parent <= text ) ; assert( child >= element && child <= text ) ; return map[parent][child] ; @@ -274,7 +274,7 @@ Node Node::AddElement( const std::string& name ) { assert( m_ptr != 0 ) ; assert( IsCompatible( GetType(), element) ) ; - + Impl *child = new Impl( name, element ) ; m_ptr->Add( child->AddRef() ) ; return Node( child ) ; @@ -302,7 +302,7 @@ void Node::AddNode( const Node& node ) assert( m_ptr != 0 ) ; assert( node.m_ptr != 0 ) ; assert( IsCompatible( GetType(), node.GetType() ) ) ; - + m_ptr->Add( node.m_ptr->AddRef() ) ; } @@ -316,7 +316,7 @@ NodeSet Node::operator[]( const std::string& name ) const { assert( m_ptr != 0 ) ; assert( !name.empty() ) ; - + Range is = m_ptr->Find( name ) ; return NodeSet( iterator(is.first), iterator(is.second) ) ; } @@ -342,7 +342,7 @@ const std::string& Node::Name() const std::string Node::Value() const { assert( m_ptr != 0 ) ; - + return m_ptr->Value() ; } @@ -361,13 +361,13 @@ std::ostream& operator<<( std::ostream& os, const Node& node ) if ( node.GetType() == Node::element ) { os << '<' << node.Name() ; - + // print attributes NodeSet attrs = node.Attr() ; if ( !attrs.empty() ) os << ' ' << attrs ; os << '>' ; - + // recursively print children for ( Node::iterator i = node.begin() ; i != node.end() ; ++i ) { @@ -386,7 +386,7 @@ std::ostream& operator<<( std::ostream& os, const Node& node ) { Node::PrintString( os, node.Value() ) ; } - + return os ; } diff --git a/libgrive/src/xml/Node.hh b/libgrive/src/xml/Node.hh index fb4b6c43..916a1dc8 100644 --- a/libgrive/src/xml/Node.hh +++ b/libgrive/src/xml/Node.hh @@ -37,7 +37,7 @@ class Node private : class Impl ; typedef std::vector ImplVec ; - + public : class iterator ; @@ -50,10 +50,10 @@ public : static Node Element( const std::string& name ) ; static Node Text( const std::string& name ) ; - + Node& operator=( const Node& node ) ; void Swap( Node& node ) ; - + Node AddElement( const std::string& name ) ; Node AddText( const std::string& text ) ; void AddNode( const Node& node ) ; @@ -63,13 +63,13 @@ public : NodeSet operator[]( const std::string& name ) const ; operator std::string() const ; bool operator==( const std::string& value ) const ; - + const std::string& Name() const ; std::string Value() const ; - + // read-only access to the reference counter. for checking. std::size_t RefCount() const ; - + enum Type { element, attr, text } ; Type GetType() const ; @@ -81,16 +81,16 @@ public : iterator end() const ; std::size_t size() const ; NodeSet Children() const ; - + NodeSet Attr() const ; std::string Attr( const std::string& attr ) const ; bool HasAttr( const std::string& attr ) const ; - + private : explicit Node( Impl *impl ) ; typedef std::pair Range ; - + private : Impl *m_ptr ; } ; @@ -105,11 +105,11 @@ class Node::iterator : public boost::iterator_adaptor< { public : iterator( ) ; - explicit iterator( ImplVec::iterator i ) ; + explicit iterator( ImplVec::iterator i ) ; private : friend class boost::iterator_core_access; - + reference dereference() const ; } ; diff --git a/libgrive/src/xml/NodeSet.cc b/libgrive/src/xml/NodeSet.cc index 42d5c488..f2c18822 100644 --- a/libgrive/src/xml/NodeSet.cc +++ b/libgrive/src/xml/NodeSet.cc @@ -108,7 +108,7 @@ void NodeSet::Add( const Node& n ) } m_tmp.AddNode( n ) ; - + // the iterators may be invalidated after adding the node m_first = m_tmp.begin() ; m_last = m_tmp.end() ; @@ -129,7 +129,7 @@ Node NodeSet::front() const { if ( empty() ) BOOST_THROW_EXCEPTION( Error() << EmptyNodeSet_(0) ) ; - + return *m_first ; } diff --git a/libgrive/src/xml/NodeSet.hh b/libgrive/src/xml/NodeSet.hh index 8820a8fd..768e5fb0 100644 --- a/libgrive/src/xml/NodeSet.hh +++ b/libgrive/src/xml/NodeSet.hh @@ -43,22 +43,22 @@ public : NodeSet& operator=( const NodeSet& ns ) ; void Swap( NodeSet& ns ) ; - + void Add( const Node& n ) ; - + iterator begin() const ; iterator end() const ; bool empty() const ; std::size_t size() const ; Node front() const ; - + NodeSet Find( const std::string& name, const std::string& value ) const ; // forwarding common Node operations to Node operator std::string() const ; NodeSet operator[]( const std::string& name ) const ; bool operator==( const std::string& value ) const ; - + private : Node m_tmp ; iterator m_first ; diff --git a/libgrive/src/xml/TreeBuilder.cc b/libgrive/src/xml/TreeBuilder.cc index c1ad385a..028aadab 100644 --- a/libgrive/src/xml/TreeBuilder.cc +++ b/libgrive/src/xml/TreeBuilder.cc @@ -21,6 +21,7 @@ #include "Error.hh" #include "Node.hh" +#include "util/log/Log.hh" #include @@ -40,11 +41,11 @@ TreeBuilder::TreeBuilder() : m_impl( new Impl ) { m_impl->stack.push_back( Node() ) ; m_impl->psr = ::XML_ParserCreate( 0 ) ; - + ::XML_SetElementHandler( m_impl->psr, &TreeBuilder::StartElement, &TreeBuilder::EndElement ) ; ::XML_SetCharacterDataHandler( m_impl->psr, &TreeBuilder::OnCharData ) ; ::XML_SetUserData( m_impl->psr , this ) ; - + is_new = true ; } @@ -56,15 +57,15 @@ Node TreeBuilder::ParseFile( const std::string& file ) { TreeBuilder tb ; ::XML_Parser p = tb.m_impl->psr ; - + std::ifstream f( file.c_str() ) ; - + const std::size_t block_size = 10 ; std::size_t count = 0 ; while ( (count = f.rdbuf()->sgetn( (char*)::XML_GetBuffer( p, block_size ), block_size ) ) > 0 ) XML_ParseBuffer( p, count, false ) ; XML_ParseBuffer( p, 0, true ) ; - + return tb.Result() ; } @@ -72,8 +73,10 @@ void TreeBuilder::ParseData( const char *data, std::size_t count, bool last ) { is_new = false ; - if ( ::XML_Parse( m_impl->psr, data, count, last ) == 0 ) + if ( ::XML_Parse( m_impl->psr, data, count, last ) == 0 ) { + Log("Error parsing XML: %1%", data, log::error); BOOST_THROW_EXCEPTION( Error() << ExpatApiError("XML_Parse") ); + } } Node TreeBuilder::Parse( const std::string& xml ) @@ -87,10 +90,10 @@ Node TreeBuilder::Result() const { // the node on the stack should be the dummy node with only one child assert( m_impl->stack.size() == 1 ) ; - + if ( m_impl->stack.front().size() != 1 ) BOOST_THROW_EXCEPTION( Error() << LogicError(0) ) ; - + return *m_impl->stack.front().begin() ; } @@ -101,22 +104,22 @@ void TreeBuilder::StartElement( void *pvthis, const char *name, const char **att assert( attr != 0 ) ; TreeBuilder *pthis = reinterpret_cast(pvthis) ; - + Node n = pthis->m_impl->stack.back().AddElement( name ) ; - + for ( std::size_t i = 0 ; attr[i] != 0 ; i += 2 ) { assert( attr[i+1] != 0 ) ; n.AddAttribute( attr[i], attr[i+1] ) ; } - + pthis->m_impl->stack.push_back( n ) ; } void TreeBuilder::EndElement( void* pvthis, const char* name ) { TreeBuilder *pthis = reinterpret_cast(pvthis) ; - + assert( pthis->m_impl->stack.back().Name() == name ) ; pthis->m_impl->stack.pop_back() ; } diff --git a/libgrive/src/xml/TreeBuilder.hh b/libgrive/src/xml/TreeBuilder.hh index fe71a996..15548088 100644 --- a/libgrive/src/xml/TreeBuilder.hh +++ b/libgrive/src/xml/TreeBuilder.hh @@ -37,10 +37,10 @@ public : public : TreeBuilder() ; ~TreeBuilder() ; - + void ParseData( const char *data, std::size_t count, bool last = false ) ; Node Result( ) const ; - + // one shot helpers static Node ParseFile( const std::string& file ) ; static Node Parse( const std::string& xml ) ; @@ -48,7 +48,7 @@ public : bool is_new ; private : - + static void StartElement( void* pvthis, const char* name, const char** attr ) ; static void EndElement( void* pvthis, const char* name ) ; static void OnCharData( void *pvthis, const char *s, int len ) ; diff --git a/libgrive/test/Assert.hh b/libgrive/test/Assert.hh index 6863ce16..ac9b1881 100644 --- a/libgrive/test/Assert.hh +++ b/libgrive/test/Assert.hh @@ -56,7 +56,7 @@ namespace grut { act << *actualFirst++ << " " ; exp << *expectFirst++ << " " ; } - + CPPUNIT_NS::Asserter::failNotEqual( exp.str(), act.str(), @@ -64,7 +64,7 @@ namespace grut { message ); } } - + inline void AssertEquals( const std::wstring& expected, const std::wstring& actual, @@ -77,7 +77,7 @@ namespace grut { sourceLine, message ) ; } - + } // end of namespace #define GRUT_ASSERT_RANGE_EQUAL(actualFirst, actualLast, expectFirst) \ diff --git a/libgrive/test/UnitTest.cc b/libgrive/test/UnitTest.cc index 19dcf503..7b485753 100644 --- a/libgrive/test/UnitTest.cc +++ b/libgrive/test/UnitTest.cc @@ -18,6 +18,10 @@ */ #include +#include +#include + +#include #include "util/log/DefaultLog.hh" @@ -34,9 +38,9 @@ int main( int argc, char **argv ) { using namespace grut ; - + gr::LogBase::Inst( std::auto_ptr(new gr::log::DefaultLog) ) ; - + CppUnit::TextUi::TestRunner runner; runner.addTest( EntryTest::suite( ) ) ; runner.addTest( StateTest::suite( ) ) ; @@ -48,6 +52,10 @@ int main( int argc, char **argv ) runner.addTest( SignalHandlerTest::suite( ) ) ; runner.addTest( NodeTest::suite( ) ) ; runner.run(); - + + std::ofstream report_file( "report.xml" ) ; + CppUnit::XmlOutputter xmloutputter ( &runner.result( ), report_file ) ; + xmloutputter.write( ) ; + report_file.close( ) ; return 0 ; } diff --git a/libgrive/test/btest/JsonValTest.cc b/libgrive/test/btest/JsonValTest.cc index d5087cdf..3a81c57c 100644 --- a/libgrive/test/btest/JsonValTest.cc +++ b/libgrive/test/btest/JsonValTest.cc @@ -41,16 +41,16 @@ BOOST_AUTO_TEST_CASE( Test ) ValBuilder b ; JsonParser::Parse( "{\"key\": 100 }", &b ) ; Val json = b.Result() ; - + BOOST_CHECK( json.Is() ) ; BOOST_CHECK_EQUAL( json["key"].As(), 100 ) ; - + StringStream ss ; JsonWriter wr( &ss ) ; json.Visit( &wr ) ; - + BOOST_CHECK_EQUAL( ss.Str(), "{\"key\":100}" ) ; - + // std::cout << ss.Str() << std::endl ; } diff --git a/libgrive/test/btest/ValTest.cc b/libgrive/test/btest/ValTest.cc index 5514825e..19d22b96 100644 --- a/libgrive/test/btest/ValTest.cc +++ b/libgrive/test/btest/ValTest.cc @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE( TestSimpleTypes ) Val null ; BOOST_CHECK_EQUAL( null.Type(), Val::null_type ) ; BOOST_CHECK( null.Is() ) ; - + Val i( 100 ) ; BOOST_CHECK_EQUAL( i.As(), 100 ) ; BOOST_CHECK_EQUAL( i.Type(), Val::int_type ) ; diff --git a/libgrive/test/drive/EntryTest.cc b/libgrive/test/drive/EntryTest.cc index 48dfa5c7..041f9085 100644 --- a/libgrive/test/drive/EntryTest.cc +++ b/libgrive/test/drive/EntryTest.cc @@ -40,19 +40,19 @@ EntryTest::EntryTest( ) void EntryTest::TestXml( ) { xml::Node root = xml::TreeBuilder::ParseFile( TEST_DATA "entry.xml" ) ; - + CPPUNIT_ASSERT( !root["entry"].empty() ) ; - + Entry subject( root["entry"].front() ) ; GRUT_ASSERT_EQUAL( "snes", subject.Title() ) ; GRUT_ASSERT_EQUAL( "\"WxYPGE8CDyt7ImBk\"", subject.ETag() ) ; GRUT_ASSERT_EQUAL( "https://docs.google.com/feeds/default/private/full/folder%3A0B5KhdsbryVeGMl83OEV1ZVc3cUE", subject.SelfHref() ) ; - + GRUT_ASSERT_EQUAL( 1U, subject.ParentHrefs().size() ) ; GRUT_ASSERT_EQUAL( "https://docs.google.com/feeds/default/private/full/folder%3A0B5KhdsbryVeGNEZjdUxzZHl3Sjg", subject.ParentHrefs().front() ) ; - + GRUT_ASSERT_EQUAL( "folder", subject.Kind() ) ; } diff --git a/libgrive/test/drive/ResourceTest.cc b/libgrive/test/drive/ResourceTest.cc index 5f69c427..a506a9ce 100644 --- a/libgrive/test/drive/ResourceTest.cc +++ b/libgrive/test/drive/ResourceTest.cc @@ -50,16 +50,16 @@ void ResourceTest::TestNormal( ) Resource root( TEST_DATA, "folder" ) ; Resource subject( "entry.xml", "file" ) ; root.AddChild( &subject ) ; - + GRUT_ASSERT_EQUAL( subject.Path(), fs::path( TEST_DATA ) / "entry.xml" ) ; - + subject.FromLocal( DateTime() ) ; GRUT_ASSERT_EQUAL( subject.MD5(), "c0742c0a32b2c909b6f176d17a6992d0" ) ; GRUT_ASSERT_EQUAL( subject.StateStr(), "local_new" ) ; - + xml::Node entry = xml::Node::Element( "entry" ) ; entry.AddElement( "updated" ).AddText( "2012-05-09T16:13:22.401Z" ) ; - + Entry remote( entry ) ; subject.FromRemote( remote, DateTime() ) ; GRUT_ASSERT_EQUAL( "local_changed", subject.StateStr() ) ; diff --git a/libgrive/test/drive/ResourceTreeTest.cc b/libgrive/test/drive/ResourceTreeTest.cc index 22285ade..ad26f35b 100644 --- a/libgrive/test/drive/ResourceTreeTest.cc +++ b/libgrive/test/drive/ResourceTreeTest.cc @@ -37,7 +37,7 @@ ResourceTreeTest::ResourceTreeTest( ) void ResourceTreeTest::TestSerialize( ) { - + } } // end of namespace grut diff --git a/libgrive/test/http/MockAgent.hh b/libgrive/test/http/MockAgent.hh index d348e62d..7a9f94b5 100644 --- a/libgrive/test/http/MockAgent.hh +++ b/libgrive/test/http/MockAgent.hh @@ -31,7 +31,7 @@ class MockAgent : public Agent { public : MockAgent() ; - + long Put( const std::string& url, const std::string& data, @@ -42,21 +42,21 @@ public : const std::string& url, Receivable *dest, const Header& hdr ) ; - + long Post( const std::string& url, const std::string& data, Receivable *dest, const Header& hdr ) ; - + long Custom( const std::string& method, const std::string& url, Receivable *dest, const Header& hdr ) ; - + std::string RedirLocation() const ; - + std::string Escape( const std::string& str ) ; std::string Unescape( const std::string& str ) ; } ; diff --git a/libgrive/test/util/DateTimeTest.cc b/libgrive/test/util/DateTimeTest.cc index 341c3a85..3cb30541 100644 --- a/libgrive/test/util/DateTimeTest.cc +++ b/libgrive/test/util/DateTimeTest.cc @@ -63,17 +63,17 @@ void DateTimeTest::TestOffByOne( ) void DateTimeTest::TestCompare( ) { DateTime s1( 1000, 2000 ), s2( 1001, 2000 ), s3( 1000, 2001 ), s4( 1001, 2000 ) ; - + CPPUNIT_ASSERT( s1 < s3 ) ; CPPUNIT_ASSERT( s1 <= s3 ) ; CPPUNIT_ASSERT( s3 > s1 ) ; CPPUNIT_ASSERT( s3 >= s1 ) ; - + CPPUNIT_ASSERT( s1 < s2 ) ; CPPUNIT_ASSERT( s1 <= s2 ) ; CPPUNIT_ASSERT( s2 > s1 ) ; CPPUNIT_ASSERT( s2 >= s1 ) ; - + CPPUNIT_ASSERT( s2 == s4 ) ; CPPUNIT_ASSERT( s2 >= s4 ) ; CPPUNIT_ASSERT( s2 <= s4 ) ; diff --git a/libgrive/test/util/FunctionTest.cc b/libgrive/test/util/FunctionTest.cc index 2b24d2d8..a7d0fd6c 100644 --- a/libgrive/test/util/FunctionTest.cc +++ b/libgrive/test/util/FunctionTest.cc @@ -38,7 +38,7 @@ void FunctionTest::TestRun( ) { Function f = &TestFunction ; Function f2 ; - + CPPUNIT_ASSERT_EQUAL( 3, f(3) ) ; CPPUNIT_ASSERT_EQUAL( std::string(), f2() ) ; } diff --git a/libgrive/test/xml/NodeTest.cc b/libgrive/test/xml/NodeTest.cc index 14e973ba..167b29de 100644 --- a/libgrive/test/xml/NodeTest.cc +++ b/libgrive/test/xml/NodeTest.cc @@ -40,18 +40,18 @@ void NodeTest::TestTree( ) Node node = Node::Element( "root" ) ; GRUT_ASSERT_EQUAL( 1UL, node.RefCount() ) ; GRUT_ASSERT_EQUAL( Node::element, node.GetType() ) ; - + Node c1 = node.AddElement( "child1" ) ; c1.AddText( "this is a line" ) ; Node c11 = c1.AddElement( "b" ) ; GRUT_ASSERT_EQUAL( 2UL, c1.RefCount() ) ; - + Node c2 = node.AddElement( "child2" ) ; Node c0 = node.AddElement( "child0" ) ; - + Node c1_ = node["child1"].front() ; Node c11_ = node["child1"]["b"].front() ; - + GRUT_ASSERT_EQUAL( 3UL, c1_.RefCount() ) ; GRUT_ASSERT_EQUAL( "child1", c1_.Name() ) ; } @@ -60,13 +60,13 @@ void NodeTest::TestParseFile( ) { Node n ; n.AddNode( TreeBuilder::Parse( "abc" ) ) ; - - + + GRUT_ASSERT_EQUAL( "entry", n["entry"].front().Name() ) ; GRUT_ASSERT_EQUAL( "link", n["entry"]["link"].front().Name() ) ; GRUT_ASSERT_EQUAL( "q", n["entry"]["link"]["@href"].front().Value() ) ; GRUT_ASSERT_EQUAL( Node::element, n["entry"]["link"]["href"].front().GetType() ) ; - + GRUT_ASSERT_EQUAL( "abc", n["entry"]["link"]["href"].front().Value() ) ; Node el = n["entry"]["link"].front() ; @@ -76,7 +76,7 @@ void NodeTest::TestParseFile( ) CPPUNIT_ASSERT_EQUAL( std::string("href"), (*i).Name() ) ; ++i ; } - + NodeSet r = n["entry"]["link"] ; GRUT_ASSERT_EQUAL( 2U, r.size() ) ; } diff --git a/package/fedora16/grive.spec b/package/fedora16/grive.spec index 03770b9d..556cdc80 100644 --- a/package/fedora16/grive.spec +++ b/package/fedora16/grive.spec @@ -36,6 +36,7 @@ BuildRequires: expat-devel BuildRequires: openssl-devel BuildRequires: boost-devel BuildRequires: binutils-devel +BuildRequires: yajl-devel %description The purpose of this project is to provide an independent implementation @@ -63,19 +64,24 @@ make %{?_smp_mflags} rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT -%post -p /sbin/ldconfig +# As long as no dynamic libs are build omit ldconfig and the glob for them. +#%post -p /sbin/ldconfig -%postun -p /sbin/ldconfig +#%postun -p /sbin/ldconfig %files -%doc COPYING README +%doc COPYING README %{_bindir}/%{name} -%{_libdir}/libgrive.so.* +%{_bindir}/b%{name} +%{_mandir}/man1/%{name}.1.gz -%files devel -%{_includedir}/%{name}* -%{_libdir}/libgrive.so +#%{_libdir}/libgrive.so.* + +# Files are not installed by cmake currently. +#%files devel +#%{_includedir}/%{name}* +#%{_libdir}/libgrive.so diff --git a/scripts/crontab.txt b/scripts/crontab.txt new file mode 100644 index 00000000..029d6597 --- /dev/null +++ b/scripts/crontab.txt @@ -0,0 +1,5 @@ +# This example runs grive on /home/USER/gdrive +# See man crontab for format +# This line runs at 5 after the hour and 35 after the hour + +5,35 * * * * /usr/bin/grive -p /home/USER/gdrive diff --git a/scripts/grive-incron b/scripts/grive-incron new file mode 100755 index 00000000..cdebc201 --- /dev/null +++ b/scripts/grive-incron @@ -0,0 +1,52 @@ +#!/bin/bash + +# Allow grive to be called from incron +# if your path is /home/User/gdrivef and this file is in /usr/local/bin then use the following incrontab line: +# /home/User/gdrive IN_CREATE,IN_DELETE,IN_CLOSE_WRITE,IN_MOVE /usr/local/bin/grive-incron $# /home/User/gdrive + +# grive-incron a bash script to allow automatic push to gdrive from a directory +# It is made to be called by # incron +# +# Copyright (C) 2014 Al Williams (al.williams@awce.com) +# +# 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/. + +PIDFILE=/tmp/grive-incron.lock + +if [ $# != 2 ] +then + >&2 echo Call from incron: \$# directory + exit 1 +fi +if [ "$1" == .grive -o "$1" == .grive_state ] +then + exit 0 # ignore grive housekeeping files +fi +# Don't run multiple copies at once + +DLY=1 + +while true + do + while [ -f "$PIDFILE" ] && kill -0 `cat "$PIDFILE"` 2>/dev/null + do + sleep $DLY + DLY=$((DLY+1)) + DLY=$((DLY % 10 )) # no more than 10 seconds + done + if ! kill -0 `cat "$PIDFILE" 2>/dev/null` 2>/dev/null + then + rm -f "$PIDFILE" + fi + if (set -o noclobber; echo $$>"$PIDFILE" ) >/dev/null + then + trap 'rm -f "$PIDFILE"' INT TERM EXIT + break + fi +done +grive -p "$2" +rm -f "$PIDFILE" +trap - INT TERM EXIT +exit 0 diff --git a/scripts/incron.txt b/scripts/incron.txt new file mode 100644 index 00000000..99806945 --- /dev/null +++ b/scripts/incron.txt @@ -0,0 +1,3 @@ +# Fix path below (2 places) and location of grive-incron script +/home/USER/gdrive IN_CREATE,IN_DELETE,IN_CLOSE_WRITE,IN_MOVE /usr/bin/grive-incron $# /home/USER/gdrive + diff --git a/scripts/readme.txt b/scripts/readme.txt new file mode 100644 index 00000000..ea661d6a --- /dev/null +++ b/scripts/readme.txt @@ -0,0 +1,40 @@ +This directory contains a simple script that allows calling +grive from incron. This will cause any changes you make +to the local directory to automatically call grive to +update Google Drive. You can copy the script to a location on your +path: + +sudo cp grive-incron /usr/local/bin + +To make this work, you also need to insert the contents of incrontab.txt +into your incrontab (after changing the paths to suit your +installation). + +To do this run: +incrontab -e + +Then use the editor that appears to insert the line with your custom +paths. You can ignore lines that start with # -- they are just comments +although you can paste them into the incrontab if you like. + +To get the reverse, you can do a similar command in your crontab (see +crontab.txt). The example syncs at 5 and 35 minutes after each hour +but you can customize that by changing the crontab line. + +crontab -e + +will bring up an editor. Copy the line without the # in front from +crontab.txt after fixing it for your specific path names. You can +skip the # lines or include them, as before. + +You probably don't want to do a crontab sync every minute because +grive takes some time to run. The grive-incron script stalls if +another copy of it or grive is running for the current user to +prevent overrun, but the crontab entry has on such protection. If you +prefer, you could use the same script with a dummy file name in crontab. +Then your crontab line would look something like this: + +5,35 * * * * /usr/local/bin/grive-incron DUMMY /home/USER/gdrive + +The word DUMMY is just a placeholder. It does not have to refer to a real +file.