From b1589bb18149cd833e56041e4d3c6f6dbfd769bf Mon Sep 17 00:00:00 2001 From: Matchman Green Date: Sun, 20 May 2012 01:44:46 +0800 Subject: [PATCH] clean up sync code --- libgrive/src/drive/Drive.cc | 28 +++------------------ libgrive/src/drive/Entry.cc | 15 +++++++++--- libgrive/src/drive/Entry.hh | 5 ++-- libgrive/src/drive/Resource.cc | 19 +++++++++------ libgrive/src/drive/Resource.hh | 39 +++++++++++++++++++++++------- libgrive/src/drive/ResourceTree.cc | 13 +++++++++- libgrive/src/drive/ResourceTree.hh | 4 +-- libgrive/src/drive/State.cc | 21 +++++++++------- libgrive/src/drive/State.hh | 7 +++--- libgrive/test/drive/StateTest.cc | 2 +- 10 files changed, 89 insertions(+), 64 deletions(-) diff --git a/libgrive/src/drive/Drive.cc b/libgrive/src/drive/Drive.cc index 9fc3fb5..87839a9 100644 --- a/libgrive/src/drive/Drive.cc +++ b/libgrive/src/drive/Drive.cc @@ -67,7 +67,7 @@ Drive::Drive( OAuth2& auth ) : Trace( "change stamp is %1%", change_stamp ) ; m_state.ChangeStamp( change_stamp ) ; - m_state.Sync( "." ) ; + m_state.FromLocal( "." ) ; ConstructDirTree( &http ) ; @@ -108,7 +108,7 @@ Drive::Drive( OAuth2& auth ) : file.Title(), p->Name() ) ; else - m_state.OnEntry( file ) ; + m_state.FromRemote( file ) ; } } @@ -146,9 +146,8 @@ void Drive::ConstructDirTree( http::Agent *http ) if ( e.Kind() == "folder" ) { if ( e.ParentHrefs().size() == 1 ) - { - m_state.OnEntry( e ) ; - } + m_state.FromRemote( e ) ; + else Log( "folder \"%1%\" has multiple parents, ignored", e.Title(), log::warning ) ; } @@ -164,26 +163,7 @@ void Drive::ConstructDirTree( http::Agent *http ) m_state.ResolveEntry() ; } -/* -void Drive::UpdateFile( Entry& entry, Resource *parent, http::Agent *http ) -{ - assert( parent != 0 ) ; - // only handle uploaded files - if ( !entry.Filename().empty() ) - { - Resource *file = new Resource( entry ) ; - parent->AddChild( file ) ; - m_files.push_back( file ) ; - - Trace( "%1% ID = %2%", file->Path(), file->ResourceID() ) ; - } - else - { - Log( "file \"%1%\" is a google document, ignored", entry.Title() ) ; - } -} -*/ void Drive::Update() { http::Agent http ; diff --git a/libgrive/src/drive/Entry.cc b/libgrive/src/drive/Entry.cc index 8b4adcd..2c39333 100644 --- a/libgrive/src/drive/Entry.cc +++ b/libgrive/src/drive/Entry.cc @@ -20,6 +20,7 @@ #include "Entry.hh" #include "CommonUri.hh" +#include "util/Crypt.hh" #include "util/Log.hh" #include "util/OS.hh" #include "xml/Node.hh" @@ -30,10 +31,6 @@ namespace gr { -Entry::Entry( const Path& file ) -{ -} - Entry::Entry( const xml::Node& n ) { Update( n ) ; @@ -47,6 +44,16 @@ Entry::Entry( const std::string& title, const std::string& kind, const std::stri { } +/// construct an entry from a file or folder in local directory +Entry::Entry( const fs::path& path ) : + m_title ( path.filename().string() ), + m_filename ( path.filename().string() ), + m_kind ( fs::is_directory(path) ? "folder" : "file" ), + m_server_md5 ( crypt::MD5( path ) ), + m_server_modified( os::FileMTime( path ) ) +{ +} + void Entry::Update( const xml::Node& n ) { m_title = n["title"] ; diff --git a/libgrive/src/drive/Entry.hh b/libgrive/src/drive/Entry.hh index 841a0d4..4a0f982 100644 --- a/libgrive/src/drive/Entry.hh +++ b/libgrive/src/drive/Entry.hh @@ -20,6 +20,7 @@ #pragma once #include "util/DateTime.hh" +#include "util/FileSystem.hh" #include #include @@ -32,8 +33,6 @@ namespace xml class Node ; } -class Path ; - /*! \brief corresponds to an "entry" in the resource feed This class is decodes an entry in the resource feed. It will stored the properties like @@ -42,7 +41,7 @@ class Path ; class Entry { public : - explicit Entry( const Path& file ) ; + explicit Entry( const fs::path& path ) ; explicit Entry( const xml::Node& n ) ; Entry( const std::string& title, const std::string& kind, const std::string& href ) ; diff --git a/libgrive/src/drive/Resource.cc b/libgrive/src/drive/Resource.cc index d9350c8..85ba866 100644 --- a/libgrive/src/drive/Resource.cc +++ b/libgrive/src/drive/Resource.cc @@ -38,14 +38,16 @@ namespace gr { Resource::Resource( const xml::Node& entry ) : - m_entry ( entry ), - m_parent ( 0 ) + m_entry ( entry ), + m_parent( 0 ), + m_state ( new_remote ) { } Resource::Resource( const Entry& entry, Resource *parent ) : - m_entry ( entry ), - m_parent ( parent ) + m_entry ( entry ), + m_parent( parent ), + m_state ( new_remote ) { } @@ -54,12 +56,15 @@ Resource::Resource( const std::string& kind, const std::string& href ) : m_entry ( name, kind, href ), - m_parent( 0 ) + m_parent( 0 ), + m_state ( new_local ) { } -void Resource::Update( const Entry& e ) +void Resource::FromRemote( const Entry& e ) { + Trace( "%1% state is %2%", e.Title(), m_state ) ; + m_state = sync ; m_entry = e ; } @@ -201,7 +206,7 @@ bool Resource::Upload( http::Agent* http, std::streambuf *file, const http::Head // upload link missing means that file is read only if ( m_entry.UploadLink().empty() ) { - Log( "Cannot upload %1%: file read-only.", m_entry.Title(), log::warning ) ; + Log( "Cannot upload %1%: file read-only. %2%", m_entry.Title(), m_state, log::warning ) ; return false ; } diff --git a/libgrive/src/drive/Resource.hh b/libgrive/src/drive/Resource.hh index d49ead0..92e1749 100644 --- a/libgrive/src/drive/Resource.hh +++ b/libgrive/src/drive/Resource.hh @@ -30,6 +30,11 @@ namespace gr { +/*! \brief A resource can be a file or a folder in the google drive + + The google drive contains a number of resources, which is represented by this class. + It also contains linkage to other resources, such as parent and childrens. +*/ class Resource { public : @@ -45,28 +50,42 @@ public : void Swap( Resource& coll ) ; // default copy ctor & op= are fine - + + bool IsFolder() const ; + std::string Name() const ; std::string SelfHref() const ; std::string ResourceID() const ; + std::string ParentHref() const ; const Resource* Parent() const ; Resource* Parent() ; - std::string ParentHref() const ; + void AddChild( Resource *child ) ; + Resource* FindChild( const std::string& title ) ; fs::path Path() const ; bool IsInRootTree() const ; - bool IsFolder() const ; - - void AddChild( Resource *child ) ; - - Resource* FindChild( const std::string& title ) ; - void Update( const Entry& e ) ; - + void FromRemote( const Entry& e ) ; void Update( http::Agent *http, const http::Headers& auth ) ; void Delete( http::Agent* http, const http::Headers& auth ) ; +private : + /// State of the resource. indicating what to do with the resource + enum State + { + /// The best state: the file is the same in google drive and in local. + sync, + + /// Resource created in local, but google drive does not have it. + /// We should create the resource in google drive and upload new content + new_local, + + /// Resource created in google drive, but not exist in local. + /// We should download the file. + new_remote + } ; + private : void Download( http::Agent* http, const fs::path& file, const http::Headers& auth ) const ; bool Upload( http::Agent* http, std::streambuf *file, const http::Headers& auth ) ; @@ -77,6 +96,8 @@ private : // not owned Resource *m_parent ; std::vector m_child ; + + State m_state ; } ; } // end of namespace diff --git a/libgrive/src/drive/ResourceTree.cc b/libgrive/src/drive/ResourceTree.cc index 2a7f940..e3f4923 100644 --- a/libgrive/src/drive/ResourceTree.cc +++ b/libgrive/src/drive/ResourceTree.cc @@ -99,6 +99,15 @@ const Resource* ResourceTree::FindByHref( const std::string& href ) const return i != map.end() ? *i : 0 ; } +/// Unlike other search functions, this one does not depend on the multi-index +/// container. It traverses the tree instead. +Resource* ResourceTree::FindByPath( const fs::path& path ) +{ + // not yet implemented + assert( false ) ; + return false ; +} + /// Reinsert should be called when the ID/HREF were updated bool ResourceTree::ReInsert( Resource *coll ) { @@ -127,7 +136,9 @@ void ResourceTree::Erase( Resource *coll ) void ResourceTree::Update( Resource *coll, const Entry& e ) { - coll->Update( e ) ; + assert( coll != 0 ) ; + + coll->FromRemote( e ) ; ReInsert( coll ) ; } diff --git a/libgrive/src/drive/ResourceTree.hh b/libgrive/src/drive/ResourceTree.hh index f3b35c1..eec869c 100644 --- a/libgrive/src/drive/ResourceTree.hh +++ b/libgrive/src/drive/ResourceTree.hh @@ -72,9 +72,9 @@ public : Resource* FindByHref( const std::string& href ) ; const Resource* FindByHref( const std::string& href ) const ; + Resource* FindByPath( const fs::path& path ) ; + bool ReInsert( Resource *coll ) ; -// void SetID( Collection *coll, const std::string& id ) ; -// void SetHref( Collection *coll, const std::string& href ) ; void Insert( Resource *coll ) ; void Erase( Resource *coll ) ; diff --git a/libgrive/src/drive/State.cc b/libgrive/src/drive/State.cc index e2598b8..71cfb39 100644 --- a/libgrive/src/drive/State.cc +++ b/libgrive/src/drive/State.cc @@ -59,12 +59,14 @@ void State::ChangeStamp( const std::string& cs ) m_change_stamp = cs ; } -void State::Sync( const fs::path& p ) +/// Synchronize local directory. Build up the resource tree from files and folders +/// of local directory. +void State::FromLocal( const fs::path& p ) { - Sync( p, m_folders.Root() ) ; + FromLocal( p, m_folders.Root() ) ; } -void State::Sync( const fs::path& p, gr::Resource* folder ) +void State::FromLocal( const fs::path& p, gr::Resource* folder ) { assert( folder != 0 ) ; assert( folder->IsFolder() ) ; @@ -77,11 +79,12 @@ void State::Sync( const fs::path& p, gr::Resource* folder ) folder->AddChild( c ) ; m_folders.Insert( c ) ; - Sync( *i, c ) ; + FromLocal( *i, c ) ; } - else if ( i->path().filename().string()[0] != '.' ) + else if ( i->path().filename().string()[0] == '.' ) + Log( "file %1% is ignored by grive", i->path().filename().string(), log::info ) ; + else { -// Trace( "file: %1% %2%", i->path().filename().string(), folder->Path() ) ; Resource *c = new Resource( i->path().filename().string(), "file", "" ) ; folder->AddChild( c ) ; m_folders.Insert( c ) ; @@ -102,7 +105,7 @@ void State::SetId( const fs::path& p, const std::string& id ) { } -void State::OnEntry( const Entry& e ) +void State::FromRemote( const Entry& e ) { if ( !Update( e ) ) { @@ -152,6 +155,8 @@ bool State::Update( const Entry& e ) Resource *child = parent->FindChild( e.Title() ) ; if ( child != 0 ) { + assert( child == m_folders.FindByHref( e.SelfHref() ) ) ; + // since we are updating the ID and Href, we need to remove it and re-add it. m_folders.Update( child, e ) ; } @@ -165,8 +170,6 @@ bool State::Update( const Entry& e ) m_folders.Insert( child ) ; fs::path child_path = child->Path() ; - Trace( "added %1%", child_path ) ; - if ( child->IsFolder() && !fs::is_directory( child_path ) ) { Log( "creating %1% directory", child_path, log::info ) ; diff --git a/libgrive/src/drive/State.hh b/libgrive/src/drive/State.hh index f3adb33..8eeb53e 100644 --- a/libgrive/src/drive/State.hh +++ b/libgrive/src/drive/State.hh @@ -38,9 +38,8 @@ public : public : explicit State( const fs::path& filename ) ; - void Sync( const fs::path& p ) ; - - void OnEntry( const Entry& e ) ; + void FromLocal( const fs::path& p ) ; + void FromRemote( const Entry& e ) ; void ResolveEntry() ; void SetId( const fs::path& p, const std::string& id ) ; @@ -58,7 +57,7 @@ public : iterator end() ; private : - void Sync( const fs::path& p, Resource *folder ) ; + void FromLocal( const fs::path& p, Resource *folder ) ; bool Update( const Entry& e ) ; std::size_t TryResolveEntry() ; diff --git a/libgrive/test/drive/StateTest.cc b/libgrive/test/drive/StateTest.cc index 6d36528..9771d06 100644 --- a/libgrive/test/drive/StateTest.cc +++ b/libgrive/test/drive/StateTest.cc @@ -36,7 +36,7 @@ StateTest::StateTest( ) void StateTest::TestSync( ) { State s( ".grive_state" ) ; - s.Sync( TEST_DATA ) ; + s.FromLocal( TEST_DATA ) ; s.Write( "" ) ; }