nix copy: Revive progress bar
This commit is contained in:
parent
dffc3fe43b
commit
c5e4404580
6 changed files with 99 additions and 2 deletions
|
@ -135,7 +135,6 @@ struct LegacySSHStore : public Store
|
||||||
|
|
||||||
if (readInt(conn->from) != 1)
|
if (readInt(conn->from) != 1)
|
||||||
throw Error("failed to add path '%s' to remote host '%s', info.path, host");
|
throw Error("failed to add path '%s' to remote host '%s', info.path, host");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void narFromPath(const Path & path, Sink & sink) override
|
void narFromPath(const Path & path, Sink & sink) override
|
||||||
|
|
|
@ -565,8 +565,12 @@ void Store::buildPaths(const PathSet & paths, BuildMode buildMode)
|
||||||
void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
|
void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
|
||||||
const Path & storePath, RepairFlag repair, CheckSigsFlag checkSigs)
|
const Path & storePath, RepairFlag repair, CheckSigsFlag checkSigs)
|
||||||
{
|
{
|
||||||
|
Activity act(actCopyPath, fmt("copying path '%s'", storePath));
|
||||||
|
|
||||||
auto info = srcStore->queryPathInfo(storePath);
|
auto info = srcStore->queryPathInfo(storePath);
|
||||||
|
|
||||||
|
//act->progress(0, info->size());
|
||||||
|
|
||||||
StringSink sink;
|
StringSink sink;
|
||||||
srcStore->narFromPath({storePath}, sink);
|
srcStore->narFromPath({storePath}, sink);
|
||||||
|
|
||||||
|
@ -600,13 +604,28 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
|
||||||
for (auto & path : storePaths)
|
for (auto & path : storePaths)
|
||||||
if (!valid.count(path)) missing.insert(path);
|
if (!valid.count(path)) missing.insert(path);
|
||||||
|
|
||||||
|
Activity act;
|
||||||
|
|
||||||
|
logger->event(evCopyStarted, act);
|
||||||
|
|
||||||
|
std::atomic<size_t> nrCopied{0};
|
||||||
|
std::atomic<size_t> nrDone{storePaths.size() - missing.size()};
|
||||||
|
|
||||||
|
auto showProgress = [&]() {
|
||||||
|
logger->event(evCopyProgress, act, storePaths.size(), nrCopied, nrDone);
|
||||||
|
};
|
||||||
|
|
||||||
ThreadPool pool;
|
ThreadPool pool;
|
||||||
|
|
||||||
processGraph<Path>(pool,
|
processGraph<Path>(pool,
|
||||||
PathSet(missing.begin(), missing.end()),
|
PathSet(missing.begin(), missing.end()),
|
||||||
|
|
||||||
[&](const Path & storePath) {
|
[&](const Path & storePath) {
|
||||||
if (dstStore->isValidPath(storePath)) return PathSet();
|
if (dstStore->isValidPath(storePath)) {
|
||||||
|
nrDone++;
|
||||||
|
showProgress();
|
||||||
|
return PathSet();
|
||||||
|
}
|
||||||
return srcStore->queryPathInfo(storePath)->references;
|
return srcStore->queryPathInfo(storePath)->references;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -616,7 +635,12 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
|
||||||
if (!dstStore->isValidPath(storePath)) {
|
if (!dstStore->isValidPath(storePath)) {
|
||||||
printInfo("copying '%s'...", storePath);
|
printInfo("copying '%s'...", storePath);
|
||||||
copyStorePath(srcStore, dstStore, storePath, repair, checkSigs);
|
copyStorePath(srcStore, dstStore, storePath, repair, checkSigs);
|
||||||
|
nrCopied++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nrDone++;
|
||||||
|
|
||||||
|
showProgress();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ static void dumpContents(const Path & path, size_t size,
|
||||||
|
|
||||||
static void dump(const Path & path, Sink & sink, PathFilter & filter)
|
static void dump(const Path & path, Sink & sink, PathFilter & filter)
|
||||||
{
|
{
|
||||||
|
checkInterrupt();
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(path.c_str(), &st))
|
if (lstat(path.c_str(), &st))
|
||||||
throw SysError(format("getting attributes of path '%1%'") % path);
|
throw SysError(format("getting attributes of path '%1%'") % path);
|
||||||
|
|
|
@ -80,4 +80,15 @@ std::atomic<uint64_t> nextId{(uint64_t) getpid() << 32};
|
||||||
|
|
||||||
Activity::Activity() : id(nextId++) { };
|
Activity::Activity() : id(nextId++) { };
|
||||||
|
|
||||||
|
Activity::Activity(ActivityType type, std::string msg)
|
||||||
|
: Activity()
|
||||||
|
{
|
||||||
|
logger->event(evStartActivity, id, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Activity::~Activity()
|
||||||
|
{
|
||||||
|
logger->event(evStopActivity, id);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,10 @@ typedef enum {
|
||||||
lvlVomit
|
lvlVomit
|
||||||
} Verbosity;
|
} Verbosity;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
actCopyPath = 100,
|
||||||
|
} ActivityType;
|
||||||
|
|
||||||
class Activity
|
class Activity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -21,6 +25,10 @@ public:
|
||||||
Activity();
|
Activity();
|
||||||
Activity(const Activity & act) : id(act.id) { };
|
Activity(const Activity & act) : id(act.id) { };
|
||||||
Activity(uint64_t id) : id(id) { };
|
Activity(uint64_t id) : id(id) { };
|
||||||
|
Activity(ActivityType type, std::string msg = "");
|
||||||
|
~Activity();
|
||||||
|
|
||||||
|
//void progress(...);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -35,6 +43,13 @@ typedef enum {
|
||||||
evSubstitutionCreated = 8,
|
evSubstitutionCreated = 8,
|
||||||
evSubstitutionStarted = 9,
|
evSubstitutionStarted = 9,
|
||||||
evSubstitutionFinished = 10,
|
evSubstitutionFinished = 10,
|
||||||
|
|
||||||
|
evCopyStarted = 100,
|
||||||
|
evCopyProgress = 101,
|
||||||
|
|
||||||
|
evStartActivity = 1000,
|
||||||
|
evStopActivity = 1001,
|
||||||
|
|
||||||
} EventType;
|
} EventType;
|
||||||
|
|
||||||
struct Event
|
struct Event
|
||||||
|
|
|
@ -27,17 +27,29 @@ private:
|
||||||
DownloadInfo(const std::string & uri) : uri(uri) { }
|
DownloadInfo(const std::string & uri) : uri(uri) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CopyInfo
|
||||||
|
{
|
||||||
|
uint64_t expected = 0;
|
||||||
|
uint64_t copied = 0;
|
||||||
|
uint64_t done = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
std::map<Activity::t, Path> builds;
|
std::map<Activity::t, Path> builds;
|
||||||
std::set<Activity::t> runningBuilds;
|
std::set<Activity::t> runningBuilds;
|
||||||
uint64_t succeededBuilds = 0;
|
uint64_t succeededBuilds = 0;
|
||||||
uint64_t failedBuilds = 0;
|
uint64_t failedBuilds = 0;
|
||||||
|
|
||||||
std::map<Activity::t, Path> substitutions;
|
std::map<Activity::t, Path> substitutions;
|
||||||
std::set<Activity::t> runningSubstitutions;
|
std::set<Activity::t> runningSubstitutions;
|
||||||
uint64_t succeededSubstitutions = 0;
|
uint64_t succeededSubstitutions = 0;
|
||||||
|
|
||||||
uint64_t downloadedBytes = 0; // finished downloads
|
uint64_t downloadedBytes = 0; // finished downloads
|
||||||
std::map<Activity::t, DownloadInfo> downloads;
|
std::map<Activity::t, DownloadInfo> downloads;
|
||||||
|
|
||||||
|
std::map<Activity::t, CopyInfo> runningCopies;
|
||||||
|
|
||||||
std::list<ActInfo> activities;
|
std::list<ActInfo> activities;
|
||||||
std::map<Activity::t, std::list<ActInfo>::iterator> its;
|
std::map<Activity::t, std::list<ActInfo>::iterator> its;
|
||||||
};
|
};
|
||||||
|
@ -167,11 +179,35 @@ public:
|
||||||
res += fmt("%1$.0f/%2$.0f KiB", current / 1024.0, expected / 1024.0);
|
res += fmt("%1$.0f/%2$.0f KiB", current / 1024.0, expected / 1024.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!state.runningCopies.empty()) {
|
||||||
|
if (!res.empty()) res += ", ";
|
||||||
|
uint64_t copied = 0, expected = 0;
|
||||||
|
for (auto & i : state.runningCopies) {
|
||||||
|
copied += i.second.copied;
|
||||||
|
expected += i.second.expected - (i.second.done - i.second.copied);
|
||||||
|
}
|
||||||
|
res += fmt("%d/%d copied", copied, expected);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void event(const Event & ev) override
|
void event(const Event & ev) override
|
||||||
{
|
{
|
||||||
|
if (ev.type == evStartActivity) {
|
||||||
|
auto state(state_.lock());
|
||||||
|
Activity::t act = ev.getI(0);
|
||||||
|
createActivity(*state, act, ev.getS(1));
|
||||||
|
update(*state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev.type == evStopActivity) {
|
||||||
|
auto state(state_.lock());
|
||||||
|
Activity::t act = ev.getI(0);
|
||||||
|
deleteActivity(*state, act);
|
||||||
|
update(*state);
|
||||||
|
}
|
||||||
|
|
||||||
if (ev.type == evBuildCreated) {
|
if (ev.type == evBuildCreated) {
|
||||||
auto state(state_.lock());
|
auto state(state_.lock());
|
||||||
state->builds[ev.getI(0)] = ev.getS(1);
|
state->builds[ev.getI(0)] = ev.getS(1);
|
||||||
|
@ -280,6 +316,16 @@ public:
|
||||||
update(*state);
|
update(*state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ev.type == evCopyProgress) {
|
||||||
|
auto state(state_.lock());
|
||||||
|
Activity::t act = ev.getI(0);
|
||||||
|
auto & i = state->runningCopies[act];
|
||||||
|
i.expected = ev.getI(1);
|
||||||
|
i.copied = ev.getI(2);
|
||||||
|
i.done = ev.getI(3);
|
||||||
|
update(*state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue