Added ability to move and rename files/directories

pull/36/merge
Dylan Wulf 2015-11-10 12:54:47 +03:00 committed by Vitaliy Filippov
parent 44cb91f94e
commit 3b608329b9
8 changed files with 130 additions and 1 deletions

View File

@ -121,6 +121,7 @@ int Main( int argc, char **argv )
( "dry-run", "Only detect which files need to be uploaded/downloaded, "
"without actually performing them." )
( "ignore", po::value<std::string>(), "Ignore files relative paths of which match this Perl RegExp." )
( "move,m", po::value<std::vector<std::string> >()->multitoken(), "Syncs, then moves a file (first argument) to new location (second argument) without reuploading or redownloading." )
;
po::variables_map vm;
@ -203,6 +204,21 @@ int Main( int argc, char **argv )
}
else
drive.DryRun() ;
if ( vm.count ( "move" ) > 0 && vm.count( "dry-run" ) == 0 )
{
if (vm["move"].as<std::vector<std::string> >().size() < 2 )
Log( "Not enough arguments for move. Move failed.", log::error );
else
{
bool success = drive.Move( vm["move"].as<std::vector<std::string> >()[0],
vm["move"].as<std::vector<std::string> >()[1] );
if (success)
Log( "Move successful!", log::info );
else
Log( "Move failed.", log::error);
}
}
config.Save() ;
Log( "Finished!", log::info ) ;

View File

@ -150,6 +150,11 @@ void Drive::DetectChanges()
}
}
bool Drive::Move( fs::path old_p, fs::path new_p )
{
return m_state.Move( m_syncer, old_p, new_p, m_options["path"].Str() );
}
void Drive::Update()
{
Log( "Synchronizing files", log::info ) ;

View File

@ -41,6 +41,7 @@ public :
Drive( Syncer *syncer, const Val& options ) ;
void DetectChanges() ;
bool Move( fs::path old_p, fs::path new_p );
void Update() ;
void DryRun() ;
void SaveState() ;

View File

@ -321,4 +321,67 @@ void State::ChangeStamp( long cstamp )
m_cstamp = cstamp ;
}
bool State::Move( Syncer* syncer, fs::path old_p, fs::path new_p, fs::path grive_root )
{
//Convert paths to canonical representations
//Also seems to remove trailing / at the end of directory paths
old_p = fs::canonical( old_p );
grive_root = fs::canonical( grive_root );
//new_p is a little special because fs::canonical() requires that the path exists
if ( new_p.string()[ new_p.string().size() - 1 ] == '/') //If new_p ends with a /, remove it
new_p = new_p.parent_path();
new_p = fs::canonical( new_p.parent_path() ) / new_p.filename();
//Fails if source file doesn't exist, or if destination file already
//exists and is not a directory, or if the source and destination are exactly the same
if ( (fs::exists(new_p) && !fs::is_directory(new_p) ) || !fs::exists(old_p) || fs::equivalent( old_p, new_p ) )
return false;
//If new path is an existing directory, move the file into the directory
//instead of trying to rename it
if ( fs::is_directory(new_p) ){
new_p = new_p / old_p.filename();
}
//Get the paths relative to grive root.
//Just finds the substring from the end of the grive_root to the end of the path
//+1s are to exclude slash at beginning of relative path
int start = grive_root.string().size() + 1;
int nLen = new_p.string().size() - (grive_root.string().size() + 1);
int oLen = old_p.string().size() - (grive_root.string().size() + 1);
if ( start + nLen != new_p.string().size() || start + oLen != old_p.string().size() )
return false;
fs::path new_p_rootrel( new_p.string().substr( start, nLen ) );
fs::path old_p_rootrel( old_p.string().substr( start, oLen ) );
//Get resources
Resource* res = m_res.Root();
Resource* newParentRes = m_res.Root();
for ( fs::path::iterator it = old_p_rootrel.begin(); it != old_p_rootrel.end(); ++it )
{
if ( *it != "." && *it != ".." && res != 0 )
res = res->FindChild(it->string());
if ( *it == ".." )
res = res->Parent();
}
for ( fs::path::iterator it = new_p_rootrel.begin(); it != new_p_rootrel.end(); ++it )
{
if ( *it != "." && *it != ".." && *it != new_p.filename() && newParentRes != 0 )
newParentRes = newParentRes->FindChild(it->string());
if ( *it == "..")
res = res->Parent();
}
//These conditions should only occur if everything is not up-to-date
if ( res == 0 || newParentRes == 0 || res->GetState() != Resource::sync ||
newParentRes->GetState() != Resource::sync ||
newParentRes->FindChild( new_p.filename().string() ) != 0 )
return false;
fs::rename(old_p, new_p); //Moves local file
syncer->Move(res, newParentRes, new_p.filename().string()); //Moves server file
return true;
}
} // end of namespace gr

View File

@ -63,7 +63,8 @@ public :
long ChangeStamp() const ;
void ChangeStamp( long cstamp ) ;
bool Move( Syncer* syncer, fs::path old_p, fs::path new_p, fs::path grive_root );
private :
void FromLocal( const fs::path& p, Resource *folder ) ;
void FromChange( const Entry& e ) ;

View File

@ -53,6 +53,7 @@ public :
virtual void Download( Resource *res, const fs::path& file );
virtual bool EditContent( Resource *res, bool new_rev ) = 0;
virtual bool Create( Resource *res ) = 0;
virtual bool Move( Resource* res, Resource* newParent, std::string newFilename ) = 0;
virtual std::auto_ptr<Feed> GetFolders() = 0;
virtual std::auto_ptr<Feed> GetAll() = 0;

View File

@ -89,6 +89,47 @@ bool Syncer2::Create( Resource *res )
return Upload( res );
}
bool Syncer2::Move( Resource* res, Resource* newParentRes, std::string newFilename )
{
if ( res->ResourceID().empty() )
{
Log("Can't rename file %1%, no server id found", res->Name());
return false;
}
Val meta;
meta.Add( "title", Val(newFilename) );
if ( res->IsFolder() )
{
meta.Add( "mimeType", Val( mime_types::folder ) );
}
std::string json_meta = WriteJson( meta );
Val valr ;
// Issue metadata update request
{
std::string addRemoveParents("");
if (res->Parent()->IsRoot() )
addRemoveParents += "&removeParents=root";
else
addRemoveParents += "&removeParents=" + res->Parent()->ResourceID();
if ( newParentRes->IsRoot() )
addRemoveParents += "&addParents=root";
else
addRemoveParents += "&addParents=" + newParentRes->ResourceID();
http::Header hdr2 ;
hdr2.Add( "Content-Type: application/json" );
http::ValResponse vrsp ;
long http_code = 0;
//Don't change modified date because we're only moving
http_code = m_http->Put( feeds::files + "/" + res->ResourceID() + "?modifiedDateBehavior=noChange" + addRemoveParents, json_meta, &vrsp, hdr2 ) ;
valr = vrsp.Response();
assert( !( valr["id"].Str().empty() ) );
}
return true;
}
std::string to_string( uint64_t n )
{
std::ostringstream s;

View File

@ -37,6 +37,7 @@ public :
void DeleteRemote( Resource *res );
bool EditContent( Resource *res, bool new_rev );
bool Create( Resource *res );
bool Move( Resource* res, Resource* newParent, std::string newFilename );
std::auto_ptr<Feed> GetFolders();
std::auto_ptr<Feed> GetAll();