X-Git-Url: https://git.distorted.org.uk/~mdw/tripe-android/blobdiff_plain/a5ec891a1f3cbe4ae9aad5d2252f39b483ed543e..HEAD:/keys.scala?ds=sidebyside diff --git a/keys.scala b/keys.scala index b9595ec..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 ----------------------------------------*/ @@ -120,10 +121,10 @@ private val DEFAULTS: Seq[(String, Config => String)] = "sig-fresh" -> { _ => "always" }, "fingerprint-hash" -> { _("hash") }); -private def parseConfig(file: File): Config = { +private def parseConfig(file: File): HashMap[String, String] = { /* Build the new configuration in a temporary place. */ - var m = HashMap[String, String](); + val m = HashMap[String, String](); /* Read the config file into our map. */ file.withReader { in => @@ -131,7 +132,7 @@ private def parseConfig(file: File): Config = { for (line <- lines(in)) { line match { case RX_COMMENT() => ok; - case RX_KEYVAL(key, value) => m += key -> value; + case RX_KEYVAL(key, value) => m(key) = value; case _ => throw new ConfigSyntaxError(file.getPath, lno, "failed to parse line"); @@ -150,7 +151,7 @@ private def readConfig(file: File): Config = { /* Fill in defaults where things have been missed out. */ for ((key, dflt) <- DEFAULTS) { if (!(m contains key)) { - try { m += key -> dflt(m); } + try { m(key) = dflt(m); } catch { case e: DefaultFailed => throw new ConfigDefaultFailed(file.getPath, key, @@ -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_!(); }