Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic inotify support #73

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 30 additions & 0 deletions cmake/Modules/FindINotifyTools.cmake
@@ -0,0 +1,30 @@
# - Find INOTIFYTOOLS
# This module finds an installed INOTIFYTOOLS package.
#
# It sets the following variables:
# INOTIFYTOOLS_FOUND - Set to false, or undefined, if INOTIFYTOOLS isn't found.
# INOTIFYTOOLS_INCLUDE_DIR - The INOTIFYTOOLS include directory.
# INOTIFYTOOLS_LIBRARY - The INOTIFYTOOLS library to link against.

FIND_PATH(INOTIFYTOOLS_INCLUDE_DIR inotifytools/inotifytools.h)
FIND_LIBRARY(INOTIFYTOOLS_LIBRARY NAMES inotifytools)

IF (INOTIFYTOOLS_INCLUDE_DIR AND INOTIFYTOOLS_LIBRARY)
SET(INOTIFYTOOLS_FOUND TRUE)
ENDIF (INOTIFYTOOLS_INCLUDE_DIR AND INOTIFYTOOLS_LIBRARY)

IF (INOTIFYTOOLS_FOUND)

# show which INOTIFYTOOLS was found only if not quiet
IF (NOT INOTIFYTOOLS_FIND_QUIETLY)
MESSAGE(STATUS "Found INOTIFYTOOLS: ${INOTIFYTOOLS_LIBRARY}")
ENDIF (NOT INOTIFYTOOLS_FIND_QUIETLY)

ELSE (INOTIFYTOOLS_FOUND)

# fatal error if INOTIFYTOOLS is required but not found
IF (INOTIFYTOOLS_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find INOTIFYTOOLS")
ENDIF (INOTIFYTOOLS_FIND_REQUIRED)

ENDIF (INOTIFYTOOLS_FOUND)
1 change: 1 addition & 0 deletions grive/CMakeLists.txt
Expand Up @@ -19,6 +19,7 @@ add_executable( grive_executable

target_link_libraries( grive_executable
${Boost_LIBRARIES}
${INotifyTools_LIBRARY}
grive
)

Expand Down
48 changes: 46 additions & 2 deletions grive/src/main.cc
Expand Up @@ -37,10 +37,15 @@
// initializing libgcrypt, must be done in executable
#include <gcrypt.h>

// inotify for watching local filesystem changes
#include <inotifytools/inotify.h>
#include <inotifytools/inotifytools.h>

#include <cassert>
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <regex.h>

const std::string client_id = "22314510474.apps.googleusercontent.com" ;
const std::string client_secret = "bl4ufi89h-9MkFlypcI7R785" ;
Expand Down Expand Up @@ -86,6 +91,7 @@ int Main( int argc, char **argv )
"instead of uploading it." )
( "dry-run", "Only detect which files need to be uploaded/downloaded, "
"without actually performing them." )
( "watch,w", "Watch folder for changes." )
;

po::variables_map vm;
Expand Down Expand Up @@ -167,7 +173,7 @@ 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;
}

Expand All @@ -178,10 +184,48 @@ int Main( int argc, char **argv )
{
drive.Update() ;
drive.SaveState() ;

if ( vm.count( "watch" ) )
{
inotifytools_ignore_events_by_regex( ".grive*", REG_EXTENDED) ;

struct inotify_event * event ;
while ( true )
{
if ( !inotifytools_initialize() ||
!inotifytools_watch_recursively( ".", IN_MODIFY |
IN_MOVE | IN_DELETE | IN_CREATE ))
{
Log( "Unable to initialize inotify!", log::critical ) ;
break ;
}

// Wait up to 5 mins for a local file change.
// After 5 mins we will update the drive regardless
// in order to pull any potential changes from
// the remote Google Drive
event = inotifytools_next_event( 300 ) ;
if (event != 0)
Log( "Local file change detected: %s", event->name, log::info ) ;
else
Log( "No local file change, polling remote Google Drive", log::info ) ;

// Remove all watches as we only need coarse grain
// file change notifications. Any events still in the
// queue can be discarded
inotifytools_cleanup();

// Wait for changes to accumulate
sleep(10);

drive.Update() ;
drive.SaveState() ;
}
}
}
else
drive.DryRun() ;

config.Save() ;
Log( "Finished!", log::info ) ;
return 0 ;
Expand Down
2 changes: 2 additions & 0 deletions libgrive/CMakeLists.txt
Expand Up @@ -11,6 +11,7 @@ find_package(BFD)
find_package(CppUnit)
find_package(Iberty)
find_package(ZLIB)
find_package(INotifyTools REQUIRED)

