Save options directly specified for download in --save-session

This change makes --save-session save only options specified for
download, more specifically, options in command-line, -i file and via
RPC. The other options from conf file and default values are not
saved.  This will drastically decrease the size of session file.
pull/73/head
Tatsuhiro Tsujikawa 2013-04-11 21:44:30 +09:00
parent 07d38e31ad
commit 4070113ef0
6 changed files with 119 additions and 34 deletions

View File

@ -51,7 +51,8 @@ Option::~Option() {}
Option::Option(const Option& option)
: table_(option.table_),
use_(option.use_)
use_(option.use_),
parent_(option.parent_)
{}
Option& Option::operator=(const Option& option)
@ -59,6 +60,7 @@ Option& Option::operator=(const Option& option)
if(this != &option) {
table_ = option.table_;
use_ = option.use_;
parent_ = option.parent_;
}
return *this;
}
@ -85,18 +87,34 @@ void Option::put(const Pref* pref, const std::string& value) {
}
bool Option::defined(const Pref* pref) const
{
return bitfield::test(use_, use_.size()*8, pref->i) ||
(parent_ && parent_->defined(pref));
}
bool Option::definedLocal(const Pref* pref) const
{
return bitfield::test(use_, use_.size()*8, pref->i);
}
bool Option::blank(const Pref* pref) const
{
return !defined(pref) || table_[pref->i].empty();
if(bitfield::test(use_, use_.size()*8, pref->i)) {
return table_[pref->i].empty();
} else {
return !parent_ || parent_->blank(pref);
}
}
const std::string& Option::get(const Pref* pref) const
{
return table_[pref->i];
if(bitfield::test(use_, use_.size()*8, pref->i)) {
return table_[pref->i];
} else if(parent_) {
return parent_->get(pref);
} else {
return A2STR::NIL;
}
}
int32_t Option::getAsInt(const Pref* pref) const {
@ -153,4 +171,14 @@ void Option::merge(const Option& option)
}
}
void Option::setParent(const SharedHandle<Option>& parent)
{
parent_ = parent;
}
const SharedHandle<Option>& Option::getParent() const
{
return parent_;
}
} // namespace aria2

View File

@ -40,6 +40,8 @@
#include <string>
#include <vector>
#include "SharedHandle.h"
namespace aria2 {
struct Pref;
@ -48,6 +50,7 @@ class Option {
private:
std::vector<std::string> table_;
std::vector<unsigned char> use_;
SharedHandle<Option> parent_;
public:
Option();
~Option();
@ -55,29 +58,41 @@ public:
Option& operator=(const Option& option);
void put(const Pref* pref, const std::string& value);
// Returns true if name is defined. Otherwise returns false.
// Note that even if the value is a empty string, this method returns true.
// Returns true if name is defined. Otherwise returns false. Note
// that even if the value is a empty string, this method returns
// true. If option is not defined in this object and parent_ is not
// NULL, lookup parent_ to check |pref| is defined.
bool defined(const Pref* pref) const;
// Just like defined(), but this function does not lookup parent_.
bool definedLocal(const Pref* pref) const;
// Returns true if name is not defined or the value is a empty string.
// Otherwise returns false.
bool blank(const Pref* pref) const;
// Returns option value for |pref|. If the |pref| is not defined in
// this object, parent_ is looked up.
const std::string& get(const Pref* pref) const;
int32_t getAsInt(const Pref* pref) const;
int64_t getAsLLInt(const Pref* pref) const;
bool getAsBool(const Pref* pref) const;
double getAsDouble(const Pref* pref) const;
// Removes |pref| from this object. This function does not modify
// parent_.
void remove(const Pref* pref);
// Removes all option values from this object. This function does
// not modify parent_.
void clear();
// Returns the option value table of this object. It does not
// contain option values in parent_ and so forth.
const std::vector<std::string>& getTable() const
{
return table_;
}
// Copy option values defined in option to this option.
// Copy option values defined in option to this option. parent_ is
// left unmodified for this object.
void merge(const Option& option);
// Sets parent Option object for this object.
void setParent(const SharedHandle<Option>& parent);
const SharedHandle<Option>& getParent() const;
};
} // namespace aria2

View File

