mirror of https://github.com/vitalif/grive2
added folder init code in state
parent
3a33db68b6
commit
cf77a2d5c4
|
@ -51,6 +51,11 @@ Collection::Collection(
|
|||
{
|
||||
}
|
||||
|
||||
void Collection::Update( const Entry& e )
|
||||
{
|
||||
m_entry = e ;
|
||||
}
|
||||
|
||||
std::string Collection::SelfHref() const
|
||||
{
|
||||
return m_entry.SelfHref() ;
|
||||
|
@ -61,6 +66,11 @@ std::string Collection::Title() const
|
|||
return m_entry.Title() ;
|
||||
}
|
||||
|
||||
std::string Collection::ResourceID() const
|
||||
{
|
||||
return m_entry.ResourceID() ;
|
||||
}
|
||||
|
||||
const Collection* Collection::Parent() const
|
||||
{
|
||||
return m_parent ;
|
||||
|
@ -120,7 +130,7 @@ void Collection::ForEachFile(
|
|||
fs::path Collection::Dir() const
|
||||
{
|
||||
assert( m_parent != this ) ;
|
||||
return m_parent != 0 ? (m_parent->Dir() / m_entry.Title()) : fs::current_path() ;
|
||||
return m_parent != 0 ? (m_parent->Dir() / m_entry.Title()) : "." ;
|
||||
}
|
||||
|
||||
bool Collection::IsInRootTree() const
|
||||
|
@ -128,6 +138,17 @@ bool Collection::IsInRootTree() const
|
|||
return m_parent == 0 ? (SelfHref() == root_href) : m_parent->IsInRootTree() ;
|
||||
}
|
||||
|
||||
Collection* Collection::FindChild( const std::string& title )
|
||||
{
|
||||
for ( std::vector<Collection*>::iterator i = m_child.begin() ; i != m_child.end() ; ++i )
|
||||
{
|
||||
assert( (*i)->m_parent == this ) ;
|
||||
if ( (*i)->Title() == title )
|
||||
return *i ;
|
||||
}
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
} // end of namespace
|
||||
|
||||
namespace std
|
||||
|
|
|
@ -37,6 +37,7 @@ public :
|
|||
explicit Collection( const xml::Node& entry ) ;
|
||||
explicit Collection( const Entry& entry ) ;
|
||||
Collection( const std::string& title, const std::string& href ) ;
|
||||
Collection( const std::string& title, Collection *parent ) ;
|
||||
|
||||
// default copy ctor & op= are fine
|
||||
|
||||
|
@ -47,6 +48,7 @@ public :
|
|||
std::string ParentHref() const ;
|
||||
fs::path Dir() const ;
|
||||
bool IsInRootTree() const ;
|
||||
std::string ResourceID() const ;
|
||||
|
||||
void AddChild( Collection *child ) ;
|
||||
void AddLeaf( File *file ) ;
|
||||
|
@ -61,6 +63,9 @@ public :
|
|||
|
||||
struct Error : virtual Exception {} ;
|
||||
|
||||
Collection* FindChild( const std::string& title ) ;
|
||||
void Update( const Entry& e ) ;
|
||||
|
||||
private :
|
||||
Entry m_entry ;
|
||||
|
||||
|
|
|
@ -69,9 +69,10 @@ Drive::Drive( OAuth2& auth ) :
|
|||
Trace( "change stamp is %1%", change_stamp ) ;
|
||||
|
||||
m_state.ChangeStamp( change_stamp ) ;
|
||||
m_state.Sync( fs::current_path() ) ;
|
||||
m_state.Sync( "." ) ;
|
||||
|
||||
ConstructDirTree( &http ) ;
|
||||
return ;
|
||||
|
||||
std::string uri = feed_base + "?showfolders=true&showroot=true" ;
|
||||
/* if ( !change_stamp.empty() )
|
||||
|
@ -85,15 +86,7 @@ Drive::Drive( OAuth2& auth ) :
|
|||
|
||||
m_resume_link = resp["link"].
|
||||
Find( "@rel", "http://schemas.google.com/g/2005#resumable-create-media" )["@href"] ;
|
||||
|
||||
// change_stamp = resp["docs:largestChangestamp"]["@value"] ;
|
||||
|
||||
// std::ofstream osfile( ".grive_state" ) ;
|
||||
// Json state ;
|
||||
// state.Add( "change_stamp", Json( change_stamp ) ) ;
|
||||
// osfile << state ;
|
||||
// osfile.close() ;
|
||||
|
||||
|
||||
bool has_next = false ;
|
||||
do
|
||||
{
|
||||
|
@ -184,7 +177,10 @@ void Drive::ConstructDirTree( http::Agent *http )
|
|||
if ( e.Kind() == "folder" )
|
||||
{
|
||||
if ( e.ParentHrefs().size() == 1 )
|
||||
{
|
||||
m_state.OnEntry( e ) ;
|
||||
m_coll.push_back( Collection( e ) ) ;
|
||||
}
|
||||
else
|
||||
Log( "folder \"%1%\" has multiple parents, ignored", e.Title(), log::warning ) ;
|
||||
}
|
||||
|
@ -198,11 +194,19 @@ void Drive::ConstructDirTree( http::Agent *http )
|
|||
resp = xml.Response() ;
|
||||
}
|
||||
|
||||
m_state.ResolveEntry() ;
|
||||
|
||||
// second, build up linkage between parent and child
|
||||
std::sort( m_coll.begin(), m_coll.end(), SortCollectionByHref() ) ;
|
||||
for ( FolderListIterator i = m_coll.begin() ; i != m_coll.end() ; ++i )
|
||||
{
|
||||
FolderListIterator pit = FindFolder( i->ParentHref() ) ;
|
||||
Collection *scoll = m_state.FindFolderByHref( i->SelfHref() ) ;
|
||||
if ( scoll )
|
||||
Trace( "found folder %1% in state", scoll->Title() ) ;
|
||||
else
|
||||
Trace( "can't found folder %1% in state", i->Title() ) ;
|
||||
|
||||
if ( pit != m_coll.end() )
|
||||
{
|
||||
// it shouldn't happen, just in case
|
||||
|
@ -217,7 +221,7 @@ void Drive::ConstructDirTree( http::Agent *http )
|
|||
|
||||
// lastly, iterating from the root, create the directories in the local file system
|
||||
assert( Root()->Parent() == 0 ) ;
|
||||
Root()->CreateSubDir( fs::current_path() ) ;
|
||||
Root()->CreateSubDir( "." ) ;
|
||||
}
|
||||
|
||||
void Drive::UpdateFile( Entry& entry, Collection& parent, http::Agent *http )
|
||||
|
@ -229,9 +233,9 @@ void Drive::UpdateFile( Entry& entry, Collection& parent, http::Agent *http )
|
|||
m_files.push_back( file ) ;
|
||||
parent.AddLeaf( file ) ;
|
||||
|
||||
Trace( "%1% ID = %2%", file->Path(), file->ResourceID() ) ;
|
||||
// Trace( "%1% ID = %2%", file->Path(), file->ResourceID() ) ;
|
||||
|
||||
m_state.SetId( file->Path(), file->ResourceID() ) ;
|
||||
// m_state.SetId( file->Path(), file->ResourceID() ) ;
|
||||
|
||||
// file->Update( http, m_http_hdr ) ;
|
||||
}
|
||||
|
|
|
@ -40,14 +40,15 @@ public :
|
|||
explicit File( const Entry& e, const Collection *parent ) ;
|
||||
|
||||
void Update( http::Agent *http, const http::Headers& auth ) ;
|
||||
|
||||
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 ) ;
|
||||
void Delete( http::Agent* http, const http::Headers& auth ) ;
|
||||
|
||||
fs::path Path() const ;
|
||||
std::string ResourceID() const ;
|
||||
|
||||
|
||||
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 ) ;
|
||||
|
||||
private :
|
||||
Entry m_entry ;
|
||||
const Collection *m_parent ;
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
|
||||
#include "State.hh"
|
||||
|
||||
#include "Collection.hh"
|
||||
#include "CommonUri.hh"
|
||||
|
||||
#include "util/Crypt.hh"
|
||||
#include "util/Log.hh"
|
||||
#include "protocol/Json.hh"
|
||||
|
@ -29,6 +32,7 @@
|
|||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/identity.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
|
@ -79,30 +83,51 @@ namespace
|
|||
|
||||
using namespace boost::multi_index ;
|
||||
|
||||
struct ById {} ;
|
||||
struct ByID {} ;
|
||||
struct ByPath {} ;
|
||||
|
||||
typedef multi_index_container<
|
||||
Resource,
|
||||
indexed_by<
|
||||
hashed_non_unique< tag<ById>, member<Resource, std::string, &Resource::id> >,
|
||||
hashed_non_unique< tag<ByID>, member<Resource, std::string, &Resource::id> >,
|
||||
hashed_unique< tag<ByPath>,member<Resource, fs::path, &Resource::path>, PathHash >
|
||||
>
|
||||
> ResourceSet ;
|
||||
|
||||
typedef ResourceSet::index<ById>::type IdIdx ;
|
||||
typedef ResourceSet::index<ByID>::type IDIdx ;
|
||||
typedef ResourceSet::index<ByPath>::type PathIdx ;
|
||||
|
||||
struct ByHref {} ;
|
||||
struct ByIdentity {} ;
|
||||
|
||||
typedef multi_index_container<
|
||||
Collection*,
|
||||
indexed_by<
|
||||
hashed_non_unique<tag<ByHref>, const_mem_fun<Collection, std::string, &Collection::SelfHref> >,
|
||||
hashed_non_unique<tag<ByID>, const_mem_fun<Collection, std::string, &Collection::ResourceID> >,
|
||||
hashed_unique<tag<ByIdentity>, identity<Collection*> >
|
||||
>
|
||||
> Folders ;
|
||||
|
||||
typedef Folders::index<ByHref>::type FoldersByHref ;
|
||||
typedef Folders::index<ByIdentity>::type FolderSet ;
|
||||
}
|
||||
|
||||
struct State::Impl
|
||||
{
|
||||
ResourceSet rs ;
|
||||
Folders folders ;
|
||||
std::string change_stamp ;
|
||||
|
||||
std::vector<Entry> unresolved ;
|
||||
} ;
|
||||
|
||||
State::State( const fs::path& filename ) :
|
||||
m_impl( new Impl )
|
||||
{
|
||||
Collection *root = new Collection( ".", root_href ) ;
|
||||
m_impl->folders.insert( root ) ;
|
||||
|
||||
if ( fs::exists( filename ) )
|
||||
Read( filename );
|
||||
}
|
||||
|
@ -131,12 +156,26 @@ void State::ChangeStamp( const std::string& cs )
|
|||
|
||||
void State::Sync( const fs::path& p )
|
||||
{
|
||||
Trace( "synchronizing = %1%", p ) ;
|
||||
FoldersByHref& idx = m_impl->folders.get<ByHref>() ;
|
||||
FoldersByHref::iterator it = idx.find( root_href ) ;
|
||||
|
||||
assert( it != idx.end() ) ;
|
||||
Sync( p, *it ) ;
|
||||
}
|
||||
|
||||
void State::Sync( const fs::path& p, Collection *folder )
|
||||
{
|
||||
// Trace( "synchronizing = %1%", p ) ;
|
||||
for ( fs::directory_iterator i( p ) ; i != fs::directory_iterator() ; ++i )
|
||||
{
|
||||
Trace( "file found = %1%", i->path() ) ;
|
||||
// Trace( "file found = %2% (%1%)", i->path(), i->path().filename() ) ;
|
||||
if ( fs::is_directory( i->path() ) )
|
||||
Sync( *i ) ;
|
||||
{
|
||||
Collection *c = new Collection( i->path().filename().string(), "" ) ;
|
||||
folder->AddChild( c ) ;
|
||||
|
||||
Sync( *i, c ) ;
|
||||
}
|
||||
else if ( i->path().filename().string()[0] != '.' )
|
||||
m_impl->rs.insert( Resource( i->path() ) ) ;
|
||||
}
|
||||
|
@ -147,7 +186,7 @@ void State::Write( const fs::path& filename ) const
|
|||
Json result ;
|
||||
result.Add( "change_stamp", Json( m_impl->change_stamp ) ) ;
|
||||
|
||||
IdIdx& idx = m_impl->rs.get<ById>() ;
|
||||
IDIdx& idx = m_impl->rs.get<ByID>() ;
|
||||
|
||||
std::vector<Json> res ;
|
||||
std::transform( idx.begin(), idx.end(),
|
||||
|
@ -156,7 +195,7 @@ void State::Write( const fs::path& filename ) const
|
|||
|
||||
result.Add( "resources", Json(res) ) ;
|
||||
|
||||
Trace( "%1%", result ) ;
|
||||
// Trace( "%1%", result ) ;
|
||||
|
||||
std::ofstream fs( filename.string().c_str() ) ;
|
||||
fs << result ;
|
||||
|
@ -178,5 +217,91 @@ void State::SetId( const fs::path& p, const std::string& id )
|
|||
}
|
||||
}
|
||||
|
||||
void State::OnEntry( const Entry& e )
|
||||
{
|
||||
if ( !Update( e ) )
|
||||
{
|
||||
Trace( "can't find parent of %1%", e.Title() ) ;
|
||||
m_impl->unresolved.push_back( e ) ;
|
||||
}
|
||||
}
|
||||
|
||||
void State::ResolveEntry()
|
||||
{
|
||||
Trace( "trying to resolve %1% entries", m_impl->unresolved.size() ) ;
|
||||
while ( !m_impl->unresolved.empty() )
|
||||
{
|
||||
if ( TryResolveEntry() == 0 )
|
||||
{
|
||||
Trace( "cannot make progress" ) ;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
Trace( "entries left = %1%", m_impl->unresolved.size() ) ;
|
||||
}
|
||||
|
||||
std::size_t State::TryResolveEntry()
|
||||
{
|
||||
assert( !m_impl->unresolved.empty() ) ;
|
||||
|
||||
std::size_t count = 0 ;
|
||||
std::vector<Entry>& en = m_impl->unresolved ;
|
||||
|
||||
for ( std::vector<Entry>::iterator i = en.begin() ; i != en.end() ; )
|
||||
{
|
||||
if ( Update( *i ) )
|
||||
{
|
||||
i = en.erase( i ) ;
|
||||
count++ ;
|
||||
}
|
||||
else
|
||||
++i ;
|
||||
}
|
||||
return count ;
|
||||
}
|
||||
|
||||
bool State::Update( const Entry& e )
|
||||
{
|
||||
FoldersByHref& folders = m_impl->folders.get<ByHref>() ;
|
||||
FoldersByHref::iterator i = folders.find( e.ParentHref() ) ;
|
||||
if ( i != folders.end() )
|
||||
{
|
||||
Trace( "found parent of folder %1%: %2%", e.Title(), (*i)->Title() ) ;
|
||||
|
||||
// see if the entry already exist in local
|
||||
Collection *child = (*i)->FindChild( e.Title() ) ;
|
||||
if ( child != 0 )
|
||||
{
|
||||
// since we are updating the ID and Href, we need to remove it and re-add it.
|
||||
FolderSet& fs = m_impl->folders.get<ByIdentity>() ;
|
||||
FolderSet::iterator c = fs.find( child ) ;
|
||||
|
||||
if ( c != fs.end() )
|
||||
fs.erase( c ) ;
|
||||
|
||||
child->Update( e ) ;
|
||||
folders.insert( child ) ;
|
||||
}
|
||||
|
||||
// folder entry exist in google drive, but not local.
|
||||
else
|
||||
{
|
||||
child = new Collection( e ) ;
|
||||
(*i)->AddChild( child ) ;
|
||||
folders.insert( child ) ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
return false ;
|
||||
}
|
||||
|
||||
Collection* State::FindFolderByHref( const std::string& href )
|
||||
{
|
||||
FoldersByHref& folders = m_impl->folders.get<ByHref>() ;
|
||||
FoldersByHref::iterator i = folders.find( href ) ;
|
||||
return i != folders.end() ? *i : 0 ;
|
||||
}
|
||||
|
||||
} // end of namespace
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
namespace gr {
|
||||
|
||||
class Json ;
|
||||
class Collection ;
|
||||
class Entry ;
|
||||
|
||||
class State
|
||||
{
|
||||
|
@ -34,6 +36,9 @@ public :
|
|||
|
||||
void Sync( const fs::path& p ) ;
|
||||
|
||||
void OnEntry( const Entry& e ) ;
|
||||
void ResolveEntry() ;
|
||||
|
||||
void SetId( const fs::path& p, const std::string& id ) ;
|
||||
|
||||
void Read( const fs::path& filename ) ;
|
||||
|
@ -42,6 +47,14 @@ public :
|
|||
std::string ChangeStamp() const ;
|
||||
void ChangeStamp( const std::string& cs ) ;
|
||||
|
||||
Collection* FindFolderByHref( const std::string& href ) ;
|
||||
Collection* FindFolderByID( const std::string& id ) ;
|
||||
|
||||
private :
|
||||
void Sync( const fs::path& p, Collection *folder ) ;
|
||||
bool Update( const Entry& e ) ;
|
||||
std::size_t TryResolveEntry() ;
|
||||
|
||||
private :
|
||||
struct Impl ;
|
||||
std::auto_ptr<Impl> m_impl ;
|
||||
|
|
Loading…
Reference in New Issue