From b1ec59e386adfa583cdbd5eb3c7536d15bbe8394 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Fri, 29 Jun 2018 10:55:47 +0100 Subject: [PATCH] keys.scala, etc.: Make merging public keys have a progress bar. And some other light fixing. --- Makefile | 2 +- keys.scala | 37 ++++++++++++++++++++++++++++--------- progress.scala | 13 +++++++++++-- terminal.scala | 13 +++++++------ 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 35467a8..d077faf 100644 --- 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 diff --git a/keys.scala b/keys.scala index 9108b38..544462e 100644 --- a/keys.scala +++ b/keys.scala @@ -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_!(); } diff --git a/progress.scala b/progress.scala index 308b535..5f81615 100644 --- a/progress.scala +++ b/progress.scala @@ -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(); diff --git a/terminal.scala b/terminal.scala index 7ca56d3..2e66aa2 100644 --- a/terminal.scala +++ b/terminal.scala @@ -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); } -- 2.11.0