diff --git a/Dockerfile b/Dockerfile
index 4d4dffc..3b82ea7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -77,6 +77,9 @@ RUN go install golang.org/x/tools/cmd/goimports@latest && \
go install golang.org/x/tools/gopls@latest
# Clone from main, build&install gonb binary, and then install it as a kernel in Jupyter.
+# - First introduce the cache-busting argument. This number can be bumped whenever we only want
+# to rebuild the gonb part.
+ARG CACHEBUST=2
WORKDIR ${HOME}
RUN git clone 'https://github.com/janpfeifer/gonb.git'
WORKDIR ${HOME}/gonb
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 196cb22..ccacdad 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -1,5 +1,11 @@
# GoNB Changelog
+## v0.10.11, 2025/02/02
+
+* New --version and -V flags to print version; Improved `%version` output. (#158)
+* Clean up, refactorings and fixed context leakage.
+* Added `version.txt` with target version for build.
+
## v0.10.10, 2025/01/28
* Reverted `replace` directive: contrary to what the AI suggested, it doesn't work when running from outside a cloned repository.
diff --git a/docs/coverage.txt b/docs/coverage.txt
index 420852f..9397b04 100644
--- a/docs/coverage.txt
+++ b/docs/coverage.txt
@@ -1,11 +1,15 @@
github.com/janpfeifer/gonb/main.go init 100.0%
-github.com/janpfeifer/gonb/main.go main 60.0%
-github.com/janpfeifer/gonb/main.go SetUpLogging 66.7%
+github.com/janpfeifer/gonb/main.go main 63.2%
+github.com/janpfeifer/gonb/main.go install 66.7%
+github.com/janpfeifer/gonb/main.go printVersion 42.9%
+github.com/janpfeifer/gonb/main.go setUpExtraLog 15.4%
+github.com/janpfeifer/gonb/main.go setUpLogging 66.7%
github.com/janpfeifer/gonb/main.go prepend 100.0%
github.com/janpfeifer/gonb/main.go UniqueIDFilter.Filter 100.0%
github.com/janpfeifer/gonb/main.go UniqueIDFilter.FilterF 100.0%
github.com/janpfeifer/gonb/main.go UniqueIDFilter.FilterS 0.0%
-github.com/janpfeifer/gonb/main.go SetUpKlog 66.7%
+github.com/janpfeifer/gonb/main.go setUpKlog 83.3%
+github.com/janpfeifer/gonb/main.go runKernel 78.3%
github.com/janpfeifer/gonb/version.go must 50.0%
github.com/janpfeifer/gonb/version.go init 100.0%
github.com/janpfeifer/gonb/cache/cache.go New 75.0%
@@ -289,8 +293,8 @@ github.com/janpfeifer/gonb/internal/goexec/wasm.go *State.ExportWasmConstants
github.com/janpfeifer/gonb/internal/goexec/wasm.go *State.RemoveWasmConstants 0.0%
github.com/janpfeifer/gonb/internal/goexec/goplsclient/conn.go *Client.ConnClose 0.0%
github.com/janpfeifer/gonb/internal/goexec/goplsclient/conn.go *Client.connCloseLocked 100.0%
-github.com/janpfeifer/gonb/internal/goexec/goplsclient/conn.go minTimeout 100.0%
-github.com/janpfeifer/gonb/internal/goexec/goplsclient/conn.go *Client.Connect 63.4%
+github.com/janpfeifer/gonb/internal/goexec/goplsclient/conn.go minTimeout 83.3%
+github.com/janpfeifer/gonb/internal/goexec/goplsclient/conn.go *Client.Connect 64.3%
github.com/janpfeifer/gonb/internal/goexec/goplsclient/conn.go *Client.NotifyDidOpenOrChange 0.0%
github.com/janpfeifer/gonb/internal/goexec/goplsclient/conn.go *Client.notifyDidOpenOrChangeLocked 0.0%
github.com/janpfeifer/gonb/internal/goexec/goplsclient/conn.go *Client.CallDefinition 0.0%
@@ -415,11 +419,16 @@ github.com/janpfeifer/gonb/internal/specialcmd/definitions.go removeDefinitionI
github.com/janpfeifer/gonb/internal/specialcmd/definitions.go removeDefinitions 91.7%
github.com/janpfeifer/gonb/internal/specialcmd/specialcmd.go Parse 84.6%
github.com/janpfeifer/gonb/internal/specialcmd/specialcmd.go joinLine 87.5%
-github.com/janpfeifer/gonb/internal/specialcmd/specialcmd.go execSpecialConfig 55.1%
+github.com/janpfeifer/gonb/internal/specialcmd/specialcmd.go execSpecialConfig 56.9%
github.com/janpfeifer/gonb/internal/specialcmd/specialcmd.go execShell 100.0%
github.com/janpfeifer/gonb/internal/specialcmd/specialcmd.go splitCmd 97.0%
github.com/janpfeifer/gonb/internal/specialcmd/track.go execTrack 27.3%
github.com/janpfeifer/gonb/internal/specialcmd/track.go execUntrack 54.5%
github.com/janpfeifer/gonb/internal/specialcmd/track.go showTrackedList 91.7%
+github.com/janpfeifer/gonb/internal/version/version.go AppVersion 66.7%
+github.com/janpfeifer/gonb/internal/version/version.go *VersionInfo.GetInfo 100.0%
+github.com/janpfeifer/gonb/internal/version/version.go *VersionInfo.String 100.0%
+github.com/janpfeifer/gonb/internal/version/version.go *VersionInfo.Print 100.0%
+github.com/janpfeifer/gonb/internal/version/version.go *VersionInfo.Markdown 0.0%
github.com/janpfeifer/gonb/internal/websocket/websocket.go Javascript 83.3%
-total (statements) 64.8%
+total (statements) 64.7%
diff --git a/examples/tests/bash_script.ipynb b/examples/tests/bash_script.ipynb
index 80546a4..27654d2 100644
--- a/examples/tests/bash_script.ipynb
+++ b/examples/tests/bash_script.ipynb
@@ -34,7 +34,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "/tmp/gonb_dec188e3\n"
+ "/tmp/gonb_359acad8\n"
]
}
],
@@ -59,7 +59,7 @@
"output_type": "stream",
"text": [
"/home/janpf/Projects/gonb/examples/tests\n",
- "/tmp/gonb_dec188e3\n",
+ "/tmp/gonb_359acad8\n",
"/home/janpf/Projects/gonb\n",
"/home/janpf/Projects/gonb\n"
]
diff --git a/examples/tests/dom.ipynb b/examples/tests/dom.ipynb
index e1a1a21..145acda 100644
--- a/examples/tests/dom.ipynb
+++ b/examples/tests/dom.ipynb
@@ -88,7 +88,7 @@
{
"data": {
"text/html": [
- "
"
+ ""
]
},
"metadata": {},
@@ -152,7 +152,7 @@
{
"data": {
"text/html": [
- ""
+ ""
]
},
"metadata": {},
diff --git a/examples/tests/goflags.ipynb b/examples/tests/goflags.ipynb
index 8d3bbdc..b47449b 100644
--- a/examples/tests/goflags.ipynb
+++ b/examples/tests/goflags.ipynb
@@ -153,9 +153,9 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "gonb_6d78d1c9/main.go:8:\tA\t\t100.0%\n",
- "gonb_6d78d1c9/main.go:12:\tB\t\t0.0%\n",
- "gonb_6d78d1c9/main.go:17:\tmain\t\t100.0%\n",
+ "gonb_334e1de4/main.go:8:\tA\t\t100.0%\n",
+ "gonb_334e1de4/main.go:12:\tB\t\t0.0%\n",
+ "gonb_334e1de4/main.go:17:\tmain\t\t100.0%\n",
"total\t\t\t\t(statements)\t75.0%\n"
]
}
@@ -238,7 +238,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "# gonb_6d78d1c9\n",
+ "# gonb_334e1de4\n",
"./main.go:10:6: can inline (*Point).ManhattanLen\n",
"./main.go:16:12: inlining call to flag.Parse\n",
"./main.go:18:27: inlining call to (*Point).ManhattanLen\n",
diff --git a/examples/tests/gonbui.ipynb b/examples/tests/gonbui.ipynb
index dde9b71..4d3b40b 100644
--- a/examples/tests/gonbui.ipynb
+++ b/examples/tests/gonbui.ipynb
@@ -22,7 +22,7 @@
"output_type": "stream",
"text": [
"%goflags=[\"--cover\" \"--covermode=set\"]\n",
- "GOCOVERDIR=/tmp/gonb_test_coverage.MljL9OTplr\n"
+ "GOCOVERDIR=/tmp/gonb_test_coverage.SYm2UwcmTW\n"
]
}
],
diff --git a/examples/tests/gotest.ipynb b/examples/tests/gotest.ipynb
index a7c3d01..15d0efd 100644
--- a/examples/tests/gotest.ipynb
+++ b/examples/tests/gotest.ipynb
@@ -287,12 +287,12 @@
"text": [
"goos: linux\n",
"goarch: amd64\n",
- "pkg: gonb_57055275\n",
+ "pkg: gonb_b37069f2\n",
"cpu: 12th Gen Intel(R) Core(TM) i9-12900K\n",
"BenchmarkFibonacciA32\n",
- "BenchmarkFibonacciA32-24 \t 172\t 6559009 ns/op\n",
+ "BenchmarkFibonacciA32-24 \t 180\t 6594959 ns/op\n",
"BenchmarkFibonacciB32\n",
- "BenchmarkFibonacciB32-24 \t350945394\t 3.942 ns/op\n",
+ "BenchmarkFibonacciB32-24 \t350331340\t 3.738 ns/op\n",
"PASS\n",
"coverage: [no statements]\n"
]
@@ -334,10 +334,10 @@
"text": [
"goos: linux\n",
"goarch: amd64\n",
- "pkg: gonb_57055275\n",
+ "pkg: gonb_b37069f2\n",
"cpu: 12th Gen Intel(R) Core(TM) i9-12900K\n",
- "BenchmarkFibonacciA32-24 \t 172\t 6583831 ns/op\n",
- "BenchmarkFibonacciB32-24 \t309453978\t 3.894 ns/op\n",
+ "BenchmarkFibonacciA32-24 \t 176\t 6570623 ns/op\n",
+ "BenchmarkFibonacciB32-24 \t305383951\t 3.899 ns/op\n",
"PASS\n",
"coverage: [no statements]\n"
]
diff --git a/examples/tests/gowork.ipynb b/examples/tests/gowork.ipynb
index aa1138e..814f084 100644
--- a/examples/tests/gowork.ipynb
+++ b/examples/tests/gowork.ipynb
@@ -36,7 +36,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "/tmp/gonb_tests_gowork_Xocdresp"
+ "/tmp/gonb_tests_gowork_pVaoudJA"
]
}
],
@@ -64,7 +64,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Temporary test package: /tmp/gonb_tests_gowork_Xocdresp\n"
+ "Temporary test package: /tmp/gonb_tests_gowork_pVaoudJA\n"
]
}
],
@@ -136,7 +136,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "\t- Added replace rule for module \"a.com/a/pkg\" to local directory \"/tmp/gonb_tests_gowork_Xocdresp\".\n"
+ "\t- Added replace rule for module \"a.com/a/pkg\" to local directory \"/tmp/gonb_tests_gowork_pVaoudJA\".\n"
]
}
],
@@ -155,7 +155,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "module gonb_bedb8330\n",
+ "module gonb_5dc14c2a\n",
"\n",
"go 1.23.5\n",
"\n",
@@ -186,7 +186,7 @@
"text/html": [
"List of files/directories being tracked:\n",
"\n",
- "- /tmp/gonb_tests_gowork_Xocdresp
\n",
+ "- /tmp/gonb_tests_gowork_pVaoudJA
\n",
"
\n"
]
},
@@ -208,7 +208,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "module gonb_bedb8330\n",
+ "module gonb_5dc14c2a\n",
"\n",
"go 1.23.5\n"
]
diff --git a/examples/tests/input_boxes.ipynb b/examples/tests/input_boxes.ipynb
index 9f2bf24..edcf89b 100644
--- a/examples/tests/input_boxes.ipynb
+++ b/examples/tests/input_boxes.ipynb
@@ -22,7 +22,7 @@
"output_type": "stream",
"text": [
"%goflags=[\"--cover\" \"--covermode=set\"]\n",
- "GOCOVERDIR=/tmp/gonb_test_coverage.MljL9OTplr\n"
+ "GOCOVERDIR=/tmp/gonb_test_coverage.SYm2UwcmTW\n"
]
}
],
diff --git a/examples/tests/vartuple.ipynb b/examples/tests/vartuple.ipynb
index 83e399d..6c1c4e1 100644
--- a/examples/tests/vartuple.ipynb
+++ b/examples/tests/vartuple.ipynb
@@ -45,7 +45,7 @@
"text/html": [
"Variables
\n",
"\n",
- "_~478741
\n",
+ "_~462823
\n",
"a
\n",
"c
\n",
"
"
diff --git a/examples/tests/widgets.ipynb b/examples/tests/widgets.ipynb
index 028ac04..7bcea3c 100644
--- a/examples/tests/widgets.ipynb
+++ b/examples/tests/widgets.ipynb
@@ -95,7 +95,7 @@
{
"data": {
"text/html": [
- ""
+ ""
]
},
"metadata": {},
@@ -189,7 +189,7 @@
{
"data": {
"text/html": [
- ""
+ ""
]
},
"metadata": {},
@@ -304,7 +304,7 @@
{
"data": {
"text/html": [
- ""
+ ""
]
},
"metadata": {},
diff --git a/examples/tests/writefile.ipynb b/examples/tests/writefile.ipynb
index 1c14bd5..c96f7fd 100644
--- a/examples/tests/writefile.ipynb
+++ b/examples/tests/writefile.ipynb
@@ -10,7 +10,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "Cell contents written to \"/tmp/gonb_nbtests_writefile_3076514072/poetry.txt\".\n"
+ "Cell contents written to \"/tmp/gonb_nbtests_writefile_2429412932/poetry.txt\".\n"
]
}
],
@@ -32,7 +32,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "Cell contents appended to \"/tmp/gonb_nbtests_writefile_3076514072/poetry.txt\".\n"
+ "Cell contents appended to \"/tmp/gonb_nbtests_writefile_2429412932/poetry.txt\".\n"
]
}
],
diff --git a/internal/goexec/elementtype_string.go b/internal/goexec/elementtype_string.go
index 475215d..84b7a33 100644
--- a/internal/goexec/elementtype_string.go
+++ b/internal/goexec/elementtype_string.go
@@ -5,7 +5,7 @@ package goexec
import "strconv"
func _() {
- // An "invalid array index" compiler err signifies that the constant values have changed.
+ // An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Invalid-0]
diff --git a/internal/goexec/goplsclient/conn.go b/internal/goexec/goplsclient/conn.go
index f098133..eeaa448 100644
--- a/internal/goexec/goplsclient/conn.go
+++ b/internal/goexec/goplsclient/conn.go
@@ -40,18 +40,22 @@ func (c *Client) connCloseLocked() {
// minTimeout extends (or returns a new context with extended Deadline), discarding the
// previous one -- not the correct use of context, but will do for now.
-func minTimeout(ctx context.Context, timeout time.Duration) context.Context {
+func minTimeout(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
+ var cancel context.CancelFunc
minDeadline := time.Now().Add(timeout)
if deadline, ok := ctx.Deadline(); !ok || deadline.After(minDeadline) {
- ctx, _ = context.WithDeadline(ctx, minDeadline)
+ ctx, cancel = context.WithDeadline(ctx, minDeadline)
+ } else {
+ cancel = func() {} // No-op.
}
- return ctx
+ return ctx, cancel
}
// Connect to the `gopls` in address given by `c.Address()`. It also starts
// a goroutine to monitor receiving requests.
func (c *Client) Connect(ctx context.Context) error {
- ctx = minTimeout(ctx, ConnectTimeout)
+ ctx, cancel := minTimeout(ctx, ConnectTimeout)
+ defer cancel()
c.mu.Lock()
defer c.mu.Unlock()
@@ -129,7 +133,8 @@ func (c *Client) NotifyDidOpenOrChange(ctx context.Context, filePath string) (er
// Silently do nothing, if no connection available.
return
}
- ctx = minTimeout(ctx, CommunicationTimeout)
+ ctx, cancel := minTimeout(ctx, CommunicationTimeout)
+ defer cancel()
c.mu.Lock()
defer c.mu.Unlock()
if c.conn == nil {
@@ -227,7 +232,8 @@ func (c *Client) CallDefinition(ctx context.Context, filePath string, line, col
// Silently do nothing, if no connection available.
return
}
- ctx = minTimeout(ctx, CommunicationTimeout)
+ ctx, cancel := minTimeout(ctx, CommunicationTimeout)
+ defer cancel()
c.mu.Lock()
defer c.mu.Unlock()
if c.conn == nil {
@@ -277,7 +283,8 @@ func (c *Client) CallHover(ctx context.Context, filePath string, line, col int)
// Silently do nothing, if no connection available.
return
}
- ctx = minTimeout(ctx, CommunicationTimeout)
+ ctx, cancel := minTimeout(ctx, CommunicationTimeout)
+ defer cancel()
c.mu.Lock()
defer c.mu.Unlock()
if c.conn == nil {
@@ -319,7 +326,8 @@ func (c *Client) CallComplete(ctx context.Context, filePath string, line, col in
// Silently do nothing, if no connection available.
return
}
- ctx = minTimeout(ctx, CommunicationTimeout)
+ ctx, cancel := minTimeout(ctx, CommunicationTimeout)
+ defer cancel()
c.mu.Lock()
defer c.mu.Unlock()
if c.conn == nil {
diff --git a/internal/goexec/goplsclient/goplsclient.go b/internal/goexec/goplsclient/goplsclient.go
index 1ef54b6..c8479dc 100644
--- a/internal/goexec/goplsclient/goplsclient.go
+++ b/internal/goexec/goplsclient/goplsclient.go
@@ -235,29 +235,32 @@ func (c *Client) FileData(filePath string) (content *FileData, updated bool, err
err = nil
}
+ // Trivial case: file doesn't exist (in filesystem and cache), or it exists in both
+ // and it is up-to-date.
if !foundInCache && !foundInFile {
// No file in cache or file system.
return
}
-
- // Deal with missing and deleted file.
if foundInCache && foundInFile && fileInfo.ModTime() == content.ContentTime {
// Fine not changed.
return
}
+ // Something needs updating.
updated = true
- if !foundInFile && foundInCache {
- // Remove notify removal.
+
+ // File no longer exists in filesystem.
+ if !foundInFile {
+ // Remove from cache.
delete(c.fileCache, filePath)
return
}
- if foundInFile && foundInCache {
- klog.V(2).Infof("File %q: stored date is %s, fileInfo mod time is %s",
+ // Create or update cache for file.
+ if foundInCache && klog.V(2).Enabled() {
+ klog.Infof("File %q: stored date is %s, fileInfo mod time is %s. Cache will be udpated.",
filePath, content.ContentTime, fileInfo.ModTime())
}
-
content = &FileData{
URI: uri.File(filePath),
Path: filePath,
diff --git a/main.go b/main.go
index b0ddf8d..29bab77 100644
--- a/main.go
+++ b/main.go
@@ -3,6 +3,8 @@ package main
import (
"flag"
"fmt"
+ "github.com/janpfeifer/gonb/internal/dispatcher"
+ "github.com/janpfeifer/gonb/internal/goexec"
"io"
"log"
"os"
@@ -10,8 +12,6 @@ import (
"time"
"github.com/gofrs/uuid"
- "github.com/janpfeifer/gonb/internal/dispatcher"
- "github.com/janpfeifer/gonb/internal/goexec"
"github.com/janpfeifer/gonb/internal/kernel"
"github.com/janpfeifer/gonb/version"
klog "k8s.io/klog/v2"
@@ -33,7 +33,7 @@ var (
var (
// UniqueID uniquely identifies a kernel execution. Used to create the temporary
// directory holding the kernel code, and for logging.
- // Set by SetUpLogging.
+ // Set by setUpLogging.
UniqueID string
coloredUniqueID string
@@ -52,112 +52,74 @@ func init() {
func main() {
klog.InitFlags(nil)
defer klog.Flush()
-
flag.Parse()
+ // --version or -V
if printVersion() {
return
}
- // Setup logging.
- if *flagExtraLog != "" {
- logFile, err := os.OpenFile(*flagExtraLog, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
- if err != nil {
- klog.Fatalf("Failed to open log file %q for writing: %+v", *flagExtraLog, err)
- }
- _, _ = fmt.Fprintf(logFile, "\n\nLogging for %q (pid=%d) starting at %s\n\n", os.Args[0], os.Getpid(), time.Now())
- logWriter = logFile
- flag.VisitAll(func(f *flag.Flag) {
- if f.Name == "logtostderr" || f.Name == "alsologtostderr" {
- if f.Value.String() == "true" {
- logWriter = io.MultiWriter(logFile, os.Stderr) // Write to STDERR and the newly open logFile.
- _ = f.Value.Set("false")
- }
- }
- })
- defer func() { _ = logFile.Close() }()
+ // Logging.
+ extraLogFile := setUpExtraLog() // --extra_log.
+ if extraLogFile != nil {
+ defer func() { _ = extraLogFile.Close() }()
}
- SetUpLogging() // "log" package.
- SetUpKlog() // "github.com/golang/klog" package
+ setUpLogging() // "log" package.
+ setUpKlog() // "k8s.io/klog/v2" package
- if *flagInstall {
- // Install kernel in Jupyter configuration.
- var extraArgs []string
- if *flagExtraLog != "" {
- extraArgs = []string{"--extra_log", *flagExtraLog}
- }
- if glogFlag := flag.Lookup("vmodule"); glogFlag != nil && glogFlag.Value.String() != "" {
- extraArgs = append(extraArgs, fmt.Sprintf("--vmodule=%s", glogFlag.Value.String()))
- }
- if glogFlag := flag.Lookup("logtostderr"); glogFlag != nil && glogFlag.Value.String() != "false" {
- extraArgs = append(extraArgs, "--logtostderr")
- }
- if glogFlag := flag.Lookup("alsologtostderr"); glogFlag != nil && glogFlag.Value.String() != "false" {
- extraArgs = append(extraArgs, "--alsologtostderr")
- }
- if glogFlag := flag.Lookup("raw_error"); glogFlag != nil && glogFlag.Value.String() != "false" {
- extraArgs = append(extraArgs, "--raw_error")
- }
- if glogFlag := flag.Lookup("work"); glogFlag != nil && glogFlag.Value.String() != "false" {
- extraArgs = append(extraArgs, "--work")
- }
- if glogFlag := flag.Lookup("comms_log"); glogFlag != nil && glogFlag.Value.String() != "false" {
- extraArgs = append(extraArgs, "--comms_log")
- }
- err := kernel.Install(extraArgs, *flagForceDeps, *flagForceCopy)
- if err != nil {
- log.Fatalf("Installation failed: %+v\n", err)
- }
+ // One of two tasks: (1) install gonb; (2) run kernel, started by JupyterServer.
+ if install() {
return
}
-
- if *flagKernel == "" {
- _, _ = fmt.Fprintf(os.Stderr, "Use either --install to install the kernel, or if started by Jupyter the flag --kernel must be provided.\n")
- flag.PrintDefaults()
- os.Exit(1)
+ if runKernel() {
+ return
}
- gocoverdir := os.Getenv("GOCOVERDIR")
- if gocoverdir != "" {
- klog.Infof("GOCOVERDIR=%s", gocoverdir)
- }
+ _, _ = fmt.Fprintf(os.Stderr, "Use either --install to install the kernel, or if started by Jupyter the flag --kernel must be provided.\n")
+ flag.PrintDefaults()
+ os.Exit(1)
+ return
+}
- _, err := exec.LookPath("go")
- if err != nil {
- klog.Exitf("Failed to find path for the `go` program: %+v\n\nCurrent PATH=%q", err, os.Getenv("PATH"))
+// install GoNB kernel as a JupyterServer configuration.
+// Returns true if installed.
+// Errors are fatal.
+func install() bool {
+ if !*flagInstall {
+ return false
}
- // Create a kernel.
- k, err := kernel.New(*flagKernel)
- klog.Infof("kernel created\n")
- if err != nil {
- log.Fatalf("Failed to start kernel: %+v", err)
+ // Install kernel in Jupyter configuration.
+ var extraArgs []string
+ if *flagExtraLog != "" {
+ extraArgs = []string{"--extra_log", *flagExtraLog}
}
- k.HandleInterrupt() // Handle Jupyter interruptions and Control+C.
-
- // Create a Go executor.
- goExec, err := goexec.New(k, UniqueID, *flagWork, *flagRawError)
- if err != nil {
- log.Fatalf("Failed to create go executor: %+v", err)
+ if glogFlag := flag.Lookup("vmodule"); glogFlag != nil && glogFlag.Value.String() != "" {
+ extraArgs = append(extraArgs, fmt.Sprintf("--vmodule=%s", glogFlag.Value.String()))
}
- goExec.Comms.LogWebSocket = *flagCommsLog
-
- // Orchestrate dispatching of messages.
- dispatcher.RunKernel(k, goExec)
- klog.V(1).Infof("Dispatcher exited.")
-
- // Stop gopls.
- err = goExec.Stop()
+ if glogFlag := flag.Lookup("logtostderr"); glogFlag != nil && glogFlag.Value.String() != "false" {
+ extraArgs = append(extraArgs, "--logtostderr")
+ }
+ if glogFlag := flag.Lookup("alsologtostderr"); glogFlag != nil && glogFlag.Value.String() != "false" {
+ extraArgs = append(extraArgs, "--alsologtostderr")
+ }
+ if glogFlag := flag.Lookup("raw_error"); glogFlag != nil && glogFlag.Value.String() != "false" {
+ extraArgs = append(extraArgs, "--raw_error")
+ }
+ if glogFlag := flag.Lookup("work"); glogFlag != nil && glogFlag.Value.String() != "false" {
+ extraArgs = append(extraArgs, "--work")
+ }
+ if glogFlag := flag.Lookup("comms_log"); glogFlag != nil && glogFlag.Value.String() != "false" {
+ extraArgs = append(extraArgs, "--comms_log")
+ }
+ err := kernel.Install(extraArgs, *flagForceDeps, *flagForceCopy)
if err != nil {
- klog.Warningf("Error during shutdown: %+v", err)
+ log.Fatalf("Installation failed: %+v\n", err)
}
- klog.V(1).Infof("goExec stopped.")
-
- // Wait for all polling goroutines.
- k.ExitWait()
- klog.Infof("Exiting...")
+ return true
}
+// printVersion returns whether version printing was requested.
func printVersion() bool {
if *flagShortVersion {
fmt.Println(version.AppVersion.String())
@@ -175,9 +137,32 @@ var (
ColorBgYellow = "\033[7;39;32m"
)
-// SetUpLogging creates a UniqueID, uses it as a prefix for logging, and sets up --extra_log if
+// setUpExtraLog
+func setUpExtraLog() *os.File {
+ if *flagExtraLog == "" {
+ return nil
+ }
+
+ logFile, err := os.OpenFile(*flagExtraLog, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
+ if err != nil {
+ klog.Fatalf("Failed to open log file %q for writing: %+v", *flagExtraLog, err)
+ }
+ _, _ = fmt.Fprintf(logFile, "\n\nLogging for %q (pid=%d) starting at %s\n\n", os.Args[0], os.Getpid(), time.Now())
+ logWriter = logFile
+ flag.VisitAll(func(f *flag.Flag) {
+ if f.Name == "logtostderr" || f.Name == "alsologtostderr" {
+ if f.Value.String() == "true" {
+ logWriter = io.MultiWriter(logFile, os.Stderr) // Write to STDERR and the newly open logFile.
+ _ = f.Value.Set("false")
+ }
+ }
+ })
+ return logFile
+}
+
+// setUpLogging creates a UniqueID, uses it as a prefix for logging, and sets up --extra_log if
// requested.
-func SetUpLogging() {
+func setUpLogging() {
log.SetPrefix(coloredUniqueID)
if logWriter != nil {
log.SetOutput(logWriter)
@@ -187,14 +172,12 @@ func SetUpLogging() {
// UniqueIDFilter prepends the UniqueID for every log line.
type UniqueIDFilter struct{}
-// prepend value to slice: it makes a copy of the slice.
-func prepend[T any](slice []T, value T) []T {
- newSlice := make([]T, len(slice)+1)
- if len(slice) > 0 {
- copy(newSlice[1:], slice)
- }
- newSlice[0] = value
- return newSlice
+// prepend value to slice.
+func prepend[T any](slice []T, element T) []T {
+ slice = append(slice, element) // It will be overwritten.
+ copy(slice[1:], slice) // Shift to the "right"
+ slice[0] = element
+ return slice
}
// Filter implements klog.LogFilter interface.
@@ -212,10 +195,60 @@ func (UniqueIDFilter) FilterS(msg string, keysAndValues []interface{}) (string,
return coloredUniqueID + msg, keysAndValues
}
-// SetUpKlog to include prefix with kernel's UniqueID.
-func SetUpKlog() {
+// setUpKlog to include prefix with kernel's UniqueID.
+func setUpKlog() {
if logWriter != nil {
klog.SetOutput(logWriter)
}
klog.SetLogFilter(UniqueIDFilter{})
+
+ // Report about profiling test coverage.
+ gocoverdir := os.Getenv("GOCOVERDIR")
+ if gocoverdir != "" {
+ klog.Infof("GOCOVERDIR=%s", gocoverdir)
+ }
+}
+
+// runKernel if --kernel is set. Returns whether the kernel was run.
+// Errors are fatal.
+func runKernel() bool {
+ if *flagKernel == "" {
+ return false
+ }
+
+ _, err := exec.LookPath("go")
+ if err != nil {
+ klog.Exitf("Failed to find path for the `go` program: %+v\n\nCurrent PATH=%q", err, os.Getenv("PATH"))
+ }
+
+ // Create a kernel.
+ k, err := kernel.New(*flagKernel)
+ klog.Infof("kernel created\n")
+ if err != nil {
+ klog.Fatalf("Failed to start kernel: %+v", err)
+ }
+ k.HandleInterrupt() // Handle Jupyter interruptions and Control+C.
+
+ // Create a Go executor.
+ goExec, err := goexec.New(k, UniqueID, *flagWork, *flagRawError)
+ if err != nil {
+ klog.Fatalf("Failed to create go executor: %+v", err)
+ }
+ goExec.Comms.LogWebSocket = *flagCommsLog
+
+ // Orchestrate dispatching of messages.
+ dispatcher.RunKernel(k, goExec)
+ klog.V(1).Infof("Dispatcher exited.")
+
+ // Stop gopls.
+ err = goExec.Stop()
+ if err != nil {
+ klog.Warningf("Error during shutdown: %+v", err)
+ }
+ klog.V(1).Infof("goExec stopped.")
+
+ // Wait for all polling goroutines.
+ k.ExitWait()
+ klog.Infof("Exiting...")
+ return true
}
diff --git a/version.go b/version.go
index d624a42..8e74620 100644
--- a/version.go
+++ b/version.go
@@ -7,8 +7,8 @@ import (
"github.com/janpfeifer/gonb/version"
)
-//go:generate bash -c "printf 'package main\nvar GitTag = \"%s\"\n' \"$(git describe --tags --abbrev=0)\" > version/versiontag.go"
-//go:generate bash -c "printf 'package main\nvar GitCommitHash = \"%s\"\n' \"$(git rev-parse HEAD)\" > version/versionhash.go"
+//go:generate bash -c "printf 'package version\nvar GitTag = \"%s\"\n' \"$(cat version.txt)\" > version/versiontag.go"
+//go:generate bash -c "printf 'package version\nvar GitCommitHash = \"%s\"\n' \"$(git rev-parse HEAD)\" > version/versionhash.go"
func must(err error) {
if err != nil {
diff --git a/version.txt b/version.txt
new file mode 100644
index 0000000..8b684d8
--- /dev/null
+++ b/version.txt
@@ -0,0 +1 @@
+v0.10.11
\ No newline at end of file
diff --git a/version/versionhash.go b/version/versionhash.go
index 9e2fccb..5b23c9e 100644
--- a/version/versionhash.go
+++ b/version/versionhash.go
@@ -1,3 +1,2 @@
package version
-
-var GitCommitHash = "05c5124f6ed019954e5ed195f7e2674a8713beca"
+var GitCommitHash = "60ff94b91e0125e8dce3e83e08ada48effdfd8a0"
diff --git a/version/versiontag.go b/version/versiontag.go
index 5a8f382..7dd2d6a 100644
--- a/version/versiontag.go
+++ b/version/versiontag.go
@@ -1,3 +1,2 @@
package version
-
-var GitTag = "v0.10.10"
+var GitTag = "v0.10.11"