diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 116ed64..4563d15 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,12 +11,18 @@ add_definitions( ) # -Weffc++ +set( + Shorteners + MD5Shortener.cpp + TruncatingShortener.cpp +) + add_executable( dirmeta dirmeta.cpp DirectoryMetadata.cpp Etc.cpp - MD5Shortener.cpp + ${Shorteners} ) target_link_libraries ( dirmeta @@ -29,7 +35,7 @@ add_executable( transpath.cpp DirectoryMetadata.cpp Etc.cpp - MD5Shortener.cpp + ${Shorteners} ) target_link_libraries ( transpath diff --git a/src/DirectoryMetadata.cpp b/src/DirectoryMetadata.cpp index afa9077..db28f41 100644 --- a/src/DirectoryMetadata.cpp +++ b/src/DirectoryMetadata.cpp @@ -37,16 +37,18 @@ DirectoryMetadata::fromFilesystem( vector& entries(dm->entries_); for ( fs::directory_iterator it(path), end; it != end; ++it ) { - const string name = it->path().filename().string(); + const string entryPath( it->path().string() ); struct stat st; - if ( lstat(name.c_str(), &st) < 0 ) { - util::throw_errno("lstat", it->path()); + if ( lstat(entryPath.c_str(), &st) < 0 ) { + util::throw_errno("lstat", entryPath); } + + const string entryName( it->path().filename().string() ); Entry entry = { - longName : name, - shortName : shortener(name), + longName : entryName, + shortName : shortener(entryName), uid : st.st_uid, gid : st.st_gid, mode : st.st_mode, diff --git a/src/DirectoryMetadata.h b/src/DirectoryMetadata.h index 84212e5..7bf2b55 100644 --- a/src/DirectoryMetadata.h +++ b/src/DirectoryMetadata.h @@ -14,6 +14,9 @@ class Etc; class DirectoryMetadata : public boost::noncopyable { + // TODO What traits does this class have to expose + // so that it works, e.g., with BOOST_FOREACH? + public: typedef boost::shared_ptr Ptr; typedef boost::shared_ptr EtcPtr; diff --git a/src/TruncatingShortener.cpp b/src/TruncatingShortener.cpp new file mode 100644 index 0000000..1ae7885 --- /dev/null +++ b/src/TruncatingShortener.cpp @@ -0,0 +1,37 @@ + +#include "TruncatingShortener.h" +#include +#include + +using namespace std; + +TruncatingShortener::TruncatingShortener(size_t maxNameLength) + : maxNameLength_(maxNameLength) +{ + // ensure minimum length +} + + +string +TruncatingShortener::operator()(const std::string& longName) { + if ( longName.size() < maxNameLength_ ) { + shortNames_.insert(longName); + return longName; + } + + string prefix(longName.substr(0, maxNameLength_ - 1)); + string shortName; + + for ( int i = 1; ; ++i ) { + const string counter(boost::lexical_cast(i)); + prefix.resize(maxNameLength_ - counter.size()); + shortName = prefix + counter; + + if ( shortNames_.insert(shortName).second ) { + return shortName; + } + } + + assert( !"Error in TruncatingShortener" ); +} + diff --git a/src/TruncatingShortener.h b/src/TruncatingShortener.h new file mode 100644 index 0000000..9947b9b --- /dev/null +++ b/src/TruncatingShortener.h @@ -0,0 +1,21 @@ + +#ifndef TRUNCATING_SHORTENER_INCLUDED_H_ +#define TRUNCATING_SHORTENER_INCLUDED_H_ + +#include "NameShortener.h" +#include +#include + +class TruncatingShortener : public NameShortener { +public: + TruncatingShortener( size_t maxNameLength ); + virtual std::string operator()(const std::string& longName); + +private: + std::set shortNames_; + const size_t maxNameLength_; +}; + +#endif // TRUNCATING_SHORTENER_INCLUDED_H_ + + diff --git a/src/dirmeta.cpp b/src/dirmeta.cpp index f2db7a6..90a6477 100644 --- a/src/dirmeta.cpp +++ b/src/dirmeta.cpp @@ -2,6 +2,7 @@ #include #include "DirectoryMetadata.h" #include "MD5Shortener.h" +#include "TruncatingShortener.h" using namespace std; @@ -14,7 +15,8 @@ main( int argc, char* argv[] ) { DirectoryMetadata::fromMetadataFile(".", argv[2]) : DirectoryMetadata::fromMetadataFile("."); } else { - MD5Shortener shortener; +// MD5Shortener shortener; + TruncatingShortener shortener(5); md = DirectoryMetadata::fromFilesystem(".", shortener); } diff --git a/src/transpath.cpp b/src/transpath.cpp index 7abf41a..464b0ab 100644 --- a/src/transpath.cpp +++ b/src/transpath.cpp @@ -1,12 +1,61 @@ -//#include "DirectoryMetadata.h" +#include "DirectoryMetadata.h" +#include "TruncatingShortener.h" +#include +#include +#include +#include +#include using namespace std; - +namespace fs = boost::filesystem; +#define foreach BOOST_FOREACH int -main( int /*argc*/, char* /*argv*/[] ) { +main( int argc, char* argv[] ) +{ + if ( argc < 2 ) { + cerr << "Usage: transpath path" << endl; + return -1; + } + + const fs::path path(argv[1]); + boost::scoped_ptr shortener( new TruncatingShortener(5) ); + DirectoryMetadata::Ptr dm; + + + fs::path prefixPath; + + if ( path.is_absolute() ) { + prefixPath = "/"; + } else { + prefixPath = "."; + } + + fs::path resultPath; + dm = DirectoryMetadata::fromFilesystem(prefixPath.string(), *shortener); + + foreach( fs::path part, path ) { + map entryMap; + + // TODO use copy algo + foreach( const DirectoryMetadata::Entry& e, make_pair(dm->cbegin(), dm->cend()) ) { + entryMap[e.longName] = e; + } + + resultPath /= entryMap[part.string()].shortName; + + prefixPath /= part; + if ( fs::is_directory(prefixPath) ) { + shortener.reset( new TruncatingShortener(5) ); + dm = DirectoryMetadata::fromFilesystem(prefixPath.string(), *shortener); + } else { + break; + } + } + cout << path << " -> " << resultPath << endl; + return 0; }