diff options
author | Norbert Preining <preining@logic.at> | 2017-10-12 05:19:26 +0000 |
---|---|---|
committer | Norbert Preining <preining@logic.at> | 2017-10-12 05:19:26 +0000 |
commit | fa79130908eed3e87903a6b9ecc2f2c7dd014c83 (patch) | |
tree | 2cdc93ed4c6419fe3b1c3cf4e56a793d0f851376 /Master | |
parent | 8fa36ac3a44c9645b949dabd122622dc121b1359 (diff) |
tlcockpit v0.6
git-svn-id: svn://tug.org/texlive/trunk@45526 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r-- | Master/texmf-dist/doc/support/tlcockpit/NEWS | 5 | ||||
-rw-r--r-- | Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar | bin | 11688515 -> 11704983 bytes | |||
-rw-r--r-- | Master/texmf-dist/source/support/tlcockpit/build.sbt | 2 | ||||
-rw-r--r-- | Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala | 225 | ||||
-rw-r--r-- | Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala | 13 |
5 files changed, 171 insertions, 74 deletions
diff --git a/Master/texmf-dist/doc/support/tlcockpit/NEWS b/Master/texmf-dist/doc/support/tlcockpit/NEWS index c1dca4d41ad..d8c84e675e8 100644 --- a/Master/texmf-dist/doc/support/tlcockpit/NEWS +++ b/Master/texmf-dist/doc/support/tlcockpit/NEWS @@ -1,5 +1,10 @@ NEWS for tlcockpit +version 0.6 +----------- +- texlive infra updates handled properly (restarting tlmgr) +- scrollable list of files in pkg info window + version 0.5 ----------- - better pkg info display diff --git a/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar b/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar Binary files differindex ac6b87c2777..0a57df3631f 100644 --- a/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar +++ b/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar diff --git a/Master/texmf-dist/source/support/tlcockpit/build.sbt b/Master/texmf-dist/source/support/tlcockpit/build.sbt index a054c933ca8..fb5cf2f98d3 100644 --- a/Master/texmf-dist/source/support/tlcockpit/build.sbt +++ b/Master/texmf-dist/source/support/tlcockpit/build.sbt @@ -1,6 +1,6 @@ name := "tlcockpit" -version := "0.5" +version := "0.6" scalaVersion := "2.12.3" diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala index d7b7162107e..696744bbeb1 100644 --- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala +++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala @@ -21,7 +21,7 @@ import scala.concurrent.ExecutionContext.Implicits.global // import scala.reflect.io.File import scala.util.{Failure, Success} import scalafx.beans.property.ObjectProperty -import scalafx.geometry.{HPos, Pos, VPos} +import scalafx.geometry.{HPos, Pos, VPos, Orientation} import scalafx.scene.Cursor import scalafx.scene.control.Alert.AlertType import scalafx.scene.image.{Image, ImageView} @@ -32,6 +32,7 @@ import scalafx.scene.control.TableColumn._ import scalafx.scene.control.TreeTableColumn._ import scalafx.scene.control.TreeItem import scalafx.scene.control.Menu._ +import scalafx.scene.control.ListCell import scalafx.scene.control.cell._ import scalafx.scene.text.Text import scalafx.Includes._ @@ -48,11 +49,10 @@ import scalafx.collections.ObservableMap // import java.awt.Desktop +// TODO when installing a collection list the additionally installed packages, too +// TODO idea pkg tree with collection -> packages +// TODO pkg info listview adjust height according to font size and # of items // TODO TreeTableView indentation is lazy -// TODO pkg info - allow opening (maybe preview) of doc files -// use WebView and pdf.js: https://stackoverflow.com/questions/18207116/displaying-pdf-in-javafx -// see https://github.com/scalafx/scalafx-ensemble/blob/master/src/main/scala/scalafx/ensemble/example/web/EnsembleWebView.scala -// TODO better layout of pkg info object ApplicationMain extends JFXApp { @@ -128,24 +128,6 @@ object ApplicationMain extends JFXApp { (ae: KeyEvent) => if (ae.code == KeyCode.Enter) callback_run_cmdline() } val outputLine = new SyncVar[String] - val tlmgr = new TlmgrProcess( - // (s:String) => outputfield.text = s, - (s: Array[String]) => { - // we don't wont normal output to be displayed - // as it is anyway returned - // outputText.clear() - // outputText.appendAll(s) - }, - (s: String) => { - // errorText.clear() - errorText.append(s) - if (s.trim != "") { - outerrpane.expanded = true - outerrtabs.selectionModel().select(1) - } - }, - (s: String) => outputLine.put(s) - ) def tlmgr_async_command(s: String, f: Array[String] => Unit): Unit = { errorText.clear() @@ -307,11 +289,22 @@ object ApplicationMain extends JFXApp { } } } - tlmgr_async_command(s"update $s", _ => { - Platform.runLater { lineUpdateFunc = { (s: String) => } } + // val cmd = if (s == "--self") "update --self --no-restart" else s"update $s" + val cmd = if (s == "--self") "update --self" else s"update $s" + tlmgr_async_command(cmd, _ => { + Platform.runLater { + lineUpdateFunc = { (s: String) => } + if (s == "--self") { + reinitialize_tlmgr() + // this doesn't work seemingly + // update_upds_list() + } + } }) } + + def do_one_pkg(what: String, pkg: String): Unit = { tlmgr_async_command(s"$what $pkg", _ => { Platform.runLater { update_pkgs_lists() } }) } @@ -388,7 +381,9 @@ object ApplicationMain extends JFXApp { } // for ismixed we && all the installed status. If all are installed, we get true val allinstalled = (kids :+ p).foldRight[Boolean](true)((k, b) => k.installed.value == "Installed" && b) - if (!allinstalled) { + val someinstalled = (kids :+ p).exists(_.installed.value == "Installed") + val mixedinstalled = !allinstalled && someinstalled + if (mixedinstalled) { // replace installed status with "Mixed" new TreeItem[TLPackage](new TreeItem[TLPackage]( new TLPackage(p.name.value, p.lrev.value.toString, p.rrev.value.toString, p.shortdesc.value, p.size.value.toString, "Mixed") @@ -418,7 +413,8 @@ object ApplicationMain extends JFXApp { } if (doit) { val infraAvailable = upds.keys.exists(_.startsWith("texlive.infra")) - val updatesAvailable = upds.keys.exists(p => !p.startsWith("texlive.infra")) + // only allow for updates of other packages when no infra update available + val updatesAvailable = !infraAvailable && upds.keys.exists(p => !p.startsWith("texlive.infra") && !(p == "root")) val newroot = new TreeItem[TLUpdate](new TLUpdate("root", "", "", "", "", "")) { children = upds .filter(_._1 != "root") @@ -430,10 +426,22 @@ object ApplicationMain extends JFXApp { update_self_menu.disable = !infraAvailable update_all_menu.disable = !updatesAvailable updateTable.root = newroot + if (infraAvailable) { + texlive_infra_update_warning() + } } } }) + def texlive_infra_update_warning(): Unit = { + new Alert(AlertType.Warning) { + initOwner(stage) + title = "TeX Live Infrastructure Update Available" + headerText = "Updates to the TeX Live Manager (Infrastructure) available." + contentText = "Please use \"Update self\" from the Menu!" + }.showAndWait() + } + def update_bkps_list(): Unit = { tlmgr_async_command("restore", lines => { // lines.drop(1).foreach(println(_)) @@ -511,8 +519,13 @@ object ApplicationMain extends JFXApp { val foo = parse_one_update_line(l) (foo.name.value, foo) }.toMap + val infraAvailable = newupds.keys.exists(_.startsWith("texlive.infra")) upds.clear() - upds ++= newupds + if (infraAvailable) { + upds ++= Seq( ("texlive.infra", newupds("texlive.infra") ) ) + } else { + upds ++= newupds + } trigger_update("upds") }) } @@ -527,6 +540,47 @@ object ApplicationMain extends JFXApp { bkps("root") = Map[String,TLBackup](("0", new TLBackup("root","0","0"))) } + def doListView(files: Seq[String], clickable: Boolean): scalafx.scene.Node = { + if (files.length <= 5) { + val vb = new VBox() + vb.children = files.map { f => + val fields = f.split(" ") + new Label(fields(0)) { + if (clickable) { + textFill = Color.Blue + onMouseClicked = { me: MouseEvent => OsTools.openFile(tlmgr.tlroot + "/" + fields(0)) } + cursor = Cursor.Hand + } + } + } + vb + } else { + val vb = new ListView[String] {} + vb.minHeight = 150 + vb.prefHeight = 150 + vb.maxHeight = 200 + vb.vgrow = Priority.Always + // TODO tighter spacing for ListView + vb.orientation = Orientation.Vertical + vb.cellFactory = { p => { + val foo = new ListCell[String] + foo.item.onChange { (_, _, str) => foo.text = str } + if (clickable) { + foo.textFill = Color.Blue + foo.onMouseClicked = { me: MouseEvent => OsTools.openFile(tlmgr.tlroot + "/" + foo.text.value) } + foo.cursor = Cursor.Hand + } + foo + } + } + // vb.children = docFiles.map { f => + vb.items = ObservableBuffer(files.map { f => + val fields = f.split(" ") + fields(0) + }) + vb + } + } def callback_show_pkg_info(pkg: String): Unit = { tlmgr_async_command(s"info --list $pkg", pkginfo => { @@ -539,6 +593,7 @@ object ApplicationMain extends JFXApp { resizable = true } dialog.dialogPane().buttonTypes = Seq(ButtonType.OK) + val isInstalled = pkgs(pkg).installed.value == "Installed" val grid = new GridPane() { hgap = 10 vgap = 10 @@ -569,6 +624,7 @@ object ApplicationMain extends JFXApp { "unknown" if (keyval.length == 2) { if (keyval(0) == "doc files" || keyval(0) == "source files" || keyval(0) == "run files" || + keyval(0).startsWith("depending package ") || keyval(0).startsWith("bin files (all platforms)") || keyval(0).startsWith("Included files, by type")) { // do nothing } else { @@ -583,47 +639,34 @@ object ApplicationMain extends JFXApp { } }) // add files section - if (runFiles.nonEmpty) { - grid.add(new Label("run files"), 0, crow) - grid.add(new Label(runFiles.mkString("\n")) { wrapText = true },1, crow) - crow += 1 - } if (docFiles.nonEmpty) { grid.add(new Label("doc files"), 0, crow) - val vb = new VBox() - vb.children = docFiles.map { f => - val fields = f.split(" ") - new Label(fields(0)) { - textFill = Color.Blue - onMouseClicked = { me: MouseEvent => - println("Do something with " + fields(0)) - // TODO while does gio return immediately on bash prompt but not here? - // ("gio open " + tlmgr.tlroot + "/" + fields(0)).! - //Desktop.getDesktop().open((tlmgr.tlroot + "/" + fields(0))) - OsTools.openFile(tlmgr.tlroot + "/" + fields(0)) - println("done") - } - cursor = Cursor.Hand - } - } //grid.add(new Label(docFiles.mkString("\n")) { wrapText = true },1, crow) - grid.add(vb,1,crow) + grid.add(doListView(docFiles.map(s => s.replaceFirst("RELOC","texmf-dist")),isInstalled),1,crow) + crow += 1 + } + if (runFiles.nonEmpty) { + grid.add(new Label("run files"), 0, crow) + // grid.add(new Label(runFiles.mkString("\n")) { wrapText = true },1, crow) + grid.add(doListView(runFiles.map(s => s.replaceFirst("RELOC","texmf-dist")),false),1,crow) crow += 1 } if (srcFiles.nonEmpty) { grid.add(new Label("src files"), 0, crow) - grid.add(new Label(srcFiles.mkString("\n")) { wrapText = true },1, crow) + // grid.add(new Label(srcFiles.mkString("\n")) { wrapText = true },1, crow) + grid.add(doListView(srcFiles.map(s => s.replaceFirst("RELOC","texmf-dist")),false),1,crow) crow += 1 } if (binFiles.nonEmpty) { grid.add(new Label("bin files"), 0, crow) - grid.add(new Label(binFiles.mkString("\n")) { wrapText = true },1, crow) + // grid.add(new Label(binFiles.mkString("\n")) { wrapText = true },1, crow) + grid.add(doListView(binFiles.map(s => s.replaceFirst("RELOC","texmf-dist")),false),1,crow) crow += 1 } - grid.columnConstraints = Seq(new ColumnConstraints(100, 150, 200), new ColumnConstraints(100, 300, 5000, Priority.Always, new HPos(HPos.Left), true)) + grid.columnConstraints = Seq(new ColumnConstraints(100, 200, 200), new ColumnConstraints(100, 400, 5000, Priority.Always, new HPos(HPos.Left), true)) dialog.dialogPane().content = grid - // dialog.width = 500 - // dialog.height = 800 + dialog.width = 600 + dialog.height = 1500 dialog.showAndWait() } }) @@ -1040,6 +1083,61 @@ object ApplicationMain extends JFXApp { icons.add(iconImage) } + + + def initialize_tlmgr(): TlmgrProcess = { + val tt = new TlmgrProcess( + // (s:String) => outputfield.text = s, + (s: Array[String]) => { + // we don't wont normal output to be displayed + // as it is anyway returned + // outputText.clear() + // outputText.appendAll(s) + }, + (s: String) => { + // errorText.clear() + errorText.append(s) + if (s.trim != "") { + outerrpane.expanded = true + outerrtabs.selectionModel().select(1) + } + }, + (s: String) => outputLine.put(s) + ) + val bar = Future { + while (true) { + val s = outputLine.take + lineUpdateFunc(s) + } + } + bar.onComplete { + case Success(value) => println(s"Got the callback, meaning = $value") + case Failure(e) => + println("lineUpdateFunc thread got interrupted -- probably old tlmgr, ignoring it!") + //e.printStackTrace + } + tt + } + + def reinitialize_tlmgr(): Unit = { + tlmgr.cleanup() + // Thread.sleep(1000) + tlmgr = initialize_tlmgr() + tlmgr_post_init() + pkgstabs.getSelectionModel().select(0) + } + + def tlmgr_post_init():Unit = { + tlmgr.start_process() + tlmgr.get_output_till_prompt() + // update_pkg_lists_to_be_renamed() // this is async done + pkgs.clear() + upds.clear() + bkps.clear() + update_pkgs_lists() + } + + /* TODO implement splash screen - see example in ProScalaFX val startalert = new Alert(AlertType.Information) startalert.setTitle("Loading package database ...") @@ -1058,21 +1156,8 @@ object ApplicationMain extends JFXApp { */ var lineUpdateFunc: String => Unit = { (l: String) => } // println(s"DEBUG: got ==$l== from tlmgr") } - - val bar = Future { - while (true) { - val s = outputLine.take - try { - lineUpdateFunc(s) - } catch { - case e: Exception => println("SOMETHING BAD IN lineUpdateFUnc happened: " + e + "\n") - } - } - } - tlmgr.start_process() - tlmgr.get_output_till_prompt() - // update_pkg_lists_to_be_renamed() // this is async done - update_pkgs_lists() + var tlmgr = initialize_tlmgr() + tlmgr_post_init() } // object ApplicationMain diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala index 33c76d6708c..169f44154fb 100644 --- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala +++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala @@ -128,6 +128,7 @@ class TlmgrProcess(updout: Array[String] => Unit, upderr: String => Unit, updlin } catch { case exc: Throwable => stdin.close() + // println("Exception in inputFn thread: " + exc + "\n") errorBuffer.append(" Input thread: Exception: " + exc + "\n") } } @@ -139,19 +140,24 @@ class TlmgrProcess(updout: Array[String] => Unit, upderr: String => Unit, updlin while (true) { line = reader.readLine if (line == null) { - // println("DDD: got null line") // println("Did read NULL from stdin giving up") // error = true } else { - // println("did read " + line + " from process") + // println("DDD did read " + line + " from process") outputString.put(line) - updline(line) + try { + updline(line) + } catch { + case exc: Throwable => + println("Update line function failed, continuing anyway (probably old tlmgr)!") + } } } stdOut.close() } catch { case exc: Throwable => stdOut.close() + // println("Exception in outputFn thread: " + exc + "\n") errorBuffer.append(" Output thread: Exception: " + exc + "\n") } } @@ -168,6 +174,7 @@ class TlmgrProcess(updout: Array[String] => Unit, upderr: String => Unit, updlin } catch { case exc: Throwable => stdErr.close() + // println("Exception in errorFn thread: " + exc + "\n") errorBuffer.append(" Error thread: Exception: " + exc + "\n") } } |