Diff:
---
Feedback.h | 7 +-
Makefile.am | 6 ++
SiteSetting.cc | 32 +++-----
SiteSetting.h | 16 ++--
SiteSpeedEstimator.cc | 194 ++++++++++++++++++++++++++++++++++++++++++++++++
SiteSpeedEstimator.h | 51 +++++++++++++
cli/CliFeedback.h | 8 ++
cli/CliPhaseFeedback.cc | 35 +++++++++
gui/GuiFeedback.h | 5 ++
gui/GuiPhaseFeedback.cc | 35 +++++++++
gui/SitePage.cc | 65 ++++++++++++----
ini.cc | 4 +-
nio-ie5.cc | 2 +-
res.pot | 10 ++-
res/en/res.rc | 2 +
resource.h | 2 +
16 files changed, 426 insertions(+), 48 deletions(-)
diff --git a/Feedback.h b/Feedback.h
index 663600a4..683e0ea1 100644
--- a/Feedback.h
+++ b/Feedback.h
@@ -15,7 +15,8 @@
#include "win32.h"
#include <string>
-/* Interface for feedback from ini parsing and URL fetching.
+/* Interface for feedback from ini parsing, URL fetching, progress reporting,
+ * etc.
*
* Used to send feedback that users need but that should not interrupt
* processing.
@@ -50,6 +51,10 @@ public:
virtual void hash_init (const char *hashalg, const std::string &url) = 0;
virtual void hash_progress (int bytes, int total_bytes) = 0;
+ // phase
+ virtual void phase_init(unsigned int id) = 0;
+ virtual void phase_progress(int distance, int total) const = 0;
+
//
virtual HWND owner () = 0;
};
diff --git a/Makefile.am b/Makefile.am
index 5d377802..a0b07089 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -69,6 +69,8 @@ inilint_SOURCES = \
cli/CliParseFeedback.cc \
cli/CliGetUrlFeedback.cc \
cli/CliHashCheckFeedback.cc \
+ cli/CliPhaseFeedback.cc \
+ cli/CliPhaseFeedback.h \
cli/CliFeedback.h \
LogSingleton.cc \
LogSingleton.h \
@@ -191,6 +193,8 @@ endif
gui/GuiGetUrlFeedback.cc \
gui/GuiFeedback.h \
gui/GuiHashCheckFeedback.cc \
+ gui/GuiPhaseFeedback.cc \
+ gui/GuiPhaseFeedback.h \
ini.cc \
ini.h \
IniDBBuilder.h \
@@ -280,6 +284,8 @@ endif
gui/SitePage.h \
SiteSetting.cc \
SiteSetting.h \
+ SiteSpeedEstimator.cc \
+ SiteSpeedEstimator.h \
source.cc \
source.h \
SourceSetting.cc \
diff --git a/SiteSetting.cc b/SiteSetting.cc
index 94cbb367..a9d4b6c9 100644
--- a/SiteSetting.cc
+++ b/SiteSetting.cc
@@ -30,7 +30,7 @@ StringArrayOption SiteOption('s', "site", IDS_HELPTEXT_SITE);
extern BoolOption UnsupportedOption;
/* Selected sites */
-SiteList site_list;
+SiteList selected_site_list;
/* Fresh mirrors + selected sites */
SiteList all_site_list;
@@ -63,8 +63,8 @@ SiteSetting::save()
io_stream *f = UserSettings::instance().open (lastMirrorKey ());
if (f)
{
- for (SiteList::const_iterator n = site_list.begin ();
- n != site_list.end (); ++n)
+ for (SiteList::const_iterator n = selected_site_list.begin ();
+ n != selected_site_list.end (); ++n)
*f << n->url;
delete f;
}
@@ -98,7 +98,7 @@ SiteSetting::registerSavedSite (const char * site)
return;
site_list_insert (all_site_list, tempSite);
- site_list.push_back (tempSite);
+ selected_site_list.push_back (tempSite);
}
void
@@ -157,38 +157,26 @@ site_list_type::site_list_type (const std::string &_url,
idx = 0;
} while (idx > 0);
key += url;
+
+ speed = 0;
}
bool
site_list_type::operator == (site_list_type const &rhs) const
{
+ // for historical reasons, we compare by key, which should give identical
+ // results to comparing by url
return stricmp (key.c_str(), rhs.key.c_str()) == 0;
}
-bool
-site_list_type::operator < (site_list_type const &rhs) const
-{
- return stricmp (key.c_str(), rhs.key.c_str()) < 0;
-}
-
-/*
- A SiteList is maintained as an in-order std::vector of site_list_type, by
- replacing it with a new object with the new item inserted in the correct
- place.
-
- Yes, we could just use an ordered container, instead.
-*/
+// insert newsite into site_list, unless it's already present
void
site_list_insert(SiteList &site_list, site_list_type newsite)
{
SiteList::iterator i = find (site_list.begin(), site_list.end(), newsite);
if (i == site_list.end())
{
- SiteList result;
- merge (site_list.begin(), site_list.end(),
- &newsite, &newsite + 1,
- inserter (result, result.begin()));
- site_list = result;
+ site_list.push_back (newsite);
}
else
*i = newsite;
diff --git a/SiteSetting.h b/SiteSetting.h
index 6d3ef87a..81176c87 100644
--- a/SiteSetting.h
+++ b/SiteSetting.h
@@ -17,6 +17,7 @@
#define SETUP_SITESETTING_H
#include <vector>
+#include <string>
class SiteSetting
{
@@ -39,6 +40,7 @@ public:
const std::string& , const std::string&, bool, bool = false,
const std::string& = "");
~site_list_type () {};
+
std::string url;
// provided by mirrors.lst but not used
std::string servername;
@@ -50,16 +52,14 @@ public:
bool noshow;
// url to redirect to
std::string redir;
-
+ // displayed_url is protocol and site name part of url
std::string displayed_url;
- // sort key
+ // tld sort key
std::string key;
+ // speed measurement (optional)
+ double speed;
+
bool operator == (const site_list_type &) const;
- bool operator != (const site_list_type &) const;
- bool operator < (const site_list_type &) const;
- bool operator <= (const site_list_type &) const;
- bool operator > (const site_list_type &) const;
- bool operator >= (const site_list_type &) const;
};
typedef std::vector <site_list_type> SiteList;
@@ -67,7 +67,7 @@ typedef std::vector <site_list_type> SiteList;
void site_list_insert(SiteList &site_list, site_list_type newsite);
/* user chosen sites */
-extern SiteList site_list;
+extern SiteList selected_site_list;
/* potential sites */
extern SiteList all_site_list;
diff --git a/SiteSpeedEstimator.cc b/SiteSpeedEstimator.cc
new file mode 100644
index 00000000..b3ba9c6d
--- /dev/null
+++ b/SiteSpeedEstimator.cc
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2026, Cygwin Contributors.
+ *
+ * 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 Jon Turney <[email protected]>
+ *
+ */
+
+#include "SiteSpeedEstimator.h"
+#include "netio.h"
+#include "ini.h"
+#include "LogSingleton.h"
+#include "Feedback.h"
+
+#include <vector>
+#include <thread>
+#include <chrono>
+#include <iomanip>
+
+SiteSpeedEstimator::SiteSpeedEstimator(SiteList &site_list)
+ : current_site_list_(&site_list)
+{
+}
+
+SiteSpeedEstimator::~SiteSpeedEstimator()
+{
+}
+
+void
+SiteSpeedEstimator::annotate_sitelist(Feedback &feedback)
+{
+ std::vector<std::thread> worker_threads;
+
+ int max_threads = std::thread::hardware_concurrency() * 2;
+
+ progress_counts_.assign(max_threads, 0);
+
+ /* Populate the work queue with indices of all sites not marked 'noshow' */
+ for (size_t i = 0; i < current_site_list_->size(); ++i)
+ if (!(*current_site_list_)[i].noshow)
+ work_queue_.push(i);
+
+ work_count = work_queue_.size();
+
+ auto start_time = std::chrono::high_resolution_clock::now();
+
+ Log (LOG_PLAIN) << "Starting speed measurement for "
+ << work_count << " site(s) with "
+ << max_threads << " concurrent thread(s)" << endLog;
+
+ /* Create worker threads */
+ for (int i = 0; i < max_threads; ++i)
+ worker_threads.emplace_back([this, i]() { worker_thread(i); });
+
+ /* Create progress reporting thread */
+ std::thread progress = std::thread([this, &feedback]() {
progress_thread(feedback); });
+
+ /* Wait for all worker threads to complete */
+ for (auto &thread : worker_threads)
+ {
+ if (thread.joinable())
+ thread.join();
+ }
+
+ /* Wait for progress reporting thread */
+ progress.join();
+
+ /* Calculate elapsed time */
+ auto end_time = std::chrono::high_resolution_clock::now();
+ double elapsed = (std::chrono::duration<double>(end_time -
start_time)).count();
+
+ Log (LOG_PLAIN) << "Speed measurement complete in " << elapsed << " seconds"
<< endLog;
+}
+
+void
+SiteSpeedEstimator::worker_thread(int worker_index)
+{
+ while (true)
+ {
+ size_t site_index;
+
+ /* Get next work item from queue (in a threadsafe manner) */
+ {
+ std::unique_lock<std::mutex> lock(queue_mutex_);
+
+ if (work_queue_.empty())
+ break;
+
+ site_index = work_queue_.front();
+ work_queue_.pop();
+ }
+
+ /* Perform the measurement */
+ double speed = estimate_speed((*current_site_list_)[site_index]);
+ (*current_site_list_)[site_index].speed = speed;
+
+ /* Increment this worker's progress count */
+ progress_counts_[worker_index]++;
+ }
+}
+
+void
+SiteSpeedEstimator::progress_thread(Feedback &feedback)
+{
+ while (true)
+ {
+ /* Count total work consumed by all workers */
+ unsigned int total_progress = 0;
+ for (unsigned int count : progress_counts_)
+ total_progress += count;
+
+ /* Report progress */
+ feedback.phase_progress(total_progress, work_count);
+
+ /* Exit if no work remains... */
+ if (total_progress >= work_count)
+ break;
+
+ /* ... otherwise wait */
+ Sleep(1000);
+ }
+}
+
+/* Maximum time allowed for a single speed test in seconds */
+#define TIMEOUT 5
+
+/* Maximum amount of test file to download (128 KB) */
+#define TEST_FILE_SIZE (1024*128)
+
+double
+SiteSpeedEstimator::estimate_speed(const site_list_type &site)
+{
+ double speed = 0;
+
+ std::string test_url = site.url;
+ if (test_url.empty())
+ return speed;
+
+ test_url += SetupArch();
+ test_url += '/';
+ test_url += SetupBaseName();
+ test_url += ".ini";
+
+ /* Attempt to open connection to URL */
+ NetIO *connection = NetIO::open(test_url.c_str(), false);
+ if (!connection || !connection->ok())
+ return speed;
+
+ auto start_time = std::chrono::high_resolution_clock::now();
+ auto timeout_time = start_time + std::chrono::seconds(TIMEOUT);
+
+ char buffer[4096];
+ size_t total_bytes = 0;
+
+ /* Download data until timeout or test_file_size reached */
+ while (true)
+ {
+ /* Check if we've exceeded the timeout */
+ auto current_time = std::chrono::high_resolution_clock::now();
+ if (current_time >= timeout_time)
+ break;
+
+ int bytes_read = connection->read(buffer, sizeof(buffer));
+ if (bytes_read <= 0)
+ break;
+
+ total_bytes += bytes_read;
+
+ /* Stop if we've downloaded enough data */
+ if (total_bytes >= TEST_FILE_SIZE)
+ break;
+ }
+
+ delete connection;
+
+ /* Calculate elapsed time */
+ auto end_time = std::chrono::high_resolution_clock::now();
+ double elapsed = (std::chrono::duration<double>(end_time -
start_time)).count();
+
+ if (elapsed > 0 && total_bytes > 0)
+ {
+ /* Calculate speed, converting bytes -> bits */
+ speed = (total_bytes * 8.0) / elapsed;
+ }
+
+ return speed;
+}
diff --git a/SiteSpeedEstimator.h b/SiteSpeedEstimator.h
new file mode 100644
index 00000000..cd23635b
--- /dev/null
+++ b/SiteSpeedEstimator.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2026, Cygwin Contributors.
+ *
+ * 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 Jon Turney <[email protected]>
+ *
+ */
+
+#ifndef SETUP_SITE_SPEED_ESTIMATOR_H
+#define SETUP_SITE_SPEED_ESTIMATOR_H
+
+#include "SiteSetting.h"
+#include <mutex>
+#include <queue>
+
+class Feedback;
+
+class SiteSpeedEstimator
+{
+public:
+ SiteSpeedEstimator(SiteList &site_list);
+ ~SiteSpeedEstimator();
+
+ /* Measure speed for each site in the list using a thread pool. */
+ void annotate_sitelist(Feedback &feedback);
+
+private:
+ /* Measure speed for a single site */
+ double estimate_speed(const site_list_type &site);
+
+ /* Worker thread function for the thread pool */
+ void worker_thread(int worker_index);
+
+ /* Progress reporting thread */
+ void progress_thread(Feedback &feedback);
+
+ std::mutex queue_mutex_;
+ std::queue<size_t> work_queue_;
+ size_t work_count;
+ std::vector<unsigned int> progress_counts_;
+ SiteList *current_site_list_;
+};
+
+#endif /* SETUP_SITE_SPEED_ESTIMATOR_H */
diff --git a/cli/CliFeedback.h b/cli/CliFeedback.h
index 1fd72244..1ac5b226 100644
--- a/cli/CliFeedback.h
+++ b/cli/CliFeedback.h
@@ -52,6 +52,14 @@ public:
void hash_init (const char *hashalg, const std::string &url);
void hash_progress (int bytes, int total_bytes);
+ // phase
+public:
+ void phase_init(unsigned int id);
+ void phase_progress(int distance, int total) const;
+
+private:
+ unsigned int prev_id;
+
// owner
public:
HWND owner () { return NULL; }
diff --git a/cli/CliPhaseFeedback.cc b/cli/CliPhaseFeedback.cc
new file mode 100644
index 00000000..07a8bfdd
--- /dev/null
+++ b/cli/CliPhaseFeedback.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2026 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 "cli/CliFeedback.h"
+#include "String++.h"
+#include <iostream>
+
+void
+CliFeedback::phase_init(unsigned int id)
+{
+ if (id != prev_id)
+ {
+ std::wstring s = LoadStringW(id);
+ std::cout << wstring_to_string(s) << std::endl;
+
+ prev_id = id;
+ }
+}
+
+void
+CliFeedback::phase_progress(int distance, int total) const
+{
+ int perc = (int)(100.0 * ((double) distance) / (double)total);
+ printf ("%d %% (%d/%d)", perc, distance, total);
+}
diff --git a/gui/GuiFeedback.h b/gui/GuiFeedback.h
index 0d8294ea..96c78786 100644
--- a/gui/GuiFeedback.h
+++ b/gui/GuiFeedback.h
@@ -59,8 +59,13 @@ public:
void hash_init (const char *hashalg, const std::string &url);
void hash_progress (int bytes, int total_bytes);
+ // phase
public:
+ void phase_init(unsigned int id);
+ void phase_progress(int distance, int total) const;
+
// owner
+public:
HWND owner () { return owner_window; }
private:
diff --git a/gui/GuiPhaseFeedback.cc b/gui/GuiPhaseFeedback.cc
new file mode 100644
index 00000000..6904f585
--- /dev/null
+++ b/gui/GuiPhaseFeedback.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2026 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 "threebar.h"
+
+#include "gui/GuiFeedback.h"
+#include "resource.h"
+
+extern ThreeBarProgressPage Progress;
+
+void
+GuiFeedback::phase_init(unsigned int id)
+{
+ Progress.SetText1 (id);
+ Progress.SetText2 ("");
+ Progress.SetText3 ("");
+ Progress.SetBar1(0);
+ Progress.SetBarLabel1(IDS_PROGRESS_PROGRESS);
+}
+
+void
+GuiFeedback::phase_progress(int distance, int total) const
+{
+ Progress.SetBar1(distance, total);
+}
diff --git a/gui/SitePage.cc b/gui/SitePage.cc
index 725d42b6..11670a05 100644
--- a/gui/SitePage.cc
+++ b/gui/SitePage.cc
@@ -40,6 +40,7 @@
#include "Exception.h"
#include "String++.h"
#include "gui/GuiFeedback.h"
+#include "SiteSpeedEstimator.h"
#define MIRROR_LIST_URL "https://cygwin.com/mirrors.lst"
@@ -86,13 +87,14 @@ SiteList cached_site_list;
SiteList dropped_site_list;
BoolOption OnlySiteOption(false, 'O', "only-site", IDS_HELPTEXT_ONLY_SITE);
+BoolOption AutoSiteOption(false, '\0', "auto-site", IDS_HELPTEXT_AUTO_SITE);
extern BoolOption UnsupportedOption;
static void
save_dialog (HWND h)
{
// Remove anything that was previously in the selected site list.
- site_list.clear ();
+ selected_site_list.clear ();
HWND listbox = GetDlgItem (h, IDC_URL_LIST);
int sel_count = SendMessage (listbox, LB_GETSELCOUNT, 0, 0);
@@ -104,7 +106,7 @@ save_dialog (HWND h)
{
int mirror =
SendMessage (listbox, LB_GETITEMDATA, sel_buffer[n], 0);
- site_list.push_back (all_site_list[mirror]);
+ selected_site_list.push_back (all_site_list[mirror]);
}
}
}
@@ -191,8 +193,8 @@ migrate_selected_site_list()
{
const std::string http = "http://";
- for (SiteList::iterator i = site_list.begin();
- i != site_list.end();
+ for (SiteList::iterator i = selected_site_list.begin();
+ i != selected_site_list.end();
++i)
{
/* If the saved selected site URL starts with "http://", and the same
URL,
@@ -281,8 +283,45 @@ get_site_list (Feedback &feedback)
delete[] theMirrorString;
delete[] theCachedString;
+ // if we don't have a selected site (and do have a mirrors list), do a speed
test
+ if ((selected_site_list.empty() || AutoSiteOption) && !all_site_list.empty())
+ {
+ feedback.phase_init(IDS_PROGRESS_MIRROR_SPEED);
+
+ SiteSpeedEstimator estimator(all_site_list);
+ estimator.annotate_sitelist(feedback);
+
+ // sort all_site_list by descending speed
+ std::sort(all_site_list.begin(), all_site_list.end(),
+ [] (site_list_type const &a, site_list_type const &b) { return
a.speed > b.speed; });
+
+ for (size_t i = 0; i < all_site_list.size(); ++i)
+ if (!all_site_list[i].noshow)
+ Log (LOG_BABBLE) << all_site_list[i].url << " " << std::fixed <<
all_site_list[i].speed << " bps" << endLog;
+
+ // also, in unattended or autosite mode, autoselect the first (fastest)
mirror
+ if (unattended_mode || AutoSiteOption)
+ {
+ // '--autosite' overrides '--site', if we were able to find a site
+ if (AutoSiteOption)
+ selected_site_list.clear();
+
+ Log (LOG_PLAIN) << "Defaulted to " << all_site_list[0].url << " (" <<
std::fixed << all_site_list[0].speed << " bps)" << endLog;
+ selected_site_list.push_back (all_site_list[0]);
+ }
+ }
+ else
+ {
+ // sort all_site_list by 'tld key'
+ std::sort(all_site_list.begin(), all_site_list.end(),
+ [] (site_list_type const &a, site_list_type const &b) { return
a.key < b.key; });
+ }
+
migrate_selected_site_list();
+ // XXX: this never returns true (indicating an error), which is probably good
+ // as the logic below would put us into a loop in unattended mode in that
+ // case.
return 0;
}
@@ -375,8 +414,8 @@ int check_dropped_mirrors (HWND h)
cache_warn_urls = "";
dropped_site_list.clear ();
- for (SiteList::const_iterator n = site_list.begin ();
- n != site_list.end (); ++n)
+ for (SiteList::const_iterator n = selected_site_list.begin ();
+ n != selected_site_list.end (); ++n)
{
SiteList::iterator i = find (all_site_list.begin(), all_site_list.end(),
*n);
@@ -456,8 +495,8 @@ SitePage::OnNext ()
save_cache_file (cache_action);
// Log all the selected URLs from the list.
- for (SiteList::const_iterator n = site_list.begin ();
- n != site_list.end (); ++n)
+ for (SiteList::const_iterator n = selected_site_list.begin ();
+ n != selected_site_list.end (); ++n)
Log (LOG_PLAIN) << "site: " << n->url << endLog;
Progress.SetActivateTask (WM_APP_START_SETUP_INI_DOWNLOAD);
@@ -526,8 +565,8 @@ SitePage::PopulateListBox ()
i != all_site_list.end (); ++i)
{
// If selected, always show
- SiteList::iterator f = find (site_list.begin(), site_list.end(), *i);
- if (f == site_list.end())
+ SiteList::iterator f = find (selected_site_list.begin(),
selected_site_list.end(), *i);
+ if (f == selected_site_list.end())
{
// Otherwise, hide redundant legacy URLs:
if (i->noshow)
@@ -540,7 +579,7 @@ SitePage::PopulateListBox ()
SendMessage (listbox, LB_SETITEMDATA, j, (i - all_site_list.begin()));
// For every selected item, remember the index
- if (f != site_list.end())
+ if (f != selected_site_list.end())
{
sel_indicies.push_back(j);
}
@@ -593,10 +632,10 @@ bool SitePage::OnMessageCmd (int id, HWND hwndctl, UINT
code)
{
all_site_list.push_back (newsite);
Log (LOG_BABBLE) << "Adding site: " << other_url << endLog;
- site_list.push_back (newsite);
+ selected_site_list.push_back (newsite);
}
else
- site_list.push_back (*i);
+ selected_site_list.push_back (*i);
// Update the list box.
PopulateListBox ();
diff --git a/ini.cc b/ini.cc
index 2d9317c9..19085474 100644
--- a/ini.cc
+++ b/ini.cc
@@ -225,8 +225,8 @@ do_remote_ini (Feedback &myFeedback)
explicitly delete these things is ridiculous. */
// iterate over all sites
- for (SiteList::const_iterator n = site_list.begin ();
- n != site_list.end (); ++n)
+ for (SiteList::const_iterator n = selected_site_list.begin ();
+ n != selected_site_list.end (); ++n)
{
IniDBBuilderPackage aBuilder (myFeedback);
bool sig_fail = false;
diff --git a/nio-ie5.cc b/nio-ie5.cc
index f76434bf..c2ee167f 100644
--- a/nio-ie5.cc
+++ b/nio-ie5.cc
@@ -179,7 +179,7 @@ NetIO_IE5::NetIO_IE5 (char const *url, bool cachable)
INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_PASSIVE;
if (!cachable) {
- flags |= INTERNET_FLAG_NO_CACHE_WRITE;
+ flags |= INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD;
} else {
flags |= INTERNET_FLAG_RESYNCHRONIZE;
}
diff --git a/res.pot b/res.pot
index 0c664676..60dfab8b 100644
--- a/res.pot
+++ b/res.pot
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-11-24 15:33+0100\n"
+"POT-Creation-Date: 2026-02-17 17:10+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
@@ -887,6 +887,10 @@ msgstr ""
msgid "Solving dependencies..."
msgstr ""
+#: STRINGTABLE.IDS_PROGRESS_MIRROR_SPEED
+msgid "Measuring mirror speeds..."
+msgstr ""
+
#: STRINGTABLE.IDS_ACTION_DEFAULT
msgid "Default"
msgstr ""
@@ -1182,6 +1186,10 @@ msgstr ""
msgid "Architecture to install (x86_64 or x86)"
msgstr ""
+#: STRINGTABLE.IDS_HELPTEXT_AUTO_SITE
+msgid "Automatically select download site, if possible"
+msgstr ""
+
#: STRINGTABLE.IDS_HELPTEXT_CATEGORIES
msgid "Specify categories to install"
msgstr ""
diff --git a/res/en/res.rc b/res/en/res.rc
index 8f45338a..6a393938 100644
--- a/res/en/res.rc
+++ b/res/en/res.rc
@@ -559,6 +559,7 @@ BEGIN
IDS_PROGRESS_CALCULATING "Calculating..."
IDS_PROGRESS_POSTINSTALL "Running..."
IDS_PROGRESS_SOLVING "Solving dependencies..."
+ IDS_PROGRESS_MIRROR_SPEED "Measuring mirror speeds..."
IDS_ACTION_DEFAULT "Default"
IDS_ACTION_INSTALL "Install"
IDS_ACTION_UNINSTALL "Uninstall"
@@ -655,6 +656,7 @@ BEGIN
IDS_HELPTEXT_ALLOW_TEST "Consider package versions marked test"
IDS_HELPTEXT_ALLOW_UNSUPPORTED_WINDOWS "Allow old, unsupported Windows
versions"
IDS_HELPTEXT_ARCH "Architecture to install (x86_64 or x86)"
+ IDS_HELPTEXT_AUTO_SITE "Automatically select download site, if possible"
IDS_HELPTEXT_CATEGORIES "Specify categories to install"
IDS_HELPTEXT_BUILD_DEPENDS "Specify packages to install the build
requirements of"
IDS_HELPTEXT_COMPACTOS "Compress installed files with Compact OS
(xpress4k, xpress8k, xpress16k, lzx)"
diff --git a/resource.h b/resource.h
index 11fef73c..5e851aea 100644
--- a/resource.h
+++ b/resource.h
@@ -108,6 +108,7 @@
#define IDS_VIEW_UNNEEDED 1212
#define IDS_UNSUPPORTED_WINDOWS_ARCH 1213
#define IDS_USER_URL_TOOLTIP 1214
+#define IDS_PROGRESS_MIRROR_SPEED 1215
#define IDS_HELPTEXT_COMPACTOS 1500
#define IDS_HELPTEXT_PUBKEY 1501
@@ -159,6 +160,7 @@
#define IDS_HELPTEXT_FOOTER 1547
#define IDS_HELPTEXT_NO_WRITE_REGISTRY 1548
#define IDS_HELPTEXT_BUILD_DEPENDS 1549
+#define IDS_HELPTEXT_AUTO_SITE 1550
// Dialogs
[setup - the official Cygwin setup program] branch master, updated. release_2.938
Jon Turney via Cygwin-apps-cvs Thu, 02 Apr 2026 07:17:08 -0700
