summaryrefslogtreecommitdiff
path: root/methods/debdelta.cc
diff options
context:
space:
mode:
Diffstat (limited to 'methods/debdelta.cc')
-rw-r--r--methods/debdelta.cc168
1 files changed, 168 insertions, 0 deletions
diff --git a/methods/debdelta.cc b/methods/debdelta.cc
new file mode 100644
index 000000000..42d91a6dc
--- /dev/null
+++ b/methods/debdelta.cc
@@ -0,0 +1,168 @@
+// Includes /*{{{*/
+#include <apt-pkg/acquire-item.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/mmap.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/acquire-method.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/hashes.h>
+#include <apt-pkg/init.h>
+
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <utime.h>
+#include <stdio.h>
+#include <errno.h>
+#include <zlib.h>
+#include <apti18n.h>
+
+/*}}}*/
+/** \brief DebdeltaMethod - TODO: say something about debdelta here!
+ * */
+class DebdeltaMethod : public pkgAcqMethod {
+ bool Debug;
+ string DebdeltaFile;
+ string FromFile;
+ string ToFile;
+protected:
+ // the main(i.e. most important) method of the debdelta method.
+ virtual bool Fetch(FetchItem *Itm);
+public:
+ DebdeltaMethod() : pkgAcqMethod("1.1", SingleInstance | SendConfig) {};
+ void MakeToFile();
+};
+
+bool DebdeltaMethod::Fetch(FetchItem *Itm) /*{{{*/
+{
+ /// Testing only...
+ //FetchResult ResTest;
+ //ResTest.Filename = "/home/ishan/devel/apt/testrepo/binary/gcc-4.6-base_4.6.0-7_amd64.deb";
+ //URIDone(ResTest);
+ //return true;
+ ///
+ Debug = _config->FindB("Debug::pkgAcquire::Debdelta", false);
+ FromFile = Itm->DestFile;
+ URI U(Itm->Uri);
+ DebdeltaFile = U.Path;
+
+ if (flExtension(FromFile) != "deb" || !FileExists(FromFile))
+ FromFile = "/";
+ if (!FileExists(DebdeltaFile))
+ return _error->Error("[Debdelta] Could not find a debdelta file.");
+ MakeToFile();
+ if (FileExists(ToFile))
+ return _error->Error("[Debdelta] New .deb already exists.");
+
+ pid_t Process = ExecFork();
+ if (Process == 0)
+ {
+ const char* Args[8] = {0};
+ Args[0] = "/usr/bin/debpatch";
+ if (!FileExists(Args[0]))
+ return _error->Error("[Debdelta] Could not find debpatch.");
+ Args[1] = "-A";
+ Args[2] = DebdeltaFile.c_str();
+ Args[3] = FromFile.c_str();
+ Args[4] = ToFile.c_str();
+ Args[5] = "1>&2";
+ Args[6] = "2>/dev/null";
+ if (Debug == true)
+ {
+ std::cerr << "[Debdelta] Command:" << std::endl;
+ std::cerr << Args[0] << " " << Args[1] << " " << Args[2] << " " << Args[3] << " "
+ << Args[4] << std::endl;
+ }
+ std::cerr << "[Debdelta] Patching " << ToFile << "...\r";
+ execv(Args[0], (char **)Args);
+ }
+ if (ExecWait(Process, "debpatch", false))
+ {
+ if (!FileExists(ToFile))
+ return _error->Error("[Debdelta] Failed to patch %s", ToFile.c_str());
+ // move the .deb to Dir::Cache::Archives
+ string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(ToFile);
+ Rename(ToFile, FinalFile);
+ ToFile = FinalFile;
+ FetchResult Res;
+ Res.Filename = ToFile;
+ if (Queue != 0)
+ URIDone(Res);
+ else
+ std::cout << "Filename: " << Res.Filename << std::endl;
+ return true;
+ }
+ return false;
+}
+
+
+void DebdeltaMethod::MakeToFile()
+{
+ string DebdeltaName = flNotDir(DebdeltaFile);
+ int NewBegin = DebdeltaName.find("_", 0);
+ string PkgName = DebdeltaName.substr(0, NewBegin);
+ NewBegin = DebdeltaName.find("_", NewBegin + 1);
+ int NewEnd = DebdeltaName.find("_", NewBegin + 1);
+ string NewVersion = DebdeltaName.substr(NewBegin + 1, NewEnd - NewBegin - 1);
+ string Arch = DebdeltaName.substr(NewEnd + 1, DebdeltaName.find(".", NewEnd + 1) - NewEnd - 1);
+ ToFile = _config->FindDir("Dir::Cache::Archives") + "partial/"
+ + PkgName + "_" + NewVersion + "_" + Arch + ".deb";
+}
+
+/*}}}*/
+/** \brief Wrapper class for testing debdelta */ /*{{{*/
+class TestDebdeltaMethod : public DebdeltaMethod {
+public:
+ /** \brief Run debdelta in debug test mode
+ *
+ * This method can be used to run the debdelta method outside
+ * of the "normal" acquire environment for easier testing.
+ *
+ * \param base basename of all files involved in this debdelta test
+ */
+ bool Run(char const *DebdeltaFile, char const *FromFile)
+ {
+ if (pkgInitConfig(*_config) == false ||
+ pkgInitSystem(*_config,_system) == false)
+ {
+ std::cerr << "[Debdelta] E: Could not initialize the system/configuration." << std::endl;
+ _error->DumpErrors();
+ return 100;
+ }
+ _config->CndSet("Debug::pkgAcquire::Debdetla", "true");
+ FetchItem *Test = new FetchItem;
+ Test->DestFile = FromFile;
+ Test->Uri = "debdelta://" + string(DebdeltaFile);
+ Test->FailIgnore = false;
+ Test->IndexFile = false;
+ Test->Next = 0;
+
+ return Fetch(Test);
+ }
+};
+
+/*}}}*/
+/** \brief Starter for the debdelta method (or its test method) {{{
+ *
+ * Used without parameters is the normal behavior for methods for
+ * the APT acquire system. While this works great for the acquire system
+ * it is very hard to test the method and therefore the method also
+ * accepts one parameter which will switch it directly to debug test mode:
+ */
+int main(int argc, char *argv[])
+{
+ if (argc <= 1)
+ {
+ DebdeltaMethod Mth;
+ return Mth.Run();
+ }
+ else
+ {
+ TestDebdeltaMethod Mth;
+ bool result = Mth.Run(argv[1], argv[2]);
+ _error->DumpErrors();
+ return result;
+ }
+}
+/*}}}*/
+