@ -112,7 +112,7 @@ bool writeOption(BufferedFile& fp, const SharedHandle<Option>& op)
for(size_t i = 1, len = option::countOption(); i < len; ++i) {
const Pref* pref = option::i2p(i);
const OptionHandler* h = oparser->find(pref);
if(h && h->getInitialOption() && op->defined(pref)) {
if(h && h->getInitialOption() && op->definedLocal(pref)) {
if(h->getCumulative()) {
const std::string& val = op->get(pref);
std::vector<std::string> v;

View File

@ -272,14 +272,16 @@ error_code::Value main(int argc, char* argv[])
// command-line. If they are left, because op is used as a template
// for new RequestGroup(such as created in RPC command), they causes
// unintentional effect.
op->remove(PREF_OUT);
op->remove(PREF_FORCE_SEQUENTIAL);
op->remove(PREF_INPUT_FILE);
op->remove(PREF_INDEX_OUT);
op->remove(PREF_SELECT_FILE);
op->remove(PREF_PAUSE);
op->remove(PREF_CHECKSUM);
op->remove(PREF_GID);
for(SharedHandle<Option> i = op; i; i = i->getParent()) {
i->remove(PREF_OUT);
i->remove(PREF_FORCE_SEQUENTIAL);
i->remove(PREF_INPUT_FILE);
i->remove(PREF_INDEX_OUT);
i->remove(PREF_SELECT_FILE);
i->remove(PREF_PAUSE);
i->remove(PREF_CHECKSUM);
i->remove(PREF_GID);
}
if(!op->getAsBool(PREF_ENABLE_RPC) && requestGroups.empty() &&
!uriListParser) {
global::cout()->printf("%s\n", MSG_NO_FILES_TO_DOWNLOAD);

View File

@ -175,6 +175,20 @@ void showCandidates
} // namespace
#ifdef __MINGW32__
namespace {
void optionNativeToUtf8(Option& op)
{
for(size_t i = 1, len = option::countOption(); i < len; ++i) {
const Pref* pref = option::i2p(i);
if(op.definedLocal(pref) && !util::isUtf8(op.get(pref))) {
op.put(pref, nativeToUtf8(op.get(pref)));
}
}
}
} // namespace
#endif // __MINGW32__
void option_processing(Option& op, std::vector<std::string>& uris,
int argc, char* argv[])
{
@ -213,9 +227,8 @@ void option_processing(Option& op, std::vector<std::string>& uris,
exit(error_code::FINISHED);
}
}
oparser->parseDefaultValues(op);
SharedHandle<Option> confOption(new Option());
oparser->parseDefaultValues(*confOption);
if(!noConf) {
std::string cfname =
ucfname.empty() ?
@ -230,7 +243,7 @@ void option_processing(Option& op, std::vector<std::string>& uris,
}
}
try {
oparser->parse(op, ss);
oparser->parse(*confOption, ss);
} catch(OptionHandlerException& e) {
global::cerr()->printf(_("Parse error in %s"), cfname.c_str());
global::cerr()->printf("\n%s", e.stackTrace().c_str());
@ -254,24 +267,21 @@ void option_processing(Option& op, std::vector<std::string>& uris,
}
}
// Override configuration with environment variables.
overrideWithEnv(op, oparser, PREF_HTTP_PROXY, "http_proxy");
overrideWithEnv(op, oparser, PREF_HTTPS_PROXY, "https_proxy");
overrideWithEnv(op, oparser, PREF_FTP_PROXY, "ftp_proxy");
overrideWithEnv(op, oparser, PREF_ALL_PROXY, "all_proxy");
overrideWithEnv(op, oparser, PREF_NO_PROXY, "no_proxy");
overrideWithEnv(*confOption, oparser, PREF_HTTP_PROXY, "http_proxy");
overrideWithEnv(*confOption, oparser, PREF_HTTPS_PROXY, "https_proxy");
overrideWithEnv(*confOption, oparser, PREF_FTP_PROXY, "ftp_proxy");
overrideWithEnv(*confOption, oparser, PREF_ALL_PROXY, "all_proxy");
overrideWithEnv(*confOption, oparser, PREF_NO_PROXY, "no_proxy");
// we must clear eof bit and seek to the beginning of the buffer.
cmdstream.clear();
cmdstream.seekg(0, std::ios::beg);
// finaly let's parse and store command-iine options.
op.setParent(confOption);
oparser->parse(op, cmdstream);
#ifdef __MINGW32__
for(size_t i = 1, len = option::countOption(); i < len; ++i) {
const Pref* pref = option::i2p(i);
if(op.defined(pref) && !util::isUtf8(op.get(pref))) {
op.put(pref, nativeToUtf8(op.get(pref)));
}
}
optionNativeToUtf8(op);
optionNativeToUtf8(*confOption);
#endif // __MINGW32__
} catch(OptionHandlerException& e) {
global::cerr()->printf("%s", e.stackTrace().c_str());

View File

@ -17,6 +17,7 @@ class OptionTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testDefined);
CPPUNIT_TEST(testBlank);
CPPUNIT_TEST(testMerge);
CPPUNIT_TEST(testParent);
CPPUNIT_TEST_SUITE_END();
private:
@ -30,6 +31,7 @@ public:
void testDefined();
void testBlank();
void testMerge();
void testParent();
};
@ -93,4 +95,32 @@ void OptionTest::testMerge()
CPPUNIT_ASSERT(!dest.defined(PREF_OUT));
}
void OptionTest::testParent()
{
Option child;
SharedHandle<Option> parent(new Option());
parent->put(PREF_TIMEOUT, "100");
child.put(PREF_DIR, "foo");
CPPUNIT_ASSERT(!child.defined(PREF_TIMEOUT));
CPPUNIT_ASSERT(!child.definedLocal(PREF_TIMEOUT));
child.setParent(parent);
CPPUNIT_ASSERT(child.defined(PREF_TIMEOUT));
CPPUNIT_ASSERT_EQUAL(std::string("100"), child.get(PREF_TIMEOUT));
CPPUNIT_ASSERT_EQUAL((int32_t)100, child.getAsInt(PREF_TIMEOUT));
CPPUNIT_ASSERT(!child.definedLocal(PREF_TIMEOUT));
// blank
CPPUNIT_ASSERT(!child.blank(PREF_DIR));
child.put(PREF_DIR, "");
CPPUNIT_ASSERT(child.blank(PREF_DIR));
CPPUNIT_ASSERT(!child.blank(PREF_TIMEOUT));
// override
child.put(PREF_TIMEOUT, "200");
CPPUNIT_ASSERT(child.defined(PREF_TIMEOUT));
CPPUNIT_ASSERT(child.definedLocal(PREF_TIMEOUT));
CPPUNIT_ASSERT_EQUAL(std::string("200"), child.get(PREF_TIMEOUT));
child.remove(PREF_TIMEOUT);
CPPUNIT_ASSERT(child.defined(PREF_TIMEOUT));
CPPUNIT_ASSERT(!child.definedLocal(PREF_TIMEOUT));
}
} // namespace aria2