not tracking the status of all files/dir in .grive_state

pull/40/head
Matchman Green 2012-05-30 01:30:06 +08:00
parent 167e2eaac5
commit 8b1b388713
12 changed files with 123 additions and 98 deletions

View File

@ -125,7 +125,7 @@ int main( int argc, char **argv )
drive.Update() ;
drive.SaveState() ;
// config.Save() ;
config.Save() ;
}
catch ( gr::Exception& e )
{

View File

@ -59,26 +59,13 @@ Drive::Drive( OAuth2& auth ) :
m_http_hdr.push_back( "Authorization: Bearer " + m_auth.AccessToken() ) ;
m_http_hdr.push_back( "GData-Version: 3.0" ) ;
http::Agent http ;
http::XmlResponse xrsp ;
http.Get( feed_metadata, &xrsp, m_http_hdr ) ;
std::string change_stamp = xrsp.Response()["docs:largestChangestamp"]["@value"] ;
Trace( "change stamp is %1%", change_stamp ) ;
m_state.ChangeStamp( change_stamp ) ;
m_state.FromLocal( "." ) ;
ConstructDirTree( &http ) ;
http::Agent http ;
SyncFolders( &http ) ;
std::string uri = feed_base + "?showfolders=true&showroot=true" ;
/* if ( !change_stamp.empty() )
{
int ichangestamp = std::atoi( change_stamp.c_str() ) + 1 ;
uri = (boost::format( "%1%&start-index=%2%" ) % uri % ichangestamp ).str() ;
}
*/
http.Get( uri, &xrsp, m_http_hdr ) ;
http::XmlResponse xrsp ;
http.Get( feed_base + "?showfolders=true&showroot=true", &xrsp, m_http_hdr ) ;
xml::Node resp = xrsp.Response() ;
m_resume_link = resp["link"].
@ -133,7 +120,7 @@ void Drive::SaveState()
m_state.Write( state_file ) ;
}
void Drive::ConstructDirTree( http::Agent *http )
void Drive::SyncFolders( http::Agent *http )
{
http::XmlResponse xml ;
http->Get( feed_base + "/-/folder?max-results=50&showroot=true", &xml, m_http_hdr ) ;
@ -175,8 +162,7 @@ void Drive::ConstructDirTree( http::Agent *http )
void Drive::Update()
{
http::Agent http ;
std::for_each( m_state.begin(), m_state.end(),
boost::bind( &Resource::Sync, _1, &http, m_http_hdr ) ) ;
m_state.Sync( &http, m_http_hdr ) ;
}
} // end of namespace

View File

@ -47,7 +47,7 @@ public :
struct Error : virtual Exception {} ;
private :
void ConstructDirTree( http::Agent *http ) ;
void SyncFolders( http::Agent *http ) ;
void file();
private :

View File

@ -21,7 +21,7 @@
#include "CommonUri.hh"
#include "http/Download.hh"
#include "http/ResponseLog.hh"
// #include "http/ResponseLog.hh"
#include "http/StringResponse.hh"
#include "http/XmlResponse.hh"
#include "protocol/Json.hh"
@ -56,7 +56,7 @@ Resource::Resource() :
m_state ( sync )
{
}
/*
/// Construct from previously serialized JSON object. The state of the
/// resource is treated as local_deleted by default. It is because the
/// state will be updated by scanning the local directory. If the state
@ -77,7 +77,7 @@ Resource::Resource( const Json& json, Resource *parent ) :
// state as local_changed
FromLocal() ;
}
*/
Resource::Resource( const xml::Node& entry ) :
m_entry ( entry ),
m_parent( 0 ),
@ -114,7 +114,7 @@ void Resource::FromRemote( const Entry& remote )
// if checksum is equal, no need to compare the mtime
else if ( remote.MD5() == m_entry.MD5() )
{
Log( "MD5 matches: %1% is already in sync", Name(), log::verbose ) ;
Log( "MD5 matches: %1% is already in sync", Path(), log::verbose ) ;
m_state = sync ;
}
@ -122,9 +122,14 @@ void Resource::FromRemote( const Entry& remote )
else
{
assert( m_state == local_new || m_state == local_changed || m_state == local_deleted ) ;
m_state = ( remote.MTime() > m_entry.MTime() ? remote_changed : m_state ) ;
m_state = ( m_state == local_new ? local_changed : m_state ) ;
// if remote is modified
if ( remote.MTime() > m_entry.MTime() )
m_state = remote_changed ;
// remote also has the file, so it's not new in local
else if ( m_state == local_new || m_state == local_deleted )
m_state = local_changed ;
Log( "%1% state is %2%", Name(), m_state, log::verbose ) ;
}
@ -132,37 +137,24 @@ void Resource::FromRemote( const Entry& remote )
m_entry.AssignID( remote ) ;
}
void Resource::FromLocal()
/// Update the resource with the attributes of local file or directory. This
/// function will propulate the fields in m_entry.
void Resource::FromLocal( const DateTime& last_sync )
{
fs::path path = Path() ;
assert( fs::exists( path ) ) ;
// root folder is always rsync
if ( m_parent == 0 )
m_state = sync ;
else if ( !fs::exists( path ) )
{
m_state = local_deleted ;
Log( "%1% in state but not exist on disk: %2%", Name(), m_state ) ;
}
else
{
m_state = local_new ;
// assume file is local_deleted?? very strange. change it tomorrow
DateTime mtime = os::FileMTime( path ) ;
m_state = ( mtime > last_sync ? local_new : local_deleted ) ;
// no need to compare MD5 or mtime for directories
if ( !IsFolder() )
{
// to save time, compare mtime before checksum
DateTime mtime = os::FileMTime( path ) ;
if ( mtime > m_entry.MTime() )
{
Log( "%1% mtime newer on disk: %2%", Name(), m_state ) ;
m_entry.Update( crypt::MD5( path ), mtime ) ;
}
else
Log( "%1% unchanged on disk: %2%", Name(), m_state ) ;
}
Log( "%1% found on disk: %2%", Name(), m_state ) ;
}
}
@ -260,31 +252,31 @@ void Resource::Sync( http::Agent *http, const http::Headers& auth )
{
case local_new :
Log( "sync %1% doesn't exist in server. upload \"%2%\"?",
Name(), m_parent->m_entry.CreateLink(), log::verbose ) ;
Path(), m_parent->m_entry.CreateLink(), log::verbose ) ;
if ( Create( http, auth ) )
m_state = sync ;
break ;
case local_deleted :
Log( "sync %1% deleted in local. delete?", m_entry.Filename(), log::verbose ) ;
Log( "sync %1% deleted in local. delete?", Path(), log::verbose ) ;
break ;
case local_changed :
Log( "sync %1% changed in local", m_entry.Filename(), log::verbose ) ;
Log( "sync %1% changed in local", Path(), log::verbose ) ;
if ( EditContent( http, auth ) )
m_state = sync ;
break ;
case remote_new :
case remote_changed :
Log( "sync %1% changed in remote. download?", m_entry.Filename(), log::verbose ) ;
Log( "sync %1% changed in remote. download?", Path(), log::verbose ) ;
Download( http, Path(), auth ) ;
m_state = sync ;
break ;
case sync :
Log( "sync %1% already in sync", m_entry.Filename(), log::verbose ) ;
Log( "sync %1% already in sync", Path(), log::verbose ) ;
break ;
default :

View File

@ -50,7 +50,7 @@ public :
explicit Resource( const xml::Node& entry ) ;
explicit Resource( const Entry& entry, Resource *parent = 0 ) ;
explicit Resource( const fs::path& path ) ;
explicit Resource( const Json& json, Resource *parent = 0 ) ;
// explicit Resource( const Json& json, Resource *parent = 0 ) ;
void Swap( Resource& coll ) ;
// default copy ctor & op= are fine
@ -72,7 +72,7 @@ public :
bool IsRoot() const ;
void FromRemote( const Entry& e ) ;
void FromLocal() ;
void FromLocal( const DateTime& last_sync ) ;
void Sync( http::Agent *http, const http::Headers& auth ) ;
void Delete( http::Agent* http, const http::Headers& auth ) ;
@ -109,7 +109,10 @@ private :
remote_new,
/// Resource exists in both local & remote, but remote is newer.
remote_changed
remote_changed,
/// Resource delete in remote, need to delete in local
remote_deleted
} ;
friend std::ostream& operator<<( std::ostream& os, State s ) ;

View File

@ -177,7 +177,7 @@ ResourceTree::iterator ResourceTree::end()
{
return m_set.get<ByIdentity>().end() ;
}
/*
void ResourceTree::Read( const Json& json )
{
Clear() ;
@ -205,5 +205,5 @@ Json ResourceTree::Serialize() const
{
return m_root->Serialize() ;
}
*/
} // end of namespace

View File

@ -89,12 +89,12 @@ public :
iterator begin() ;
iterator end() ;
void Read( const Json& json ) ;
Json Serialize() const ;
// void Read( const Json& json ) ;
// Json Serialize() const ;
private :
void Clear() ;
void AddTree( Resource *node, const Json& json ) ;
// void AddTree( Resource *node, const Json& json ) ;
private :
details::Folders m_set ;

View File

@ -43,16 +43,6 @@ State::State( const fs::path& filename )
Read( filename ) ;
}
std::string State::ChangeStamp() const
{
return m_change_stamp ;
}
void State::ChangeStamp( const std::string& cs )
{
m_change_stamp = cs ;
}
/// Synchronize local directory. Build up the resource tree from files and folders
/// of local directory.
void State::FromLocal( const fs::path& p )
@ -66,7 +56,7 @@ void State::FromLocal( const fs::path& p, gr::Resource* folder )
assert( folder->IsFolder() ) ;
// sync the folder itself
folder->FromLocal() ;
folder->FromLocal( m_last_sync ) ;
for ( fs::directory_iterator i( p ) ; i != fs::directory_iterator() ; ++i )
{
@ -82,12 +72,13 @@ void State::FromLocal( const fs::path& p, gr::Resource* folder )
Resource *c = folder->FindChild( fname ) ;
if ( c == 0 )
{
Log( "detected new file %1% in local", fname, log::verbose ) ;
c = new Resource( i->path() ) ;
folder->AddChild( c ) ;
m_res.Insert( c ) ;
}
c->FromLocal( m_last_sync ) ;
if ( fs::is_directory( i->path() ) )
FromLocal( *i, c ) ;
}
@ -157,15 +148,23 @@ bool State::Update( const Entry& e )
// the directory
else if ( e.Kind() == "folder" || !e.Filename().empty() )
{
child = new Resource( e ) ;
parent->AddChild( child ) ;
m_res.Insert( child ) ;
fs::path child_path = child->Path() ;
if ( child->IsFolder() && !fs::is_directory( child_path ) )
// TODO: compare the last sync time to determine which one is newer
if ( e.MTime() > m_last_sync )
{
Log( "creating %1% directory", child_path, log::info ) ;
fs::create_directories( child_path ) ;
child = new Resource( e ) ;
parent->AddChild( child ) ;
m_res.Insert( child ) ;
fs::path child_path = child->Path() ;
if ( child->IsFolder() && !fs::is_directory( child_path ) )
{
Log( "creating %1% directory", child_path, log::info ) ;
fs::create_directories( child_path ) ;
}
}
else
{
Trace( "should I delete the local %1%/%2%", parent->Path(), e.Filename() ) ;
}
}
else
@ -202,23 +201,40 @@ State::iterator State::end()
void State::Read( const fs::path& filename )
{
if ( fs::exists( filename ) )
try
{
Json json = Json::ParseFile( filename.string() ) ;
m_change_stamp = json["change_stamp"].Str() ;
m_res.Read( json["rtree"] ) ;
Json last_sync = json["last_sync"] ;
m_last_sync.Assign(
last_sync["sec"].Int(),
last_sync["nsec"].Int() ) ;
}
catch ( Exception& )
{
m_last_sync.Assign(0) ;
}
}
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() ) );
Json result ;
result.Add( "change_stamp", Json( m_change_stamp ) ) ;
result.Add( "rtree", m_res.Serialize() ) ;
result.Add( "last_sync", last_sync ) ;
std::ofstream fs( filename.string().c_str() ) ;
fs << result ;
}
void State::Sync( http::Agent *http, const http::Headers& auth )
{
std::for_each( m_res.begin(), m_res.end(),
boost::bind( &Resource::Sync, _1, http, auth ) ) ;
m_last_sync = DateTime::Now() ;
}
} // end of namespace

