mirror of https://github.com/vitalif/grive2
Added ability to move and rename files/directories
parent
44cb91f94e
commit
3b608329b9
|
@ -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 ) ;
|
||||
|
|
|
@ -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 ) ;
|
||||
|
|
|
@ -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() ;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ) ;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue