Jelajahi Sumber

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.
Tatsuhiro Tsujikawa 12 tahun lalu
induk
melakukan
4070113ef0
6 mengubah file dengan 119 tambahan dan 34 penghapusan
  1. 31 3
      src/Option.cc
  2. 22 7
      src/Option.h
  3. 1 1
      src/SessionSerializer.cc
  4. 10 8
      src/main.cc
  5. 25 15
      src/option_processing.cc
  6. 30 0
      test/OptionTest.cc

+ 31 - 3
src/Option.cc

@@ -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

+ 22 - 7
src/Option.h

@@ -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

+ 1 - 1
src/SessionSerializer.cc

@@ -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;

+ 10 - 8
src/main.cc

@@ -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);

+ 25 - 15
src/option_processing.cc

@@ -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());

+ 30 - 0
test/OptionTest.cc

@@ -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