View File

@ -20,6 +20,9 @@
#pragma once
#include "ResourceTree.hh"
#include "http/Agent.hh"
#include "util/DateTime.hh"
#include "util/FileSystem.hh"
#include <memory>
@ -45,13 +48,12 @@ public :
void Read( const fs::path& filename ) ;
void Write( const fs::path& filename ) const ;
std::string ChangeStamp() const ;
void ChangeStamp( const std::string& cs ) ;
Resource* FindByHref( const std::string& href ) ;
Resource* FindByID( const std::string& id ) ;
Resource* Find( const fs::path& path ) ;
void Sync( http::Agent *http, const http::Headers& auth ) ;
iterator begin() ;
iterator end() ;
@ -61,8 +63,8 @@ private :
std::size_t TryResolveEntry() ;
private :
ResourceTree m_res ; ;
std::string m_change_stamp ;
ResourceTree m_res ;
DateTime m_last_sync ;
std::vector<Entry> m_unresolved ;
} ;

View File

@ -19,6 +19,15 @@
#include "DateTime.hh"
#include "Exception.hh"
// boost headers
#include <boost/throw_exception.hpp>
#include <boost/exception/errinfo_api_function.hpp>
#include <boost/exception/errinfo_at_line.hpp>
#include <boost/exception/errinfo_errno.hpp>
#include <boost/exception/info.hpp>
#include <sstream>
#include <cassert>
@ -55,15 +64,30 @@ DateTime::DateTime( const std::string& iso ) :
}
}
DateTime::DateTime( std::time_t sec, unsigned long nsec ) :
m_sec ( sec + nsec / 1000000000 ),
m_nsec ( nsec % 1000000000 )
DateTime::DateTime( std::time_t sec, unsigned long nsec )
{
Assign( sec, nsec ) ;
}
void DateTime::Assign( std::time_t sec, unsigned long nsec )
{
m_sec = sec + nsec / 1000000000 ;
m_nsec = nsec % 1000000000 ;
}
DateTime DateTime::Now()
{
return DateTime( std::time(0) ) ;
struct timeval tv = {} ;
if ( ::gettimeofday( &tv, 0 ) != 0 )
{
BOOST_THROW_EXCEPTION(
Exception()
<< boost::errinfo_api_function("gettimeofday")
<< boost::errinfo_errno(errno)
) ;
}
return DateTime( tv.tv_sec, tv.tv_usec * 1000 ) ;
}
std::string DateTime::Format( const std::string& format ) const

View File

@ -34,6 +34,8 @@ public :
explicit DateTime( const std::string& iso ) ;
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 ;

View File

@ -39,7 +39,7 @@ void ResourceTest::TestNormal( )
Json json ;
json.Add( "name", Json( "abc.txt" ) ) ;
Resource subject( json, 0 ) ;
// Resource subject( json, 0 ) ;
}
} // end of namespace grut