/*----- Imports -----------------------------------------------------------*/
-import scala.collection.mutable.HashMap;
+import scala.collection.mutable.{ArrayBuffer, HashMap};
import java.io.{Closeable, File, IOException};
import java.lang.{Long => JLong};
import sys.FileImplicits._;
import sys.FileInfo.{DIR, REG};
-import progress.{Eyecandy, SimpleModel, DataModel};
+import progress.{Eyecandy, SimpleModel, DataModel, DetailedModel};
+import Implicits.truish;
/*----- Useful regular expressions ----------------------------------------*/
}
private val keydatefmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
+
class PrivateKey private[keys](repo: Repository, dir: File) {
private[this] lazy val keyring = dir/"keyring";
private[this] lazy val meta = parseConfig(dir/"meta");
* because Java doesn't have proper unsigned integers. There's
* `parseUnsignedInt' in Java 1.8, but that limits our Android targets.
* And Scala has put its own `Long' object in the way of Java's so we
- * need this circumolution.
+ * need this circumlocution.
*/
(JLong.parseLong(info("keyid"), 16)&0xffffffff).toInt;
}
/* Confirm that the configuration in the new archive is sane. */
checkConfigSanity(unpkdir/"tripe-keys.conf", ic);
- /* Build the public keyring. (Observe the quadratic performance.) */
- ic.operation("collecting public keys") { or =>
+ /* Build the public keyring. */
+ ic.job(new SimpleModel("counting public keys", -1)) { jr =>
+
+ /* Delete the accumulated keyring. */
val pubkeys = unpkdir/"keyring.pub";
pubkeys.remove_!();
- reposdir foreachFile { file => file.getName match {
- case RX_PUBKEY(peer) if file.isreg_! =>
- or.step(peer);
- runCommand("key", "-k", pubkeys.getPath, "merge", file.getPath);
+
+ /* Figure out which files we need to hack. */
+ var kv = ArrayBuffer[File]();
+ reposdir.foreachFile { file => file.getName match {
+ case RX_PUBKEY(peer) if file.isreg_! => kv += file;
case _ => ok;
} }
+ kv = kv.sorted;
+ val m = new DetailedModel("collecting public keys", kv.length);
+ var i: Long = 0;
+
+ /* Work through the key files. */
+ for (k <- kv) {
+ m.detail = k.getName;
+ if (!i) jr.change(m, i);
+ else jr.step(i);
+ runCommand("key", "-k", pubkeys.getPath, "merge", k.getPath);
+ i += 1;
+ }
+
+ /* Clean up finally. */
(unpkdir/"keyring.pub.old").remove_!();
}
class SimpleModel(val what: String, val max: Long) extends Model;
+class DetailedModel(what: String, max: Long) extends SimpleModel(what, max) {
+ var detail: String = null;
+ override def format(cur: Long): String = {
+ val sb = new StringBuilder;
+ sb ++= super.format(cur);
+ if (detail != null) { sb += ' '; sb ++= detail; }
+ sb.result
+ }
+}
+
private val UDATA = Seq("kB", "MB", "GB", "TB", "PB", "EB");
trait DataModel extends Model {
def step(detail: String);
}
-def withReporter[T, P <: BaseReporter]
- (rep: P, body: P => T): T = {
+def withReporter[T, P <: BaseReporter](rep: P, body: P => T): T = {
val ret = try { body(rep) }
catch { case e: Exception => rep.failed(e); throw e; }
rep.done();
import java.lang.System.{currentTimeMillis, out => stdout};
import sys.isatty;
+import Implicits.truish;
/*----- Main code ---------------------------------------------------------*/
def clear() { note(""); }
def commit() {
- if (last != "") {
+ if (last) {
if (eyecandyp) stdout.write('\n');
else stdout.println(last);
last = "";
extends progress.JobReporter {
private final val width = 40;
private final val spinner = """/-\|""";
- private final val mingap = 100;
+ private final val mingap = 50;
private[this] var step: Int = 0;
private[this] var sweep: Int = 0;
private[this] val t0 = currentTimeMillis;
val max = model.max;
val sb = new StringBuilder;
- sb ++= model.what; sb += ' ';
+ sb ++= model.what; sb += ':'; sb += ' ';
/* Step the spinner. */
sb += spinner(step); sb += ' ';
sb += ']';
/* Quantitative progress. */
- val f = model.format(cur); if (f != "") { sb += ' '; sb ++= f; }
+ val f = model.format(cur); if (f) { sb += ' '; sb ++= f; }
if (max > 0) sb ++= (100*cur/max).formatted(" %3d%%");
/* Estimated time to completion. */
def done() {
val t = formatDuration(ceil((currentTimeMillis - t0)/1000.0).toInt);
- record(s"${model.what} done ($t)");
+ record(s"${model.what}: done ($t)");
}
def failed(e: Exception)
- { record(s"${model.what} FAILED: ${e.getMessage}"); }
+ { record(s"${model.what}: FAILED: ${e.getMessage}"); }
step(0);
}