Add a Config class to simplify adding configuration settings
The typical use is to inherit Config and add Setting<T> members:
  class MyClass : private Config
  {
    Setting<int> foo{this, 123, "foo", "the number of foos to use"};
    Setting<std::string> bar{this, "blabla", "bar", "the name of the bar"};
    MyClass() : Config(readConfigFile("/etc/my-app.conf"))
    {
      std::cout << foo << "\n"; // will print 123 unless overriden
    }
  };
Currently, this is used by Store and its subclasses for store
parameters. You now get a warning if you specify a non-existant store
parameter in a store URI.
			
			
This commit is contained in:
		
							parent
							
								
									568a099c88
								
							
						
					
					
						commit
						2040240e23
					
				
					 16 changed files with 334 additions and 40 deletions
				
			
		|  | @ -79,10 +79,7 @@ struct BinaryCacheStoreAccessor : public FSAccessor | ||||||
| 
 | 
 | ||||||
| BinaryCacheStore::BinaryCacheStore(const Params & params) | BinaryCacheStore::BinaryCacheStore(const Params & params) | ||||||
|     : Store(params) |     : Store(params) | ||||||
|     , compression(get(params, "compression", "xz")) |  | ||||||
|     , writeNARListing(get(params, "write-nar-listing", "0") == "1") |  | ||||||
| { | { | ||||||
|     auto secretKeyFile = get(params, "secret-key", ""); |  | ||||||
|     if (secretKeyFile != "") |     if (secretKeyFile != "") | ||||||
|         secretKey = std::unique_ptr<SecretKey>(new SecretKey(readFile(secretKeyFile))); |         secretKey = std::unique_ptr<SecretKey>(new SecretKey(readFile(secretKeyFile))); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,14 +13,16 @@ struct NarInfo; | ||||||
| 
 | 
 | ||||||
| class BinaryCacheStore : public Store | class BinaryCacheStore : public Store | ||||||
| { | { | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  |     const Setting<std::string> compression{this, "xz", "compression", "NAR compression method ('xz', 'bzip2', or 'none')"}; | ||||||
|  |     const Setting<bool> writeNARListing{this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"}; | ||||||
|  |     const Setting<Path> secretKeyFile{this, "", "secret-key", "path to secret key used to sign the binary cache"}; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
| 
 | 
 | ||||||
|     std::unique_ptr<SecretKey> secretKey; |     std::unique_ptr<SecretKey> secretKey; | ||||||
| 
 | 
 | ||||||
|     std::string compression; |  | ||||||
| 
 |  | ||||||
|     bool writeNARListing; |  | ||||||
| 
 |  | ||||||
| protected: | protected: | ||||||
| 
 | 
 | ||||||
|     BinaryCacheStore(const Params & params); |     BinaryCacheStore(const Params & params); | ||||||
|  |  | ||||||
|  | @ -3051,13 +3051,11 @@ Path DerivationGoal::openLogFile() | ||||||
|     string baseName = baseNameOf(drvPath); |     string baseName = baseNameOf(drvPath); | ||||||
| 
 | 
 | ||||||
|     /* Create a log file. */ |     /* Create a log file. */ | ||||||
|     Path dir = (format("%1%/%2%/%3%/") % worker.store.logDir % worker.store.drvsLogDir % string(baseName, 0, 2)).str(); |     Path dir = fmt("%s/%s/%s/", worker.store.logDir, worker.store.drvsLogDir, string(baseName, 0, 2)); | ||||||
|     createDirs(dir); |     createDirs(dir); | ||||||
| 
 | 
 | ||||||
|     Path logFileName = (format("%1%/%2%%3%") |     Path logFileName = fmt("%s/%s%s", dir, string(baseName, 2), | ||||||
|         % dir |         settings.compressLog ? ".bz2" : ""); | ||||||
|         % string(baseName, 2) |  | ||||||
|         % (settings.compressLog ? ".bz2" : "")).str(); |  | ||||||
| 
 | 
 | ||||||
|     fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666); |     fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666); | ||||||
|     if (!fdLogFile) throw SysError(format("creating log file ‘%1%’") % logFileName); |     if (!fdLogFile) throw SysError(format("creating log file ‘%1%’") % logFileName); | ||||||
|  |  | ||||||
|  | @ -12,6 +12,10 @@ static std::string uriScheme = "ssh://"; | ||||||
| 
 | 
 | ||||||
| struct LegacySSHStore : public Store | struct LegacySSHStore : public Store | ||||||
| { | { | ||||||
|  |     const Setting<int> maxConnections{this, 1, "max-connections", "maximum number of concurrent SSH connections"}; | ||||||
|  |     const Setting<Path> sshKey{this, "", "ssh-key", "path to an SSH private key"}; | ||||||
|  |     const Setting<bool> compress{this, false, "compress", "whether to compress the connection"}; | ||||||
|  | 
 | ||||||
|     struct Connection |     struct Connection | ||||||
|     { |     { | ||||||
|         std::unique_ptr<SSHMaster::Connection> sshConn; |         std::unique_ptr<SSHMaster::Connection> sshConn; | ||||||
|  | @ -29,16 +33,16 @@ struct LegacySSHStore : public Store | ||||||
|         : Store(params) |         : Store(params) | ||||||
|         , host(host) |         , host(host) | ||||||
|         , connections(make_ref<Pool<Connection>>( |         , connections(make_ref<Pool<Connection>>( | ||||||
|             std::max(1, std::stoi(get(params, "max-connections", "1"))), |             std::max(1, (int) maxConnections), | ||||||
|             [this]() { return openConnection(); }, |             [this]() { return openConnection(); }, | ||||||
|             [](const ref<Connection> & r) { return true; } |             [](const ref<Connection> & r) { return true; } | ||||||
|             )) |             )) | ||||||
|         , master( |         , master( | ||||||
|             host, |             host, | ||||||
|             get(params, "ssh-key", ""), |             sshKey, | ||||||
|             // Use SSH master only if using more than 1 connection.
 |             // Use SSH master only if using more than 1 connection.
 | ||||||
|             connections->capacity() > 1, |             connections->capacity() > 1, | ||||||
|             get(params, "compress", "") == "true") |             compress) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9,9 +9,6 @@ namespace nix { | ||||||
| 
 | 
 | ||||||
| LocalFSStore::LocalFSStore(const Params & params) | LocalFSStore::LocalFSStore(const Params & params) | ||||||
|     : Store(params) |     : Store(params) | ||||||
|     , rootDir(get(params, "root")) |  | ||||||
|     , stateDir(canonPath(get(params, "state", rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir))) |  | ||||||
|     , logDir(canonPath(get(params, "log", rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir))) |  | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -88,6 +85,8 @@ void LocalFSStore::narFromPath(const Path & path, Sink & sink) | ||||||
| 
 | 
 | ||||||
| const string LocalFSStore::drvsLogDir = "drvs"; | const string LocalFSStore::drvsLogDir = "drvs"; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| std::shared_ptr<std::string> LocalFSStore::getBuildLog(const Path & path_) | std::shared_ptr<std::string> LocalFSStore::getBuildLog(const Path & path_) | ||||||
| { | { | ||||||
|     auto path(path_); |     auto path(path_); | ||||||
|  | @ -110,8 +109,8 @@ std::shared_ptr<std::string> LocalFSStore::getBuildLog(const Path & path_) | ||||||
| 
 | 
 | ||||||
|         Path logPath = |         Path logPath = | ||||||
|             j == 0 |             j == 0 | ||||||
|             ? (format("%1%/%2%/%3%/%4%") % logDir % drvsLogDir % string(baseName, 0, 2) % string(baseName, 2)).str() |             ? fmt("%s/%s/%s/%s", logDir, drvsLogDir, string(baseName, 0, 2), string(baseName, 2)) | ||||||
|             : (format("%1%/%2%/%3%") % logDir % drvsLogDir % baseName).str(); |             : fmt("%s/%s/%s", logDir, drvsLogDir, baseName); | ||||||
|         Path logBz2Path = logPath + ".bz2"; |         Path logBz2Path = logPath + ".bz2"; | ||||||
| 
 | 
 | ||||||
|         if (pathExists(logPath)) |         if (pathExists(logPath)) | ||||||
|  |  | ||||||
|  | @ -38,13 +38,14 @@ namespace nix { | ||||||
| LocalStore::LocalStore(const Params & params) | LocalStore::LocalStore(const Params & params) | ||||||
|     : Store(params) |     : Store(params) | ||||||
|     , LocalFSStore(params) |     , LocalFSStore(params) | ||||||
|     , realStoreDir(get(params, "real", rootDir != "" ? rootDir + "/nix/store" : storeDir)) |     , realStoreDir_{this, false, rootDir != "" ? rootDir + "/nix/store" : storeDir, "real", | ||||||
|  |         "physical path to the Nix store"} | ||||||
|  |     , realStoreDir(realStoreDir_) | ||||||
|     , dbDir(stateDir + "/db") |     , dbDir(stateDir + "/db") | ||||||
|     , linksDir(realStoreDir + "/.links") |     , linksDir(realStoreDir + "/.links") | ||||||
|     , reservedPath(dbDir + "/reserved") |     , reservedPath(dbDir + "/reserved") | ||||||
|     , schemaPath(dbDir + "/schema") |     , schemaPath(dbDir + "/schema") | ||||||
|     , trashDir(realStoreDir + "/trash") |     , trashDir(realStoreDir + "/trash") | ||||||
|     , requireSigs(trim(settings.get("signed-binary-caches", std::string("*"))) != "") // FIXME: rename option
 |  | ||||||
|     , publicKeys(getDefaultPublicKeys()) |     , publicKeys(getDefaultPublicKeys()) | ||||||
| { | { | ||||||
|     auto state(_state.lock()); |     auto state(_state.lock()); | ||||||
|  |  | ||||||
|  | @ -67,6 +67,8 @@ private: | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 
 | 
 | ||||||
|  |     PathSetting realStoreDir_; | ||||||
|  | 
 | ||||||
|     const Path realStoreDir; |     const Path realStoreDir; | ||||||
|     const Path dbDir; |     const Path dbDir; | ||||||
|     const Path linksDir; |     const Path linksDir; | ||||||
|  | @ -76,7 +78,9 @@ public: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 
 | 
 | ||||||
|     bool requireSigs; |     Setting<bool> requireSigs{(Store*) this, | ||||||
|  |         trim(settings.get("signed-binary-caches", std::string("*"))) != "", | ||||||
|  |         "require-sigs", "whether store paths should have a trusted signature on import"}; | ||||||
| 
 | 
 | ||||||
|     PublicKeys publicKeys; |     PublicKeys publicKeys; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ template Paths readStorePaths(Store & store, Source & from); | ||||||
| RemoteStore::RemoteStore(const Params & params) | RemoteStore::RemoteStore(const Params & params) | ||||||
|     : Store(params) |     : Store(params) | ||||||
|     , connections(make_ref<Pool<Connection>>( |     , connections(make_ref<Pool<Connection>>( | ||||||
|             std::max(1, std::stoi(get(params, "max-connections", "1"))), |             std::max(1, (int) maxConnections), | ||||||
|             [this]() { return openConnectionWrapper(); }, |             [this]() { return openConnectionWrapper(); }, | ||||||
|             [](const ref<Connection> & r) { return r->to.good() && r->from.good(); } |             [](const ref<Connection> & r) { return r->to.good() && r->from.good(); } | ||||||
|             )) |             )) | ||||||
|  |  | ||||||
|  | @ -22,6 +22,9 @@ class RemoteStore : public virtual Store | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 
 | 
 | ||||||
|  |     const Setting<int> maxConnections{(Store*) this, 1, | ||||||
|  |             "max-connections", "maximum number of concurrent connections to the Nix daemon"}; | ||||||
|  | 
 | ||||||
|     RemoteStore(const Params & params); |     RemoteStore(const Params & params); | ||||||
| 
 | 
 | ||||||
|     /* Implementations of abstract store API methods. */ |     /* Implementations of abstract store API methods. */ | ||||||
|  |  | ||||||
|  | @ -125,22 +125,22 @@ S3Helper::DownloadResult S3Helper::getObject( | ||||||
| 
 | 
 | ||||||
| struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore | struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore | ||||||
| { | { | ||||||
|  |     const Setting<std::string> region{this, Aws::Region::US_EAST_1, "region", {"aws-region"}}; | ||||||
|  |     const Setting<std::string> narinfoCompression{this, "", "narinfo-compression", "compression method for .narinfo files"}; | ||||||
|  |     const Setting<std::string> lsCompression{this, "", "ls-compression", "compression method for .ls files"}; | ||||||
|  |     const Setting<std::string> logCompression{this, "", "log-compression", "compression method for log/* files"}; | ||||||
|  | 
 | ||||||
|     std::string bucketName; |     std::string bucketName; | ||||||
| 
 | 
 | ||||||
|     Stats stats; |     Stats stats; | ||||||
| 
 | 
 | ||||||
|     S3Helper s3Helper; |     S3Helper s3Helper; | ||||||
| 
 | 
 | ||||||
|     std::string narinfoCompression, lsCompression, logCompression; |  | ||||||
| 
 |  | ||||||
|     S3BinaryCacheStoreImpl( |     S3BinaryCacheStoreImpl( | ||||||
|         const Params & params, const std::string & bucketName) |         const Params & params, const std::string & bucketName) | ||||||
|         : S3BinaryCacheStore(params) |         : S3BinaryCacheStore(params) | ||||||
|         , bucketName(bucketName) |         , bucketName(bucketName) | ||||||
|         , s3Helper(get(params, "aws-region", Aws::Region::US_EAST_1)) |         , s3Helper(region) | ||||||
|         , narinfoCompression(get(params, "narinfo-compression", "")) |  | ||||||
|         , lsCompression(get(params, "ls-compression", "")) |  | ||||||
|         , logCompression(get(params, "log-compression", "")) |  | ||||||
|     { |     { | ||||||
|         diskCache = getNarInfoDiskCache(); |         diskCache = getNarInfoDiskCache(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -14,16 +14,19 @@ class SSHStore : public RemoteStore | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 
 | 
 | ||||||
|  |     const Setting<Path> sshKey{(Store*) this, "", "ssh-key", "path to an SSH private key"}; | ||||||
|  |     const Setting<bool> compress{(Store*) this, false, "compress", "whether to compress the connection"}; | ||||||
|  | 
 | ||||||
|     SSHStore(const std::string & host, const Params & params) |     SSHStore(const std::string & host, const Params & params) | ||||||
|         : Store(params) |         : Store(params) | ||||||
|         , RemoteStore(params) |         , RemoteStore(params) | ||||||
|         , host(host) |         , host(host) | ||||||
|         , master( |         , master( | ||||||
|             host, |             host, | ||||||
|             get(params, "ssh-key", ""), |             sshKey, | ||||||
|             // Use SSH master only if using more than 1 connection.
 |             // Use SSH master only if using more than 1 connection.
 | ||||||
|             connections->capacity() > 1, |             connections->capacity() > 1, | ||||||
|             get(params, "compress", "") == "true") |             compress) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -241,8 +241,8 @@ Path Store::computeStorePathForText(const string & name, const string & s, | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Store::Store(const Params & params) | Store::Store(const Params & params) | ||||||
|     : storeDir(get(params, "store", settings.nixStore)) |     : Config(params) | ||||||
|     , state({std::stoi(get(params, "path-info-cache-size", "65536"))}) |     , state({(size_t) pathInfoCacheSize}) | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -718,7 +718,10 @@ ref<Store> openStore(const std::string & uri, const Store::Params & params) | ||||||
| { | { | ||||||
|     for (auto fun : *RegisterStoreImplementation::implementations) { |     for (auto fun : *RegisterStoreImplementation::implementations) { | ||||||
|         auto store = fun(uri, params); |         auto store = fun(uri, params); | ||||||
|         if (store) return ref<Store>(store); |         if (store) { | ||||||
|  |             store->warnUnused(); | ||||||
|  |             return ref<Store>(store); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     throw Error(format("don't know how to open Nix store ‘%s’") % uri); |     throw Error(format("don't know how to open Nix store ‘%s’") % uri); | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| #include "lru-cache.hh" | #include "lru-cache.hh" | ||||||
| #include "sync.hh" | #include "sync.hh" | ||||||
| #include "globals.hh" | #include "globals.hh" | ||||||
|  | #include "config.hh" | ||||||
| 
 | 
 | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <limits> | #include <limits> | ||||||
|  | @ -224,13 +225,17 @@ struct BuildResult | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Store : public std::enable_shared_from_this<Store> | class Store : public std::enable_shared_from_this<Store>, public Config | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 
 | 
 | ||||||
|     typedef std::map<std::string, std::string> Params; |     typedef std::map<std::string, std::string> Params; | ||||||
| 
 | 
 | ||||||
|     const Path storeDir; |     const PathSetting storeDir_{this, false, settings.nixStore, | ||||||
|  |         "store", "path to the Nix store"}; | ||||||
|  |     const Path storeDir = storeDir_; | ||||||
|  | 
 | ||||||
|  |     const Setting<int> pathInfoCacheSize{this, 65536, "path-info-cache-size", "size of the in-memory store path information cache"}; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 
 | 
 | ||||||
|  | @ -585,9 +590,19 @@ protected: | ||||||
| class LocalFSStore : public virtual Store | class LocalFSStore : public virtual Store | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     const Path rootDir; | 
 | ||||||
|     const Path stateDir; |     // FIXME: the (Store*) cast works around a bug in gcc that causes
 | ||||||
|     const Path logDir; |     // it to emit the call to the Option constructor. Clang works fine
 | ||||||
|  |     // either way.
 | ||||||
|  |     const PathSetting rootDir{(Store*) this, true, "", | ||||||
|  |         "root", "directory prefixed to all other paths"}; | ||||||
|  |     const PathSetting stateDir{(Store*) this, false, | ||||||
|  |         rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir, | ||||||
|  |         "state", "directory where Nix will store state"}; | ||||||
|  |     const PathSetting logDir{(Store*) this, false, | ||||||
|  |         rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir, | ||||||
|  |         "log", "directory where Nix will store state"}; | ||||||
|  | 
 | ||||||
|     const static string drvsLogDir; |     const static string drvsLogDir; | ||||||
| 
 | 
 | ||||||
|     LocalFSStore(const Params & params); |     LocalFSStore(const Params & params); | ||||||
|  |  | ||||||
							
								
								
									
										112
									
								
								src/libutil/config.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/libutil/config.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | ||||||
|  | #include "config.hh" | ||||||
|  | #include "args.hh" | ||||||
|  | 
 | ||||||
|  | namespace nix { | ||||||
|  | 
 | ||||||
|  | void Config::set(const std::string & name, const std::string & value) | ||||||
|  | { | ||||||
|  |     auto i = _settings.find(name); | ||||||
|  |     if (i == _settings.end()) | ||||||
|  |         throw UsageError("unknown setting '%s'", name); | ||||||
|  |     i->second.setting->set(value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Config::add(AbstractSetting * setting) | ||||||
|  | { | ||||||
|  |     _settings.emplace(setting->name, Config::SettingData{false, setting}); | ||||||
|  |     for (auto & alias : setting->aliases) | ||||||
|  |         _settings.emplace(alias, Config::SettingData{true, setting}); | ||||||
|  | 
 | ||||||
|  |     bool set = false; | ||||||
|  | 
 | ||||||
|  |     auto i = initials.find(setting->name); | ||||||
|  |     if (i != initials.end()) { | ||||||
|  |         setting->set(i->second); | ||||||
|  |         initials.erase(i); | ||||||
|  |         set = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (auto & alias : setting->aliases) { | ||||||
|  |         auto i = initials.find(alias); | ||||||
|  |         if (i != initials.end()) { | ||||||
|  |             if (set) | ||||||
|  |                 warn("setting '%s' is set, but it's an alias of '%s' which is also set", | ||||||
|  |                     alias, setting->name); | ||||||
|  |             else { | ||||||
|  |                 setting->set(i->second); | ||||||
|  |                 initials.erase(i); | ||||||
|  |                 set = true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Config::warnUnused() | ||||||
|  | { | ||||||
|  |     for (auto & i : initials) | ||||||
|  |         warn("unknown setting '%s'", i.first); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string Config::dump() | ||||||
|  | { | ||||||
|  |     std::string res; | ||||||
|  |     for (auto & opt : _settings) | ||||||
|  |         if (!opt.second.isAlias) | ||||||
|  |             res += opt.first + " = " + opt.second.setting->to_string() + "\n"; | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AbstractSetting::AbstractSetting( | ||||||
|  |     const std::string & name, | ||||||
|  |     const std::string & description, | ||||||
|  |     const std::set<std::string> & aliases) | ||||||
|  |     : name(name), description(description), aliases(aliases) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> void Setting<std::string>::set(const std::string & str) | ||||||
|  | { | ||||||
|  |     value = str; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> std::string Setting<std::string>::to_string() | ||||||
|  | { | ||||||
|  |     return value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> void Setting<int>::set(const std::string & str) | ||||||
|  | { | ||||||
|  |     try { | ||||||
|  |         value = std::stoi(str); | ||||||
|  |     } catch (...) { | ||||||
|  |         throw UsageError("setting '%s' has invalid value '%s'", name, str); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> std::string Setting<int>::to_string() | ||||||
|  | { | ||||||
|  |     return std::to_string(value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> void Setting<bool>::set(const std::string & str) | ||||||
|  | { | ||||||
|  |     value = str == "true" || str == "1"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> std::string Setting<bool>::to_string() | ||||||
|  | { | ||||||
|  |     return value ? "true" : "false"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PathSetting::set(const std::string & str) | ||||||
|  | { | ||||||
|  |     if (str == "") { | ||||||
|  |         if (allowEmpty) | ||||||
|  |             value = ""; | ||||||
|  |         else | ||||||
|  |             throw UsageError("setting '%s' cannot be empty", name); | ||||||
|  |     } else | ||||||
|  |         value = canonPath(str); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										151
									
								
								src/libutil/config.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/libutil/config.hh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,151 @@ | ||||||
|  | #include <map> | ||||||
|  | #include <set> | ||||||
|  | 
 | ||||||
|  | #include "types.hh" | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | namespace nix { | ||||||
|  | 
 | ||||||
|  | class Args; | ||||||
|  | class AbstractSetting; | ||||||
|  | 
 | ||||||
|  | /* A class to simplify providing configuration settings. The typical
 | ||||||
|  |    use is to inherit Config and add Setting<T> members: | ||||||
|  | 
 | ||||||
|  |    class MyClass : private Config | ||||||
|  |    { | ||||||
|  |      Setting<int> foo{this, 123, "foo", "the number of foos to use"}; | ||||||
|  |      Setting<std::string> bar{this, "blabla", "bar", "the name of the bar"}; | ||||||
|  | 
 | ||||||
|  |      MyClass() : Config(readConfigFile("/etc/my-app.conf")) | ||||||
|  |      { | ||||||
|  |        std::cout << foo << "\n"; // will print 123 unless overriden
 | ||||||
|  |      } | ||||||
|  |    }; | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | class Config | ||||||
|  | { | ||||||
|  |     friend class AbstractSetting; | ||||||
|  | 
 | ||||||
|  |     struct SettingData | ||||||
|  |     { | ||||||
|  |         bool isAlias = false; | ||||||
|  |         AbstractSetting * setting; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     std::map<std::string, SettingData> _settings; | ||||||
|  | 
 | ||||||
|  |     StringMap initials; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  |     Config(const StringMap & initials) | ||||||
|  |         : initials(initials) | ||||||
|  |     { } | ||||||
|  | 
 | ||||||
|  |     void set(const std::string & name, const std::string & value); | ||||||
|  | 
 | ||||||
|  |     void add(AbstractSetting * setting); | ||||||
|  | 
 | ||||||
|  |     void warnUnused(); | ||||||
|  | 
 | ||||||
|  |     std::string dump(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class AbstractSetting | ||||||
|  | { | ||||||
|  |     friend class Config; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  |     const std::string name; | ||||||
|  |     const std::string description; | ||||||
|  |     const std::set<std::string> aliases; | ||||||
|  | 
 | ||||||
|  |     int created = 123; | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  | 
 | ||||||
|  |     AbstractSetting( | ||||||
|  |         const std::string & name, | ||||||
|  |         const std::string & description, | ||||||
|  |         const std::set<std::string> & aliases); | ||||||
|  | 
 | ||||||
|  |     virtual ~AbstractSetting() | ||||||
|  |     { | ||||||
|  |         // Check against a gcc miscompilation causing our constructor
 | ||||||
|  |         // not to run.
 | ||||||
|  |         assert(created == 123); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     virtual void set(const std::string & value) = 0; | ||||||
|  | 
 | ||||||
|  |     virtual std::string to_string() = 0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* A setting of type T. */ | ||||||
|  | template<typename T> | ||||||
|  | class Setting : public AbstractSetting | ||||||
|  | { | ||||||
|  | protected: | ||||||
|  | 
 | ||||||
|  |     T value; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  |     Setting(Config * options, | ||||||
|  |         const T & def, | ||||||
|  |         const std::string & name, | ||||||
|  |         const std::string & description, | ||||||
|  |         const std::set<std::string> & aliases = {}) | ||||||
|  |         : AbstractSetting(name, description, aliases) | ||||||
|  |         , value(def) | ||||||
|  |     { | ||||||
|  |         options->add(this); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     operator const T &() const { return value; } | ||||||
|  |     bool operator ==(const T & v2) const { return value == v2; } | ||||||
|  |     bool operator !=(const T & v2) const { return value != v2; } | ||||||
|  |     void operator =(const T & v) { value = v; } | ||||||
|  | 
 | ||||||
|  |     void set(const std::string & str) override; | ||||||
|  | 
 | ||||||
|  |     std::string to_string() override; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template<typename T> | ||||||
|  | std::ostream & operator <<(std::ostream & str, const Setting<T> & opt) | ||||||
|  | { | ||||||
|  |     str << (const T &) opt; | ||||||
|  |     return str; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* A special setting for Paths. These are automatically canonicalised
 | ||||||
|  |    (e.g. "/foo//bar/" becomes "/foo/bar"). */ | ||||||
|  | class PathSetting : public Setting<Path> | ||||||
|  | { | ||||||
|  |     bool allowEmpty; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  |     PathSetting(Config * options, | ||||||
|  |         bool allowEmpty, | ||||||
|  |         const Path & def, | ||||||
|  |         const std::string & name, | ||||||
|  |         const std::string & description, | ||||||
|  |         const std::set<std::string> & aliases = {}) | ||||||
|  |         : Setting<Path>(options, def, name, description, aliases) | ||||||
|  |         , allowEmpty(allowEmpty) | ||||||
|  |     { | ||||||
|  |         set(value); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void set(const std::string & str) override; | ||||||
|  | 
 | ||||||
|  |     Path operator +(const char * p) const { return value + p; } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| #include <list> | #include <list> | ||||||
| #include <set> | #include <set> | ||||||
| #include <memory> | #include <memory> | ||||||
|  | #include <map> | ||||||
| 
 | 
 | ||||||
| #include <boost/format.hpp> | #include <boost/format.hpp> | ||||||
| 
 | 
 | ||||||
|  | @ -141,6 +142,7 @@ private: | ||||||
| 
 | 
 | ||||||
| typedef list<string> Strings; | typedef list<string> Strings; | ||||||
| typedef set<string> StringSet; | typedef set<string> StringSet; | ||||||
|  | typedef std::map<std::string, std::string> StringMap; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Paths are just strings. */ | /* Paths are just strings. */ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue