Experimental support for syncing Google Documents (issue #46)

FIXME:
- Files are "remote changed" and re-downloaded after being uploaded, which is
  indeed correct because they really differ after re-downloading, but should be fixed
- Extension is added to filename after uploading
googledocs
Vitaliy Filippov 2016-05-17 00:17:59 +03:00
parent 1bd86307c6
commit 6670ae2d24
4 changed files with 46 additions and 12 deletions

View File

@ -76,6 +76,7 @@ Enjoy!
- ignore regexp does not persist anymore (note that Grive will still track it to not - ignore regexp does not persist anymore (note that Grive will still track it to not
accidentally delete remote files when changing ignore regexp) accidentally delete remote files when changing ignore regexp)
- added options to limit upload and download speed - added options to limit upload and download speed
- added ability to sync google documents
### Grive2 v0.5 ### Grive2 v0.5

View File

@ -169,7 +169,9 @@ void Resource::FromRemoteFile( const Entry& remote )
{ {
Trace( "file %1% change stamp = %2%", Path(), remote.ChangeStamp() ) ; Trace( "file %1% change stamp = %2%", Path(), remote.ChangeStamp() ) ;
if ( remote.MTime().Sec() > m_mtime.Sec() || remote.MD5() != m_md5 || remote.ChangeStamp() > 0 ) if ( remote.MTime().Sec() > m_mtime.Sec() ||
( !remote.MD5().empty() && remote.MD5() != m_md5 ) ||
remote.ChangeStamp() > 0 )
{ {
Log( "file %1% is created in remote (change %2%)", path, Log( "file %1% is created in remote (change %2%)", path,
remote.ChangeStamp(), log::verbose ) ; remote.ChangeStamp(), log::verbose ) ;
@ -182,17 +184,17 @@ void Resource::FromRemoteFile( const Entry& remote )
m_state = local_deleted ; m_state = local_deleted ;
} }
} }
// remote checksum unknown, assume the file is not changed in remote // remote download URL unknown, skip file
else if ( remote.MD5().empty() ) else if ( remote.ContentSrc().empty() )
{ {
Log( "file %1% has unknown checksum in remote. assumed in sync", Log( "file %1% has unknown download URL. assumed in sync",
Path(), log::verbose ) ; Path(), log::verbose ) ;
m_state = sync ; m_state = sync ;
} }
// if checksum is equal, no need to compare the mtime // if checksum is equal, no need to compare the mtime
else if ( remote.MD5() == m_md5 ) else if ( !remote.MD5().empty() && remote.MD5() == m_md5 )
{ {
Log( "file %1% is already in sync", Path(), log::verbose ) ; Log( "file %1% is already in sync", Path(), log::verbose ) ;
m_state = sync ; m_state = sync ;
@ -209,13 +211,21 @@ void Resource::FromRemoteFile( const Entry& remote )
Log( "file %1% is changed in remote", path, log::verbose ) ; Log( "file %1% is changed in remote", path, log::verbose ) ;
m_state = remote_changed ; m_state = remote_changed ;
} }
// google document
else if ( remote.MD5().empty() && m_state == remote_deleted )
{
Log( "file %1% has no MD5 and is in sync", path, log::verbose ) ;
m_state = sync ;
}
// remote also has the file, so it's not new in local // remote also has the file, so it's not new in local
else if ( m_state == local_new || m_state == remote_deleted ) else if ( m_state == local_new || m_state == remote_deleted )
{ {
Log( "file %1% is changed in local", path, log::verbose ) ; Log( "file %1% is changed in local", path, log::verbose ) ;
m_state = local_changed ; m_state = local_changed ;
} }
else else
Trace( "file %1% state is %2%", m_name, m_state ) ; Trace( "file %1% state is %2%", m_name, m_state ) ;
} }

View File

@ -151,7 +151,7 @@ void State::FromRemote( const Entry& e )
// common checkings // common checkings
if ( !e.IsDir() && ( fn.empty() || e.ContentSrc().empty() ) ) if ( !e.IsDir() && ( fn.empty() || e.ContentSrc().empty() ) )
Log( "%1% \"%2%\" is a google document, ignored", k, e.Name(), log::verbose ) ; Log( "%1% \"%2%\" has no download link or filename, ignored", k, e.Name(), log::verbose ) ;
else if ( fn.find('/') != fn.npos ) else if ( fn.find('/') != fn.npos )
Log( "%1% \"%2%\" contains a slash in its name, ignored", k, e.Name(), log::verbose ) ; Log( "%1% \"%2%\" contains a slash in its name, ignored", k, e.Name(), log::verbose ) ;

View File

@ -66,10 +66,33 @@ void Entry2::Update( const Val& item )
m_is_removed = file["labels"]["trashed"].Bool() ; m_is_removed = file["labels"]["trashed"].Bool() ;
if ( !m_is_dir ) if ( !m_is_dir )
{ {
if ( !file.Has( "md5Checksum" ) || !file.Has("downloadUrl") ) if ( !file.Has( "md5Checksum" ) && file.Has( "exportLinks" ) )
{ {
// This is either a google docs document or a not-yet-uploaded file. Ignore it. // This is a google docs document.
// FIXME: We'll need to compare timestamps to support google docs. const Val::Object& obj = file["exportLinks"].AsObject() ;
const char ooxml[] = "application/vnd.openxmlformats-officedocument";
for ( Val::Object::const_iterator i = obj.begin() ; i != obj.end() ; ++i )
if ( i->first.substr( 0, sizeof( ooxml ) - 1 ) == ooxml )
m_content_src = i->second.Str();
if ( m_content_src.empty() )
m_content_src = obj.begin()->second.Str();
if ( !m_content_src.empty() )
{
size_t pos = m_content_src.find( "exportFormat=" );
if ( pos != std::string::npos )
{
size_t end = m_content_src.find( '&', pos+13 );
if ( end == std::string::npos )
end = m_content_src.length();
std::string fmt = m_content_src.substr( pos+13, end-pos-13 );
if ( m_filename.substr( m_filename.length() - fmt.length() - 1 ) != "."+fmt )
m_filename += "."+fmt;
}
}
}
else if ( !file.Has( "md5Checksum" ) || !file.Has("downloadUrl") )
{
// This is a not-yet-uploaded file. Ignore it.
m_is_removed = true; m_is_removed = true;
} }
else else