# additional headers if build unit tests
IF ( CPPUNIT_FOUND )
Expand Down Expand Up @@ -84,6 +85,7 @@ target_link_libraries( grive
${Boost_LIBRARIES}
${IBERTY_LIBRARY}
${EXPAT_LIBRARY}
${INOTIFYTOOLS_LIBRARY}
${OPT_LIBS}
)

Expand Down
84 changes: 42 additions & 42 deletions libgrive/src/drive/Drive.cc
Expand Up @@ -60,46 +60,6 @@ Drive::Drive( OAuth2& auth, const Json& options ) :
m_http_hdr.Add( "Authorization: Bearer " + m_auth.AccessToken() ) ;
m_http_hdr.Add( "GData-Version: 3.0" ) ;

Log( "Reading local directories", log::info ) ;
m_state.FromLocal( "." ) ;

http::CurlAgent http ;

long prev_stamp = m_state.ChangeStamp() ;
Trace( "previous change stamp is %1%", prev_stamp ) ;

// get metadata
http::XmlResponse xrsp ;
// http::ResponseLog log( "meta-", ".xml", &xrsp ) ;
http.Get( "https://docs.google.com/feeds/metadata/default", &xrsp, m_http_hdr ) ;
m_state.ChangeStamp(
std::atoi(xrsp.Response()["docs:largestChangestamp"]["@value"].front().Value().c_str()) ) ;

SyncFolders( &http ) ;

Log( "Reading remote server file list", log::info ) ;
http.Get( feed_base + "?showfolders=true&showroot=true", &xrsp, m_http_hdr ) ;
xml::Node resp = xrsp.Response() ;

m_resume_link = resp["link"].
Find( "@rel", "http://schemas.google.com/g/2005#resumable-create-media" )["@href"] ;

Feed feed( resp ) ;
do
{
std::for_each( feed.begin(), feed.end(), boost::bind( &Drive::FromRemote, this, _1 ) ) ;
} while ( feed.GetNext( &http, m_http_hdr ) ) ;

// pull the changes feed
if ( prev_stamp != -1 )
{
boost::format changes_uri( "https://docs.google.com/feeds/default/private/changes?start-index=%1%" ) ;
// http::ResponseLog log2( "changes-", ".xml", &xrsp ) ;
http.Get( (changes_uri%(prev_stamp+1)).str(), &xrsp, m_http_hdr ) ;

Feed changes( xrsp.Response() ) ;
std::for_each( changes.begin(), changes.end(), boost::bind( &Drive::FromChange, this, _1 ) ) ;
}
}

void Drive::FromRemote( const Entry& entry )
Expand Down Expand Up @@ -171,10 +131,50 @@ void Drive::SyncFolders( http::Agent *http )

void Drive::Update()
{
Log( "Synchronizing files", log::info ) ;
Log( "Reading local directories", log::info ) ;
m_state.FromLocal( "." ) ;

http::CurlAgent http ;
m_state.Sync( &http, m_http_hdr ) ;

long prev_stamp = m_state.ChangeStamp() ;
Trace( "previous change stamp is %1%", prev_stamp ) ;

// get metadata
http::XmlResponse xrsp ;
// http::ResponseLog log( "meta-", ".xml", &xrsp ) ;
http.Get( "https://docs.google.com/feeds/metadata/default", &xrsp, m_http_hdr ) ;
m_state.ChangeStamp(
std::atoi(xrsp.Response()["docs:largestChangestamp"]["@value"].front().Value().c_str()) ) ;

SyncFolders( &http ) ;

Log( "Reading remote server file list", log::info ) ;
http.Get( feed_base + "?showfolders=true&showroot=true", &xrsp, m_http_hdr ) ;
xml::Node resp = xrsp.Response() ;

m_resume_link = resp["link"].
Find( "@rel", "http://schemas.google.com/g/2005#resumable-create-media" )["@href"] ;

Feed feed( resp ) ;
do
{
std::for_each( feed.begin(), feed.end(), boost::bind( &Drive::FromRemote, this, _1 ) ) ;
} while ( feed.GetNext( &http, m_http_hdr ) ) ;

// pull the changes feed
if ( prev_stamp != -1 )
{
boost::format changes_uri( "https://docs.google.com/feeds/default/private/changes?start-index=%1%" ) ;
// http::ResponseLog log2( "changes-", ".xml", &xrsp ) ;
http.Get( (changes_uri%(prev_stamp+1)).str(), &xrsp, m_http_hdr ) ;

Feed changes( xrsp.Response() ) ;
std::for_each( changes.begin(), changes.end(), boost::bind( &Drive::FromChange, this, _1 ) ) ;
}
Log( "Synchronizing files", log::info ) ;

http::CurlAgent http2 ;
m_state.Sync( &http2, m_http_hdr ) ;
}

void Drive::DryRun()
Expand Down