This is the mail archive of the
cygwin-apps-cvs
mailing list for the cygwin-apps project.
[setup - the official Cygwin setup program] branch master, updated. release_2.885
- From: jturney at sourceware dot org
- To: cygwin-apps-cvs at sourceware dot org
- Date: 28 Jan 2018 16:45:00 -0000
- Subject: [setup - the official Cygwin setup program] branch master, updated. release_2.885
https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=bb8a17ba89743eeaa17574504395d4a9968edfc8
commit bb8a17ba89743eeaa17574504395d4a9968edfc8
Merge: b7bcb7e b1902cb
Author: Jon Turney <jon.turney@dronecode.org.uk>
Date: Sun Jan 28 15:12:03 2018 +0000
Merge branch 'topic/libsolv'
Diff:
---
IniDBBuilderPackage.cc | 346 ++++++----------
IniDBBuilderPackage.h | 32 +-
Makefile.am | 9 +-
PackageSpecification.cc | 18 +
PackageSpecification.h | 9 +-
PickPackageLine.cc | 1 -
PickView.cc | 4 -
README | 28 ++
bootstrap.sh | 2 +-
choose.cc | 171 ++++++--
choose.h | 10 +-
configure.ac | 2 +
confirm.cc | 148 +++++++
confirm.h | 34 ++
cygpackage.cc | 143 -------
cygpackage.h | 74 ----
desktop.cc | 1 -
download.cc | 76 ++---
filemanip.cc | 18 +-
filemanip.h | 1 -
ini.cc | 8 +-
inilex.ll | 3 +
iniparse.yy | 9 +
install.cc | 99 ++---
libsolv.cc | 1018 +++++++++++++++++++++++++++++++++++++++++++++++
libsolv.h | 276 +++++++++++++
main.cc | 4 +
package_db.cc | 301 ++++++++++++--
package_db.h | 34 ++-
package_depends.cc | 19 +-
package_depends.h | 2 +-
package_meta.cc | 130 +++++--
package_meta.h | 21 +-
package_version.cc | 320 ---------------
package_version.h | 164 +--------
prereq.cc | 245 +++---------
prereq.h | 27 +-
res.rc | 42 ++-
resource.h | 6 +-
39 files changed, 2430 insertions(+), 1425 deletions(-)
diff --git a/IniDBBuilderPackage.cc b/IniDBBuilderPackage.cc
index a964ee0..4169634 100644
--- a/IniDBBuilderPackage.cc
+++ b/IniDBBuilderPackage.cc
@@ -22,8 +22,6 @@
#include "IniParseFeedback.h"
#include "package_db.h"
#include "package_meta.h"
-#include "package_version.h"
-#include "cygpackage.h"
#include "ini.h"
// for strtoul
#include <string.h>
@@ -34,7 +32,7 @@
using namespace std;
IniDBBuilderPackage::IniDBBuilderPackage (IniParseFeedback const &aFeedback) :
-cp (0), cbpv (), cspv (), currentSpec (0), currentNodeList (0), trust (0), _feedback (aFeedback){}
+currentSpec (0), _feedback (aFeedback){}
IniDBBuilderPackage::~IniDBBuilderPackage()
{
@@ -67,33 +65,34 @@ IniDBBuilderPackage::buildVersion (const std::string& aVersion)
}
void
-IniDBBuilderPackage::buildPackage (const std::string& name)
+IniDBBuilderPackage::buildPackage (const std::string& _name)
{
-#if DEBUG
- if (cp)
- {
- Log (LOG_BABBLE) << "Finished with package " << cp->name << endLog;
- if (cbpv)
- {
- Log (LOG_BABBLE) << "Version " << cbpv.Canonical_version() << endLog;
- Log (LOG_BABBLE) << "Depends:";
- dumpPackageDepends (cbpv.depends(), Log (LOG_BABBLE));
- Log (LOG_BABBLE) << endLog;
- }
- }
-#endif
- packagedb db;
- cp = db.findBinary (PackageSpecification(name));
- if (!cp)
- {
- cp = new packagemeta (name);
- db.packages.insert (packagedb::packagecollection::value_type(cp->name,cp));
- }
- cbpv = cygpackage::createInstance (name, package_binary);
- cspv = packageversion ();
+ process();
+
+ /* Reset for next package */
+ name = _name;
+ message_id = "";
+ message_string = "";
+ categories.clear();
+ replace_versions.clear();
+
+ cbpv.reponame = release;
+ cbpv.version = "";
+ cbpv.vendor = release;
+ cbpv.sdesc = "";
+ cbpv.ldesc = "";
+ cbpv.stability = TRUST_CURR;
+ cbpv.type = package_binary;
+ cbpv.spkg = PackageSpecification();
+ cbpv.spkg_id = packageversion();
+ cbpv.requires = NULL;
+ cbpv.obsoletes = NULL;
+ cbpv.archive = packagesource();
+
currentSpec = NULL;
currentNodeList = NULL;
- trust = TRUST_CURR;
+ dependsNodeList = PackageDepends();
+ obsoletesNodeList = PackageDepends();
#if DEBUG
Log (LOG_BABBLE) << "Created package " << name << endLog;
#endif
@@ -102,20 +101,19 @@ IniDBBuilderPackage::buildPackage (const std::string& name)
void
IniDBBuilderPackage::buildPackageVersion (const std::string& version)
{
- cbpv.setCanonicalVersion (version);
- add_correct_version();
+ cbpv.version = version;
}
void
IniDBBuilderPackage::buildPackageSDesc (const std::string& theDesc)
{
- cbpv.set_sdesc(theDesc);
+ cbpv.sdesc = theDesc;
}
void
IniDBBuilderPackage::buildPackageLDesc (const std::string& theDesc)
{
- cbpv.set_ldesc(theDesc);
+ cbpv.ldesc = theDesc;
}
void
@@ -124,21 +122,23 @@ IniDBBuilderPackage::buildPackageInstall (const std::string& path,
char *hash,
hashType type)
{
- process_src (*cbpv.source(), path);
- setSourceSize (*cbpv.source(), size);
+ // set archive path, size, mirror, hash
+ cbpv.archive.set_canonical(path.c_str());
+ cbpv.archive.size = atoi(size.c_str());
+ cbpv.archive.sites.push_back(site(parse_mirror));
switch (type) {
case hashType::sha512:
- if (hash && !cbpv.source()->sha512_isSet)
+ if (hash && !cbpv.archive.sha512_isSet)
{
- memcpy (cbpv.source()->sha512sum, hash, sizeof(cbpv.source()->sha512sum));
- cbpv.source()->sha512_isSet = true;
+ memcpy (cbpv.archive.sha512sum, hash, sizeof(cbpv.archive.sha512sum));
+ cbpv.archive.sha512_isSet = true;
}
break;
case hashType::md5:
- if (hash && !cbpv.source()->md5.isSet())
- cbpv.source()->md5.set((unsigned char *)hash);
+ if (hash && !cbpv.archive.md5.isSet())
+ cbpv.archive.md5.set((unsigned char *)hash);
break;
case hashType::none:
@@ -152,91 +152,70 @@ IniDBBuilderPackage::buildPackageSource (const std::string& path,
char *hash,
hashType type)
{
- packagedb db;
- /* get an appropriate metadata */
- csp = db.findSource (PackageSpecification (cbpv.Name()));
- if (!csp)
- {
- /* Copy the existing meta data to a new source package */
- csp = new packagemeta (*cp);
- /* delete versions information */
- csp->versions.clear();
- csp->desired = packageversion();
- csp->installed = packageversion();
- csp->curr = packageversion();
- csp->exp = packageversion();
- db.sourcePackages.insert (packagedb::packagecollection::value_type(csp->name,csp));
- }
- /* create a source packageversion */
- cspv = cygpackage::createInstance (cbpv.Name(), package_source);
- cspv.setCanonicalVersion (cbpv.Canonical_version());
- set<packageversion>::iterator i=find (csp->versions.begin(),
- csp->versions.end(), cspv);
- if (i == csp->versions.end())
- {
- csp->add_version (cspv);
- }
- else
- cspv = *i;
-
- if (!cspv.source()->Canonical())
- cspv.source()->set_canonical (path.c_str());
- cspv.source()->sites.push_back(site(parse_mirror));
+ /* When there is a source: line, we invent a package to contain the source,
+ and make it the source package for this package. */
- /* creates the relationship between binary and source packageversions */
- cbpv.setSourcePackageSpecification (PackageSpecification (cspv.Name()));
- PackageSpecification &spec = cbpv.sourcePackageSpecification();
- spec.setOperator (PackageSpecification::Equals);
- spec.setVersion (cbpv.Canonical_version());
+ /* create a source package version */
+ SolverPool::addPackageData cspv = cbpv;
+ cspv.type = package_source;
+ cspv.requires = NULL;
+ cspv.obsoletes = NULL;
- setSourceSize (*cspv.source(), size);
+ /* set archive path, size, mirror, hash */
+ cspv.archive = packagesource();
+ cspv.archive.set_canonical(path.c_str());
+ cspv.archive.size = atoi(size.c_str());
+ cspv.archive.sites.push_back(site(parse_mirror));
switch (type) {
case hashType::sha512:
- if (hash && !cspv.source()->sha512_isSet)
+ if (hash && !cspv.archive.sha512_isSet)
{
- memcpy (cspv.source()->sha512sum, hash, sizeof(cspv.source()->sha512sum));
- cspv.source()->sha512_isSet = true;
+ memcpy (cspv.archive.sha512sum, hash, sizeof(cspv.archive.sha512sum));
+ cspv.archive.sha512_isSet = true;
}
break;
case hashType::md5:
- if (hash && !cspv.source()->md5.isSet())
- cspv.source()->md5.set((unsigned char *)hash);
+ if (hash && !cspv.archive.md5.isSet())
+ cspv.archive.md5.set((unsigned char *)hash);
break;
case hashType::none:
break;
}
+
+ packagedb db;
+ packageversion spkg_id = db.addSource (name + "-src", cspv);
+
+ /* create relationship between binary and source packageversions */
+ cbpv.spkg = PackageSpecification(name + "-src");
+ cbpv.spkg_id = spkg_id;
}
void
-IniDBBuilderPackage::buildPackageTrust (int newtrust)
+IniDBBuilderPackage::buildPackageTrust (trusts newtrust)
{
- trust = newtrust;
- if (newtrust != TRUST_UNKNOWN)
- {
- cbpv = cygpackage::createInstance (cp->name, package_binary);
- cspv = packageversion ();
- }
+ process();
+ cbpv.stability = newtrust;
}
void
IniDBBuilderPackage::buildPackageCategory (const std::string& name)
{
- cp->add_category (name);
+ categories.insert(name);
}
void
IniDBBuilderPackage::buildBeginDepends ()
{
#if DEBUG
- Log (LOG_BABBLE) << "Beginning of a depends statement for " << cp->name
- << endLog;
+ Log (LOG_BABBLE) << "Beginning of a depends statement " << endLog;
#endif
currentSpec = NULL;
- cbpv.depends()->clear();
- currentNodeList = cbpv.depends();
+ dependsNodeList = PackageDepends();
+ currentNodeList = &dependsNodeList;
+ cbpv.requires = &dependsNodeList;
}
void
@@ -246,55 +225,49 @@ IniDBBuilderPackage::buildBeginBuildDepends ()
Log (LOG_BABBLE) << "Beginning of a Build-Depends statement" << endLog;
#endif
currentSpec = NULL;
- currentNodeList = NULL; /* there is currently nowhere to store Build-Depends information */
+ currentNodeList = NULL;
+ /* there is currently nowhere to store Build-Depends information */
}
void
-IniDBBuilderPackage::buildSourceName (const std::string& name)
+IniDBBuilderPackage::buildBeginObsoletes ()
{
- if (cbpv)
- {
- cbpv.setSourcePackageSpecification (PackageSpecification (name));
#if DEBUG
- Log (LOG_BABBLE) << "\"" << cbpv.sourcePackageSpecification() <<
- "\" is the source package for " << cp->name << "." << endLog;
+ Log (LOG_BABBLE) << "Beginning of an obsoletes statement" << endLog;
#endif
- }
- else
- _feedback.warning ((std::string ("Attempt to set source for package")
- + std::string(cp->name)
- + "before creation of a version.").c_str());
+ currentSpec = NULL;
+ obsoletesNodeList = PackageDepends();
+ currentNodeList = &obsoletesNodeList;
+ cbpv.obsoletes = &obsoletesNodeList;
}
void
-IniDBBuilderPackage::buildSourceNameVersion (const std::string& version)
+IniDBBuilderPackage::buildSourceName (const std::string& _name)
{
- if (cbpv)
- {
- cbpv.sourcePackageSpecification().setOperator (PackageSpecification::Equals);
- cbpv.sourcePackageSpecification().setVersion (version);
+ // When there is a Source: line, that names a real source package
+ packagedb db;
+ cbpv.spkg = PackageSpecification(_name);
+ cbpv.spkg_id = db.findSourceVersion (PackageSpecification(_name, cbpv.version));
#if DEBUG
- Log (LOG_BABBLE) << "The source version needed for " << cp->name <<
- " is " << version << "." << endLog;
+ Log (LOG_BABBLE) << "\"" << _name << "\" is the source package for " << name << "." << endLog;
#endif
- }
- else
- _feedback.warning ((std::string ("Attempt to set source version for package")
- + std::string(cp->name)
- + "before creation of a version.").c_str());
+}
+
+void
+IniDBBuilderPackage::buildSourceNameVersion (const std::string& version)
+{
+ // XXX: should be stored as sourceevr
}
void
IniDBBuilderPackage::buildPackageListNode (const std::string & name)
{
- if (currentNodeList)
- {
#if DEBUG
- Log (LOG_BABBLE) << "New node '" << name << "' for package list" << endLog;
+ Log (LOG_BABBLE) << "New node '" << name << "' for package list" << endLog;
#endif
- currentSpec = new PackageSpecification (name);
- currentNodeList->push_back (currentSpec);
- }
+ currentSpec = new PackageSpecification (name);
+ if (currentNodeList)
+ currentNodeList->push_back (currentSpec);
}
void
@@ -308,13 +281,8 @@ IniDBBuilderPackage::buildPackageListOperator (PackageSpecification::_operators
endLog;
#endif
}
- else
- _feedback.warning ((std::string ("Attempt to set an operator for package ")
- + std::string(cp->name)
- + " with no current specification.").c_str());
}
-
void
IniDBBuilderPackage::buildPackageListOperatorVersion (const std::string& aVersion)
{
@@ -326,110 +294,50 @@ IniDBBuilderPackage::buildPackageListOperatorVersion (const std::string& aVersio
endLog;
#endif
}
- else
- _feedback.warning ((std::string ("Attempt to set an operator version for package ")
- + std::string(cp->name)
- + " with no current specification.").c_str());
}
-/* privates */
-
void
-IniDBBuilderPackage::add_correct_version()
+IniDBBuilderPackage::buildMessage (const std::string& _message_id, const std::string& _message_string)
{
- if (currentNodeList)
- *cbpv.depends() = *currentNodeList;
-
- int merged = 0;
- for (set<packageversion>::iterator n = cp->versions.begin();
- !merged && n != cp->versions.end(); ++n)
- if (*n == cbpv )
- {
- packageversion ver = *n;
- /* ASSUMPTIONS:
- categories and requires are consistent for the same version across
- all mirrors
- */
- /*
- XXX: if the versions are equal but the size/md5sum are different,
- we should alert the user, as they may not be getting what they expect...
- */
- /* Copy the binary mirror across if this site claims to have an install */
- if (cbpv.source()->sites.size() )
- ver.source()->sites.push_back(site (cbpv.source()->sites.begin()->key));
- /* Copy the descriptions across */
- if (cbpv.SDesc ().size() && !n->SDesc ().size())
- ver.set_sdesc (cbpv.SDesc ());
- if (cbpv.LDesc ().size() && !n->LDesc ().size())
- ver.set_ldesc (cbpv.LDesc ());
- if (cbpv.depends()->size() && !ver.depends ()->size())
- *ver.depends() = *cbpv.depends();
- /* TODO: other package lists */
- /* Prevent dangling references */
- currentNodeList = NULL;
- currentSpec = NULL;
- cbpv = *n;
- merged = 1;
-#if DEBUG
- Log (LOG_BABBLE) << cp->name << " merged with an existing version " << cbpv.Canonical_version() << endLog;
-#endif
- }
-
- if (!merged)
- {
- cp->add_version (cbpv);
-#if DEBUG
- Log (LOG_BABBLE) << cp->name << " version " << cbpv.Canonical_version() << " added" << endLog;
-#endif
- }
-
- /*
- Should this version be the one selected for this package at a given
- stability/trust setting? After merging potentially multiple package
- databases, we should pick the one with the highest version number.
- */
- packageversion *v = NULL;
- switch (trust)
- {
- case TRUST_CURR:
- v = &(cp->curr);
- break;
- case TRUST_TEST:
- v = &(cp->exp);
- break;
- }
-
- if (v)
- {
- int comparison = packageversion::compareVersions(cbpv, *v);
-
- if ((bool)(*v))
- Log (LOG_BABBLE) << "package " << cp->name << " comparing versions " << cbpv.Canonical_version() << " and " << v->Canonical_version() << ", result was " << comparison << endLog;
-
- if (comparison > 0)
- {
- *v = cbpv;
- }
- }
+ message_id = _message_id;
+ message_string = _message_string;
}
void
-IniDBBuilderPackage::process_src (packagesource &src, const std::string& path)
+IniDBBuilderPackage::buildPackageReplaceVersionsList (const std::string& version)
{
- if (!src.Canonical())
- src.set_canonical (path.c_str());
- src.sites.push_back(site(parse_mirror));
+ replace_versions.insert(version);
}
+/* privates */
void
-IniDBBuilderPackage::setSourceSize (packagesource &src, const std::string& size)
+IniDBBuilderPackage::process ()
{
- if (!src.size)
- src.size = atoi(size.c_str());
-}
+ if (!name.size())
+ return;
-void
-IniDBBuilderPackage::buildMessage (const std::string& message_id, const std::string& message)
-{
- cp->set_message (message_id, message);
+#if DEBUG
+ Log (LOG_BABBLE) << "Finished with package " << name << endLog;
+ Log (LOG_BABBLE) << "Version " << cbpv.version << endLog;
+#endif
+
+ /* Transfer the accumulated package information to packagedb */
+ packagedb db;
+ packagemeta *pkg = db.addBinary (name, cbpv);
+
+ // For no good historical reason, some data lives in packagemeta rather than
+ // the packageversion
+ for (auto i = categories.begin(); i != categories.end(); i++)
+ {
+ pkg->add_category(*i);
+ }
+ pkg->set_message(message_id, message_string);
+ pkg->set_version_blacklist(replace_versions);
+
+ // Reset for next version
+ cbpv.version = "";
+ cbpv.type = package_binary;
+ cbpv.spkg = PackageSpecification();
+ cbpv.spkg_id = packageversion();
+ cbpv.archive = packagesource();
}
diff --git a/IniDBBuilderPackage.h b/IniDBBuilderPackage.h
index 323b186..da2d97d 100644
--- a/IniDBBuilderPackage.h
+++ b/IniDBBuilderPackage.h
@@ -17,11 +17,15 @@
#define SETUP_INIDBBUILDERPACKAGE_H
#include <vector>
-#include "package_version.h"
+#include <set>
+
+#include "package_message.h"
+#include "PackageTrust.h"
+#include "String++.h"
+#include "libsolv.h"
class IniParseFeedback;
class packagesource;
-class packagemeta;
enum class hashType { none, md5, sha512 };
@@ -42,21 +46,24 @@ public:
void buildPackageSource (const std::string&, const std::string&,
char *, hashType);
- void buildPackageTrust (int);
+ void buildPackageTrust (trusts);
void buildPackageCategory (const std::string& );
void buildBeginDepends ();
void buildBeginBuildDepends ();
+ void buildBeginObsoletes ();
void buildMessage (const std::string&, const std::string&);
void buildSourceName (const std::string& );
void buildSourceNameVersion (const std::string& );
void buildPackageListNode (const std::string& );
void buildPackageListOperator (PackageSpecification::_operators const &);
void buildPackageListOperatorVersion (const std::string& );
+ void buildPackageReplaceVersionsList (const std::string& );
void set_arch (const std::string& a) { arch = a; }
void set_release (const std::string& rel) { release = rel; }
+ // setup.ini header data
unsigned int timestamp;
std::string arch;
std::string release;
@@ -64,17 +71,20 @@ public:
std::string parse_mirror;
private:
- void add_correct_version();
- void process_src (packagesource &src, const std::string& );
- void setSourceSize (packagesource &src, const std::string& );
+ void process ();
- packagemeta *cp;
- packageversion cbpv;
- packagemeta *csp;
- packageversion cspv;
+ // package data
+ std::string name;
+ std::set <std::string, casecompare_lt_op> categories;
+ std::string message_id;
+ std::string message_string;
PackageSpecification *currentSpec;
PackageDepends *currentNodeList;
- int trust;
+ PackageDepends dependsNodeList;
+ PackageDepends obsoletesNodeList;
+ SolverPool::addPackageData cbpv;
+ std::set <std::string> replace_versions;
+
IniParseFeedback const &_feedback;
};
diff --git a/Makefile.am b/Makefile.am
index a238d88..37341b9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -98,7 +98,7 @@ inilint_SOURCES = \
String++.h
@SETUP@_LDADD = \
- libgetopt++/libgetopt++.la -lgcrypt -lgpg-error -llzma -lbz2 -lz \
+ libgetopt++/libgetopt++.la -lgcrypt -lgpg-error -llzma -lbz2 -lz -lsolv -lregex \
-lshlwapi -lcomctl32 -lole32 -lws2_32 -lpsapi -luuid -lntdll -lwininet -lmingw32
@SETUP@_LDFLAGS = -mwindows -Wc,-static -static-libtool-libs
@SETUP@_SOURCES = \
@@ -119,6 +119,8 @@ inilint_SOURCES = \
compress_gz.h \
compress_xz.cc \
compress_xz.h \
+ confirm.cc \
+ confirm.h \
ConnectionSetting.cc \
ConnectionSetting.h \
ControlAdjuster.cc \
@@ -126,8 +128,6 @@ inilint_SOURCES = \
crypto.cc \
crypto.h \
cyg-pubkey.h \
- cygpackage.cc \
- cygpackage.h \
desktop.cc \
desktop.h \
dialog.cc \
@@ -171,6 +171,8 @@ inilint_SOURCES = \
IOStreamProvider.h \
KeysSetting.cc \
KeysSetting.h \
+ libsolv.cc \
+ libsolv.h \
localdir.cc \
localdir.h \
LogFile.cc \
@@ -206,7 +208,6 @@ inilint_SOURCES = \
package_meta.h \
package_source.cc \
package_source.h \
- package_version.cc \
package_version.h \
PackageSpecification.cc \
PackageSpecification.h \
diff --git a/PackageSpecification.cc b/PackageSpecification.cc
index 247f3da..b58ad80 100644
--- a/PackageSpecification.cc
+++ b/PackageSpecification.cc
@@ -22,12 +22,30 @@ PackageSpecification::PackageSpecification (const std::string& packageName)
{
}
+PackageSpecification::PackageSpecification (const std::string& packageName,
+ const std::string& packageVersion)
+ : _packageName (packageName) , _operator (Equals), _version (packageVersion)
+{
+}
+
const std::string&
PackageSpecification::packageName () const
{
return _packageName;
}
+const PackageSpecification::_operators
+PackageSpecification::op() const
+{
+ return _operator;
+}
+
+const std::string&
+PackageSpecification::version() const
+{
+ return _version;
+}
+
void
PackageSpecification::setOperator (_operators anOperator)
{
diff --git a/PackageSpecification.h b/PackageSpecification.h
index 4c3ed6d..b881494 100644
--- a/PackageSpecification.h
+++ b/PackageSpecification.h
@@ -18,7 +18,9 @@
#include <iosfwd>
#include "String++.h"
-class packageversion;
+
+class SolvableVersion;
+typedef SolvableVersion packageversion;
/* Describe a package - i.e. we need version 5 of apt */
@@ -27,6 +29,8 @@ class PackageSpecification
public:
PackageSpecification () : _packageName (), _operator(Equals) {}
PackageSpecification (const std::string& packageName);
+ PackageSpecification (const std::string& packageName,
+ const std::string &packageVersion);
~PackageSpecification () {}
enum _operators
@@ -39,6 +43,9 @@ public:
};
const std::string& packageName() const;
+ const _operators op() const;
+ const std::string& version() const;
+
void setOperator (_operators);
void setVersion (const std::string& );
diff --git a/PickPackageLine.cc b/PickPackageLine.cc
index 31103ce..2caeafe 100644
--- a/PickPackageLine.cc
+++ b/PickPackageLine.cc
@@ -16,7 +16,6 @@
#include "PickPackageLine.h"
#include "PickView.h"
#include "package_db.h"
-#include "package_version.h"
void
PickPackageLine::paint (HDC hdc, HRGN unused, int x, int y, int col_num, int show_cat)
diff --git a/PickView.cc b/PickView.cc
index 2e1beda..c583eea 100644
--- a/PickView.cc
+++ b/PickView.cc
@@ -21,7 +21,6 @@
#include "PickPackageLine.h"
#include "PickCategoryLine.h"
#include "package_db.h"
-#include "package_version.h"
#include "dialog.h"
#include "resource.h"
/* For 'source' */
@@ -944,9 +943,6 @@ PickView::defaultTrust (trusts trust)
{
this->deftrust = trust;
- packagedb db;
- db.defaultTrust(trust);
-
// force the picker to redraw
RECT r = GetClientRect ();
InvalidateRect (this->GetHWND(), &r, TRUE);
diff --git a/README b/README
index 120049c..9be9c50 100644
--- a/README
+++ b/README
@@ -3,6 +3,10 @@ for the Cygwin net releases.
HOW TO BUILD:
-------------
+
+Cygwin
+------
+
Setup should build out-of-the-box on any Cygwin environment that has all the
required packages and their dependencies installed:
@@ -10,6 +14,7 @@ required packages and their dependencies installed:
- mingw64-${arch}-headers
- mingw64-${arch}-gcc-g++
- mingw64-${arch}-libgcrypt
+ - mingw64-${arch}-libsolv
- mingw64-${arch}-bzip2
- mingw64-${arch}-xz
- mingw64-${arch}-zlib
@@ -26,6 +31,29 @@ to make changes to the build system.
- flex
- bison
+Fedora
+------
+
+Setup should also build out-of-the-box in a Fedora environment that has all the
+required packages and their dependencies installed:
+
+ - make
+ - libtool
+ - mingw${arch}-gcc-c++
+ - mingw${arch}-zlib-static
+ - mingw${arch}-libgcrypt-static
+ - mingw${arch}-libgnurx-static (*)
+ - mingw${arch}-libsolv-static
+ - mingw${arch}-bzip2-static
+ - mingw${arch}-xz-libs-static
+ - mingw${arch}-winpthreads-static
+ - upx (optional)
+
+The ${arch} needs to be replaced with either "32" or "64"
+depending on the target architecture to build for.
+
+(*) Requires 'dnf copr enable jturney/mingw-libsolv'
+
Build commands:
0) If building from git, obtain this project's code:
diff --git a/bootstrap.sh b/bootstrap.sh
index f21206d..1d388da 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -21,7 +21,7 @@ bootstrap() {
cd "$srcdir"
# Make sure we are running in the right directory
-if [ ! -f cygpackage.cc ]; then
+if [ ! -f main.cc ]; then
echo "You must run this script from the directory containing it"
exit 1
fi
diff --git a/choose.cc b/choose.cc
index a676a64..9cf3a50 100644
--- a/choose.cc
+++ b/choose.cc
@@ -48,7 +48,6 @@
#include "package_db.h"
#include "package_meta.h"
-#include "package_version.h"
#include "threebar.h"
#include "Generic.h"
@@ -64,7 +63,6 @@ static BoolOption UpgradeAlsoOption (false, 'g', "upgrade-also", "Also upgrade i
static BoolOption CleanOrphansOption (false, 'o', "delete-orphans", "Remove orphaned packages");
static BoolOption ForceCurrentOption (false, 'f', "force-current", "Select the current version for all packages");
static BoolOption PruneInstallOption (false, 'Y', "prune-install", "Prune the installation to only the requested packages");
-static BoolOption MirrorOption (false, 'm', "mirror-mode", "Skip package availability check when installing from local directory (requires local directory to be clean mirror!)");
using namespace std;
@@ -79,7 +77,8 @@ static ControlAdjuster::ControlInfo ChooserControlsInfo[] = {
{IDC_CHOOSE_SEARCH_LABEL, CP_LEFT, CP_TOP},
{IDC_CHOOSE_SEARCH_EDIT, CP_LEFT, CP_TOP},
{IDC_CHOOSE_KEEP, CP_RIGHT, CP_TOP},
- {IDC_CHOOSE_CURR, CP_RIGHT, CP_TOP},
+ {IDC_CHOOSE_BEST, CP_RIGHT, CP_TOP},
+ {IDC_CHOOSE_SYNC, CP_RIGHT, CP_TOP},
{IDC_CHOOSE_EXP, CP_RIGHT, CP_TOP},
{IDC_CHOOSE_VIEW, CP_LEFT, CP_TOP},
{IDC_LISTVIEW_POS, CP_RIGHT, CP_TOP},
@@ -91,7 +90,7 @@ static ControlAdjuster::ControlInfo ChooserControlsInfo[] = {
ChooserPage::ChooserPage () :
cmd_show_set (false), saved_geom (false), saw_geom_change (false),
- timer_id (DEFAULT_TIMER_ID)
+ timer_id (DEFAULT_TIMER_ID), activated (false)
{
sizeProcessor.AddControlInfo (ChooserControlsInfo);
@@ -153,13 +152,34 @@ ChooserPage::createListview ()
chooser->setViewMode (!is_new_install || UpgradeAlsoOption || hasManualSelections ?
PickView::views::PackagePending : PickView::views::Category);
SendMessage (GetDlgItem (IDC_CHOOSE_VIEW), CB_SETCURSEL, (WPARAM)chooser->getViewMode(), 0);
-
- /* FIXME: do we need to init the desired fields ? */
- static int ta[] = { IDC_CHOOSE_KEEP, IDC_CHOOSE_CURR, IDC_CHOOSE_EXP, 0 };
- rbset (GetHWND (), ta, IDC_CHOOSE_CURR);
ClearBusy ();
}
+void
+ChooserPage::initialUpdateState()
+{
+ // set the initial update state
+ if (ForceCurrentOption)
+ {
+ update_mode_id = IDC_CHOOSE_SYNC;
+ changeTrust(update_mode_id, false, true);
+ }
+ else if (hasManualSelections && !UpgradeAlsoOption)
+ {
+ // if packages are added or removed on the command-line and --upgrade-also
+ // isn't used, we keep the current versions of everything else
+ update_mode_id = IDC_CHOOSE_KEEP;
+ }
+ else
+ {
+ update_mode_id = IDC_CHOOSE_BEST;
+ changeTrust (update_mode_id, false, true);
+ }
+
+ static int ta[] = { IDC_CHOOSE_KEEP, IDC_CHOOSE_BEST, IDC_CHOOSE_SYNC, 0 };
+ rbset (GetHWND (), ta, update_mode_id);
+}
+
/* TODO: review ::overrides for possible consolidation */
void
ChooserPage::getParentRect (HWND parent, HWND child, RECT * r)
@@ -248,14 +268,30 @@ ChooserPage::OnInit ()
SendMessage(viewlist, CB_ADDSTRING, 0, (LPARAM)PickView::mode_caption((PickView::views)view));
}
- SetBusy ();
- if (source == IDC_SOURCE_DOWNLOAD || source == IDC_SOURCE_LOCALDIR)
- packagemeta::ScanDownloadedFiles (MirrorOption);
+ if (source == IDC_SOURCE_DOWNLOAD)
+ setPrompt("Select packages to download ");
+ else
+ setPrompt("Select packages to install ");
- packagedb db;
- db.setExistence ();
- db.fillMissingCategory ();
+ createListview ();
+
+ AddTooltip (IDC_CHOOSE_KEEP, IDS_TRUSTKEEP_TOOLTIP);
+ AddTooltip (IDC_CHOOSE_BEST, IDS_TRUSTCURR_TOOLTIP);
+ AddTooltip (IDC_CHOOSE_SYNC, IDS_TRUSTSYNC_TOOLTIP);
+ AddTooltip (IDC_CHOOSE_EXP, IDS_TRUSTEXP_TOOLTIP);
+ AddTooltip (IDC_CHOOSE_VIEW, IDS_VIEWBUTTON_TOOLTIP);
+ AddTooltip (IDC_CHOOSE_HIDE, IDS_HIDEOBS_TOOLTIP);
+ AddTooltip (IDC_CHOOSE_SEARCH_EDIT, IDS_SEARCH_TOOLTIP);
+ /* Set focus to search edittext control. */
+ PostMessage (GetHWND (), WM_NEXTDLGCTL,
+ (WPARAM) GetDlgItem (IDC_CHOOSE_SEARCH_EDIT), TRUE);
+}
+
+void
+ChooserPage::applyCommandLinePackageSelection()
+{
+ packagedb db;
for (packagedb::packagecollection::iterator i = db.packages.begin ();
i != db.packages.end (); ++i)
{
@@ -264,8 +300,7 @@ ChooserPage::OnInit ()
bool deleted = pkg.isManuallyDeleted();
bool basemisc = (pkg.categories.find ("Base") != pkg.categories.end ()
|| pkg.categories.find ("Orphaned") != pkg.categories.end ());
- bool upgrade = wanted || (!pkg.installed && basemisc)
- || UpgradeAlsoOption || !hasManualSelections;
+ bool upgrade = wanted || (!pkg.installed && basemisc);
bool install = wanted && !deleted && !pkg.installed;
bool reinstall = (wanted || basemisc) && deleted;
bool uninstall = (!(wanted || basemisc) && (deleted || PruneInstallOption))
@@ -276,38 +311,36 @@ ChooserPage::OnInit ()
pkg.set_action (packagemeta::Reinstall_action, pkg.curr);
else if (uninstall)
pkg.set_action (packagemeta::Uninstall_action, packageversion ());
- else if (PruneInstallOption || ForceCurrentOption)
+ else if (PruneInstallOption)
pkg.set_action (packagemeta::Default_action, pkg.curr);
else if (upgrade)
pkg.set_action (packagemeta::Default_action, pkg.trustp(true, TRUST_UNKNOWN));
else
pkg.set_action (packagemeta::Default_action, pkg.installed);
}
-
- ClearBusy ();
-
- if (source == IDC_SOURCE_DOWNLOAD)
- setPrompt("Select packages to download ");
- else
- setPrompt("Select packages to install ");
- createListview ();
-
- AddTooltip (IDC_CHOOSE_KEEP, IDS_TRUSTKEEP_TOOLTIP);
- AddTooltip (IDC_CHOOSE_CURR, IDS_TRUSTCURR_TOOLTIP);
- AddTooltip (IDC_CHOOSE_EXP, IDS_TRUSTEXP_TOOLTIP);
- AddTooltip (IDC_CHOOSE_VIEW, IDS_VIEWBUTTON_TOOLTIP);
- AddTooltip (IDC_CHOOSE_HIDE, IDS_HIDEOBS_TOOLTIP);
- AddTooltip (IDC_CHOOSE_SEARCH_EDIT, IDS_SEARCH_TOOLTIP);
-
- /* Set focus to search edittext control. */
- PostMessage (GetHWND (), WM_NEXTDLGCTL,
- (WPARAM) GetDlgItem (IDC_CHOOSE_SEARCH_EDIT), TRUE);
}
void
ChooserPage::OnActivate()
{
- chooser->refresh();;
+ SetBusy();
+
+ packagedb db;
+ db.prep();
+
+ if (!activated)
+ {
+ // Do things which should only happen once, but rely on packagedb being
+ // ready to use, so OnInit() is too early
+ applyCommandLinePackageSelection();
+ initialUpdateState();
+
+ activated = true;
+ }
+
+ ClearBusy();
+
+ chooser->refresh();
PlaceDialog (true);
}
@@ -360,6 +393,7 @@ ChooserPage::OnBack ()
void
ChooserPage::keepClicked()
{
+ update_mode_id = IDC_CHOOSE_KEEP;
packagedb db;
for (packagedb::packagecollection::iterator i = db.packages.begin ();
i != db.packages.end (); ++i)
@@ -372,12 +406,57 @@ ChooserPage::keepClicked()
}
void
-ChooserPage::changeTrust(trusts aTrust)
+ChooserPage::changeTrust(int button, bool test, bool initial)
{
SetBusy ();
- chooser->defaultTrust (aTrust);
+
+ update_mode_id = button;
+
+ SolverSolution::updateMode mode;
+ switch (button)
+ {
+ default:
+ case IDC_CHOOSE_KEEP:
+ mode = SolverSolution::keep;
+ break;
+
+ case IDC_CHOOSE_BEST:
+ mode = SolverSolution::updateBest;
+ break;
+
+ case IDC_CHOOSE_SYNC:
+ mode = SolverSolution::updateForce;
+ break;
+ }
+
+ packagedb db;
+ SolverTasks q;
+
+ // usually we want to apply the solver to an empty task list to get the list
+ // of packages to upgrade (if any)
+ if (initial)
+ {
+ // but initially we want a task list with any package changes caused by
+ // command line options
+ // (also note the installed version to avoid generating spurious taskKeep
+ // or taskSkip tasks)
+ for (packagedb::packagecollection::iterator p = db.packages.begin ();
+ p != db.packages.end (); ++p)
+ {
+ packagemeta *pkg = p->second;
+ pkg->default_version = pkg->installed;
+ }
+ q.setTasks();
+ }
+ db.defaultTrust(q, mode, test);
+
+ // configure PickView so 'test' or 'curr' version is chosen when an
+ // uninstalled package is first clicked on.
+ chooser->defaultTrust (test ? TRUST_TEST : TRUST_CURR);
+
chooser->refresh();
- PrereqChecker::setTrust (aTrust);
+
+ PrereqChecker::setTestPackages(test);
ClearBusy ();
}
@@ -444,14 +523,18 @@ ChooserPage::OnMessageCmd (int id, HWND hwndctl, UINT code)
keepClicked();
break;
- case IDC_CHOOSE_CURR:
+ case IDC_CHOOSE_BEST:
if (IsButtonChecked (id))
- changeTrust (TRUST_CURR);
+ changeTrust (id, IsButtonChecked(IDC_CHOOSE_EXP), false);
break;
- case IDC_CHOOSE_EXP:
+ case IDC_CHOOSE_SYNC:
if (IsButtonChecked (id))
- changeTrust (TRUST_TEST);
+ changeTrust (id, IsButtonChecked(IDC_CHOOSE_EXP), false);
+ break;
+
+ case IDC_CHOOSE_EXP:
+ changeTrust(update_mode_id, IsButtonChecked (id), false);
break;
case IDC_CHOOSE_HIDE:
diff --git a/choose.h b/choose.h
index 46f0f35..32a1650 100644
--- a/choose.h
+++ b/choose.h
@@ -54,11 +54,13 @@ private:
RECT getDefaultListViewSize();
void getParentRect (HWND parent, HWND child, RECT * r);
void keepClicked();
- void changeTrust(trusts aTrust);
+ void changeTrust(int button, bool test, bool initial);
void logOnePackageResult(packagemeta const *aPkg);
void logResults();
void setPrompt(char const *aPrompt);
void PlaceDialog (bool);
+ void applyCommandLinePackageSelection();
+ void initialUpdateState();
PickView *chooser;
static HWND ins_dialog;
@@ -73,10 +75,8 @@ private:
WINDOWPLACEMENT wp;
UINT wpi[sizeof (WINDOWPLACEMENT) / sizeof (UINT)];
};
-
-
-
-
+ int update_mode_id;
+ bool activated;
};
#endif /* SETUP_CHOOSE_H */
diff --git a/configure.ac b/configure.ac
index 2c610ed..dcab4ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -57,6 +57,8 @@ AC_CHECK_HEADER(zlib.h, , missing_deps="$missing_deps zlib")
AC_CHECK_HEADER(bzlib.h, , missing_deps="$missing_deps libbz2")
AC_CHECK_HEADER(lzma.h, , missing_deps="$missing_deps liblzma")
AC_CHECK_HEADER(gcrypt.h, , missing_deps="$missing_deps libgcrypt")
+AC_CHECK_HEADER(solv/pool.h, , missing_deps="$missing_deps libsolv")
+AC_CHECK_HEADER(regex.h, , missing_deps="$missing_deps libregex")
if test -n "$missing_deps"; then
AC_MSG_ERROR([missing prerequisites: $missing_deps])
diff --git a/confirm.cc b/confirm.cc
new file mode 100644
index 0000000..7e949d8
--- /dev/null
+++ b/confirm.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * A copy of the GNU General Public License can be found at
+ * http://www.gnu.org/
+ *
+ */
+
+#include "confirm.h"
+#include "threebar.h"
+#include "resource.h"
+#include "state.h"
+#include "ControlAdjuster.h"
+#include "package_db.h"
+#include "package_meta.h"
+
+extern ThreeBarProgressPage Progress;
+
+// Sizing information.
+static ControlAdjuster::ControlInfo ConfirmControlsInfo[] = {
+ {IDC_CONFIRM_EDIT, CP_STRETCH, CP_STRETCH},
+ {0, CP_LEFT, CP_TOP}
+};
+
+// ---------------------------------------------------------------------------
+// implements class ConfirmPage
+// ---------------------------------------------------------------------------
+
+ConfirmPage::ConfirmPage ()
+{
+ sizeProcessor.AddControlInfo (ConfirmControlsInfo);
+}
+
+bool
+ConfirmPage::Create ()
+{
+ return PropertyPage::Create (IDD_CONFIRM);
+}
+
+void
+ConfirmPage::OnInit ()
+{
+ // set the edit-area to a larger font
+ SetDlgItemFont(IDC_CONFIRM_EDIT, "MS Shell Dlg", 10);
+}
+
+void
+ConfirmPage::OnActivate()
+{
+ // generate a report on actions we're going to take
+ std::string s = "";
+
+ packagedb db;
+ const SolverTransactionList & trans = db.solution.transactions ();
+
+ // first list things we will erase
+ if (source != IDC_SOURCE_DOWNLOAD)
+ {
+ for (SolverTransactionList::const_iterator i = trans.begin ();
+ i != trans.end (); i++)
+ {
+ if (i->type == SolverTransaction::transErase)
+ {
+ packageversion pv = i->version;
+ packagemeta *pkg = db.findBinary (PackageSpecification (pv.Name ()));
+
+ s += "Uninstall ";
+ s += i->version.Name();
+ s += " ";
+ s += i->version.Canonical_version();
+ if (pkg->desired)
+ s += " (automatically added)";
+ s += "\r\n";
+ }
+ }
+ }
+
+ // then list things downloaded or installed
+ for (SolverTransactionList::const_iterator i = trans.begin ();
+ i != trans.end (); i++)
+ {
+ packageversion pv = i->version;
+ packagemeta *pkg = db.findBinary (PackageSpecification (pv.Name ()));
+
+ if (i->type == SolverTransaction::transInstall)
+ {
+ if (source != IDC_SOURCE_DOWNLOAD)
+ s += "Install ";
+ else
+ s += "Download ";
+ s += i->version.Name();
+ s += " ";
+ s += i->version.Canonical_version();
+ if (!pkg->desired)
+ s += " (automatically added)";
+ s += "\r\n";
+ }
+ }
+
+ // be explicit about doing nothing
+ if (s.empty())
+ s += "No changes";
+
+ SetDlgItemText (GetHWND (), IDC_CONFIRM_EDIT, s.c_str ());
+
+ // move focus to 'next' button, so enter doesn't get eaten by edit control
+ HWND nextButton = ::GetDlgItem(::GetParent(GetHWND()), 0x3024 /* ID_WIZNEXT */);
+ PostMessage (GetHWND (), WM_NEXTDLGCTL, (WPARAM)nextButton, TRUE);
+}
+
+long
+ConfirmPage::OnNext ()
+{
+ return whatNext();
+}
+
+long
+ConfirmPage::whatNext ()
+{
+ if (source == IDC_SOURCE_LOCALDIR)
+ {
+ // Next, install
+ Progress.SetActivateTask (WM_APP_START_INSTALL);
+ }
+ else
+ {
+ // Next, start download from internet
+ Progress.SetActivateTask (WM_APP_START_DOWNLOAD);
+ }
+ return IDD_INSTATUS;
+}
+
+long
+ConfirmPage::OnBack ()
+{
+ return IDD_CHOOSE;
+}
+
+long
+ConfirmPage::OnUnattended ()
+{
+ return whatNext();
+}
diff --git a/confirm.h b/confirm.h
new file mode 100644
index 0000000..fe11ee0
--- /dev/null
+++ b/confirm.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * A copy of the GNU General Public License can be found at
+ * http://www.gnu.org/
+ *
+ */
+
+#ifndef SETUP_CONFIRM_H
+#define SETUP_CONFIRM_H
+
+#include "proppage.h"
+
+class ConfirmPage:public PropertyPage
+{
+public:
+ ConfirmPage ();
+ virtual ~ConfirmPage () { };
+ bool Create ();
+ virtual void OnInit ();
+ virtual void OnActivate ();
+ virtual long OnNext ();
+ virtual long OnBack ();
+ virtual long OnUnattended ();
+private:
+ long whatNext ();
+};
+
+#endif /* SETUP_CONFIRM_H */
diff --git a/cygpackage.cc b/cygpackage.cc
deleted file mode 100644
index 32b9403..0000000
--- a/cygpackage.cc
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2001, Robert Collins.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * A copy of the GNU General Public License can be found at
- * http://www.gnu.org/
- *
- * Written by Robert Collins <rbtcollins@hotmail.com>
- *
- */
-
-/* this is the parent class for all package operations.
- */
-
-#include "cygpackage.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "io_stream.h"
-#include "compress.h"
-
-#include "package_version.h"
-#include "cygpackage.h"
-#include "LogSingleton.h"
-
-/* this constructor creates an invalid package - further details MUST be provided */
-cygpackage::cygpackage ():
-name (),
-vendor (),
-packagev (),
-canonical (),
-sdesc (),
-ldesc (),
-type (package_binary)
-{
- /* FIXME: query the install database for the currently installed
- * version details
- */
-}
-
-packageversion
-cygpackage::createInstance (const std::string& pkgname,
- const package_type_t type)
-{
- cygpackage *temp = new cygpackage;
- temp->name = pkgname;
- temp->type = type;
- return packageversion(temp);
-}
-
-packageversion
-cygpackage::createInstance (const std::string& pkgname,
- const std::string& version,
- package_type_t const newtype)
-{
- cygpackage *temp = new cygpackage;
- temp->name = pkgname;
- temp->type = newtype;
- temp->setCanonicalVersion (version);
- return packageversion(temp);
-}
-
-/* tell the version */
-void
-cygpackage::setCanonicalVersion (const std::string& version)
-{
- canonical = version;
-
- const char *start = canonical.c_str();
- const char *curr = strchr(start, '-');
-
- if (curr)
- {
- const char *next;
- while ((next = strchr (curr + 1, '-')))
- curr = next;
-
- /* package version appears after the last '-' in the version string */
- packagev = curr + 1;
- /* vendor version is everything up to that last '-' */
- vendor.assign(canonical.c_str(), (size_t)(curr - start));
- }
- else
- {
- // FIXME: What's up with the "0"? It's probably a mistake, and should be
- // "". It used to be written as 0, and was subject to a bizarre implicit
- // conversion by the unwise String(int) constructor.
- packagev = "0";
- vendor = version;
- }
-}
-
-cygpackage::~cygpackage ()
-{
-}
-
-const std::string
-cygpackage::Name ()
-{
- return name;
-}
-
-const std::string
-cygpackage::Vendor_version ()
-{
- return vendor;
-}
-
-const std::string
-cygpackage::Package_version ()
-{
- return packagev;
-}
-
-std::string const
-cygpackage::Canonical_version ()
-{
- return canonical;
-}
-
-void
-cygpackage::set_sdesc (const std::string& desc)
-{
- sdesc = desc;
-}
-
-void
-cygpackage::set_ldesc (const std::string& desc)
-{
- ldesc = desc;
-}
-
-#if 0
-package_stability_t cygpackage::Stability ()
-{
- return stability;
-}
-#endif
diff --git a/cygpackage.h b/cygpackage.h
deleted file mode 100644
index c6d0657..0000000
--- a/cygpackage.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2001, Robert Collins.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * A copy of the GNU General Public License can be found at
- * http://www.gnu.org/
- *
- * Written by Robert Collins <rbtcollins@hotmail.com>
- *
- */
-
-#ifndef SETUP_CYGPACKAGE_H
-#define SETUP_CYGPACKAGE_H
-
-/* This is a cygwin specific package class, that should be able to
- * arbitrate acceess to cygwin binary packages amd cygwin source packages
- */
-
-#include "package_version.h"
-
-class io_stream;
-
-class cygpackage:public _packageversion
-{
-public:
- virtual const std::string Name ();
- virtual const std::string Vendor_version ();
- virtual const std::string Package_version ();
- virtual const std::string Canonical_version ();
- virtual package_type_t Type ()
- {
- return type;
- };
- virtual void set_sdesc (const std::string& );
- virtual void set_ldesc (const std::string& );
- virtual const std::string SDesc ()
- {
- return sdesc;
- };
- virtual const std::string LDesc ()
- {
- return ldesc;
- };
-
- /* pass the name of the package when constructing */
- void setCanonicalVersion (const std::string& );
-
- virtual ~ cygpackage ();
-
- /* pass the name of the package when constructing */
- static packageversion createInstance (const std::string& pkgname,
- const package_type_t type);
-
- static packageversion createInstance (const std::string& pkgname,
- const std::string& version,
- package_type_t const);
-
-private:
- cygpackage ();
- std::string name;
- std::string vendor;
- std::string packagev;
- std::string canonical;
- std::string sdesc, ldesc;
-
-// package_stability_t stability;
- package_type_t type;
-};
-
-#endif /* SETUP_CYGPACKAGE_H */
diff --git a/desktop.cc b/desktop.cc
index 24908f8..927c02f 100644
--- a/desktop.cc
+++ b/desktop.cc
@@ -35,7 +35,6 @@
#include "mklink2.h"
#include "package_db.h"
#include "package_meta.h"
-#include "package_version.h"
#include "filemanip.h"
#include "io_stream.h"
#include "getopt++/BoolOption.h"
diff --git a/download.cc b/download.cc
index 129b226..0cb3352 100644
--- a/download.cc
+++ b/download.cc
@@ -39,21 +39,16 @@
#include "package_db.h"
#include "package_meta.h"
-#include "package_version.h"
#include "package_source.h"
#include "threebar.h"
#include "Exception.h"
-#include "getopt++/BoolOption.h"
-
using namespace std;
extern ThreeBarProgressPage Progress;
-BoolOption IncludeSource (false, 'I', "include-source", "Automatically install source for every package installed");
-
// Return true if selected checks pass, false if they don't and the
// user chooses to delete the file; otherwise throw an exception.
static bool
@@ -283,59 +278,42 @@ do_download_thread (HINSTANCE h, HWND owner)
Progress.SetText3 ("");
packagedb db;
- /* calculate the amount needed */
- for (packagedb::packagecollection::iterator i = db.packages.begin ();
- i != db.packages.end (); ++i)
+ const SolverTransactionList &t = db.solution.transactions();
+
+ /* calculate the total size of the download */
+ for (SolverTransactionList::const_iterator i = t.begin (); i != t.end (); ++i)
{
- packagemeta & pkg = *(i->second);
- if (pkg.desired && (pkg.picked () || pkg.srcpicked ()))
- {
- packageversion version = pkg.desired;
- packageversion sourceversion = version.sourcePackage();
- try
- {
- if (pkg.picked())
- {
- if (!check_for_cached (*version.source(), owner))
- total_download_bytes += version.source()->size;
- }
- if (pkg.srcpicked () || IncludeSource)
- {
- if (!check_for_cached (*sourceversion.source(), owner))
- total_download_bytes += sourceversion.source()->size;
- }
- }
- catch (Exception * e)
- {
- // We know what to do with these..
- if (e->errNo() == APPERR_CORRUPT_PACKAGE)
- fatal (owner, IDS_CORRUPT_PACKAGE, pkg.name.c_str());
- // Unexpected exception.
- throw e;
- }
- }
+ if (i->type != SolverTransaction::transInstall)
+ continue;
+ packageversion version = i->version;
+
+ try
+ {
+ if (!check_for_cached (*version.source(), owner))
+ total_download_bytes += version.source()->size;
+ }
+ catch (Exception * e)
+ {
+ // We know what to do with these..
+ if (e->errNo() == APPERR_CORRUPT_PACKAGE)
+ fatal (owner, IDS_CORRUPT_PACKAGE, version.Name().c_str());
+ // Unexpected exception.
+ throw e;
+ }
}
/* and do the download. FIXME: This here we assign a new name for the cached version
* and check that above.
*/
- for (packagedb::packagecollection::iterator i = db.packages.begin ();
- i != db.packages.end (); ++i)
+ for (SolverTransactionList::const_iterator i = t.begin (); i != t.end (); ++i)
{
- packagemeta & pkg = *(i->second);
- if (pkg.desired && (pkg.picked () || pkg.srcpicked ()))
+ if (i->type != SolverTransaction::transInstall)
+ continue;
+ packageversion version = i->version;
+
{
int e = 0;
- packageversion version = pkg.desired;
- packageversion sourceversion = version.sourcePackage();
- if (pkg.picked())
- {
- e += download_one (*version.source(), owner);
- }
- if (sourceversion && (pkg.srcpicked() || IncludeSource))
- {
- e += download_one (*sourceversion.source (), owner);
- }
+ e += download_one (*version.source(), owner);
errors += e;
if (e)
download_failures.push_back (version);
diff --git a/filemanip.cc b/filemanip.cc
index d1d27be..265a2a7 100644
--- a/filemanip.cc
+++ b/filemanip.cc
@@ -43,22 +43,6 @@ get_file_size (const std::string& name)
return rv;
}
-std::string
-base (const std::string& aString)
-{
- if (!aString.size())
- return "";
- const char *s = aString.c_str();
- std::string rv = s;
- while (*s)
- {
- if ((*s == '/' || *s == ':' || *s == '\\') && s[1])
- rv = s + 1;
- s++;
- }
- return rv;
-}
-
/* returns the number of characters of path that
* precede the extension
*/
@@ -89,7 +73,7 @@ parse_filename (const string &fn, fileparse & f)
f.tail = fn.substr (n, string::npos);
- p = new_cstr_char_array (base (fn.substr (0, n)));
+ p = new_cstr_char_array (fn.substr (0, n));
char const *ext;
/* TODO: make const and non-const trail variant. */
if ((ext = trail (p, "-src")))
diff --git a/filemanip.h b/filemanip.h
index 5594519..451211f 100644
--- a/filemanip.h
+++ b/filemanip.h
@@ -30,7 +30,6 @@ struct fileparse
};
int parse_filename (const std::string& fn, fileparse & f);
-std::string base (const std::string& );
size_t get_file_size (const std::string& );
std::string backslash (const std::string& s);
const char * trail (const char *, const char *);
diff --git a/ini.cc b/ini.cc
index 87443a8..d807ed6 100644
--- a/ini.cc
+++ b/ini.cc
@@ -347,16 +347,16 @@ do_remote_ini (HWND owner)
static bool
do_ini_thread (HINSTANCE h, HWND owner)
{
+ packagedb db;
+ db.init();
+
bool ini_error = true;
+
if (source == IDC_SOURCE_LOCALDIR)
ini_error = do_local_ini (owner);
else
ini_error = do_remote_ini (owner);
- packagedb db;
- db.upgrade();
- db.removeEmptyCategories();
-
if (ini_error)
return false;
diff --git a/inilex.ll b/inilex.ll
index 13422b1..95888cf 100644
--- a/inilex.ll
+++ b/inilex.ll
@@ -118,10 +118,13 @@ B64 [a-zA-Z0-9_-]
"message:" return MESSAGE;
"Source:" return SOURCEPACKAGE;
"Build-Depends:" return BUILDDEPENDS;
+"replace-versions:" return REPLACE_VERSIONS;
"category:"|"Section:" return CATEGORY;
"requires:" return REQUIRES;
[dD]"epends:" return DEPENDS;
+[dD]"epends2:" return DEPENDS;
+[oO]"bsoletes:" return OBSOLETES;
^{STR}":" ignore_line ();
diff --git a/iniparse.yy b/iniparse.yy
index 18ebe2a..e5c514b 100644
--- a/iniparse.yy
+++ b/iniparse.yy
@@ -37,6 +37,7 @@ extern int yylineno;
%token STRING
%token SETUP_TIMESTAMP SETUP_VERSION PACKAGEVERSION INSTALL SOURCE SDESC LDESC
+%token REPLACE_VERSIONS
%token CATEGORY DEPENDS REQUIRES
%token T_PREV T_CURR T_TEST T_OTHER
%token MD5 SHA512
@@ -45,6 +46,7 @@ extern int yylineno;
%token COMMA NL AT
%token OPENBRACE CLOSEBRACE EQUAL GT LT GTEQUAL LTEQUAL
%token BUILDDEPENDS
+%token OBSOLETES
%token MESSAGE
%token ARCH RELEASE
@@ -103,6 +105,9 @@ singleitem /* non-empty */
| DEPENDS { iniBuilder->buildBeginDepends(); } versionedpackagelist NL
| REQUIRES { iniBuilder->buildBeginDepends(); } versionedpackagelistsp NL
| BUILDDEPENDS { iniBuilder->buildBeginBuildDepends(); } versionedpackagelist NL
+ | OBSOLETES { iniBuilder->buildBeginObsoletes(); } versionedpackagelist NL
+ | REPLACE_VERSIONS versionlist NL
+
| MESSAGE STRING STRING NL { iniBuilder->buildMessage ($2, $3); }
| error NL { yyerror (std::string("unrecognized line ")
+ stringify(yylineno)
@@ -153,4 +158,8 @@ operator /* non-empty */
| GTEQUAL { iniBuilder->buildPackageListOperator (PackageSpecification::MoreThanEquals); }
;
+versionlist: /* empty */
+ | versionlist STRING { iniBuilder->buildPackageReplaceVersionsList ($2); }
+ ;
+
%%
diff --git a/install.cc b/install.cc
index 366aeb2..3dd491e 100644
--- a/install.cc
+++ b/install.cc
@@ -68,7 +68,6 @@ static long long int total_bytes = 0;
static long long int total_bytes_sofar = 0;
static int package_bytes = 0;
-extern BoolOption IncludeSource;
static BoolOption NoReplaceOnReboot (false, 'r', "no-replaceonreboot",
"Disable replacing in-use files on next "
"reboot.");
@@ -815,26 +814,21 @@ do_install_thread (HINSTANCE h, HWND owner)
/* Writes Cygwin/setup/rootdir registry value */
create_install_root ();
- vector <packagemeta *> install_q, uninstall_q, sourceinstall_q;
+ vector <packageversion> install_q, uninstall_q, sourceinstall_q;
packagedb db;
+ const SolverTransactionList &t = db.solution.transactions();
/* Calculate the amount of data to md5sum */
Progress.SetText1("Calculating...");
long long int md5sum_total_bytes = 0;
- for (packagedb::packagecollection::iterator i = db.packages.begin ();
- i != db.packages.end (); ++i)
+ for (SolverTransactionList::const_iterator i = t.begin (); i != t.end (); ++i)
{
- packagemeta & pkg = *(i->second);
+ packageversion version = i->version;
- if (pkg.picked())
+ if (i->type == SolverTransaction::transInstall)
{
- md5sum_total_bytes += pkg.desired.source()->size;
- }
-
- if (pkg.srcpicked() || IncludeSource)
- {
- md5sum_total_bytes += pkg.desired.sourcePackage ().source()->size;
+ md5sum_total_bytes += version.source()->size;
}
}
@@ -844,58 +838,37 @@ do_install_thread (HINSTANCE h, HWND owner)
net install, the hashes will have already been verified at download
time, and all calls to check_hash() below should instantly return. */
long long int md5sum_total_bytes_sofar = 0;
- for (packagedb::packagecollection::iterator i = db.packages.begin ();
- i != db.packages.end (); ++i)
+ for (SolverTransactionList::const_iterator i = t.begin (); i != t.end (); ++i)
{
- packagemeta & pkg = *(i->second);
+ packageversion version = i->version;
- if (pkg.picked())
+ if (i->type == SolverTransaction::transInstall)
{
try
{
- (*pkg.desired.source ()).check_hash ();
+ (*version.source ()).check_hash ();
}
catch (Exception *e)
{
- if (yesno (owner, IDS_SKIP_PACKAGE, e->what()) == IDYES)
- pkg.pick (false);
+ yesno (owner, IDS_SKIP_PACKAGE, e->what());
}
- if (pkg.picked())
{
- md5sum_total_bytes_sofar += pkg.desired.source()->size;
- total_bytes += pkg.desired.source()->size;
- install_q.push_back (&pkg);
+ md5sum_total_bytes_sofar += version.source()->size;
+ total_bytes += version.source()->size;
+
+ // source packages are kept in a separate queue as they are installed
+ // differently: root is /usr/src, install isn't recorded, etc.
+ if (version.Type() == package_source)
+ sourceinstall_q.push_back (version);
+ else
+ install_q.push_back (version);
}
}
- if (pkg.srcpicked() || IncludeSource)
+ /* Uninstall, upgrade or reinstall */
+ if (i->type == SolverTransaction::transErase)
{
- bool skiprequested = false ;
- try
- {
- (*pkg.desired.sourcePackage ().source ()).check_hash ();
- }
- catch (Exception *e)
- {
- if (yesno (owner, IDS_SKIP_PACKAGE, e->what()) == IDYES)
- {
- skiprequested = true ; //(err occurred,) skip pkg desired
- pkg.srcpick (false);
- }
- }
- if (pkg.srcpicked() || (IncludeSource && !skiprequested))
- {
- md5sum_total_bytes_sofar += pkg.desired.sourcePackage ().source()->size;
- total_bytes += pkg.desired.sourcePackage ().source()->size;
- sourceinstall_q.push_back (&pkg);
- }
- }
-
- /* Upgrade or reinstall */
- if ((pkg.installed && pkg.desired != pkg.installed)
- || pkg.picked ())
- {
- uninstall_q.push_back (&pkg);
+ uninstall_q.push_back (version);
}
if (md5sum_total_bytes > 0)
@@ -904,27 +877,31 @@ do_install_thread (HINSTANCE h, HWND owner)
/* start with uninstalls - remove files that new packages may replace */
Progress.SetBar2(0);
- for (vector <packagemeta *>::iterator i = uninstall_q.begin ();
+ for (vector <packageversion>::iterator i = uninstall_q.begin ();
i != uninstall_q.end (); ++i)
{
- myInstaller.preremoveOne (**i);
+ packagemeta *pkgm = db.findBinary (PackageSpecification(i->Name()));
+ myInstaller.preremoveOne (*pkgm);
Progress.SetBar2(std::distance(uninstall_q.begin(), i) + 1, uninstall_q.size());
}
Progress.SetBar2(0);
- for (vector <packagemeta *>::iterator i = uninstall_q.begin ();
+ for (vector <packageversion>::iterator i = uninstall_q.begin ();
i != uninstall_q.end (); ++i)
{
- myInstaller.uninstallOne (**i);
+ packagemeta *pkgm = db.findBinary (PackageSpecification(i->Name()));
+ myInstaller.uninstallOne (*pkgm);
Progress.SetBar2(std::distance(uninstall_q.begin(), i) + 1, uninstall_q.size());
}
- for (vector <packagemeta *>::iterator i = install_q.begin ();
+ for (vector <packageversion>::iterator i = install_q.begin ();
i != install_q.end (); ++i)
{
- packagemeta & pkg = **i;
+ packageversion & pkg = *i;
+ packagemeta *pkgm = db.findBinary (PackageSpecification(i->Name()));
+
try {
- myInstaller.installOne (pkg, pkg.desired, *pkg.desired.source(),
+ myInstaller.installOne (*pkgm, pkg, *pkg.source(),
"cygfile://", "/", owner);
}
catch (exception *e)
@@ -939,12 +916,12 @@ do_install_thread (HINSTANCE h, HWND owner)
}
}
- for (vector <packagemeta *>::iterator i = sourceinstall_q.begin ();
+ for (vector <packageversion>::iterator i = sourceinstall_q.begin ();
i != sourceinstall_q.end (); ++i)
{
- packagemeta & pkg = **i;
- myInstaller.installOne (pkg, pkg.desired.sourcePackage(),
- *pkg.desired.sourcePackage().source(),
+ packagemeta *pkgm = db.findSource (PackageSpecification(i->Name()));
+ packageversion & pkg = *i;
+ myInstaller.installOne (*pkgm, pkg, *pkg.source(),
"cygfile://", "/usr/src/", owner);
}
diff --git a/libsolv.cc b/libsolv.cc
new file mode 100644
index 0000000..135d9af
--- /dev/null
+++ b/libsolv.cc
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (c) 2017 Jon Turney
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * A copy of the GNU General Public License can be found at
+ * http://www.gnu.org/
+ *
+ */
+
+#include "libsolv.h"
+#include "package_db.h"
+#include "package_meta.h"
+
+#include "solv/solver.h"
+#include "solv/solverdebug.h"
+#include "solv/evr.h"
+
+#include "LogSingleton.h"
+#include <iomanip>
+
+// ---------------------------------------------------------------------------
+// Utility functions for mapping between Operators and Relation Ids
+// ---------------------------------------------------------------------------
+
+static Id
+Operator2RelId(PackageSpecification::_operators op)
+{
+ switch (op)
+ {
+ case PackageSpecification::Equals:
+ return REL_EQ;
+ case PackageSpecification::LessThan:
+ return REL_LT;
+ case PackageSpecification::MoreThan:
+ return REL_GT;
+ case PackageSpecification::LessThanEquals:
+ return REL_LT | REL_EQ;
+ case PackageSpecification::MoreThanEquals:
+ return REL_GT | REL_EQ;
+ }
+
+ return 0;
+}
+
+static PackageSpecification::_operators
+RelId2Operator(Id id)
+{
+ switch (id)
+ {
+ case REL_EQ:
+ return PackageSpecification::Equals;
+ case REL_LT:
+ return PackageSpecification::LessThan;
+ case REL_GT:
+ return PackageSpecification::MoreThan;
+ case REL_LT | REL_EQ:
+ return PackageSpecification::LessThanEquals;
+ case REL_GT | REL_EQ:
+ return PackageSpecification::MoreThanEquals;
+ }
+
+ return PackageSpecification::Equals;
+}
+
+// ---------------------------------------------------------------------------
+// implements class SolvableVersion
+//
+// a wrapper around a libsolv Solvable
+// ---------------------------------------------------------------------------
+
+Id
+SolvableVersion::name_id () const
+{
+ Solvable *solvable = pool_id2solvable(pool, id);
+ return solvable->name;
+}
+
+const std::string
+SolvableVersion::Name () const
+{
+ if (!id)
+ return "";
+ return pool_id2str(pool, name_id());
+}
+
+const std::string
+SolvableVersion::Canonical_version() const
+{
+ if (!id)
+ return "";
+ Solvable *solvable = pool_id2solvable(pool, id);
+ return std::string(pool_id2str(pool, solvable->evr));
+}
+
+package_type_t
+SolvableVersion::Type () const
+{
+ if (!id)
+ return package_binary;
+ Solvable *solvable = pool_id2solvable(pool, id);
+ if (solvable->arch == ARCH_SRC)
+ return package_source;
+ else
+ return package_binary;
+}
+
+const PackageDepends
+SolvableVersion::depends() const
+{
+ return deplist(SOLVABLE_REQUIRES);
+}
+
+const PackageDepends
+SolvableVersion::obsoletes() const
+{
+ return deplist(SOLVABLE_OBSOLETES);
+}
+
+// helper function which returns the deplist for a given key, as a PackageDepends
+const PackageDepends
+SolvableVersion::deplist(Id keyname) const
+{
+ static PackageDepends empty_package;
+ if (!id)
+ return empty_package;
+ Solvable *solvable = pool_id2solvable(pool, id);
+
+ Queue q;
+ queue_init(&q);
+
+ if (repo_lookup_idarray(solvable->repo, id, keyname, &q))
+ {
+ // convert
+ PackageDepends dep;
+
+ for (int i = 0; i < q.count; i++)
+ {
+#ifdef DEBUG
+ Log (LOG_PLAIN) << "dep " << std::hex << q.elements[i] << ": " << pool_dep2str(pool, q.elements[i]) << endLog;
+#endif
+
+ const char *name = pool_id2str(pool, q.elements[i]);
+ PackageSpecification *spec = new PackageSpecification (name);
+
+ if (ISRELDEP(id))
+ {
+ Reldep *rd = GETRELDEP(pool, id);
+ spec->setOperator(RelId2Operator(rd->flags));
+ spec->setVersion(pool_id2str(pool, rd->evr));
+ }
+
+ dep.push_back (spec);
+ }
+
+ queue_empty(&q);
+
+ return dep;
+ }
+
+ // otherwise, return an empty depends list
+ return empty_package;
+}
+
+const std::string
+SolvableVersion::SDesc () const
+{
+ if (!id)
+ return "";
+ Solvable *solvable = pool_id2solvable(pool, id);
+ const char *sdesc = repo_lookup_str(solvable->repo, id, SOLVABLE_SUMMARY);
+
+ if (!sdesc)
+ return "";
+
+ return sdesc;
+}
+
+const std::string
+SolvableVersion::sourcePackageName () const
+{
+ if (!id)
+ return "";
+
+ // extract source package name
+ Solvable *solvable = pool_id2solvable(pool, id);
+ Id spkg = repo_lookup_id(solvable->repo, id, SOLVABLE_SOURCENAME);
+
+ // has no such attribute
+ if (!spkg)
+ return "";
+
+ return std::string(pool_id2str(pool, spkg));
+}
+
+SolvableVersion
+SolvableVersion::sourcePackage () const
+{
+ if (!id)
+ return SolvableVersion();
+
+ // extract source package id
+ Solvable *solvable = pool_id2solvable(pool, id);
+ Id spkg_attr = pool_str2id(pool, "solvable:sourceid", 1);
+ Id spkg_id = repo_lookup_id(solvable->repo, id, spkg_attr);
+
+ // has no such attribute
+ if (!spkg_id)
+ return SolvableVersion();
+
+ return SolvableVersion(spkg_id, pool);
+}
+
+void
+SolvableVersion::fixup_spkg_id (SolvableVersion spkg_id) const
+{
+ if (!id)
+ return;
+ Solvable *solvable = pool_id2solvable(pool, id);
+ Repodata *data = repo_last_repodata(solvable->repo);
+ Id handle = id;
+ Id spkg_attr = pool_str2id(pool, "solvable:sourceid", 1);
+ repodata_set_id(data, handle, spkg_attr, spkg_id.id);
+}
+
+packagesource *
+SolvableVersion::source() const
+{
+ static packagesource empty_source = packagesource();
+ if (!id) {
+ return &empty_source;
+ }
+
+ Solvable *solvable = pool_id2solvable(pool, id);
+ Id psrc_attr = pool_str2id(pool, "solvable:packagesource", 1);
+ return (packagesource *)repo_lookup_num(solvable->repo, id, psrc_attr, (unsigned long long)&empty_source);
+}
+
+bool
+SolvableVersion::accessible () const
+{
+ // The 'accessible' check used to test if an archive was available locally or
+ // from a mirror.
+ //
+ // This seems utterly pointless. as binary packages which aren't 'accessible'
+ // never get to appear in the package list.
+ //
+ // For source packages, it's equivalent to the bool conversion operator.)
+ //
+ if (id != 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+package_stability_t
+SolvableVersion::Stability () const
+{
+ if (!id)
+ return TRUST_UNKNOWN;
+ Solvable *solvable = pool_id2solvable(pool, id);
+ Id stability_attr = pool_str2id(pool, "solvable:stability", 1);
+ return (package_stability_t)repo_lookup_num(solvable->repo, id, stability_attr, TRUST_UNKNOWN);
+}
+
+bool
+SolvableVersion::operator <(SolvableVersion const &rhs) const
+{
+ return (compareVersions(*this, rhs) < 0);
+}
+
+bool
+SolvableVersion::operator ==(SolvableVersion const &rhs) const
+{
+ return (compareVersions(*this, rhs) == 0);
+}
+
+bool
+SolvableVersion::operator !=(SolvableVersion const &rhs) const
+{
+ return (compareVersions(*this, rhs) != 0);
+}
+
+int
+SolvableVersion::compareVersions(const SolvableVersion &a,
+ const SolvableVersion &b)
+{
+ if (a.id == b.id)
+ return 0;
+
+ // if a and b are different, at least one of them has a pool
+ Pool *pool = a.pool ? a.pool : b.pool;
+
+ Solvable *sa = a.id ? pool_id2solvable(a.pool, a.id) : NULL;
+ Solvable *sb = b.id ? pool_id2solvable(b.pool, b.id) : NULL;
+
+ // empty versions compare as if their version is the empty string
+ Id evra = sa ? sa->evr : pool_str2id(pool, "", 1);
+ Id evrb = sb ? sb->evr : pool_str2id(pool, "", 1);
+
+ return pool_evrcmp(pool, evra, evrb, EVRCMP_COMPARE);
+}
+
+// ---------------------------------------------------------------------------
+// implements class SolverPool
+//
+// a simplified wrapper for libsolv
+// ---------------------------------------------------------------------------
+
+static
+void debug_callback(Pool *pool, void *data, int type, const char *str)
+{
+ if (type & (SOLV_FATAL|SOLV_ERROR))
+ LogPlainPrintf("libsolv: %s", str);
+ else
+ LogBabblePrintf("libsolv: %s", str);
+}
+
+SolverPool::SolverPool()
+{
+ init();
+}
+
+void
+SolverPool::init()
+{
+ /* create a pool */
+ pool = pool_create();
+
+ pool_setdebugcallback(pool, debug_callback, NULL);
+
+ int level = 1;
+#if DEBUG
+ level = 3;
+#endif
+ pool_setdebuglevel(pool, level);
+
+ /* create the repo to hold installed packages */
+ SolvRepo *installed = getRepo("_installed");
+ pool_set_installed(pool, installed->repo);
+}
+
+void
+SolverPool::clear()
+{
+ repos.clear();
+ pool_free(pool);
+ pool = NULL;
+
+ init();
+}
+
+SolvRepo *
+SolverPool::getRepo(const std::string &name, bool test)
+{
+ RepoList::iterator i = repos.find(name);
+ if (i != repos.end())
+ return i->second;
+
+ /* create repo if not found */
+ SolvRepo *r = new(SolvRepo);
+ r->repo = repo_create(pool, name.c_str());
+
+ /* create attribute store, with no local pool */
+ r->data = repo_add_repodata(r->repo, 0);
+
+ /* remember if this is a test stability repo */
+ r->test = test;
+
+ /* set default priority */
+ r->repo->priority = SolvRepo::priorityNormal;
+
+ repos[name] = r;
+
+ return r;
+}
+
+/*
+ Helper function to convert a PackageDepends list to libsolv dependencies.
+*/
+Id
+SolverPool::makedeps(Repo *repo, PackageDepends *requires)
+{
+ Id deps = 0;
+
+ for (PackageDepends::iterator i = requires->begin();
+ i != requires->end();
+ i++)
+ {
+ Id name = pool_str2id(pool, (*i)->packageName().c_str(), 1);
+
+ if ((*i)->version().size() == 0)
+ {
+ // no relation, so dependency is just on package name
+ deps = repo_addid_dep(repo, deps, name, 0);
+ }
+ else
+ {
+ // otherwise, dependency is on package name with a version condition
+ Id evr = pool_str2id(pool, (*i)->version().c_str(), 1);
+ int rel = pool_rel2id(pool, name, evr, Operator2RelId((*i)->op()), 1);
+
+ deps = repo_addid_dep(repo, deps, rel, 0);
+ }
+ }
+
+ return deps;
+}
+
+SolvableVersion
+SolverPool::addPackage(const std::string& pkgname, const addPackageData &pkgdata)
+{
+ std::string repoName = pkgdata.reponame;
+ bool test = false;
+
+ /* It's simplest to place test packages into a separate repo, and
+ then arrange for that repo to have low priority, if we don't want
+ to install those packages by default */
+
+ if (pkgdata.stability == TRUST_TEST && repoName != "_installed")
+ {
+ repoName = pkgdata.reponame + "_test_";
+ test = true;
+ }
+
+ SolvRepo *r = getRepo(repoName, test);
+ Repo *repo = r->repo;
+
+ /* create a solvable */
+ Id s = repo_add_solvable(repo);
+ Solvable *solvable = pool_id2solvable(pool, s);
+
+ /* initialize solvable for this packageo/version/etc. */
+ solvable->name = pool_str2id(pool, pkgname.c_str(), 1);
+ solvable->arch = (pkgdata.type == package_binary) ? ARCH_ANY : ARCH_SRC;
+ solvable->evr = pool_str2id(repo->pool, pkgdata.version.c_str(), 1);
+ solvable->vendor = pool_str2id(repo->pool, pkgdata.vendor.c_str(), 1);
+ solvable->provides = repo_addid_dep(repo, solvable->provides, pool_rel2id(pool, solvable->name, solvable->evr, REL_EQ, 1), 0);
+ if (pkgdata.requires)
+ solvable->requires = makedeps(repo, pkgdata.requires);
+ if (pkgdata.obsoletes)
+ solvable->obsoletes = makedeps(repo, pkgdata.obsoletes);
+
+ /* a solvable can also store arbitrary attributes not needed for dependency
+ resolution, if we need them */
+
+ Repodata *data = r->data;
+ Id handle = s;
+#if DEBUG
+ Log (LOG_PLAIN) << "solvable " << s << " name " << pkgname << endLog;
+#endif
+
+ /* store short description attribute */
+ repodata_set_str(data, handle, SOLVABLE_SUMMARY, pkgdata.sdesc.c_str());
+ /* store long description attribute */
+ repodata_set_str(data, handle, SOLVABLE_DESCRIPTION, pkgdata.ldesc.c_str());
+
+ /* store source-package attribute */
+ const std::string sname = pkgdata.spkg.packageName();
+ if (!sname.empty())
+ repodata_set_id(data, handle, SOLVABLE_SOURCENAME, pool_str2id(pool, sname.c_str(), 1));
+ else
+ repodata_set_void(data, handle, SOLVABLE_SOURCENAME);
+ /* solvable:sourceevr may also be available from spkg but assumed to be same
+ as evr for the moment */
+
+ /* store source-package id */
+ /* (If the source-package hasn't been seen yet, we don't know what it's Id
+ will be. That gets fixed up later.) */
+ if (pkgdata.spkg_id)
+ {
+ Id spkg_attr = pool_str2id(pool, "solvable:sourceid", 1);
+ repodata_set_id(data, handle, spkg_attr, pkgdata.spkg_id.id);
+ }
+
+ /* we could store packagesource information as attributes ...
+
+ e.g.
+ size SOLVABLE_DOWNLOADSIZE
+ pathname SOLVABLE_MEDIAFILE
+ site SOLVABLE_MEDIABASE
+ checksum SOLVABLE_CHECKSUM
+
+ ... but for the moment, we just store a pointer to a packagesource object
+ */
+ Id psrc_attr = pool_str2id(pool, "solvable:packagesource", 1);
+ packagesource *psrc = new packagesource(pkgdata.archive);
+ repodata_set_num(data, handle, psrc_attr, (intptr_t)psrc);
+
+ /* store stability level attribute */
+ Id stability_attr = pool_str2id(pool, "solvable:stability", 1);
+ repodata_set_num(data, handle, stability_attr, pkgdata.stability);
+
+#if 0
+ repodata_internalize(data);
+
+ /* debug: verify the attributes we've just set get retrieved correctly */
+ SolvableVersion sv = SolvableVersion(s, pool);
+ const std::string check_sdesc = sv.SDesc();
+ if (pkgdata.sdesc.compare(check_sdesc) != 0) {
+ Log (LOG_PLAIN) << pkgname << " has sdesc mismatch: '" << pkgdata.sdesc << "' and '"
+ << check_sdesc << "'" << endLog;
+ }
+ if (!sname.empty()) {
+ SolvableVersion check_spkg = sv.sourcePackage();
+ Solvable *check_spkg_solvable = pool_id2solvable(pool, check_spkg.id);
+ std::string check_sname = pool_id2str(pool, check_spkg_solvable->name);
+ if (sname.compare(check_sname) != 0) {
+ Log (LOG_PLAIN) << pkgname << " has spkg mismatch: '" << pkgdata.spkg.packageName()
+ << "' and '" << check_sname << "'" << endLog;
+ }
+ }
+ packagesource *check_archive = sv.source();
+ if (check_archive != psrc)
+ Log (LOG_PLAIN) << pkgname << " has archive mismatch: " << psrc
+ << " and " << check_archive << endLog;
+ package_stability_t check_stability = sv.Stability();
+ if (check_stability != pkgdata.stability) {
+ Log (LOG_PLAIN) << pkgname << " has stability mismatch: " << pkgdata.stability
+ << " and " << check_stability << endLog;
+ }
+#endif
+
+ return SolvableVersion(s, pool);
+}
+
+void
+SolverPool::internalize()
+{
+ /* Make attribute data available to queries */
+ for (RepoList::iterator i = repos.begin();
+ i != repos.end();
+ i++)
+ {
+ repodata_internalize(i->second->data);
+ }
+}
+
+void
+SolverTasks::setTasks()
+{
+ // go through all packages, adding changed ones to the solver task list
+ packagedb db;
+ tasks.clear();
+
+ for (packagedb::packagecollection::iterator p = db.packages.begin ();
+ p != db.packages.end (); ++p)
+ {
+ packagemeta *pkg = p->second;
+
+ // decode UI state to action
+ // keep and skip need attention only when they differ from the
+ // solver's solution
+ if (pkg->installed != pkg->desired)
+ {
+ if (pkg->desired)
+ add(pkg->desired, taskInstall); // install/upgrade
+ else
+ add(pkg->installed, taskUninstall); // uninstall
+ }
+ else if (pkg->installed)
+ {
+ if (pkg->picked())
+ add(pkg->installed, taskReinstall); // reinstall
+ else if (pkg->installed != pkg->default_version)
+ add(pkg->installed, taskKeep); // keep
+ else
+ {
+ // if installed (with no action selected), but blacklisted, force
+ // a distupgrade of this package
+ if (pkg->isBlacklisted(pkg->installed))
+ {
+ add(pkg->installed, taskForceDistUpgrade);
+ }
+ }
+ }
+ else if (pkg->default_version)
+ add(pkg->default_version, taskSkip); // skip
+
+ // only install action makes sense for source packages
+ if (pkg->srcpicked())
+ {
+ if (pkg->desired)
+ add(pkg->desired.sourcePackage(), taskInstall);
+ else
+ add(pkg->installed.sourcePackage(), taskInstall);
+ }
+ }
+}
+
+void
+SolverPool::use_test_packages(bool use_test_packages)
+{
+ // Give repos containing test packages higher priority than normal
+ // if wanted, otherwise lower priority.
+ SolvRepo::priority_t p = use_test_packages ? SolvRepo::priorityNormal : SolvRepo::priorityLow;
+ for (RepoList::iterator i = repos.begin();
+ i != repos.end();
+ i++)
+ {
+ if (i->second->test)
+ i->second->setPriority(p);
+ }
+}
+
+// ---------------------------------------------------------------------------
+// implements class SolverSolution
+//
+// A wrapper around the libsolv solver
+// ---------------------------------------------------------------------------
+
+SolverSolution::SolverSolution(SolverPool &_pool) : pool(_pool), solv(NULL)
+{
+ queue_init(&job);
+}
+
+SolverSolution::~SolverSolution()
+{
+ clear();
+}
+
+void
+SolverSolution::clear()
+{
+ if (solv)
+ {
+ solver_free(solv);
+ solv = NULL;
+ }
+ queue_free(&job);
+}
+
+void
+SolverSolution::trans2db() const
+{
+ packagedb db;
+ // First reset all packages to the "no change" state
+ for (packagedb::packagecollection::iterator i = db.packages.begin();
+ i != db.packages.end(); i++)
+ {
+ packagemeta *pkg = i->second;
+ pkg->desired = pkg->default_version = pkg->installed;
+ pkg->pick(false);
+ }
+ // Now make changes according to trans. transErase requires some
+ // care; it could either be a "plain" uninstall, or it could be
+ // paired with a transInstall for an upgrade/downgrade or reinstall.
+ for (SolverTransactionList::const_iterator i = trans.begin();
+ i != trans.end(); i++)
+ {
+ const packageversion & pv = i->version;
+ packagemeta *pkg = db.findBinary(PackageSpecification(pv.Name()));
+ if (!pkg)
+ // Can't happen - throw an exception?
+ {
+ Log (LOG_PLAIN) << "Can't happen. No packagemeta for "
+ << pv.Name() << endLog;
+ return;
+ }
+ switch (i->type)
+ {
+ case SolverTransaction::transInstall:
+ if (pv.Type() == package_binary)
+ {
+ pkg->desired = pkg->default_version = pv;
+ pkg->pick(true);
+ }
+ else // source package
+ pkg->srcpick(true);
+ break;
+ case SolverTransaction::transErase:
+ // Only relevant if pkg is still in its "no change" state
+ if (pkg->desired == pkg->installed && !pkg->picked())
+ pkg->desired = pkg->default_version = packageversion();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void
+SolverSolution::db2trans()
+{
+ trans.clear();
+ packagedb db;
+
+ for (packagedb::packagecollection::iterator p = db.packages.begin ();
+ p != db.packages.end (); ++p)
+ {
+ packagemeta *pkg = p->second;
+ if (pkg->desired && pkg->picked()) // install/upgrade/reinstall
+ {
+ trans.push_back(SolverTransaction(pkg->desired, SolverTransaction::transInstall));
+ if (pkg->installed)
+ trans.push_back(SolverTransaction(pkg->installed, SolverTransaction::transErase));
+ }
+ else if (!pkg->desired && pkg->installed) // uninstall
+ trans.push_back(SolverTransaction(pkg->installed, SolverTransaction::transErase));
+
+ if (pkg->srcpicked())
+ {
+ if (pkg->desired)
+ trans.push_back(SolverTransaction(pkg->desired.sourcePackage(), SolverTransaction::transInstall));
+ else
+ trans.push_back(SolverTransaction(pkg->installed.sourcePackage(), SolverTransaction::transInstall));
+ }
+ }
+}
+
+static
+std::ostream &operator<<(std::ostream &stream,
+ SolverTransaction::transType type)
+{
+ switch (type)
+ {
+ case SolverTransaction::transInstall:
+ stream << "install";
+ break;
+ case SolverTransaction::transErase:
+ stream << "erase";
+ break;
+ default:
+ stream << "unknown";
+ }
+ return stream;
+}
+
+void
+SolverSolution::tasksToJobs(SolverTasks &tasks, updateMode update, Queue &job)
+{
+ // solver accepts a queue containing pairs of (cmd, id) tasks
+ // cmd is job and selection flags ORed together
+ for (SolverTasks::taskList::const_iterator i = tasks.tasks.begin();
+ i != tasks.tasks.end();
+ i++)
+ {
+ const SolvableVersion &sv = (*i).first;
+
+ switch ((*i).second)
+ {
+ case SolverTasks::taskInstall:
+ queue_push2(&job, SOLVER_INSTALL | SOLVER_SOLVABLE, sv.id);
+ break;
+ case SolverTasks::taskUninstall:
+ queue_push2(&job, SOLVER_ERASE | SOLVER_SOLVABLE, sv.id);
+ break;
+ case SolverTasks::taskReinstall:
+ // we don't know how to ask solver for this, so we just add the erase
+ // and install later
+ break;
+ case SolverTasks::taskKeep:
+ queue_push2(&job, SOLVER_LOCK | SOLVER_SOLVABLE, sv.id);
+ break;
+ case SolverTasks::taskSkip:
+ queue_push2(&job, SOLVER_LOCK | SOLVER_SOLVABLE_NAME, sv.name_id());
+ break;
+ case SolverTasks::taskForceDistUpgrade:
+ queue_push2(&job, SOLVER_DISTUPGRADE | SOLVER_SOLVABLE, sv.id);
+ break;
+ default:
+ Log (LOG_PLAIN) << "unknown task " << (*i).second << endLog;
+ }
+ }
+
+ // Ask solver to update packages
+ switch (update)
+ {
+ case keep:
+ break;
+
+ case updateBest:
+ // Update to best version
+ queue_push2(&job, SOLVER_UPDATE | SOLVER_SOLVABLE_ALL, 0);
+ break;
+
+ case updateForce:
+ // Bring installed, non-orphaned packages in sync with the ones in the
+ // repository
+ queue_push2(&job, SOLVER_DISTUPGRADE | SOLVER_SOLVABLE_ALL, 0);
+ break;
+ }
+
+ // Ask solver to check dependencies of installed packages.
+ queue_push2(&job, SOLVER_VERIFY | SOLVER_SOLVABLE_ALL, 0);
+}
+
+bool
+SolverSolution::update(SolverTasks &tasks, updateMode update, bool use_test_packages)
+{
+ Log (LOG_PLAIN) << "solving: " << tasks.tasks.size() << " tasks," <<
+ " update: " << (update ? "yes" : "no") << "," <<
+ " use test packages: " << (use_test_packages ? "yes" : "no") << endLog;
+
+ pool.use_test_packages(use_test_packages);
+
+ queue_free(&job);
+ tasksToJobs(tasks, update, job);
+
+ if (!solv)
+ solv = solver_create(pool.pool);
+
+ return solve();
+}
+
+bool
+SolverSolution::solve()
+{
+ solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1);
+ solver_set_flag(solv, SOLVER_FLAG_ALLOW_DOWNGRADE, 0);
+ solver_set_flag(solv, SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE, 1);
+ solver_set_flag(solv, SOLVER_FLAG_DUP_ALLOW_DOWNGRADE, 1);
+ solver_solve(solv, &job);
+
+ int pcnt = solver_problem_count(solv);
+ solver_printdecisions(solv);
+
+ solutionToTransactionList();
+
+ return (pcnt == 0);
+}
+
+void
+SolverSolution::solutionToTransactionList()
+{
+ // get transactions for solution
+ Transaction *t = solver_create_transaction(solv);
+ transaction_order(t, 0);
+ transaction_print(t);
+
+ // massage into SolverTransactions form
+ trans.clear();
+ for (int i = 0; i < t->steps.count; i++)
+ {
+ Id id = t->steps.elements[i];
+ SolverTransaction::transType tt = type(t, i);
+ if (tt != SolverTransaction::transIgnore)
+ trans.push_back(SolverTransaction(SolvableVersion(id, pool.pool), tt));
+ }
+
+ transaction_free(t);
+
+ dumpTransactionList();
+}
+
+void
+SolverSolution::augmentTasks(SolverTasks &tasks)
+{
+ // add install and remove tasks for anything marked as reinstall
+ for (SolverTasks::taskList::const_iterator i = tasks.tasks.begin();
+ i != tasks.tasks.end();
+ i++)
+ {
+ const SolvableVersion &sv = (*i).first;
+
+ if (((*i).second) == SolverTasks::taskReinstall)
+ {
+ trans.push_back(SolverTransaction(SolvableVersion(sv.id, pool.pool),
+ SolverTransaction::transErase));
+ trans.push_back(SolverTransaction(SolvableVersion(sv.id, pool.pool),
+ SolverTransaction::transInstall));
+ }
+ }
+}
+
+void
+SolverSolution::addSource(bool include_source)
+{
+ // if include_source mode is on, also install source for everything we are
+ // installing
+ if (include_source)
+ {
+ // (this uses indicies into the vector, as iterators might become
+ // invalidated by doing push_back)
+ size_t n = trans.size();
+ for (size_t i = 0; i < n; i++)
+ {
+ if (trans[i].type == SolverTransaction::transInstall)
+ {
+ SolvableVersion src_version = trans[i].version.sourcePackage();
+ if (src_version)
+ trans.push_back(SolverTransaction(src_version,
+ SolverTransaction::transInstall));
+ }
+ }
+ }
+}
+
+void
+SolverSolution::dumpTransactionList() const
+{
+ if (trans.size())
+ {
+ Log (LOG_PLAIN) << "Augmented Transaction List:" << endLog;
+ for (SolverTransactionList::const_iterator i = trans.begin ();
+ i != trans.end ();
+ ++i)
+ {
+ Log (LOG_PLAIN) << std::setw(4) << std::distance(trans.begin(), i)
+ << std::setw(8) << i->type
+ << std::setw(48) << i->version.Name()
+ << std::setw(20) << i->version.Canonical_version() << endLog;
+ }
+ }
+ else
+ Log (LOG_PLAIN) << "Augmented Transaction List: is empty" << endLog;
+}
+
+void SolverSolution::applyDefaultProblemSolutions()
+{
+ // adjust the task list with the default solutions
+ int pcnt = solver_problem_count(solv);
+ for (Id problem = 1; problem <= pcnt; problem++)
+ {
+ int scnt = solver_solution_count(solv, problem);
+ solver_take_solution(solv, problem, scnt, &job);
+ }
+
+ // re-solve
+ if (!solve())
+ Log (LOG_PLAIN) << "default solutions did not solve all problems!" << endLog;
+}
+
+const SolverTransactionList &
+SolverSolution::transactions() const
+{
+ return trans;
+}
+
+// Construct a string reporting the problems and solutions
+std::string
+SolverSolution::report() const
+{
+ packagedb db;
+ std::string r = "";
+ int pcnt = solver_problem_count(solv);
+ for (Id problem = 1; problem <= pcnt; problem++)
+ {
+ r += "Problem " + std::to_string(problem) + "/" + std::to_string(pcnt);
+ r += "\n";
+
+ Id probr = solver_findproblemrule(solv, problem);
+ Id dep, source, target;
+ SolverRuleinfo type = solver_ruleinfo(solv, probr, &source, &target, &dep);
+ if (source == db.basepkg.id)
+ r += "package " + std::string(pool_dep2str(pool.pool, dep)) + " is a Base package and is therefore required";
+ else
+ r += solver_problemruleinfo2str(solv, type, source, target, dep);
+ r += "\n";
+
+ int scnt = solver_solution_count(solv, problem);
+ for (Id solution = 1; solution <= scnt; solution++)
+ {
+ r += "Solution " + std::to_string(solution) + "/" + std::to_string(scnt);
+ if (solution == scnt) r += " (default)";
+ r += "\n";
+
+ Id p, rp, element;
+ element = 0;
+ while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
+ {
+ r += " - ";
+ if (p == db.basepkg.id)
+ r += "allow deinstallation of Base packages";
+ else
+ r += solver_solutionelement2str(solv, p, rp);
+ r += "\n";
+ }
+ }
+ }
+
+ // since package arch isn't set usefully at the moment, remove all ".any" from
+ // package names in the problem report string.
+ std::string any = ".any";
+ size_t pos;
+ while ((pos = r.find(any)) != std::string::npos)
+ {
+ r.replace(pos, any.length(), "");
+ }
+
+ return r;
+}
+
+// helper function to map transaction type
+SolverTransaction::transType
+SolverSolution::type(Transaction *trans, int pos)
+{
+ Id tt = transaction_type(trans, trans->steps.elements[pos],
+ SOLVER_TRANSACTION_SHOW_ACTIVE);
+
+ // if active side of transaction is nothing, ask again for passive side of
+ // transaction
+ if (tt == SOLVER_TRANSACTION_IGNORE)
+ tt = transaction_type(trans, trans->steps.elements[pos], 0);
+
+ switch(tt)
+ {
+ case SOLVER_TRANSACTION_INSTALL:
+ case SOLVER_TRANSACTION_REINSTALL:
+ case SOLVER_TRANSACTION_UPGRADE:
+ case SOLVER_TRANSACTION_DOWNGRADE:
+ return SolverTransaction::transInstall;
+ case SOLVER_TRANSACTION_ERASE:
+ case SOLVER_TRANSACTION_REINSTALLED:
+ case SOLVER_TRANSACTION_UPGRADED:
+ case SOLVER_TRANSACTION_DOWNGRADED:
+ return SolverTransaction::transErase;
+ default:
+ Log (LOG_PLAIN) << "unknown transaction type " << std::hex << tt << endLog;
+ case SOLVER_TRANSACTION_CHANGE:
+ case SOLVER_TRANSACTION_CHANGED:
+ case SOLVER_TRANSACTION_IGNORE:
+ return SolverTransaction::transIgnore;
+ }
+};
diff --git a/libsolv.h b/libsolv.h
new file mode 100644
index 0000000..6a6e0b3
--- /dev/null
+++ b/libsolv.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2017 Jon Turney
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * A copy of the GNU General Public License can be found at
+ * http://www.gnu.org/
+ *
+ */
+
+#ifndef LIBSOLV_H
+#define LIBSOLV_H
+
+#include "solv/pool.h"
+#include "solv/repo.h"
+#include "solv/solver.h"
+#include "PackageSpecification.h"
+#include "PackageTrust.h"
+#include "package_source.h"
+#include "package_depends.h"
+#include <map>
+#include <vector>
+
+typedef trusts package_stability_t;
+
+typedef enum
+{
+ package_binary,
+ package_source
+}
+package_type_t;
+
+// ---------------------------------------------------------------------------
+// interface to class SolverVersion
+//
+// a wrapper around a libsolv Solvable
+// ---------------------------------------------------------------------------
+
+class SolverPool;
+class SolverSolution;
+
+class SolvableVersion
+{
+ public:
+ SolvableVersion() : id(0), pool(0) {};
+ SolvableVersion(Id _id, Pool *_pool) : id(_id), pool(_pool) {};
+
+ // converted to a bool, this is true if this isn't the result of the default
+ // constructor (an 'empty' version, in some sense)
+ explicit operator bool () const { return (id != 0); }
+
+ const std::string Name () const;
+ const std::string SDesc () const;
+ // In setup-speak, 'Canonical' version means 'e:v-r', the non-decomposed version
+ const std::string Canonical_version () const;
+ // Return the dependency list
+ const PackageDepends depends() const;
+ // Return the obsoletes list
+ const PackageDepends obsoletes() const;
+ bool accessible () const;
+ package_type_t Type () const;
+ package_stability_t Stability () const;
+ // the associated source package name, if this is a binary package
+ const std::string sourcePackageName () const;
+ // the associated source package, if this is a binary package
+ SolvableVersion sourcePackage () const;
+ // where this package archive can be obtained from
+ packagesource *source() const;
+
+ // fixup spkg_id
+ void fixup_spkg_id(SolvableVersion spkg_id) const;
+
+ // utility function to compare package versions
+ static int compareVersions(const SolvableVersion &a, const SolvableVersion &b);
+
+ // comparison operators
+
+ // these are somewhat necessary as otherwise we are compared as bool values
+ bool operator == (SolvableVersion const &) const;
+ bool operator != (SolvableVersion const &) const;
+
+ // these are only well defined for versions of the same package
+ bool operator < (SolvableVersion const &) const;
+ bool operator <= (SolvableVersion const &) const;
+ bool operator > (SolvableVersion const &) const;
+ bool operator >= (SolvableVersion const &) const;
+
+ private:
+ Id id;
+ Pool *pool;
+
+ friend SolverPool;
+ friend SolverSolution;
+
+ const PackageDepends deplist(Id keyname) const;
+ Id name_id () const;
+};
+
+// ---------------------------------------------------------------------------
+// Helper class SolvRepo
+//
+// ---------------------------------------------------------------------------
+
+class SolvRepo
+{
+public:
+ typedef enum
+ {
+ priorityLow = 0,
+ priorityNormal,
+ priorityHigh,
+ } priority_t;
+ Repo *repo;
+ Repodata *data;
+ bool test;
+ void setPriority(priority_t p) { repo->priority = p; }
+};
+
+// ---------------------------------------------------------------------------
+// interface to class SolverPool
+//
+// a simplified wrapper for libsolv
+// ---------------------------------------------------------------------------
+
+class SolverPool
+{
+public:
+ SolverPool();
+ void clear();
+ SolvRepo *getRepo(const std::string &name, bool test = false);
+
+ // Utility class for passing arguments to addPackage()
+ class addPackageData
+ {
+ public:
+ std::string reponame;
+ std::string version;
+ std::string vendor;
+ std::string sdesc;
+ std::string ldesc;
+ package_stability_t stability;
+ package_type_t type;
+ packagesource archive;
+ PackageSpecification spkg;
+ SolvableVersion spkg_id;
+ PackageDepends *requires;
+ PackageDepends *obsoletes;
+ };
+
+ SolvableVersion addPackage(const std::string& pkgname,
+ const addPackageData &pkgdata);
+
+ void internalize(void);
+ void use_test_packages(bool use_test_packages);
+
+
+private:
+ void init();
+ Id makedeps(Repo *repo, PackageDepends *requires);
+ Pool *pool;
+
+ typedef std::map<std::string, SolvRepo *> RepoList;
+ RepoList repos;
+
+ friend SolverSolution;
+};
+
+
+// ---------------------------------------------------------------------------
+// interface to class SolverTaskQueue
+//
+// This is used to contain a set of package install/uninstall tasks selected via
+// the UI to be passed to solver
+// ---------------------------------------------------------------------------
+
+class SolverTasks
+{
+ public:
+ enum task
+ {
+ taskInstall,
+ taskUninstall,
+ taskReinstall,
+ taskKeep,
+ taskSkip,
+ taskForceDistUpgrade,
+ };
+ void add(const SolvableVersion &v, task t)
+ {
+ tasks.push_back(taskList::value_type(v, t));
+ };
+ /* Create solver tasks corresponding to state of database */
+ void setTasks();
+
+ private:
+ typedef std::vector<std::pair<const SolvableVersion, task>> taskList;
+ taskList tasks;
+
+ friend SolverSolution;
+};
+
+// ---------------------------------------------------------------------------
+// SolverTransactionList
+//
+// a list of transactions output by the solver
+// ---------------------------------------------------------------------------
+
+class SolverTransaction
+{
+ public:
+ typedef enum
+ {
+ transIgnore,
+ transInstall,
+ transErase,
+ } transType;
+
+ SolverTransaction(SolvableVersion version_, transType type_) :
+ version(version_), type(type_) {};
+
+ SolvableVersion version;
+ transType type;
+};
+
+typedef std::vector<SolverTransaction> SolverTransactionList;
+
+// ---------------------------------------------------------------------------
+// interface to class SolverSolution
+//
+// A wrapper around the libsolv solver
+// ---------------------------------------------------------------------------
+
+class SolverSolution
+{
+ public:
+ SolverSolution(SolverPool &_pool);
+ ~SolverSolution();
+ void clear();
+
+ /* Reset package database to correspond to trans */
+ void trans2db() const;
+
+ /* Reset transaction list to correspond to package database */
+ void db2trans();
+
+ enum updateMode
+ {
+ keep, // don't update
+ updateBest, // update to best version
+ updateForce, // distupdate: downgrade if necessary to best version in repo
+ };
+ bool update(SolverTasks &tasks, updateMode update, bool use_test_packages);
+ void augmentTasks(SolverTasks &tasks);
+ void addSource(bool include_source);
+ void applyDefaultProblemSolutions();
+ std::string report() const;
+
+ const SolverTransactionList &transactions() const;
+ void dumpTransactionList() const;
+
+ private:
+ static SolverTransaction::transType type(Transaction *trans, int pos);
+ bool solve();
+ void tasksToJobs(SolverTasks &tasks, updateMode update, Queue &job);
+ void solutionToTransactionList();
+
+ SolverPool &pool;
+ Solver *solv;
+ Queue job;
+ SolverTransactionList trans;
+};
+
+#endif // LIBSOLV_H
diff --git a/main.cc b/main.cc
index 028f8de..2e57f94 100644
--- a/main.cc
+++ b/main.cc
@@ -55,6 +55,7 @@
#include "site.h"
#include "choose.h"
#include "prereq.h"
+#include "confirm.h"
#include "threebar.h"
#include "desktop.h"
#include "postinstallresults.h"
@@ -135,6 +136,7 @@ main_display ()
SitePage Site;
ChooserPage Chooser;
PrereqPage Prereq;
+ ConfirmPage Confirm;
DesktopSetupPage Desktop;
PropSheet MainWindow;
@@ -175,6 +177,7 @@ main_display ()
Site.Create ();
Chooser.Create ();
Prereq.Create ();
+ Confirm.Create ();
Progress.Create ();
PostInstallResults.Create ();
Desktop.Create ();
@@ -189,6 +192,7 @@ main_display ()
MainWindow.AddPage (&Site);
MainWindow.AddPage (&Chooser);
MainWindow.AddPage (&Prereq);
+ MainWindow.AddPage (&Confirm);
MainWindow.AddPage (&Progress);
MainWindow.AddPage (&PostInstallResults);
MainWindow.AddPage (&Desktop);
diff --git a/package_db.cc b/package_db.cc
index cac98d7..730cb78 100644
--- a/package_db.cc
+++ b/package_db.cc
@@ -31,24 +31,50 @@
#include "compress.h"
#include "filemanip.h"
-
#include "package_version.h"
-#include "cygpackage.h"
#include "package_db.h"
#include "package_meta.h"
#include "Exception.h"
#include "Generic.h"
#include "LogSingleton.h"
#include "resource.h"
+#include "libsolv.h"
+#include "csu_util/version_compare.h"
+#include "getopt++/BoolOption.h"
+
+static BoolOption MirrorOption (false, 'm', "mirror-mode", "Skip package availability check when installing from local directory (requires local directory to be clean mirror!)");
using namespace std;
packagedb::packagedb ()
{
- io_stream *db = 0;
+}
+
+void
+packagedb::init ()
+{
+ installeddbread = 0;
+ installeddbver = 0;
+ prepped = false;
+
+ packages.clear();
+ sourcePackages.clear();
+ categories.clear();
+ solver.clear();
+ solution.clear();
+ basepkg = packageversion();
+ dependencyOrderedPackages.clear();
+}
+
+void
+packagedb::read ()
+{
if (!installeddbread)
{
- /* no parameters. Read in the local installation database. */
+ solver.internalize();
+
+ /* Read in the local installation database. */
+ io_stream *db = 0;
db = io_stream::open ("cygfile:///etc/setup/installed.db", "rt", 0);
installeddbread = 1;
if (!db)
@@ -98,23 +124,61 @@ packagedb::packagedb ()
if (!parseable)
continue;
- packagemeta *pkg = findBinary (PackageSpecification(pkgname));
- if (!pkg)
- {
- pkg = new packagemeta (pkgname);
- packages.insert (packagedb::packagecollection::value_type(pkgname, pkg));
- }
-
- packageversion binary =
- cygpackage::createInstance (pkgname, f.ver,
- package_binary);
-
- pkg->add_version (binary);
- pkg->set_installed (binary);
- pkg->desired = pkg->installed;
+ SolverPool::addPackageData data;
+ data.reponame = "_installed";
+ data.version = f.ver;
+ data.type = package_binary;
+
+ // very limited information is available from installed.db, so
+ // we put our best guesses here...
+ data.vendor = "cygwin";
+ data.requires = NULL;
+ data.obsoletes = NULL;
+ data.sdesc = "";
+ data.ldesc = "";
+ data.stability = TRUST_UNKNOWN;
+ data.spkg = PackageSpecification(std::string(pkgname) + "-src", f.ver);
+
+ // supplement this with sdesc, source, and stability
+ // information from setup.ini, if possible...
+ packageversion pv = findBinaryVersion(PackageSpecification(pkgname, f.ver));
+ PackageDepends dep;
+ PackageDepends obs;
+ if (pv)
+ {
+ data.sdesc = pv.SDesc();
+ data.archive = *pv.source();
+ data.stability = pv.Stability();
+ data.spkg_id = pv.sourcePackage();
+ data.spkg = pv.sourcePackageName();
+ dep = pv.depends();
+ data.requires = &dep;
+ obs = pv.obsoletes();
+ data.obsoletes = &obs;
+ }
+ else
+ // This version is no longer available. It could
+ // be old, or it could be a previous test release
+ // that has been replaced by a new test release.
+ // Try to get some info from the packagemeta.
+ {
+ packagemeta *pkgm = findBinary(PackageSpecification(pkgname));
+ if (pkgm)
+ {
+ data.sdesc = pkgm->curr.SDesc();
+ if (pkgm->curr
+ && version_compare (f.ver, pkgm->curr.Canonical_version()) > 0)
+ data.stability = TRUST_TEST;
+ }
+ }
+
+ packagemeta *pkg = packagedb::addBinary (pkgname, data);
+
+ pkg->set_installed_version (f.ver);
if (dbver == 3)
pkg->user_picked = (user_picked & 1);
+
}
delete db;
db = 0;
@@ -127,6 +191,80 @@ packagedb::packagedb ()
installeddbver = dbver;
}
}
+ solver.internalize();
+}
+
+/* Create the fictitious basepkg */
+void
+packagedb::makeBase()
+{
+ SolverPool::addPackageData data;
+ data.reponame = "_installed";
+ data.version = "0.0-0";
+ data.type = package_binary;
+ data.vendor = "cygwin";
+ data.sdesc = "Ficitious package that requires all Base packages";
+ data.ldesc = "Ficitious package that requires all Base packages";
+ data.obsoletes = NULL;
+ data.stability = TRUST_CURR;
+ // data.spkg = PackageSpecification();
+ // data.spkg_id = packageversion();
+
+ PackageDepends dep;
+ for (std::vector <packagemeta *>::const_iterator i = categories["Base"].begin();
+ i != categories["Base"].end(); i++)
+ {
+ packagemeta *pkg = *i;
+ PackageSpecification *spec = new PackageSpecification(pkg->name);
+ dep.push_back(spec);
+ }
+ data.requires = &dep;
+
+ basepkg = solver.addPackage("base", data);
+ /* We don't register this in packagemeta */
+}
+
+/* Add a package version to the packagedb */
+packagemeta *
+packagedb::addBinary (const std::string &pkgname,
+ const SolverPool::addPackageData &pkgdata)
+{
+ /* If pkgname isn't already in packagedb, add a packagemeta */
+ packagemeta *pkg = findBinary (PackageSpecification(pkgname));
+ if (!pkg)
+ {
+ pkg = new packagemeta (pkgname);
+ packages.insert (packagedb::packagecollection::value_type(pkgname, pkg));
+ }
+
+ /* Create the SolvableVersion */
+ SolvableVersion sv = solver.addPackage(pkgname, pkgdata);
+
+ /* Register it in packagemeta */
+ pkg->add_version (sv, pkgdata);
+
+ return pkg;
+}
+
+packageversion
+packagedb::addSource (const std::string &pkgname,
+ const SolverPool::addPackageData &pkgdata)
+{
+ /* If pkgname isn't already in packagedb, add a packagemeta */
+ packagemeta *pkg = findSource (PackageSpecification(pkgname));
+ if (!pkg)
+ {
+ pkg = new packagemeta (pkgname);
+ sourcePackages.insert (packagedb::packagecollection::value_type(pkgname, pkg));
+ }
+
+ /* Create the SolvableVersion */
+ SolvableVersion sv = solver.addPackage(pkgname, pkgdata);
+
+ /* Register it in packagemeta */
+ pkg->add_version (sv, pkgdata);
+
+ return sv;
}
int
@@ -201,6 +339,21 @@ packagedb::findBinary (PackageSpecification const &spec) const
return NULL;
}
+packageversion
+packagedb::findBinaryVersion (PackageSpecification const &spec) const
+{
+ packagedb::packagecollection::iterator n = packages.find(spec.packageName());
+ if (n != packages.end())
+ {
+ packagemeta & pkgm = *(n->second);
+ for (set<packageversion>::iterator i=pkgm.versions.begin();
+ i != pkgm.versions.end(); ++i)
+ if (spec.satisfies (*i))
+ return *i;
+ }
+ return packageversion();
+}
+
packagemeta *
packagedb::findSource (PackageSpecification const &spec) const
{
@@ -216,15 +369,34 @@ packagedb::findSource (PackageSpecification const &spec) const
return NULL;
}
+packageversion
+packagedb::findSourceVersion (PackageSpecification const &spec) const
+{
+ packagedb::packagecollection::iterator n = sourcePackages.find(spec.packageName());
+ if (n != sourcePackages.end())
+ {
+ packagemeta & pkgm = *(n->second);
+ for (set<packageversion>::iterator i = pkgm.versions.begin();
+ i != pkgm.versions.end(); ++i)
+ if (spec.satisfies (*i))
+ return *i;
+ }
+ return packageversion();
+}
+
/* static members */
int packagedb::installeddbread = 0;
int packagedb::installeddbver = 0;
+bool packagedb::prepped = false;
packagedb::packagecollection packagedb::packages;
packagedb::categoriesType packagedb::categories;
packagedb::packagecollection packagedb::sourcePackages;
PackageDBActions packagedb::task = PackageDB_Install;
+packageversion packagedb::basepkg;
std::vector <packagemeta *> packagedb::dependencyOrderedPackages;
+SolverPool packagedb::solver;
+SolverSolution packagedb::solution(packagedb::solver);
#include <stack>
@@ -312,8 +484,9 @@ ConnectedLoopFinder::visit(packagemeta *nodeToVisit)
nodesInStronglyConnectedComponent.push(nodeToVisit);
/* walk through each node */
- PackageDepends::const_iterator dp = nodeToVisit->installed.depends()->begin();
- while (dp != nodeToVisit->installed.depends()->end())
+ const PackageDepends deps = nodeToVisit->installed.depends();
+ PackageDepends::const_iterator dp = deps.begin();
+ while (dp != deps.end())
{
/* check for an installed match */
if (checkForInstalled (*dp))
@@ -428,22 +601,12 @@ packagedb::fillMissingCategory ()
}
void
-packagedb::defaultTrust (trusts trust)
+packagedb::defaultTrust (SolverTasks &q, SolverSolution::updateMode mode, bool test)
{
- for (packagedb::packagecollection::iterator i = packages.begin (); i != packages.end (); ++i)
- {
- packagemeta & pkg = *(i->second);
- if (pkg.installed
- || pkg.categories.find ("Base") != pkg.categories.end ()
- || pkg.categories.find ("Orphaned") != pkg.categories.end ())
- {
- pkg.desired = pkg.trustp (true, trust);
- if (pkg.desired)
- pkg.pick (pkg.desired.accessible() && pkg.desired != pkg.installed);
- }
- else
- pkg.desired = packageversion ();
- }
+ solution.update(q, mode, test);
+
+ // reflect that task list into packagedb
+ solution.trans2db();
}
void
@@ -501,8 +664,9 @@ packagedb::guessUserPicked()
continue;
/* walk through each node */
- std::vector <PackageSpecification *>::const_iterator dp = pkgm.installed.depends()->begin();
- while (dp != pkgm.installed.depends()->end())
+ const PackageDepends deps = pkgm.installed.depends();
+ std::vector <PackageSpecification *>::const_iterator dp = deps.begin();
+ while (dp != deps.end())
{
/* check for an installed match */
if (checkForInstalled(*dp))
@@ -521,3 +685,66 @@ packagedb::guessUserPicked()
}
}
}
+
+void
+packagedb::fixup_source_package_ids()
+{
+ for (packagecollection::iterator i = packages.begin ();
+ i != packages.end (); ++i)
+ {
+ packagemeta &pkgm = *(i->second);
+
+ for (set<packageversion>::iterator i = pkgm.versions.begin();
+ i != pkgm.versions.end(); ++i)
+ {
+ /* If spkg_id is already known for this package, there's nothing to
+ fix. */
+ if (i->sourcePackage())
+ continue;
+
+ /* Some packages really have no source, indicated by no [sS]ource:
+ line in setup.ini, which becomes an empty source package name */
+ const std::string spkg = i->sourcePackageName();
+ if (spkg.empty())
+ continue;
+
+ /* Otherwise, we need to find the source package and fix up the source
+ package id*/
+ packageversion spkg_id = findSourceVersion(PackageSpecification(spkg,
+ i->Canonical_version()));
+
+ if (spkg_id)
+ {
+ i->fixup_spkg_id(spkg_id);
+ }
+ else
+ {
+ Log (LOG_BABBLE) << "No source package for '" << i->Name() << "' " << i->Canonical_version() << ", source package name '" << spkg << "'" << endLog;
+ }
+ }
+ }
+}
+
+void
+packagedb::prep()
+{
+ /* make packagedb ready for use for chooser */
+ if (prepped)
+ return;
+
+ makeBase();
+ read();
+ upgrade();
+ fixup_source_package_ids();
+ removeEmptyCategories();
+
+ /* XXX: this needs to be broken out somewhere where it can do progress
+ reporting, as it can take a long time... */
+ if (source == IDC_SOURCE_DOWNLOAD || source ==IDC_SOURCE_LOCALDIR)
+ packagemeta::ScanDownloadedFiles (MirrorOption);
+
+ setExistence ();
+ fillMissingCategory ();
+
+ prepped = true;
+}
diff --git a/package_db.h b/package_db.h
index 59737c0..e500e4b 100644
--- a/package_db.h
+++ b/package_db.h
@@ -57,23 +57,29 @@ typedef std::vector <packagemeta *>::iterator PackageDBConnectedIterator;
*/
+#include "libsolv.h"
#include <PackageTrust.h>
class packagedb
{
public:
packagedb ();
+ void init();
/* 0 on success */
int flush ();
- void upgrade ();
+ void prep();
+
packagemeta * findBinary (PackageSpecification const &) const;
+ packageversion findBinaryVersion (PackageSpecification const &) const;
packagemeta * findSource (PackageSpecification const &) const;
+ packageversion findSourceVersion (PackageSpecification const &spec) const;
+ packagemeta * addBinary (const std::string &pkgname, const SolverPool::addPackageData &pkgdata);
+ packageversion addSource (const std::string &pkgname, const SolverPool::addPackageData &pkgdata);
+
PackageDBConnectedIterator connectedBegin();
PackageDBConnectedIterator connectedEnd();
- void fillMissingCategory();
- void defaultTrust (trusts trust);
- void setExistence();
- void removeEmptyCategories();
+
+ void defaultTrust (SolverTasks &q, SolverSolution::updateMode mode, bool test);
typedef std::map <std::string, packagemeta *> packagecollection;
/* all seen binary packages */
@@ -84,12 +90,28 @@ public:
typedef std::map <std::string, std::vector <packagemeta *>, casecompare_lt_op > categoriesType;
static categoriesType categories;
static PackageDBActions task;
+ /* a ficitious package that requires all packages in the Base category */
+ static packageversion basepkg;
+
+ static SolverPool solver;
+ static SolverSolution solution;
+
private:
+ void makeBase();
+ void read();
+ void upgrade ();
+ void fixup_source_package_ids();
+ void removeEmptyCategories();
+ void fillMissingCategory();
+ void setExistence();
+ void guessUserPicked(void);
+
static int installeddbread; /* do we have to reread this */
static int installeddbver;
+ static bool prepped;
+
friend class ConnectedLoopFinder;
static std::vector <packagemeta *> dependencyOrderedPackages;
- void guessUserPicked(void);
};
#endif /* SETUP_PACKAGE_DB_H */
diff --git a/package_depends.cc b/package_depends.cc
index e288c0b..a03f5a0 100644
--- a/package_depends.cc
+++ b/package_depends.cc
@@ -15,19 +15,16 @@
#include <LogSingleton.h>
void
-dumpPackageDepends (PackageDepends const *currentList,
+dumpPackageDepends (PackageDepends const ¤tList,
std::ostream &logger)
{
- if (currentList)
+ Log (LOG_BABBLE) << "( ";
+ PackageDepends::const_iterator i = currentList.begin();
+ while (true)
{
- Log (LOG_BABBLE) << "( ";
- PackageDepends::const_iterator i = currentList->begin();
- while (true)
- {
- if (i == currentList->end()) break;
- Log (LOG_BABBLE) << **i << " ";
- ++i;
- }
- Log (LOG_BABBLE) << ")";
+ if (i == currentList.end()) break;
+ Log (LOG_BABBLE) << **i << " ";
+ ++i;
}
+ Log (LOG_BABBLE) << ")";
}
diff --git a/package_depends.h b/package_depends.h
index af3fa01..36f7f6f 100644
--- a/package_depends.h
+++ b/package_depends.h
@@ -19,6 +19,6 @@
typedef std::vector <PackageSpecification *> PackageDepends;
-void dumpPackageDepends (PackageDepends const *currentList, std::ostream &);
+void dumpPackageDepends (PackageDepends const ¤tList, std::ostream &);
#endif // PACKAGE_DEPENDS_H
diff --git a/package_meta.cc b/package_meta.cc
index af494f4..c488e35 100644
--- a/package_meta.cc
+++ b/package_meta.cc
@@ -35,11 +35,7 @@ using namespace std;
/* this goes at the same time */
#include "win32.h"
-
#include "script.h"
-
-#include "package_version.h"
-#include "cygpackage.h"
#include "package_db.h"
#include <algorithm>
@@ -128,19 +124,98 @@ packagemeta::~packagemeta()
}
void
-packagemeta::add_version (packageversion & thepkg)
+packagemeta::add_version (packageversion & thepkg, const SolverPool::addPackageData &pkgdata)
+{
+ /*
+ If a packageversion for the same version number is already present,allow
+ this version to replace it.
+
+ There is a problem where multiple repos provide a package. It's never been
+ clear which repo should win. With this implementation, the last one added
+ will win.
+
+ We rely on this by adding packages from installed.db last.
+ */
+
+ set <packageversion>::iterator i = versions.find(thepkg);
+ if (i != versions.end())
+ {
+ versions.erase(i);
+ }
+
+ /* Add the version */
+ std::pair<std::set <packageversion>::iterator, bool> result = versions.insert (thepkg);
+
+ if (!result.second)
+ Log (LOG_PLAIN) << "Failed to add version " << thepkg.Canonical_version() << " in package " << name << endLog;
+#ifdef DEBUG
+ else
+ Log (LOG_PLAIN) << "Added version " << thepkg.Canonical_version() << " in package " << name << endLog;
+#endif
+
+ /* Record the highest version at a given stability level */
+ /* (This has to be written somewhat carefully as attributes aren't
+ internalized yet so we can't look at them) */
+ packageversion *v = NULL;
+ switch (pkgdata.stability)
+ {
+ case TRUST_CURR:
+ v = &(this->curr);
+ break;
+ case TRUST_TEST:
+ v = &(this->exp);
+ break;
+ default:
+ break;
+ }
+
+ if (v)
+ {
+ /* Any version is always greater than no version */
+ int comparison = 1;
+ if (*v)
+ comparison = SolvableVersion::compareVersions(thepkg, *v);
+
+#ifdef DEBUG
+ if ((bool)(*v))
+ Log (LOG_BABBLE) << "package " << thepkg.Name() << " comparing versions " << thepkg.Canonical_version() << " and " << v->Canonical_version() << ", result was " << comparison << endLog;
+#endif
+
+ if (comparison >= 0)
+ {
+ *v = thepkg;
+ }
+ }
+}
+
+bool
+packagemeta::isBlacklisted(const packageversion &version) const
{
- /* todo: check return value */
- versions.insert (thepkg);
+ for (std::set<std::string>::iterator i = version_blacklist.begin();
+ i != version_blacklist.end();
+ i++)
+ {
+ if (i->compare(version.Canonical_version()) == 0)
+ return true;
+ }
+
+ return false;
}
-/* assumption: package thepkg is already in the metadata list. */
void
-packagemeta::set_installed (packageversion & thepkg)
+packagemeta::set_installed_version (const std::string &version)
{
- set<packageversion>::const_iterator temp = versions.find (thepkg);
- if (temp != versions.end())
- installed = thepkg;
+ set<packageversion>::iterator i;
+ for (i = versions.begin(); i != versions.end(); i++)
+ {
+ if (version.compare(i->Canonical_version()) == 0)
+ {
+ installed = *i;
+
+ /* and mark as Keep */
+ desired = installed;
+ }
+ }
}
void
@@ -174,12 +249,6 @@ packagemeta::getReadableCategoryList () const
).visitor.result;
}
-static bool
-hasSDesc(packageversion const &pkg)
-{
- return pkg.SDesc().size();
-}
-
static void
parseNames (std::set<string> &parsed, std::string &option)
{
@@ -304,11 +373,15 @@ bool packagemeta::isManuallyDeleted() const
const std::string
packagemeta::SDesc () const
{
- set<packageversion>::iterator i = find_if (versions.begin(), versions.end(), hasSDesc);
- if (i == versions.end())
- return std::string();
- return i->SDesc ();
-};
+ set<packageversion>::iterator i;
+ for (i = versions.begin(); i != versions.end(); i++)
+ {
+ if (i->SDesc().size())
+ return i->SDesc ();
+ }
+
+ return std::string();
+}
/* Return an appropriate caption given the current action. */
std::string
@@ -525,13 +598,10 @@ packagemeta::logAllVersions () const
{
Log (LOG_BABBLE) << " [" << trustLabel(*i) <<
"] ver=" << i->Canonical_version() << endLog;
- if (i->depends()->size())
- {
- std::ostream & logger = Log (LOG_BABBLE);
- logger << " depends=";
- dumpPackageDepends(i->depends(), logger);
- logger << endLog;
- }
+ std::ostream & logger = Log (LOG_BABBLE);
+ logger << " depends=";
+ dumpPackageDepends(i->depends(), logger);
+ logger << endLog;
}
#if 0
Log (LOG_BABBLE) << " inst=" << i->
diff --git a/package_meta.h b/package_meta.h
index 8041aa1..32372e2 100644
--- a/package_meta.h
+++ b/package_meta.h
@@ -16,7 +16,8 @@
#ifndef SETUP_PACKAGE_META_H
#define SETUP_PACKAGE_META_H
-class packageversion;
+class SolvableVersion;
+typedef SolvableVersion packageversion;
class packagemeta;
#include <set>
@@ -28,7 +29,7 @@ class packagemeta;
typedef std::pair<const std::string, std::vector<packagemeta *> > Category;
-/* NOTE: A packagemeta without 1 packageversion is invalid! */
+/* NOTE: A packagemeta without 1 version is invalid! */
class packagemeta
{
public:
@@ -42,8 +43,8 @@ public:
~packagemeta ();
- void add_version (packageversion &);
- void set_installed (packageversion &);
+ void add_version (packageversion &, const SolverPool::addPackageData &);
+ void set_installed_version (const std::string &);
void addToCategoryBase();
bool hasNoCategories() const;
void setDefaultCategories();
@@ -77,6 +78,11 @@ public:
message.set (message_id, message_string);
}
+ void set_version_blacklist(std::set <std::string> &_list)
+ {
+ version_blacklist = _list;
+ }
+
std::string action_caption () const;
packageversion trustp (bool _default, trusts const t) const
{
@@ -130,6 +136,8 @@ public:
packageversion curr;
/* ditto for "test" (experimental) */
packageversion exp;
+ /* which one is the default according to the solver */
+ packageversion default_version;
/* Now for the user stuff :] */
/* What version does the user want ? */
packageversion desired;
@@ -154,6 +162,9 @@ public:
void addScript(Script const &);
std::vector <Script> &scripts();
+ /* this version is undesirable */
+ bool isBlacklisted(const packageversion &version) const;
+
protected:
packagemeta &operator= (packagemeta const &);
private:
@@ -163,6 +174,8 @@ private:
bool _picked; /* true if desired version is to be (re)installed */
bool _srcpicked;
+
+ std::set <std::string> version_blacklist;
};
#endif /* SETUP_PACKAGE_META_H */
diff --git a/package_version.cc b/package_version.cc
deleted file mode 100644
index 2587fbb..0000000
--- a/package_version.cc
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (c) 2001, 2003 Robert Collins.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * A copy of the GNU General Public License can be found at
- * http://www.gnu.org/
- *
- * Written by Robert Collins <rbtcollins@hotmail.com>
- *
- */
-
-/* this is the parent class for all package operations.
- */
-
-#include "package_version.h"
-#include "package_db.h"
-#include "package_meta.h"
-#include "LogSingleton.h"
-#include "state.h"
-#include "resource.h"
-#include <algorithm>
-#include "csu_util/version_compare.h"
-
-using namespace std;
-
-/* a default class to avoid special casing empty packageversions */
-
-/* TODO place into the class header */
-class _defaultversion : public _packageversion
-{
-public:
- _defaultversion()
- {
- // never try to free me!
- ++references;
- }
- const std::string Name(){return std::string();}
- const std::string Vendor_version() {return std::string();}
- const std::string Package_version() {return std::string();}
- const std::string Canonical_version() {return std::string();}
- void setCanonicalVersion (const std::string& ) {}
- package_type_t Type () {return package_binary;}
- const std::string SDesc () {return std::string();}
- void set_sdesc (const std::string& ) {}
- const std::string LDesc () {return std::string();}
- void set_ldesc (const std::string& ) {}
-};
-static _defaultversion defaultversion;
-
-/* the wrapper class */
-packageversion::packageversion() : data (&defaultversion)
-{
- ++data->references;
-}
-
-/* Create from an actual package */
-packageversion::packageversion (_packageversion *pkg)
-{
- if (pkg)
- data = pkg;
- else
- data = &defaultversion;
- ++data->references;
-}
-
-packageversion::packageversion (packageversion const &existing) :
-data(existing.data)
-{
- ++data->references;
-}
-
-packageversion::~packageversion()
-{
- if (--data->references == 0)
- delete data;
-}
-
-packageversion &
-packageversion::operator= (packageversion const &rhs)
-{
- ++rhs.data->references;
- if (--data->references == 0)
- delete data;
- data = rhs.data;
- return *this;
-}
-
-bool
-packageversion::operator ! () const
-{
- return !data->Name().size();
-}
-
-packageversion::operator bool () const
-{
- return data->Name().size();
-}
-
-bool
-packageversion::operator == (packageversion const &rhs) const
-{
- if (this == &rhs || data == rhs.data)
- return true;
- else
- return data->Name () == rhs.data->Name() && data->Canonical_version () == rhs.data->Canonical_version();
-}
-
-bool
-packageversion::operator != (packageversion const &rhs) const
-{
- return ! (*this == rhs);
-}
-
-bool
-packageversion::operator < (packageversion const &rhs) const
-{
- int t = casecompare(data->Name(), rhs.data->Name());
- if (t < 0)
- return true;
- else if (t > 0)
- return false;
- else if (casecompare (data->Canonical_version(), rhs.data->Canonical_version()) < 0)
- return true;
- return false;
-}
-
-const std::string
-packageversion::Name () const
-{
- return data->Name ();
-}
-
-const std::string
-packageversion::Vendor_version() const
-{
- return data->Vendor_version();
-}
-
-const std::string
-packageversion::Package_version() const
-{
- return data->Package_version();
-}
-
-const std::string
-packageversion::Canonical_version() const
-{
- return data->Canonical_version();
-}
-
-void
-packageversion::setCanonicalVersion (const std::string& ver)
-{
- data->setCanonicalVersion (ver);
-}
-
-package_type_t
-packageversion::Type () const
-{
- return data->Type ();
-}
-
-const std::string
-packageversion::SDesc () const
-{
- return data->SDesc ();
-}
-
-void
-packageversion::set_sdesc (const std::string& sdesc)
-{
- data->set_sdesc (sdesc);
-}
-
-const std::string
-packageversion::LDesc () const
-{
- return data->LDesc ();
-}
-
-void
-packageversion::set_ldesc (const std::string& ldesc)
-{
- data->set_ldesc (ldesc);
-}
-
-packageversion
-packageversion::sourcePackage() const
-{
- return data->sourcePackage();
-}
-
-PackageSpecification &
-packageversion::sourcePackageSpecification () const
-{
- return data->sourcePackageSpecification ();
-}
-
-void
-packageversion::setSourcePackageSpecification (PackageSpecification const &spec)
-{
- data->setSourcePackageSpecification(spec);
-}
-
-PackageDepends *
-packageversion::depends()
-{
- return &data->depends;
-}
-
-const PackageDepends *
-packageversion::depends() const
-{
- return &data->depends;
-}
-
-packagesource *
-packageversion::source () const
-{
- return &data->source;
-}
-
-bool
-packageversion::accessible() const
-{
- return data->accessible();
-}
-
-
-int
-packageversion::compareVersions(const packageversion &a, const packageversion &b)
-{
- /* Compare Vendor_version */
- int comparison = version_compare(a.Vendor_version(), b.Vendor_version());
-
-#if DEBUG
- Log (LOG_BABBLE) << "vendor version comparison " << a.Vendor_version() << " and " << b.Vendor_version() << ", result was " << comparison << endLog;
-#endif
-
- if (comparison != 0)
- {
- return comparison;
- }
-
- /* Vendor_version are tied, compare Package_version */
-#if DEBUG
- Log (LOG_BABBLE) << "package version comparison " << a.Package_version() << " and " << b.Package_version() << ", result was " << comparison << endLog;
-#endif
-
- comparison = version_compare(a.Package_version(), b.Package_version());
- return comparison;
-}
-
-/* the parent data class */
-
-_packageversion::_packageversion ():references (0)
-{
-}
-
-_packageversion::~_packageversion ()
-{
-}
-
-PackageSpecification &
-_packageversion::sourcePackageSpecification ()
-{
- return _sourcePackage;
-}
-
-void
-_packageversion::setSourcePackageSpecification (PackageSpecification const &spec)
-{
- _sourcePackage = spec;
-}
-
-packageversion
-_packageversion::sourcePackage ()
-{
- if (!sourceVersion)
- {
- packagedb db;
- packagemeta * pkg;
- pkg = db.findSource (_sourcePackage);
- /* no valid source meta available, just return the default
- (blank) package version
- */
- if (!pkg)
- return sourceVersion;
- set<packageversion>::iterator i=pkg->versions.begin();
- while (i != pkg->versions.end())
- {
- packageversion const & ver = * i;
- if (_sourcePackage.satisfies (ver))
- sourceVersion = ver;
- ++i;
- }
- }
- return sourceVersion;
-}
-
-// is archive accessible
-bool
-_packageversion::accessible() const
-{
- // cached ?
- if (source.Cached ())
- return true;
- // net access allowed?
- if (::source == IDC_SOURCE_LOCALDIR)
- return false;
- // retrievable ?
- if (source.sites.size() || source.Cached ())
- return true;
- // otherwise, not accessible
- return false;
-}
diff --git a/package_version.h b/package_version.h
index 90d576d..43cf146 100644
--- a/package_version.h
+++ b/package_version.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2003 Robert Collins.
+ * Copyright (c) 2017 Jon Turney
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -9,165 +9,13 @@
* A copy of the GNU General Public License can be found at
* http://www.gnu.org/
*
- * Written by Robert Collins <rbtcollins@hotmail.com>
- *
- */
-
-#ifndef SETUP_PACKAGE_VERSION_H
-#define SETUP_PACKAGE_VERSION_H
-
-/* This is a package version abstrct class, that should be able to
- * arbitrate acceess to cygwin binary packages, cygwin source package,
- * and the rpm and deb equivalents of the same.
- */
-
-/* standard binary package metadata:
- * Name (ie mutt
- * Vendor Version (ie 2.5.1)
- * Package Version (ie 16)
- * Stability
- * Files
*/
-/* For non installed files, this class can be populated via information about
- * what is available on the net, or by parsing a specific package file.
- * for installed packages, this class should represent what is currently installed,
- * - updated by what net metadata has about it.
- * i.e. the stability of this version will change simply because the net mirrors
- * now consider it old.
- */
-
-class CategoryList;
-
-/*Required for parsing */
-#include "package_source.h"
-#include "PackageSpecification.h"
-#include "PackageTrust.h"
-#include "package_depends.h"
-
-typedef enum
-{
- package_invalid,
- package_old,
- package_current,
- package_experimental
-}
-package_stability_t;
-
-typedef enum
-{
- package_binary,
- package_source
-}
-package_type_t;
-
-/* A wrapper class to be copied by value that
- references the same package.
- Nothing is virtual, because the wrapper cannot be inherited.
- However, as all the methods are implemented in the referenced
- _packageversion, that class allows virtual overriding.
- */
-
-class _packageversion;
-class packagemeta;
-
-/* This class has pointer semantics
- Specifically: a=b does not alter the value of *a.
- */
-class packageversion
-{
-public:
- packageversion (); /* creates an empty packageversion */
- packageversion (_packageversion *); /* used when creating an instance */
- packageversion (packageversion const &);
- ~packageversion ();
- packageversion &operator= (packageversion const &);
- bool operator ! () const; /* true if the package is invalid. (i.e.
- uninitialised */
- operator bool () const; /* returns ! !() */
- bool operator == (packageversion const &) const; /* equality */
- bool operator != (packageversion const &) const;
- bool operator < (packageversion const &) const;
- bool operator <= (packageversion const &) const;
- bool operator > (packageversion const &) const;
- bool operator >= (packageversion const &) const;
-
- const std::string Name () const;
- const std::string Vendor_version () const;
- const std::string Package_version () const;
- const std::string Canonical_version () const;
- void setCanonicalVersion (const std::string& );
- package_type_t Type () const;
- const std::string SDesc () const;
- void set_sdesc (const std::string& );
- const std::string LDesc () const;
- void set_ldesc (const std::string& );
- packageversion sourcePackage () const;
- PackageSpecification & sourcePackageSpecification () const;
- void setSourcePackageSpecification (PackageSpecification const &);
-
- /* invariant: these never return NULL */
- PackageDepends *depends();
- const PackageDepends *depends() const;
-
- /* invariant: never null */
- packagesource *source() const; /* where can we source the file from */
-
- bool accessible () const;
-
- /* ensure that the depends clause is satisfied */
- int set_requirements (trusts deftrust, size_t depth = 0);
-
- /* utility function to compare package versions */
- static int compareVersions(const packageversion &a, const packageversion &b);
-
-private:
- _packageversion *data; /* Invariant: * data is always valid */
-};
-
-class _packageversion
-{
-public:
- _packageversion();
- virtual ~_packageversion();
- /* for list inserts/mgmt. */
- std::string key;
- /* name is needed here, because if we are querying a file, the data may be embedded in
- the file */
- virtual const std::string Name () = 0;
- virtual const std::string Vendor_version () = 0;
- virtual const std::string Package_version () = 0;
- virtual const std::string Canonical_version () = 0;
- virtual void setCanonicalVersion (const std::string& ) = 0;
-// virtual package_stability_t Stability () = 0;
- virtual package_type_t Type () = 0;
- virtual const std::string SDesc () = 0;
- virtual void set_sdesc (const std::string& ) = 0;
- virtual const std::string LDesc () = 0;
- virtual void set_ldesc (const std::string& ) = 0;
- /* only semantically meaningful for binary packages */
- /* direct link to the source package for this binary */
- /* if multiple versions exist and the source doesn't discriminate
- then the most recent is used
- */
- virtual packageversion sourcePackage ();
- virtual PackageSpecification & sourcePackageSpecification ();
- virtual void setSourcePackageSpecification (PackageSpecification const &);
-
- PackageDepends depends;
-
- packagesource source; /* where can we source the file from */
+#ifndef PACKAGE_VERSION_H
+#define PACKAGE_VERSION_H
- virtual bool accessible () const;
+#include "libsolv.h"
- /* TODO: Implement me:
- static package_meta * scan_package (io_stream *);
- */
- size_t references;
-protected:
- /* only meaningful for binary packages */
- PackageSpecification _sourcePackage;
- packageversion sourceVersion;
-};
+typedef SolvableVersion packageversion;
-#endif /* SETUP_PACKAGE_VERSION_H */
+#endif // PACKAGE_VERSION_H
diff --git a/prereq.cc b/prereq.cc
index 0a46ad1..8fcd3ba 100644
--- a/prereq.cc
+++ b/prereq.cc
@@ -13,27 +13,16 @@
*
*/
-#include "win32.h"
-#include <commctrl.h>
-#include <stdio.h>
-#include <io.h>
-#include <ctype.h>
-#include <process.h>
-#include <queue>
-
#include "prereq.h"
-#include "dialog.h"
#include "resource.h"
#include "state.h"
-#include "propsheet.h"
#include "threebar.h"
-#include "Generic.h"
#include "LogSingleton.h"
#include "ControlAdjuster.h"
#include "package_db.h"
-#include "package_meta.h"
-#include "msg.h"
+
#include "Exception.h"
+#include "getopt++/BoolOption.h"
// Sizing information.
static ControlAdjuster::ControlInfo PrereqControlsInfo[] = {
@@ -43,6 +32,7 @@ static ControlAdjuster::ControlInfo PrereqControlsInfo[] = {
};
extern ThreeBarProgressPage Progress;
+BoolOption IncludeSource (false, 'I', "include-source", "Automatically install source for every package installed");
// ---------------------------------------------------------------------------
// implements class PrereqPage
@@ -73,7 +63,7 @@ void
PrereqPage::OnActivate()
{
// if we have gotten this far, then PrereqChecker has already run isMet
- // and found that there were missing packages; so we can just call
+ // and found that there were problems; so we can just call
// getUnmetString to format the results and display it
std::string s;
@@ -88,53 +78,50 @@ long
PrereqPage::OnNext ()
{
HWND h = GetHWND ();
+ packagedb db;
if (!IsDlgButtonChecked (h, IDC_PREREQ_CHECK))
{
// breakage imminent! danger, danger
int res = MessageBox (h,
- "The listed packages are required for packages depending on them to "
- "work. We strongly recommend that you allow Setup to select them."
+ "Some packages may not work properly if you continue."
"\r\n\r\n"
- "Are you sure you want to proceed without these packages?",
- "WARNING - Required Packages Not Selected",
+ "Are you sure you want to proceed (NOT RECOMMENDED)?",
+ "WARNING - Unsolved Problems",
MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2);
if (res == IDNO)
return -1;
else
- Log (LOG_PLAIN) <<
- "NOTE! User refused suggested missing dependencies! "
+ {
+ Log (LOG_PLAIN) <<
+ "NOTE! User continued with unsolved problems! "
"Expect some packages to give errors or not function at all." << endLog;
+ // Change the solver's transaction list to reflect the user's choices.
+ db.solution.db2trans();
+ }
}
else
{
- // add the missing requirements
- PrereqChecker p;
- p.selectMissing ();
+ db.solution.applyDefaultProblemSolutions();
}
- return whatNext();
-}
+ PrereqChecker p;
+ p.finalize();
-long
-PrereqPage::whatNext ()
-{
- if (source == IDC_SOURCE_LOCALDIR)
- {
- // Next, install
- Progress.SetActivateTask (WM_APP_START_INSTALL);
- }
- else
- {
- // Next, start download from internet
- Progress.SetActivateTask (WM_APP_START_DOWNLOAD);
- }
- return IDD_INSTATUS;
+ return IDD_CONFIRM;
}
long
PrereqPage::OnBack ()
{
+ // Add reinstall tasks
+ PrereqChecker p;
+ p.augment();
+
+ // Reset the package database to correspond to the solver's solution
+ packagedb db;
+ db.solution.trans2db();
+
return IDD_CHOOSE;
}
@@ -145,11 +132,7 @@ PrereqPage::OnUnattended ()
if (unattended_mode == chooseronly)
return -1;
- // in unattended mode, add the missing requirements, then carry on to download/install
- PrereqChecker p;
- p.selectMissing ();
-
- return whatNext();
+ return IDD_CONFIRM;
}
// ---------------------------------------------------------------------------
@@ -157,170 +140,55 @@ PrereqPage::OnUnattended ()
// ---------------------------------------------------------------------------
// instantiate the static members
-map <packagemeta *, vector <packagemeta *>, packagemeta_ltcomp> PrereqChecker::unmet;
-map <std::string, vector <packagemeta *> > PrereqChecker::notfound;
-trusts PrereqChecker::theTrust = TRUST_CURR;
+bool PrereqChecker::use_test_packages;
+SolverTasks PrereqChecker::q;
-/* This function builds a list of unmet dependencies to present to the user on
- the PrereqPage propsheet.
-
- The data is stored in two associative maps:
- unmet[package] = vector of packages that depend on package.
- notfound[package-name] = vector of packages that depend on package.
-*/
bool
PrereqChecker::isMet ()
{
packagedb db;
- Progress.SetText1 ("Checking prerequisites...");
+ Progress.SetText1 ("Solving dependencies...");
Progress.SetText2 ("");
Progress.SetText3 ("");
- // clear static data each time this is called
- unmet.clear ();
- notfound.clear ();
-
- // packages that need to be checked for dependencies
- queue <packagemeta *> todo;
-
- // go through all packages, adding desired ones to the initial work list
- for (packagedb::packagecollection::iterator p = db.packages.begin ();
- p != db.packages.end (); ++p)
- {
- if (p->second->desired)
- todo.push (p->second);
- }
-
- int max = todo.size();
- int pos = 0;
+ // Create task list corresponding to current state of package database
+ q.setTasks();
- // churn through the work list
- while (!todo.empty ())
- {
- // get the first package off the work list
- packagemeta *pack = todo.front ();
- todo.pop ();
-
- pos++;
- Progress.SetText2 (pack->name.c_str());
- static char buf[100];
- sprintf(buf, "%d %% (%d/%d)", pos * 100 / max, pos, max);
- Progress.SetText3(buf);
- Progress.SetBar1(pos, max);
-
- // Fetch the dependencies of the package. This assumes that the
- // dependencies of all versions are all the same.
- const PackageDepends *deps = pack->curr.depends ();
-
- // go through the package's dependencies
- for (PackageDepends::const_iterator d =
- deps->begin (); d != deps->end (); ++d)
- {
- PackageSpecification *dep_spec = *d;
- packagemeta *dep = db.findBinary (*dep_spec);
-
- if (dep)
- {
- if (!(dep->desired && dep_spec->satisfies (dep->desired)))
- {
- // we've got an unmet dependency
- if (unmet.find (dep) == unmet.end ())
- {
- // newly found dependency: add to worklist
- todo.push (dep);
- max++;
- }
- unmet[dep].push_back (pack);
- }
- }
- else
- {
- // dependency on a package which doesn't have any binary versions
- // (i.e. it is source only or doesn't exist)
- Log (LOG_PLAIN) << "package " << pack->name << " has dependency "
- << dep_spec->packageName() << " we can't find" << endLog;
- notfound[dep_spec->packageName()].push_back (pack);
- }
- }
- }
-
- return unmet.empty () && notfound.empty ();
+ // apply solver to those tasks and global state (use test or not)
+ return db.solution.update(q, SolverSolution::keep, use_test_packages);
}
-/* Formats 'unmet' as a string for display to the user. */
void
-PrereqChecker::getUnmetString (std::string &s)
+PrereqChecker::finalize ()
{
- s = "";
+ augment();
- {
- map <std::string, vector <packagemeta *> >::iterator i;
- for (i = notfound.begin(); i != notfound.end(); i++)
- {
- s = s + i->first
- + "\t(not found)"
- + "\r\n\tRequired by: ";
- for (unsigned int j = 0; j < i->second.size(); j++)
- {
- s += i->second[j]->name;
- if (j != i->second.size() - 1)
- s += ", ";
- }
- s += "\r\n\r\n";
- }
- }
-
- map <packagemeta *, vector <packagemeta *>, packagemeta_ltcomp>::iterator i;
- for (i = unmet.begin(); i != unmet.end(); i++)
- {
- s = s + i->first->name
- + "\t(" + i->first->trustp (false, theTrust).Canonical_version ()
- + ")\r\n\t" + i->first->SDesc ()
- + "\r\n\tRequired by: ";
- for (unsigned int j = 0; j < i->second.size(); j++)
- {
- s += i->second[j]->name;
- if (j != i->second.size() - 1)
- s += ", ";
- }
- s += "\r\n\r\n";
- }
+ packagedb db;
+ db.solution.addSource(IncludeSource);
+ db.solution.dumpTransactionList();
}
-/* Takes the keys of 'unmet' and selects them, using the current trust. */
void
-PrereqChecker::selectMissing ()
+PrereqChecker::augment ()
{
packagedb db;
+ db.solution.augmentTasks(q);
+}
- // provide a default, even though this should have been set for us
- if (!theTrust)
- theTrust = TRUST_CURR;
+/* Formats problems and solutions as a string for display to the user. */
+void
+PrereqChecker::getUnmetString (std::string &s)
+{
+ packagedb db;
+ s = db.solution.report();
- // get each of the keys of 'unmet'
- map <packagemeta *, vector <packagemeta *>, packagemeta_ltcomp>::iterator i;
- for (i = unmet.begin(); i != unmet.end(); i++)
+ //
+ size_t pos = 0;
+ while ((pos = s.find("\n", pos)) != std::string::npos)
{
- packagemeta *pkg = i->first;
- packageversion vers = pkg->trustp (false, theTrust);
- pkg->desired = vers;
- pkg->srcpick (false);
-
- if (vers == i->first->installed)
- {
- pkg->pick (false);
- Log (LOG_PLAIN) << "Adding required dependency " << i->first->name <<
- ": Selecting already-installed version " <<
- i->first->installed.Canonical_version () << "." << endLog;
- }
- else
- {
- pkg->pick (vers.accessible ());
- Log (LOG_PLAIN) << "Adding required dependency " << i->first->name <<
- ": Selecting version " << vers.Canonical_version () <<
- " for installation." << endLog;
- }
+ s.replace(pos, 1, "\r\n");
+ pos += 2;
}
}
@@ -336,11 +204,8 @@ do_prereq_check_thread(HINSTANCE h, HWND owner)
if (p.isMet ())
{
- if (source == IDC_SOURCE_LOCALDIR)
- Progress.SetActivateTask (WM_APP_START_INSTALL); // install
- else
- Progress.SetActivateTask (WM_APP_START_DOWNLOAD); // start download
- retval = IDD_INSTATUS;
+ p.finalize();
+ retval = IDD_CONFIRM;
}
else
{
diff --git a/prereq.h b/prereq.h
index 163af6e..749d3eb 100644
--- a/prereq.h
+++ b/prereq.h
@@ -27,32 +27,27 @@ public:
virtual long OnNext ();
virtual long OnBack ();
virtual long OnUnattended ();
-private:
- long whatNext ();
};
class PrereqChecker
{
public:
- // checks all dependecies, populates 'unmet'
- // returns true if unsatisfied dependencies exist
+ // returns true if no dependency problems exist
bool isMet ();
-
+
// formats 'unmet' as a string for display
void getUnmetString (std::string &s);
-
- // selects/picks the needed packages that were missing
- void selectMissing ();
-
- // notes the current trust (for use in selectMissing)
- static void setTrust (trusts t) { theTrust = t; };
+
+ // finialize the transaction list
+ void finalize ();
+
+ void augment ();
+
+ static void setTestPackages (bool t) { use_test_packages = t; };
private:
-
- // this is the actual hash_map that does all the work
- static map <packagemeta *, vector <packagemeta *>, packagemeta_ltcomp> unmet;
- static map <std::string, vector <packagemeta *> > notfound;
- static trusts theTrust;
+ static bool use_test_packages;
+ static SolverTasks q;
};
#endif /* SETUP_PREREQ_H */
diff --git a/res.rc b/res.rc
index 5b7d239..745b396 100644
--- a/res.rc
+++ b/res.rc
@@ -315,8 +315,9 @@ END
// Right-aligned controls.
#define SETUP_EXP_X (SETUP_STANDARD_DIALOG_W - SETUP_KPCE_W - 7)
-#define SETUP_CURR_X (SETUP_EXP_X - SETUP_KPCE_W - 5)
-#define SETUP_KEEP_X (SETUP_CURR_X - SETUP_KPCE_W - 5)
+#define SETUP_SYNC_X (SETUP_EXP_X - SETUP_KPCE_W - 5)
+#define SETUP_BEST_X (SETUP_SYNC_X - SETUP_KPCE_W - 5)
+#define SETUP_KEEP_X (SETUP_BEST_X - SETUP_KPCE_W - 5)
// Left-aligned controls.
#define SETUP_VIEW_X (7)
@@ -350,9 +351,11 @@ BEGIN
SETUP_CLEAR_W, 14
CONTROL "&Keep", IDC_CHOOSE_KEEP, "Button", BS_AUTORADIOBUTTON
| WS_GROUP | WS_TABSTOP, SETUP_KEEP_X, 30, SETUP_KPCE_W, 14
- CONTROL "C&urrent", IDC_CHOOSE_CURR, "Button", BS_AUTORADIOBUTTON,
- SETUP_CURR_X, 30, SETUP_KPCE_W, 14
- CONTROL "&Test", IDC_CHOOSE_EXP, "Button", BS_AUTORADIOBUTTON,
+ CONTROL "&Best", IDC_CHOOSE_BEST, "Button", BS_AUTORADIOBUTTON,
+ SETUP_BEST_X, 30, SETUP_KPCE_W, 14
+ CONTROL "&Sync", IDC_CHOOSE_SYNC, "Button", BS_AUTORADIOBUTTON,
+ SETUP_SYNC_X, 30, SETUP_KPCE_W, 14
+ CONTROL "&Test", IDC_CHOOSE_EXP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
SETUP_EXP_X, 30, SETUP_KPCE_W, 14
CONTROL "", IDC_HEADSEPARATOR, "Static", SS_BLACKFRAME | SS_SUNKEN,
0, 28, SETUP_STANDARD_DIALOG_W, 1
@@ -378,9 +381,9 @@ BEGIN
ICON IDI_CYGWIN,IDC_HEADICON,SETUP_HEADICON_X,0,21,20
LTEXT "Resolving Dependencies",IDC_STATIC_HEADER_TITLE
,7,0,258,8,NOT WS_GROUP
- LTEXT "The following packages are required to satisfy "
+ LTEXT "The following problems occured trying to satisfy "
"dependencies.",IDC_STATIC,21,9,239,16,NOT WS_GROUP
- CONTROL "&Select required packages (RECOMMENDED)"
+ CONTROL "&Accept default problem solutions"
,IDC_PREREQ_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
7,167,225,14
EDITTEXT IDC_PREREQ_EDIT,7,41,303,124,WS_VSCROLL | WS_HSCROLL |
@@ -389,6 +392,22 @@ BEGIN
END
+IDD_CONFIRM DIALOG DISCARDABLE 0, 0, SETUP_STANDARD_DIALOG_DIMS
+STYLE DS_MODALFRAME | DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Cygwin Setup - Review and confirm changes"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "",IDC_HEADSEPARATOR,"Static",SS_BLACKFRAME | SS_SUNKEN,
+ 0,28,SETUP_STANDARD_DIALOG_W,1
+ ICON IDI_CYGWIN,IDC_HEADICON,SETUP_HEADICON_X,0,21,20
+ LTEXT "Review and confirm changes",IDC_STATIC_HEADER_TITLE
+ ,7,0,258,8,NOT WS_GROUP
+ EDITTEXT IDC_CONFIRM_EDIT,7,41,325,131,WS_VSCROLL | WS_HSCROLL |
+ ES_LEFT | ES_MULTILINE | ES_READONLY | ES_AUTOHSCROLL |
+ ES_AUTOVSCROLL
+END
+
IDD_DROPPED DIALOG DISCARDABLE 0, 0, SETUP_STANDARD_DIALOG_W, 142
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Cygwin Setup - Use dropped mirrors?"
@@ -558,10 +577,11 @@ BEGIN
IDS_TRUSTKEEP_TOOLTIP "Sets all packages to their currently installed "
"version. This is equivalent to telling setup not to make any "
"changes to any package."
- IDS_TRUSTCURR_TOOLTIP "Globally select the version that is currently "
- "considered the most stable. (RECOMMENDED)"
- IDS_TRUSTEXP_TOOLTIP "Globally select the most recent version, even if "
- "that version is considered experimental or for test use by the maintainer."
+ IDS_TRUSTCURR_TOOLTIP "Sets all packages to the best version available. "
+ "(RECOMMENDED)"
+ IDS_TRUSTSYNC_TOOLTIP "Sets all packages to the version available from the "
+ "package respository, downgrading if necessary."
+ IDS_TRUSTEXP_TOOLTIP "Enable test packages."
IDS_VIEWBUTTON_TOOLTIP "Select the package view. This determines "
"which packages are shown below.\r\n"
"\r\n"
diff --git a/resource.h b/resource.h
index 70d90ca..31e080f 100644
--- a/resource.h
+++ b/resource.h
@@ -40,6 +40,7 @@
#define IDS_INSTALLEDB_VERSION 140
#define IDS_DOWNLOAD_INCOMPLETE_EXIT 141
#define IDS_QUERY_CORRUPT 142
+#define IDS_TRUSTSYNC_TOOLTIP 143
// Dialogs
@@ -68,6 +69,7 @@
#define IDD_POSTINSTALL 222
#define IDD_FILE_INUSE 223
#define IDD_DOWNLOAD_ERROR 224
+#define IDD_CONFIRM 225
// Bitmaps
@@ -120,7 +122,7 @@
#define IDC_LISTVIEW_POS 530
#define IDC_CHOOSE_VIEW 531
#define IDC_CHOOSE_EXP 532
-#define IDC_CHOOSE_CURR 533
+#define IDC_CHOOSE_BEST 533
#define IDC_CHOOSE_LIST 535
#define IDC_INS_ACTION 536
#define IDC_ROOT_DESKTOP 537
@@ -179,3 +181,5 @@
#define IDC_NET_DIRECT_LEGACY 593
#define IDC_DOWNLOAD_EDIT 594
#define IDC_CHOOSE_DO_SEARCH 595
+#define IDC_CHOOSE_SYNC 596
+#define IDC_CONFIRM_EDIT 597