From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18495 invoked by alias); 11 Dec 2017 18:14:32 -0000 Mailing-List: contact cygwin-apps-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: cygwin-apps-cvs-owner@sourceware.org Received: (qmail 18453 invoked by uid 9795); 11 Dec 2017 18:14:32 -0000 Date: Mon, 11 Dec 2017 18:14:00 -0000 Message-ID: <20171211181432.18402.qmail@sourceware.org> From: jturney@sourceware.org To: cygwin-apps-cvs@sourceware.org Subject: [setup - the official Cygwin setup program] branch master, updated. release_2.883 X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: a7c7dea653e9e5ccfe702a8d25dbcbd82a7f0beb X-Git-Newrev: c80470f644aac93e989c42111095fca534d4150d X-SW-Source: 2017-q4/txt/msg00047.txt.bz2 https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=c80470f644aac93e989c42111095fca534d4150d commit c80470f644aac93e989c42111095fca534d4150d Author: Jon Turney Date: Sat Nov 4 16:09:01 2017 +0000 Simplify LocalDirPage::OnNext() Never go directly to IDD_CHOOSE from LocalDirPage::OnNext(), go to IDD_INSTATUS with WM_APP_START_SETUP_INI_DOWNLOAD (if source == IDC_SOURCE_LOCALDIR), otherwise IDD_NET (which eventually leads there) https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=bd185b7bebe17f1da64b1c1808c2b789c0996ef1 commit bd185b7bebe17f1da64b1c1808c2b789c0996ef1 Author: Jon Turney Date: Sat Nov 4 15:37:58 2017 +0000 Make do_ini() succeed if found_ini_list is empty Rather than count the number of .ini files read in do_{local,remote}_ini, and assume success if greater than zero, actually track if an error occured. This is a subtle change of behaviour if more than one .ini file is read: previously all we needed was one to succeed, now we need them all to succeed. (Note that site_list should never be empty, and it's still an error if we don't find an .ini file from a site, so the practical effect is to make do_local_ini succeed with an empty found_ini_list) https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=cccc9ec3fe854150295ddeed08dba7cb1fff4f14 commit cccc9ec3fe854150295ddeed08dba7cb1fff4f14 Author: Jon Turney Date: Sun Oct 29 17:20:51 2017 +0000 Fix invalid iterator use in packagedb::removeEmptyCategories() https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=347e23de4d9fa6f22fdc153692440de937091e27 commit 347e23de4d9fa6f22fdc153692440de937091e27 Author: Jon Turney Date: Fri Sep 29 14:18:44 2017 +0100 Make removeEmptyCategories() explicit, rather than a side effect of defaultTrust() It's unclear that this can ever do anything. The list of categories is built as we see packages in those categories, so I don't know how we can ever get an empty category. https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=c58b62ea2a61db534e544565eb4840d9a35d8ebb commit c58b62ea2a61db534e544565eb4840d9a35d8ebb Author: Jon Turney Date: Wed Apr 26 16:22:30 2017 +0100 Hoist scan() up from packageversion to packagemeta https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=70191308aa651b7b564eddb7e89622c15406dbbd commit 70191308aa651b7b564eddb7e89622c15406dbbd Author: Jon Turney Date: Tue Apr 25 23:44:08 2017 +0100 Hoist uninstall up to Installer::uninstallOne() This calls packagemeta, which applies to packageversion (which delegates through packageversion_ to cygpackage) to return lines from the .lst.gz file (pretending that we know it contains a file list for that specific version) and to remove the .lst.gz file when done. Move this all up into Installer::uninstallOne(), where it's all in the same place as the operation it is reversing, Installer::installOne(). https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=4209699d87cb7ec9cc69cfbd6d280068e21914ee commit 4209699d87cb7ec9cc69cfbd6d280068e21914ee Author: Jon Turney Date: Wed Apr 26 15:20:14 2017 +0100 Hoist pick() up to packagemeta We are always writing packagemeta.desired.pick(bool, packagemeta). This kind of suggests something not quite right. The pick flag means install/reinstall, so despite being stored per packageversion, is only significant to download/install for the desired version. There's a slight wrinkle in that we want to also set/clear this flag for the source packageversion. We can't change this to point to packagemeta rather than packageversion, as that may not be the same for all versions, so instead just track this flag separately as srcpicked. Note that there is still a complicated mapping between the state of desired and pick and the action represented in the UI: desired == empty, installed == desired : skip desired == empty, installed != desired : uninstall desired == installed, pick == true : reinstall desired == installed, pick == false : keep desired != installed, pick == true : upgrade desired != installed, pick == false : invalid v2: Make explicit that when desired == empty, pick is false (previously this was implict, as setting pick for defaultversion was ignored) https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=621df5b3123585193e6b9413a8b79abb0f16311a commit 621df5b3123585193e6b9413a8b79abb0f16311a Author: Jon Turney Date: Tue May 23 22:19:15 2017 +0100 Hoist addScript() etc. up from packageversion to packagemeta We're only interesting in storing scripts and later running them from the desired version as we install it, so despite being stored per packageversion, this is only significant for the desired version. Hoist it up from packageversion to packagemeta. https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/setup.git;h=51296e795292f98350715fc1eb3971a8c4bdda2b commit 51296e795292f98350715fc1eb3971a8c4bdda2b Author: Jon Turney Date: Wed Dec 6 19:37:38 2017 +0000 Reset dependency list for each requires:/depends: Reset dependency list for each requires:/depends:, otherwise, they are concatenated. Also, drop useless dump of dependency list before we start reading it. Diff: --- IniDBBuilderPackage.cc | 2 +- PickPackageLine.cc | 13 ++-- PickView.cc | 8 +- cygpackage.cc | 46 +----------- cygpackage.h | 14 ---- download.cc | 12 ++-- ini.cc | 40 +++++----- install.cc | 94 +++++++++++++++++++++--- localdir.cc | 25 ++++--- package_db.cc | 20 ++++- package_db.h | 2 + package_meta.cc | 193 +++++++++++++++++++++++++----------------------- package_meta.h | 21 +++++- package_version.cc | 98 +------------------------ package_version.h | 26 ------- postinstall.cc | 6 +- prereq.cc | 11 ++- 17 files changed, 283 insertions(+), 348 deletions(-) diff --git a/IniDBBuilderPackage.cc b/IniDBBuilderPackage.cc index ad1cc88..a964ee0 100644 --- a/IniDBBuilderPackage.cc +++ b/IniDBBuilderPackage.cc @@ -233,9 +233,9 @@ IniDBBuilderPackage::buildBeginDepends () #if DEBUG Log (LOG_BABBLE) << "Beginning of a depends statement for " << cp->name << endLog; - dumpPackageDepends (currentNodeList, Log (LOG_BABBLE)); #endif currentSpec = NULL; + cbpv.depends()->clear(); currentNodeList = cbpv.depends(); } diff --git a/PickPackageLine.cc b/PickPackageLine.cc index a158966..31103ce 100644 --- a/PickPackageLine.cc +++ b/PickPackageLine.cc @@ -44,7 +44,7 @@ PickPackageLine::paint (HDC hdc, HRGN unused, int x, int y, int col_num, int sho /* current version */ pkg.desired == pkg.installed || /* no source */ !pkg.desired.accessible()) theView.DrawIcon (hdc, x + HMARGIN/2, by, theView.bm_checkna); - else if (pkg.desired.picked()) + else if (pkg.picked()) theView.DrawIcon (hdc, x + HMARGIN/2, by, theView.bm_checkyes); else theView.DrawIcon (hdc, x + HMARGIN/2, by, theView.bm_checkno); @@ -67,7 +67,7 @@ PickPackageLine::paint (HDC hdc, HRGN unused, int x, int y, int col_num, int sho /* when no source mirror available */ !pkg.desired.sourcePackage().accessible()) theView.DrawIcon (hdc, x + HMARGIN/2, by, theView.bm_checkna); - else if (pkg.desired.sourcePackage().picked()) + else if (pkg.srcpicked()) theView.DrawIcon (hdc, x + HMARGIN/2, by, theView.bm_checkyes); else theView.DrawIcon (hdc, x + HMARGIN/2, by, theView.bm_checkno); @@ -100,7 +100,7 @@ PickPackageLine::paint (HDC hdc, HRGN unused, int x, int y, int col_num, int sho /* Include the size of the binary package, and if selected, the source package as well. */ sz += picked.source()->size; - if (picked.sourcePackage().picked()) + if (pkg.srcpicked()) sz += picked.sourcePackage().source()->size; /* If size still 0, size must be unknown. */ @@ -133,14 +133,13 @@ PickPackageLine::click (int const myrow, int const ClickedRow, int const x) && x <= theView.headers[theView.bintick_col + 1].x - HMARGIN / 2) { if (pkg.desired.accessible ()) - pkg.desired.pick (!pkg.desired.picked (), &pkg); + pkg.pick (!pkg.picked ()); } else if (x >= theView.headers[theView.srctick_col].x - HMARGIN / 2 && x <= theView.headers[theView.srctick_col + 1].x - HMARGIN / 2) { if (pkg.desired.sourcePackage ().accessible ()) - pkg.desired.sourcePackage ().pick ( - !pkg.desired.sourcePackage ().picked (), NULL); + pkg.srcpick (!pkg.srcpicked ()); } /* Unchecking binary while source is unchecked or vice versa is equivalent @@ -152,7 +151,7 @@ PickPackageLine::click (int const myrow, int const ClickedRow, int const x) (x >= theView.headers[theView.srctick_col].x - HMARGIN / 2 && x <= theView.headers[theView.srctick_col + 1].x - HMARGIN / 2)) { - if (!pkg.desired.picked () && !pkg.desired.sourcePackage ().picked ()) + if (!pkg.picked () && !pkg.srcpicked ()) pkg.desired = packageversion (); } diff --git a/PickView.cc b/PickView.cc index 0d7af7a..d24866c 100644 --- a/PickView.cc +++ b/PickView.cc @@ -175,13 +175,13 @@ PickView::setViewMode (views mode) || (view_mode == PickView::views::PackagePending && ((!pkg.desired && pkg.installed) || // uninstall (pkg.desired && - (pkg.desired.picked () || // install bin - pkg.desired.sourcePackage ().picked ())))) // src + (pkg.picked () || // install bin + pkg.srcpicked ())))) // src // "Up to date" : installed packages that will not be changed || (view_mode == PickView::views::PackageKeeps && - (pkg.installed && pkg.desired && !pkg.desired.picked () - && !pkg.desired.sourcePackage ().picked ())) + (pkg.installed && pkg.desired && !pkg.picked () + && !pkg.srcpicked ())) // "Not installed" || (view_mode == PickView::views::PackageSkips && diff --git a/cygpackage.cc b/cygpackage.cc index 56c1da8..32b9403 100644 --- a/cygpackage.cc +++ b/cygpackage.cc @@ -36,12 +36,8 @@ packagev (), canonical (), sdesc (), ldesc (), -type (package_binary), -listdata (), -listfile () +type (package_binary) { - memset( getfilenamebuffer, '\0', CYG_PATH_MAX); - /* FIXME: query the install database for the currently installed * version details */ @@ -104,46 +100,6 @@ cygpackage::~cygpackage () } const std::string -cygpackage::getfirstfile () -{ - if (listdata) - delete listdata; - listfile = - io_stream::open ("cygfile:///etc/setup/" + name + ".lst.gz", "rb", 0); - listdata = compress::decompress (listfile); - if (!listdata) - return std::string(); - /* std::string(NULL) will crash, so be careful to test for that. */ - const char *result = listdata->gets (getfilenamebuffer, sizeof (getfilenamebuffer)); - if (result == NULL) - Log (LOG_PLAIN) << "Corrupt package listing for " << name << ", can't uninstall old files." << endLog; - return std::string (result ? result : ""); -} - -const std::string -cygpackage::getnextfile () -{ - if (listdata) - { - /* std::string(NULL) will crash, so be careful to test for that. */ - const char *sz = listdata->gets (getfilenamebuffer, - sizeof (getfilenamebuffer)); - if (sz) - return std::string(sz); - } - return std::string(); -} - -void -cygpackage::uninstall () -{ - if (listdata) - delete listdata; - listdata = 0; - io_stream::remove ("cygfile:///etc/setup/" + name + ".lst.gz"); -} - -const std::string cygpackage::Name () { return name; diff --git a/cygpackage.h b/cygpackage.h index 4022472..c6d0657 100644 --- a/cygpackage.h +++ b/cygpackage.h @@ -20,9 +20,6 @@ * arbitrate acceess to cygwin binary packages amd cygwin source packages */ -/* for MAX_PATH */ -#include "win32.h" - #include "package_version.h" class io_stream; @@ -48,19 +45,11 @@ public: { return ldesc; }; - virtual void uninstall (); - /* pass the name of the package when constructing */ void setCanonicalVersion (const std::string& ); - virtual ~ cygpackage (); - /* TODO: we should probably return a metaclass - file name & path & size & type - - ie doc/script/binary - */ - virtual const std::string getfirstfile (); - virtual const std::string getnextfile (); /* pass the name of the package when constructing */ static packageversion createInstance (const std::string& pkgname, @@ -77,12 +66,9 @@ private: std::string packagev; std::string canonical; std::string sdesc, ldesc; - char getfilenamebuffer[CYG_PATH_MAX]; // package_stability_t stability; package_type_t type; - - io_stream *listdata, *listfile; }; #endif /* SETUP_CYGPACKAGE_H */ diff --git a/download.cc b/download.cc index 5a7a1c2..b606eb1 100644 --- a/download.cc +++ b/download.cc @@ -258,18 +258,18 @@ do_download_thread (HINSTANCE h, HWND owner) i != db.packages.end (); ++i) { packagemeta & pkg = *(i->second); - if (pkg.desired.picked () || pkg.desired.sourcePackage ().picked ()) + if (pkg.desired && (pkg.picked () || pkg.srcpicked ())) { packageversion version = pkg.desired; packageversion sourceversion = version.sourcePackage(); try { - if (version.picked()) + if (pkg.picked()) { if (!check_for_cached (*version.source())) total_download_bytes += version.source()->size; } - if (sourceversion.picked () || IncludeSource) + if (pkg.srcpicked () || IncludeSource) { if (!check_for_cached (*sourceversion.source())) total_download_bytes += sourceversion.source()->size; @@ -293,16 +293,16 @@ do_download_thread (HINSTANCE h, HWND owner) i != db.packages.end (); ++i) { packagemeta & pkg = *(i->second); - if (pkg.desired.picked () || pkg.desired.sourcePackage ().picked ()) + if (pkg.desired && (pkg.picked () || pkg.srcpicked ())) { int e = 0; packageversion version = pkg.desired; packageversion sourceversion = version.sourcePackage(); - if (version.picked()) + if (pkg.picked()) { e += download_one (*version.source(), owner); } - if (sourceversion && (sourceversion.picked() || IncludeSource)) + if (sourceversion && (pkg.srcpicked() || IncludeSource)) { e += download_one (*sourceversion.source (), owner); } diff --git a/ini.cc b/ini.cc index 82990a2..f021ed2 100644 --- a/ini.cc +++ b/ini.cc @@ -205,10 +205,10 @@ check_ini_sig (io_stream* ini_file, io_stream* ini_sig_file, return ini_file; } -static int +static bool do_local_ini (HWND owner) { - size_t ini_count = 0; + bool ini_error = false; GuiParseFeedback myFeedback; IniDBBuilderPackage aBuilder (myFeedback); io_stream *ini_file, *ini_sig_file; @@ -233,6 +233,7 @@ do_local_ini (HWND owner) // no setup found or signature invalid note (owner, IDS_SETUPINI_MISSING, SetupBaseName.c_str (), "localdir"); + ini_error = true; } else { @@ -245,12 +246,11 @@ do_local_ini (HWND owner) rfc1738_unescape (current_ini_name.substr (ldl, cap - ldl)); ini_init (ini_file, &aBuilder, myFeedback); - /*yydebug = 1; */ - if (yyparse () || yyerror_count > 0) - myFeedback.error (yyerror_messages); - else - ++ini_count; + { + myFeedback.error (yyerror_messages); + ini_error = true; + } if (aBuilder.timestamp > setup_timestamp) { @@ -261,13 +261,13 @@ do_local_ini (HWND owner) ini_file = NULL; } } - return ini_count; + return ini_error; } -static int +static bool do_remote_ini (HWND owner) { - size_t ini_count = 0; + bool ini_error = false; GuiParseFeedback myFeedback; IniDBBuilderPackage aBuilder (myFeedback); io_stream *ini_file = NULL, *ini_sig_file; @@ -303,6 +303,7 @@ do_remote_ini (HWND owner) { // no setup found or signature invalid note (owner, IDS_SETUPINI_MISSING, SetupBaseName.c_str (), n->url.c_str ()); + ini_error = true; } else { @@ -311,10 +312,11 @@ do_remote_ini (HWND owner) aBuilder.parse_mirror = n->url; ini_init (ini_file, &aBuilder, myFeedback); - /*yydebug = 1; */ - if (yyparse () || yyerror_count > 0) - myFeedback.error (yyerror_messages); + { + myFeedback.error (yyerror_messages); + ini_error = true; + } else { /* save known-good setup.ini locally */ @@ -329,7 +331,6 @@ do_remote_ini (HWND owner) io_stream::remove (fp); delete out; } - ++ini_count; } if (aBuilder.timestamp > setup_timestamp) { @@ -340,22 +341,23 @@ do_remote_ini (HWND owner) ini_file = NULL; } } - return ini_count; + return ini_error; } static bool do_ini_thread (HINSTANCE h, HWND owner) { - size_t ini_count = 0; + bool ini_error = true; if (source == IDC_SOURCE_LOCALDIR) - ini_count = do_local_ini (owner); + ini_error = do_local_ini (owner); else - ini_count = do_remote_ini (owner); + ini_error = do_remote_ini (owner); packagedb db; db.upgrade(); + db.removeEmptyCategories(); - if (ini_count == 0) + if (ini_error) return false; if (get_root_dir ().c_str ()) diff --git a/install.cc b/install.cc index a47edcd..8505199 100644 --- a/install.cc +++ b/install.cc @@ -165,10 +165,81 @@ Installer::preremoveOne (packagemeta & pkg) void Installer::uninstallOne (packagemeta & pkg) { + if (!pkg.installed) + return; + Progress.SetText1 ("Uninstalling..."); Progress.SetText2 (pkg.name.c_str()); Log (LOG_PLAIN) << "Uninstalling " << pkg.name << endLog; - pkg.uninstall (); + + std::set dirs; + + io_stream *listfile = io_stream::open ("cygfile:///etc/setup/" + pkg.name + ".lst.gz", "rb", 0); + io_stream *listdata = compress::decompress (listfile); + + while (listdata) + { + char getfilenamebuffer[CYG_PATH_MAX]; + const char *sz = listdata->gets (getfilenamebuffer, sizeof (getfilenamebuffer)); + if (sz == NULL) + break; + + std::string line(sz); + + /* Insert the paths of all parent directories of line into dirs. */ + size_t idx = line.length(); + while ((idx = line.find_last_of('/', idx-1)) != string::npos) + { + std::string dir_path = line.substr(0, idx); + bool was_new = dirs.insert(dir_path).second; + /* If the path was already present in dirs, then all parent paths + * must necessarily be present also, so don't do any further work. + * */ + if (!was_new) break; + } + + std::string d = cygpath ("/" + line); + WCHAR wname[d.size () + 11]; /* Prefix + ".lnk". */ + mklongpath (wname, d.c_str (), d.size () + 11); + DWORD dw = GetFileAttributesW (wname); + if (dw != INVALID_FILE_ATTRIBUTES + && !(dw & FILE_ATTRIBUTE_DIRECTORY)) + { + Log (LOG_BABBLE) << "unlink " << d << endLog; + SetFileAttributesW (wname, dw & ~FILE_ATTRIBUTE_READONLY); + DeleteFileW (wname); + } + /* Check for Windows shortcut of same name. */ + d += ".lnk"; + wcscat (wname, L".lnk"); + dw = GetFileAttributesW (wname); + if (dw != INVALID_FILE_ATTRIBUTES + && !(dw & FILE_ATTRIBUTE_DIRECTORY)) + { + Log (LOG_BABBLE) << "unlink " << d << endLog; + SetFileAttributesW (wname, dw & ~FILE_ATTRIBUTE_READONLY); + DeleteFileW (wname); + } + } + + /* Remove the listing file */ + delete listdata; + io_stream::remove ("cygfile:///etc/setup/" + pkg.name + ".lst.gz"); + + /* An STL set maintains itself in sorted order. Thus, iterating over it + * in reverse order will ensure we process directories depth-first. */ + set::const_iterator it = dirs.end(); + while (it != dirs.begin()) + { + it--; + std::string d = cygpath("/" + *it); + WCHAR wname[d.size () + 11]; + mklongpath (wname, d.c_str (), d.size () + 11); + if (RemoveDirectoryW (wname)) + Log (LOG_BABBLE) << "rmdir " << d << endLog; + } + + pkg.installed = packageversion(); num_uninstalls++; } @@ -492,7 +563,7 @@ Installer::installOne (packagemeta &pkgm, const packageversion &ver, lst->write (tmp.c_str(), tmp.size()); } if (Script::isAScript (fn)) - pkgm.desired.addScript (Script (canonicalfn)); + pkgm.addScript (Script (canonicalfn)); int iteration = 0; archive::extract_results extres; @@ -758,12 +829,12 @@ do_install_thread (HINSTANCE h, HWND owner) { packagemeta & pkg = *(i->second); - if (pkg.desired.picked()) + if (pkg.picked()) { md5sum_total_bytes += pkg.desired.source()->size; } - if (pkg.desired.sourcePackage ().picked() || IncludeSource) + if (pkg.srcpicked() || IncludeSource) { md5sum_total_bytes += pkg.desired.sourcePackage ().source()->size; } @@ -777,7 +848,7 @@ do_install_thread (HINSTANCE h, HWND owner) { packagemeta & pkg = *(i->second); - if (pkg.desired.picked()) + if (pkg.picked()) { try { @@ -786,9 +857,9 @@ do_install_thread (HINSTANCE h, HWND owner) catch (Exception *e) { if (yesno (owner, IDS_SKIP_PACKAGE, e->what()) == IDYES) - pkg.desired.pick (false, &pkg); + pkg.pick (false); } - if (pkg.desired.picked()) + if (pkg.picked()) { md5sum_total_bytes_sofar += pkg.desired.source()->size; total_bytes += pkg.desired.source()->size; @@ -796,7 +867,7 @@ do_install_thread (HINSTANCE h, HWND owner) } } - if (pkg.desired.sourcePackage ().picked() || IncludeSource) + if (pkg.srcpicked() || IncludeSource) { bool skiprequested = false ; try @@ -808,10 +879,10 @@ do_install_thread (HINSTANCE h, HWND owner) if (yesno (owner, IDS_SKIP_PACKAGE, e->what()) == IDYES) { skiprequested = true ; //(err occurred,) skip pkg desired - pkg.desired.sourcePackage ().pick (false, &pkg); + pkg.srcpick (false); } } - if (pkg.desired.sourcePackage().picked() || (IncludeSource && !skiprequested)) + if (pkg.srcpicked() || (IncludeSource && !skiprequested)) { md5sum_total_bytes_sofar += pkg.desired.sourcePackage ().source()->size; total_bytes += pkg.desired.sourcePackage ().source()->size; @@ -819,8 +890,9 @@ do_install_thread (HINSTANCE h, HWND owner) } } + /* Upgrade or reinstall */ if ((pkg.installed && pkg.desired != pkg.installed) - || pkg.installed.picked ()) + || pkg.picked ()) { uninstall_q.push_back (&pkg); } diff --git a/localdir.cc b/localdir.cc index 4a7ce2a..0561a30 100644 --- a/localdir.cc +++ b/localdir.cc @@ -266,21 +266,18 @@ LocalDirPage::OnNext () { if (source == IDC_SOURCE_LOCALDIR) { - if (do_from_local_dir (GetInstance (), GetHWND (), local_dir)) - { - Progress.SetActivateTask (WM_APP_START_SETUP_INI_DOWNLOAD); - return IDD_INSTATUS; - } - return IDD_CHOOSE; + do_from_local_dir (GetInstance (), GetHWND (), local_dir); + Progress.SetActivateTask (WM_APP_START_SETUP_INI_DOWNLOAD); + return IDD_INSTATUS; } } else if (attr == INVALID_FILE_ATTRIBUTES && (GetLastError () == ERROR_FILE_NOT_FOUND || GetLastError () == ERROR_PATH_NOT_FOUND)) { - if (source == IDC_SOURCE_LOCALDIR && unattended_mode) - return IDD_CHOOSE; - else if (source == IDC_SOURCE_LOCALDIR) + if (source == IDC_SOURCE_LOCALDIR) + { + if (!unattended_mode) { // Check the user really wants only to uninstall. char msgText[1000]; @@ -290,8 +287,12 @@ LocalDirPage::OnNext () snprintf (msg, sizeof (msg), msgText, local_dir.c_str (), is_64bit ? "x86_64" : "x86"); int ret = MessageBox (h, msg, 0, MB_ICONEXCLAMATION | MB_OKCANCEL); - return (ret == IDOK) ? IDD_CHOOSE : -1; + if (ret == IDCANCEL) + return -1; } + Progress.SetActivateTask (WM_APP_START_SETUP_INI_DOWNLOAD); + return IDD_INSTATUS; + } else if (offer_to_create (GetHWND (), local_dir.c_str ())) return -1; tryLocalDir = true; @@ -322,10 +323,12 @@ LocalDirPage::OnNext () return -1; else tryLocalDir = (ret == IDRETRY); + // XXX: On IDIGNORE we drop through to IDD_NET, which is wrong in + // the source == IDC_SOURCE_LOCALDIR case? } } - return 0; + return 0; // IDD_NET } long diff --git a/package_db.cc b/package_db.cc index dbec17e..cac98d7 100644 --- a/package_db.cc +++ b/package_db.cc @@ -439,20 +439,32 @@ packagedb::defaultTrust (trusts trust) { pkg.desired = pkg.trustp (true, trust); if (pkg.desired) - pkg.desired.pick (pkg.desired.accessible() && pkg.desired != pkg.installed, &pkg); + pkg.pick (pkg.desired.accessible() && pkg.desired != pkg.installed); } else pkg.desired = packageversion (); } +} + +void +packagedb::removeEmptyCategories() +{ + std::vector empty; - // side effect, remove categories with no packages. for (packagedb::categoriesType::iterator n = packagedb::categories.begin(); n != packagedb::categories.end(); ++n) if (!n->second.size()) { - Log (LOG_BABBLE) << "Removing empty category " << n->first << endLog; - packagedb::categories.erase (n++); + empty.push_back(n->first); } + + for (unsigned int i = 0; i < empty.size(); ++i) + { + packagedb::categoriesType::iterator n = packagedb::categories.find(empty[i]); + Log (LOG_BABBLE) << "Removing empty category " << empty[i] << endLog; + if (n != packagedb::categories.end()) + packagedb::categories.erase(n); + } } void diff --git a/package_db.h b/package_db.h index d02dbc4..59737c0 100644 --- a/package_db.h +++ b/package_db.h @@ -73,6 +73,8 @@ public: void fillMissingCategory(); void defaultTrust (trusts trust); void setExistence(); + void removeEmptyCategories(); + typedef std::map packagecollection; /* all seen binary packages */ static packagecollection packages; diff --git a/package_meta.cc b/package_meta.cc index b35b554..7b79738 100644 --- a/package_meta.cc +++ b/package_meta.cc @@ -44,6 +44,9 @@ using namespace std; #include #include "Generic.h" +#include "download.h" +#include "Exception.h" +#include "resource.h" using namespace std; @@ -140,76 +143,6 @@ packagemeta::set_installed (packageversion & thepkg) installed = thepkg; } -/* uninstall a package if it's installed */ -void -packagemeta::uninstall () -{ - if (installed) - { - /* this will need to be pushed down to the version, or even the source level - * to allow differences between formats to be seamlessly managed - * but for now: here is ok - */ - set dirs; - string line = installed.getfirstfile (); - - while (line.size()) - { - /* Insert the paths of all parent directories of line into dirs. */ - size_t idx = line.length(); - while ((idx = line.find_last_of('/', idx-1)) != string::npos) - { - string dir_path = line.substr(0, idx); - bool was_new = dirs.insert(dir_path).second; - /* If the path was already present in dirs, then all parent paths - * must necessarily be present also, so don't do any further work. - * */ - if (!was_new) break; - } - - std::string d = cygpath ("/" + line); - WCHAR wname[d.size () + 11]; /* Prefix + ".lnk". */ - mklongpath (wname, d.c_str (), d.size () + 11); - DWORD dw = GetFileAttributesW (wname); - if (dw != INVALID_FILE_ATTRIBUTES - && !(dw & FILE_ATTRIBUTE_DIRECTORY)) - { - Log (LOG_BABBLE) << "unlink " << d << endLog; - SetFileAttributesW (wname, dw & ~FILE_ATTRIBUTE_READONLY); - DeleteFileW (wname); - } - /* Check for Windows shortcut of same name. */ - d += ".lnk"; - wcscat (wname, L".lnk"); - dw = GetFileAttributesW (wname); - if (dw != INVALID_FILE_ATTRIBUTES - && !(dw & FILE_ATTRIBUTE_DIRECTORY)) - { - Log (LOG_BABBLE) << "unlink " << d << endLog; - SetFileAttributesW (wname, dw & ~FILE_ATTRIBUTE_READONLY); - DeleteFileW (wname); - } - line = installed.getnextfile (); - } - installed.uninstall (); - - /* An STL set maintains itself in sorted order. Thus, iterating over it - * in reverse order will ensure we process directories depth-first. */ - set::const_iterator it = dirs.end(); - while (it != dirs.begin()) - { - it--; - std::string d = cygpath("/" + *it); - WCHAR wname[d.size () + 11]; - mklongpath (wname, d.c_str (), d.size () + 11); - if (RemoveDirectoryW (wname)) - Log (LOG_BABBLE) << "rmdir " << d << endLog; - } - } - installed = packageversion(); -} - - void packagemeta::add_category (const std::string& cat) { @@ -385,9 +318,9 @@ packagemeta::action_caption () const return "Uninstall"; else if (!desired) return "Skip"; - else if (desired == installed && desired.picked()) + else if (desired == installed && picked()) return packagedb::task == PackageDB_Install ? "Reinstall" : "Retrieve"; - else if (desired == installed && desired.sourcePackage() && desired.sourcePackage().picked()) + else if (desired == installed && desired.sourcePackage() && srcpicked()) /* FIXME: Redo source should come up if the tarball is already present locally */ return "Source"; else if (desired == installed) /* and neither src nor bin */ @@ -405,15 +338,15 @@ packagemeta::set_action (trusts const trust) /* Keep the picked settings of the former desired version, if any, and make sure at least one of them is picked. If both are unpicked, pick the binary version. */ - bool source_picked = desired && desired.sourcePackage().picked (); - bool binary_picked = !desired || desired.picked () || !source_picked; + bool source_picked = desired && srcpicked (); + bool binary_picked = !desired || picked () || !source_picked; /* If we're on "Keep" on the installed version, and the version is available, switch to "Reinstall". */ - if (desired && desired == installed && !desired.picked () + if (desired && desired == installed && !picked () && desired.accessible ()) { - desired.pick (true, this); + pick (true); return; } @@ -445,12 +378,16 @@ packagemeta::set_action (trusts const trust) /* If the next version is the installed version, unpick it. This will have the desired effect to show the package in "Keep" mode. See also above for the code switching to "Reinstall". */ - desired.pick (desired != installed && binary_picked, this); - desired.sourcePackage ().pick (desired.sourcePackage().accessible () - && source_picked, NULL); + pick (desired != installed && binary_picked); + srcpick (desired.sourcePackage().accessible () && source_picked); } else - desired = packageversion (); + { + desired = packageversion (); + pick(false); + srcpick(false); + } + /* Memorize the fact that the user picked at least once. */ if (!installed) user_picked = true; @@ -469,8 +406,8 @@ packagemeta::set_action (_actions action, packageversion const &default_version) desired = default_version; if (desired) { - desired.pick (desired != installed, this); - desired.sourcePackage ().pick (false, NULL); + pick (desired != installed); + srcpick (false); } } else @@ -486,18 +423,18 @@ packagemeta::set_action (_actions action, packageversion const &default_version) if (desired.accessible ()) { user_picked = true; - desired.pick (true, this); - desired.sourcePackage ().pick (false, NULL); + pick (true); + srcpick (false); } else { - desired.pick (false, NULL); - desired.sourcePackage ().pick (true, NULL); + pick (false); + srcpick (true); } else { - desired.pick (false, NULL); - desired.sourcePackage ().pick (false, NULL); + pick (false); + srcpick (false); } } return; @@ -507,8 +444,8 @@ packagemeta::set_action (_actions action, packageversion const &default_version) desired = installed; if (desired) { - desired.pick (true, this); - desired.sourcePackage ().pick (false, NULL); + pick (true); + srcpick (false); } } else if (action == Uninstall_action) @@ -518,6 +455,34 @@ packagemeta::set_action (_actions action, packageversion const &default_version) } bool +packagemeta::picked () const +{ + return _picked; +} + +void +packagemeta::pick (bool picked) +{ + _picked = picked; + + // side effect: display message when picked (if not already seen) + if (picked) + this->message.display (); +} + +bool +packagemeta::srcpicked () const +{ + return _srcpicked; +} + +void +packagemeta::srcpick (bool picked) +{ + _srcpicked = picked; +} + +bool packagemeta::accessible () const { for (set::iterator i=versions.begin(); @@ -610,7 +575,7 @@ packagemeta::logSelectionStatus() const const std::string installed = pkg.installed ? pkg.installed.Canonical_version () : "none"; - Log (LOG_BABBLE) << "[" << pkg.name << "] action=" << action << " trust=" << trust << " installed=" << installed << " src?=" << (pkg.desired && pkg.desired.sourcePackage().picked() ? "yes" : "no") << endLog; + Log (LOG_BABBLE) << "[" << pkg.name << "] action=" << action << " trust=" << trust << " installed=" << installed << " src?=" << (pkg.desired && srcpicked() ? "yes" : "no") << endLog; if (pkg.categories.size ()) Log (LOG_BABBLE) << " categories=" << for_each(pkg.categories.begin(), pkg.categories.end(), StringConcatenator(", ")).result << endLog; #if 0 @@ -628,6 +593,36 @@ packagemeta::logSelectionStatus() const pkg.logAllVersions(); } +/* scan for local copies of package */ +void +packagemeta::scan (const packageversion &pkg, bool mirror_mode) +{ + /* Already have something */ + if (!pkg) + return; + + /* Remove mirror sites. + * FIXME: This is a bit of a hack. + */ + try + { + if (!check_for_cached (*(pkg.source ()), mirror_mode) + && ::source == IDC_SOURCE_LOCALDIR) + pkg.source ()->sites.clear (); + } + catch (Exception * e) + { + // We can ignore these, since we're clearing the source list anyway + if (e->errNo () == APPERR_CORRUPT_PACKAGE) + { + pkg.source ()->sites.clear (); + return; + } + // Unexpected exception. + throw e; + } +} + void packagemeta::ScanDownloadedFiles (bool mirror_mode) { @@ -647,10 +642,10 @@ packagemeta::ScanDownloadedFiles (bool mirror_mode) && (*i != pkg.installed || pkg.installed == pkg.curr || pkg.installed == pkg.exp); - const_cast(*i).scan (lazy_scan); + scan (*i, lazy_scan); packageversion foo = *i; packageversion pkgsrcver = foo.sourcePackage (); - pkgsrcver.scan (lazy_scan); + scan (pkgsrcver, lazy_scan); /* For local installs, if there is no src and no bin, the version * is unavailable @@ -696,3 +691,15 @@ packagemeta::addToCategoryAll() { add_category ("All"); } + +void +packagemeta::addScript(Script const &aScript) +{ + scripts_.push_back(aScript); +} + +std::vector