TuttleOFX
1
|
00001 #include <sam/common/utility.hpp> 00002 #include <sam/common/options.hpp> 00003 00004 #include <boost/filesystem/operations.hpp> 00005 #include <boost/filesystem/exception.hpp> 00006 #include <boost/exception/diagnostic_information.hpp> 00007 #include <boost/foreach.hpp> 00008 #include <boost/algorithm/string.hpp> 00009 #include <boost/algorithm/string/split.hpp> 00010 #include <boost/program_options.hpp> 00011 #include <boost/shared_ptr.hpp> 00012 00013 #include <detector.hpp> 00014 #include <Sequence.hpp> 00015 00016 #include <algorithm> 00017 #include <iterator> 00018 00019 namespace bpo = boost::program_options; 00020 namespace bfs = boost::filesystem; 00021 namespace bal = boost::algorithm; 00022 00023 bool selectRange = false; 00024 std::ssize_t firstImage = 0; 00025 std::ssize_t lastImage = 0; 00026 00027 // A helper function to simplify the main part. 00028 template<class T> 00029 std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) 00030 { 00031 copy( v.begin(), v.end(), std::ostream_iterator<T>( std::cout, " " ) ); 00032 return os; 00033 } 00034 00035 void removeSequence( const sequenceParser::Sequence& s ) 00036 { 00037 std::ssize_t first; 00038 std::ssize_t last; 00039 if( selectRange ) 00040 { 00041 first = std::max( s.getFirstTime(), firstImage ); 00042 last = std::min( s.getLastTime(), lastImage ); 00043 } 00044 else 00045 { 00046 first = s.getFirstTime(); 00047 last = s.getLastTime(); 00048 } 00049 // TUTTLE_TCOUT( "remove sequence." ); 00050 // TUTTLE_TCOUT("remove from " << first << " to " << last); 00051 00052 for( sequenceParser::Time t = first; t <= last; t += s.getStep() ) 00053 { 00054 bfs::path sFile = s.getAbsoluteFilenameAt(t); 00055 if( !bfs::exists( sFile ) ) 00056 { 00057 TUTTLE_LOG_ERROR( "Could not remove (file not exist): " << sFile.string() ); 00058 } 00059 else 00060 { 00061 TUTTLE_LOG_TRACE( "remove: " << tuttle::common::Color::get()->_folder << sFile.string() << tuttle::common::Color::get()->_std ); 00062 try 00063 { 00064 bfs::remove( sFile ); 00065 } 00066 catch( const boost::filesystem::filesystem_error& e ) 00067 { 00068 // if( e.code() == boost::system::errc::permission_denied ) 00069 // "permission denied" 00070 TUTTLE_LOG_ERROR( "sam-rm: Error:\t\n" << e.what() ); 00071 /// @todo cin 00072 // TUTTLE_LOG_INFO( "sam-rm: Continue ? (Yes/No/Yes for All/No for All)" ); 00073 } 00074 } 00075 } 00076 } 00077 00078 void removeFileObject( boost::ptr_vector<sequenceParser::FileObject> &listing, std::vector<boost::filesystem::path> ¬Removed ) 00079 { 00080 // TUTTLE_TCOUT( "removeFileObject." ); 00081 BOOST_FOREACH( const sequenceParser::FileObject& s, listing ) 00082 { 00083 if( !(s.getMaskType () == sequenceParser::eMaskTypeDirectory)) 00084 { 00085 TUTTLE_LOG_TRACE( "remove: " << s ); 00086 if( s.getMaskType () == sequenceParser::eMaskTypeSequence ) 00087 removeSequence( static_cast<const sequenceParser::Sequence&>( s ) ); 00088 else 00089 { 00090 std::vector<bfs::path> paths = s.getFiles(); 00091 for(unsigned int i=0; i<paths.size(); i++) 00092 bfs::remove( paths.at(i) ); 00093 } 00094 } 00095 else // is a directory 00096 { 00097 std::vector<boost::filesystem::path> paths = s.getFiles(); 00098 for(unsigned int i=0; i<paths.size(); i++) 00099 { 00100 if( bfs::is_empty( paths.at(i) ) ) 00101 { 00102 TUTTLE_LOG_TRACE( "remove: " << s ); 00103 bfs::remove( paths.at(i) ); 00104 } 00105 else 00106 { 00107 notRemoved.push_back( paths.at(i) ); 00108 } 00109 } 00110 } 00111 } 00112 } 00113 00114 void removeFiles( std::vector<boost::filesystem::path> &listing ) 00115 { 00116 std::sort(listing.begin(), listing.end()); 00117 std::reverse(listing.begin(), listing.end()); 00118 BOOST_FOREACH( const boost::filesystem::path& paths, listing ) 00119 { 00120 if( bfs::is_empty( paths ) ) 00121 { 00122 TUTTLE_LOG_TRACE( "remove: " << tuttle::common::Color::get()->_folder << paths << tuttle::common::Color::get()->_std ); 00123 bfs::remove( paths ); 00124 } 00125 else 00126 { 00127 TUTTLE_LOG_ERROR( "could not remove " << paths ); 00128 } 00129 } 00130 } 00131 00132 00133 int main( int argc, char** argv ) 00134 { 00135 signal(SIGINT, signal_callback_handler); 00136 00137 using namespace tuttle::common; 00138 using namespace sam; 00139 00140 boost::shared_ptr<formatters::Formatter> formatter( formatters::Formatter::get() ); 00141 boost::shared_ptr<Color> color( Color::get() ); 00142 00143 sequenceParser::EMaskType researchMask = sequenceParser::eMaskTypeSequence; // by default show sequences 00144 sequenceParser::EMaskOptions descriptionMask = sequenceParser::eMaskOptionsColor; // by default show nothing 00145 bool recursiveListing = false; 00146 std::vector<std::string> paths; 00147 std::vector<std::string> filters; 00148 00149 formatter->init_logging(); 00150 00151 // Declare the supported options. 00152 bpo::options_description mainOptions; 00153 mainOptions.add_options() 00154 ( kAllOptionString, kAllOptionMessage ) 00155 ( kDirectoriesOptionString, kDirectoriesOptionMessage ) 00156 ( kExpressionOptionString, bpo::value<std::string>(), kExpressionOptionMessage ) 00157 ( kFilesOptionString, kFilesOptionMessage ) 00158 ( kHelpOptionString, kHelpOptionMessage ) 00159 ( kIgnoreOptionString, kIgnoreOptionMessage ) 00160 ( kPathOptionString, kPathOptionMessage ) 00161 ( kRecursiveOptionString, kRecursiveOptionMessage ) 00162 ( kVerboseOptionString, bpo::value<int>()->default_value( 2 ), kVerboseOptionMessage ) 00163 ( kQuietOptionString, kQuietOptionMessage ) 00164 ( kColorOptionString, kColorOptionMessage ) 00165 ( kFirstImageOptionString, bpo::value<std::ssize_t>(), kFirstImageOptionMessage ) 00166 ( kLastImageOptionString, bpo::value<std::ssize_t>(), kLastImageOptionMessage ) 00167 ( kFullRMPathOptionString, kFullRMPathOptionMessage ) 00168 ( kBriefOptionString, kBriefOptionMessage ); 00169 00170 // describe hidden options 00171 bpo::options_description hidden; 00172 hidden.add_options() 00173 ( kInputDirOptionString, bpo::value< std::vector<std::string> >(), kInputDirOptionMessage ) 00174 ( kEnableColorOptionString, bpo::value<std::string>(), kEnableColorOptionMessage ); 00175 00176 // define default options 00177 bpo::positional_options_description pod; 00178 pod.add(kInputDirOptionString, -1); 00179 00180 bpo::options_description cmdline_options; 00181 cmdline_options.add( mainOptions ).add( hidden ); 00182 00183 bpo::positional_options_description pd; 00184 pd.add( "", -1 ); 00185 00186 //parse the command line, and put the result in vm 00187 bpo::variables_map vm; 00188 00189 bpo::notify( vm ); 00190 00191 try 00192 { 00193 bpo::store( bpo::command_line_parser(argc, argv).options(cmdline_options).positional(pod).run(), vm ); 00194 00195 // get environment options and parse them 00196 if( const char* env_rm_options = std::getenv("SAM_RM_OPTIONS") ) 00197 { 00198 const std::vector<std::string> vecOptions = bpo::split_unix( env_rm_options, " " ); 00199 bpo::store( bpo::command_line_parser(vecOptions).options(cmdline_options).positional(pod).run(), vm ); 00200 } 00201 if( const char* env_rm_options = std::getenv("SAM_OPTIONS") ) 00202 { 00203 const std::vector<std::string> vecOptions = bpo::split_unix( env_rm_options, " " ); 00204 bpo::store( bpo::command_line_parser(vecOptions).options(cmdline_options).positional(pod).run(), vm ); 00205 } 00206 } 00207 catch( const bpo::error& e) 00208 { 00209 TUTTLE_LOG_ERROR( "sam-rm: command line error: " << e.what() ); 00210 exit( 254 ); 00211 } 00212 catch(...) 00213 { 00214 TUTTLE_LOG_ERROR( "sam-rm: unknown error in command line." ); 00215 exit( 254 ); 00216 } 00217 00218 if( vm.count( kColorOptionLongName ) ) 00219 { 00220 color->enable(); 00221 } 00222 00223 if( vm.count( kEnableColorOptionLongName ) ) 00224 { 00225 const std::string str = vm[kEnableColorOptionLongName].as<std::string>(); 00226 if( string_to_boolean(str) ) 00227 { 00228 color->enable(); 00229 } 00230 else 00231 { 00232 color->disable(); 00233 } 00234 } 00235 00236 if( vm.count( kHelpOptionLongName ) ) 00237 { 00238 TUTTLE_LOG_INFO( color->_blue << "TuttleOFX project [" << kUrlTuttleofxProject << "]" << color->_std ); 00239 TUTTLE_LOG_INFO( "" ); 00240 TUTTLE_LOG_INFO( color->_blue << "NAME" << color->_std ); 00241 TUTTLE_LOG_INFO( color->_green << "\tsam-rm - remove file sequences" << color->_std ); 00242 TUTTLE_LOG_INFO( "" ); 00243 TUTTLE_LOG_INFO( color->_blue << "SYNOPSIS" << color->_std ); 00244 TUTTLE_LOG_INFO( color->_green << "\tsam-rm [options] [sequence_pattern]" << color->_std ); 00245 TUTTLE_LOG_INFO( "" ); 00246 TUTTLE_LOG_INFO( color->_blue << "DESCRIPTION" << color->_std << std::endl ); 00247 TUTTLE_LOG_INFO( "" ); 00248 TUTTLE_LOG_INFO( "Remove sequence of files, and could remove trees (folder, files and sequences)." ); 00249 TUTTLE_LOG_INFO( "" ); 00250 TUTTLE_LOG_INFO( color->_blue << "OPTIONS" << color->_std ); 00251 TUTTLE_LOG_INFO( "" ); 00252 TUTTLE_LOG_INFO( mainOptions ); 00253 00254 TUTTLE_LOG_INFO( color->_blue << "EXAMPLES" << color->_std ); 00255 SAM_EXAMPLE_TITLE_COUT( "Sequence possible definitions: " ); 00256 SAM_EXAMPLE_LINE_COUT ( "Auto-detect padding : ", "seq.@.jpg" ); 00257 SAM_EXAMPLE_LINE_COUT ( "Padding of 8 (usual style): ", "seq.########.jpg" ); 00258 SAM_EXAMPLE_LINE_COUT ( "Padding of 8 (printf style): ", "seq.%08d.jpg" ); 00259 SAM_EXAMPLE_TITLE_COUT( "Delete: " ); 00260 SAM_EXAMPLE_LINE_COUT ( "A sequence:", "sam-rm /path/to/sequence/seq.@.jpg" ); 00261 SAM_EXAMPLE_LINE_COUT ( "Sequences in a directory:", "sam-rm /path/to/sequence/" ); 00262 TUTTLE_LOG_INFO( "" ); 00263 00264 return 0; 00265 } 00266 00267 if( vm.count( kBriefOptionLongName) ) 00268 { 00269 TUTTLE_LOG_INFO( color->_green << "remove file sequences" << color->_std ); 00270 return 0; 00271 } 00272 00273 if(vm.count( kExpressionOptionLongName)) 00274 { 00275 bal::split( filters, vm["expression"].as<std::string>(), bal::is_any_of(",")); 00276 } 00277 00278 if( vm.count( kDirectoriesOptionLongName ) ) 00279 { 00280 researchMask |= sequenceParser::eMaskTypeDirectory; 00281 } 00282 00283 if( vm.count( kFilesOptionLongName ) ) 00284 { 00285 researchMask |= sequenceParser::eMaskTypeFile; 00286 } 00287 00288 if( vm.count( kIgnoreOptionLongName ) ) 00289 { 00290 researchMask &= ~sequenceParser::eMaskTypeSequence; 00291 } 00292 00293 switch( vm[ kVerboseOptionLongName ].as< int >() ) 00294 { 00295 case 0 : formatter->setLogLevel( boost::log::trivial::trace ); break; 00296 case 1 : formatter->setLogLevel( boost::log::trivial::debug ); break; 00297 case 2 : formatter->setLogLevel( boost::log::trivial::info ); break; 00298 case 3 : formatter->setLogLevel( boost::log::trivial::warning ); break; 00299 case 4 : formatter->setLogLevel( boost::log::trivial::error ); break; 00300 case 5 : formatter->setLogLevel( boost::log::trivial::fatal ); break; 00301 default : formatter->setLogLevel( boost::log::trivial::warning ); break; 00302 } 00303 if( vm.count(kQuietOptionLongName) ) 00304 { 00305 formatter->setLogLevel( boost::log::trivial::fatal ); 00306 } 00307 00308 if( vm.count( kFirstImageOptionLongName ) ) 00309 { 00310 selectRange = true; 00311 firstImage = vm[kFirstImageOptionLongName].as< std::ssize_t >(); 00312 } 00313 00314 if( vm.count( kLastImageOptionLongName ) ) 00315 { 00316 selectRange = true; 00317 lastImage = vm[kLastImageOptionLongName].as< std::ssize_t >(); 00318 } 00319 00320 if( vm.count( kFullRMPathOptionLongName ) ) 00321 { 00322 researchMask |= sequenceParser::eMaskTypeDirectory; 00323 researchMask |= sequenceParser::eMaskTypeFile; 00324 researchMask |= sequenceParser::eMaskTypeSequence; 00325 } 00326 00327 if( vm.count( kAllOptionLongName ) ) 00328 { 00329 // add .* files 00330 descriptionMask |= sequenceParser::eMaskOptionsDotFile; 00331 } 00332 00333 if( vm.count( kPathOptionLongName ) ) 00334 { 00335 descriptionMask |= sequenceParser::eMaskOptionsPath; 00336 } 00337 00338 // defines paths, but if no directory specify in command line, we add the current path 00339 if( vm.count( kInputDirOptionLongName ) ) 00340 { 00341 paths = vm[kInputDirOptionLongName].as< std::vector<std::string> >(); 00342 } 00343 else 00344 { 00345 TUTTLE_LOG_ERROR( "No sequence and/or directory are specified." ); 00346 return 1; 00347 } 00348 00349 if( vm.count( kRecursiveOptionLongName ) ) 00350 { 00351 recursiveListing = true; 00352 } 00353 // for(unsigned int i=0; i<filters.size(); i++) 00354 // TUTTLE_LOG_TRACE("filters = " << filters.at(i)); 00355 // TUTTLE_LOG_TRACE("research mask = " << researchMask); 00356 // TUTTLE_LOG_TRACE("options mask = " << descriptionMask); 00357 00358 try 00359 { 00360 std::vector<boost::filesystem::path> pathsNoRemoved; 00361 00362 BOOST_FOREACH( bfs::path path, paths ) 00363 { 00364 // TUTTLE_TCOUT( "path: "<< path ); 00365 if( bfs::exists( path ) ) 00366 { 00367 if( bfs::is_directory( path ) ) 00368 { 00369 //TUTTLE_TCOUT( "is a directory" ); 00370 if(recursiveListing) 00371 { 00372 for ( bfs::recursive_directory_iterator end, dir(path); dir != end; ++dir ) 00373 { 00374 if( bfs::is_directory( *dir ) ) 00375 { 00376 //TUTTLE_TCOUT( *dir ); 00377 boost::ptr_vector<sequenceParser::FileObject> listing = sequenceParser::fileObjectInDirectory( ( (bfs::path) *dir ).string(), filters, researchMask, descriptionMask ); 00378 removeFileObject( listing, pathsNoRemoved ); 00379 } 00380 } 00381 } 00382 boost::ptr_vector<sequenceParser::FileObject> listing = sequenceParser::fileObjectInDirectory( path.string(), filters, researchMask, descriptionMask ); 00383 removeFileObject( listing, pathsNoRemoved ); 00384 } 00385 else 00386 { 00387 //TUTTLE_TCOUT( "is NOT a directory "<< path.branch_path() << " | "<< path.leaf() ); 00388 filters.push_back( path.leaf().string() ); 00389 boost::ptr_vector<sequenceParser::FileObject> listing = sequenceParser::fileObjectInDirectory( path.branch_path().string(), filters, researchMask, descriptionMask ); 00390 removeFileObject( listing, pathsNoRemoved ); 00391 } 00392 } 00393 else 00394 { 00395 // TUTTLE_TCOUT( "not exist ...." ); 00396 try 00397 { 00398 sequenceParser::Sequence s(path.branch_path(), descriptionMask ); 00399 s.initFromDetection( path.string(), sequenceParser::Sequence::ePatternDefault ); 00400 if( s.getNbFiles() ) 00401 { 00402 // TUTTLE_TCOUT( s ); 00403 removeSequence( s ); 00404 } 00405 } 00406 catch(... ) 00407 { 00408 TUTTLE_LOG_ERROR( "Unrecognized pattern \"" << path << "\"" ); 00409 } 00410 } 00411 } 00412 // delete not empty folder the first time 00413 removeFiles( pathsNoRemoved ); 00414 } 00415 catch( bfs::filesystem_error &ex ) 00416 { 00417 TUTTLE_LOG_ERROR( ex.what() ); 00418 } 00419 catch( ... ) 00420 { 00421 TUTTLE_LOG_ERROR( boost::current_exception_diagnostic_information() ); 00422 } 00423 return 0; 00424 } 00425