chiark / gitweb /
keys.scala, etc.: Make merging public keys have a progress bar. master
authorMark Wooding <mdw@distorted.org.uk>
Fri, 29 Jun 2018 09:55:47 +0000 (10:55 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 29 Jun 2018 09:55:47 +0000 (10:55 +0100)
And some other light fixing.

Makefile
keys.scala
progress.scala
terminal.scala

index 35467a877b689832c391beb27ca111f8ee68cebe..d077faf01bf75fc7858705460b7639adb3def07e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -586,7 +586,7 @@ realclean::; rm -f $(REALCLEANFILES)
 
 repl: $(CLASSSTAMPS) $(foreach a,$(APKLIBS),$(JNIDIR.host-$(hostcpu))/$a)
        $(SCALA) -cp $(CLASSDIR) -Yno-load-impl-class \
-               -Djava.lib.path=$(JNIDIR.host-$(hostcpu)) \
+               -Djava.library.path=$(JNIDIR.host-$(hostcpu)) \
 
 t:; : $(show)
 .PHONY: t
index 9108b38aca701f2bb28ecb356f2b07e494f3d616..544462e05244dce67b92ad82984f429ad4ae05d8 100644 (file)
@@ -27,7 +27,7 @@ package uk.org.distorted.tripe; package object keys {
 
 /*----- Imports -----------------------------------------------------------*/
 
-import scala.collection.mutable.HashMap;
+import scala.collection.mutable.{ArrayBuffer, HashMap};
 
 import java.io.{Closeable, File, IOException};
 import java.lang.{Long => JLong};
@@ -41,7 +41,8 @@ import sys.Errno.EEXIST;
 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 ----------------------------------------*/
 
@@ -275,6 +276,7 @@ def checkConfigSanity(file: File, ic: Eyecandy) {
 }
 
 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");
@@ -318,7 +320,7 @@ class PrivateKey private[keys](repo: Repository, dir: File) {
      * 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;
   }
@@ -595,16 +597,33 @@ class Repository(val root: File) extends Closeable {
     /* 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_!();
     }
 
index 308b535636b795b3587726baabc1e9ad306a15df..5f81615ff9a04cc23526315ee9ff32b64d7c90e9 100644 (file)
@@ -64,6 +64,16 @@ trait Model {
 
 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 {
@@ -90,8 +100,7 @@ trait OperationReporter extends BaseReporter {
   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();
index 7ca56d3fcbae93def7ffa42faad6317b1ba0843d..2e66aa288dca70c099eb0ba0e73c73baea72f501 100644 (file)
@@ -32,6 +32,7 @@ import java.lang.Math.ceil;
 import java.lang.System.{currentTimeMillis, out => stdout};
 
 import sys.isatty;
+import Implicits.truish;
 
 /*----- Main code ---------------------------------------------------------*/
 
@@ -78,7 +79,7 @@ object TerminalEyecandy extends Eyecandy {
   def clear() { note(""); }
 
   def commit() {
-    if (last != "") {
+    if (last) {
       if (eyecandyp) stdout.write('\n');
       else stdout.println(last);
       last = "";
@@ -98,7 +99,7 @@ object TerminalEyecandy extends Eyecandy {
          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;
@@ -114,7 +115,7 @@ object TerminalEyecandy extends Eyecandy {
 
       val max = model.max;
       val sb = new StringBuilder;
-      sb ++= model.what; sb += ' ';
+      sb ++= model.what; sb += ':'; sb += ' ';
 
       /* Step the spinner. */
       sb += spinner(step); sb += ' ';
@@ -140,7 +141,7 @@ object TerminalEyecandy extends Eyecandy {
       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. */
@@ -157,11 +158,11 @@ object TerminalEyecandy extends Eyecandy {
 
     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);
   }