From c284cb4cfc94eef2bcf0cb8cbc9250cf8387e069 Mon Sep 17 00:00:00 2001 From: Romein van Buren Date: Sat, 24 Jun 2023 10:11:32 +0200 Subject: [PATCH 1/8] Started working on shell feature (WIP) --- frontend/src/components/codeeditor.svelte | 57 +++++++++ frontend/src/components/icon.svelte | 2 + frontend/src/components/objecteditor.svelte | 53 +-------- frontend/src/lib/stores/hosttree.js | 6 + .../connection/collection/index.svelte | 3 + .../connection/collection/shell.svelte | 109 ++++++++++++++++++ frontend/wailsjs/go/app/App.d.ts | 2 + frontend/wailsjs/go/app/App.js | 4 + internal/app/app.go | 4 + internal/app/collection_shell.go | 83 +++++++++++++ 10 files changed, 276 insertions(+), 47 deletions(-) create mode 100644 frontend/src/components/codeeditor.svelte create mode 100644 frontend/src/organisms/connection/collection/shell.svelte create mode 100644 internal/app/collection_shell.go diff --git a/frontend/src/components/codeeditor.svelte b/frontend/src/components/codeeditor.svelte new file mode 100644 index 0000000..262eaea --- /dev/null +++ b/frontend/src/components/codeeditor.svelte @@ -0,0 +1,57 @@ + + +
+ + diff --git a/frontend/src/components/icon.svelte b/frontend/src/components/icon.svelte index 5a024b0..a30708e 100644 --- a/frontend/src/components/icon.svelte +++ b/frontend/src/components/icon.svelte @@ -142,5 +142,7 @@ {:else if name === 'loading'} + {:else if name === 'shell'} + {/if} diff --git a/frontend/src/components/objecteditor.svelte b/frontend/src/components/objecteditor.svelte index ecb7359..756d9d4 100644 --- a/frontend/src/components/objecteditor.svelte +++ b/frontend/src/components/objecteditor.svelte @@ -1,41 +1,16 @@ -
- - + diff --git a/frontend/src/lib/stores/hosttree.js b/frontend/src/lib/stores/hosttree.js index c5c08d1..5806cab 100644 --- a/frontend/src/lib/stores/hosttree.js +++ b/frontend/src/lib/stores/hosttree.js @@ -16,6 +16,7 @@ import { DropCollection, DropDatabase, DropIndex, + ExecuteShellScript, GetIndexes, Hosts, OpenCollection, @@ -239,6 +240,11 @@ async function refresh() { }); }); }; + + collection.executeShellScript = async function(script) { + const result = await ExecuteShellScript(hostKey, dbKey, collKey, script); + return result; + }; } await refresh(); diff --git a/frontend/src/organisms/connection/collection/index.svelte b/frontend/src/organisms/connection/collection/index.svelte index a9a9aaf..dd33f35 100644 --- a/frontend/src/organisms/connection/collection/index.svelte +++ b/frontend/src/organisms/connection/collection/index.svelte @@ -9,6 +9,7 @@ import Indexes from './indexes.svelte'; import Insert from './insert.svelte'; import Remove from './remove.svelte'; + import Shell from './shell.svelte'; import Stats from './stats.svelte'; import Update from './update.svelte'; @@ -50,6 +51,7 @@ { key: 'remove', icon: 'trash', title: 'Remove' }, { key: 'indexes', icon: 'list', title: 'Indexes' }, { key: 'aggregate', icon: 're', title: 'Aggregate' }, + { key: 'shell', icon: 'shell', title: 'Shell' }, ]} bind:selectedKey={tab} /> @@ -61,6 +63,7 @@ {:else if tab === 'remove'} {:else if tab === 'indexes'} {:else if tab === 'aggregate'} + {:else if tab === 'shell'} {/if} {/key} diff --git a/frontend/src/organisms/connection/collection/shell.svelte b/frontend/src/organisms/connection/collection/shell.svelte new file mode 100644 index 0000000..03581fd --- /dev/null +++ b/frontend/src/organisms/connection/collection/shell.svelte @@ -0,0 +1,109 @@ + + +
+
+ + + +
+ {#if result.errorTitle || result.errorDescription} + + + + {:else} +
{result.output || ''}
+ {/if} +
+
+ +
+ {#key result} +
+ {#if result?.status} + Exit code: {result.status} + {/if} +
+ {/key} + + +
+
+ + diff --git a/frontend/wailsjs/go/app/App.d.ts b/frontend/wailsjs/go/app/App.d.ts index 9e3dd2c..e1268e5 100755 --- a/frontend/wailsjs/go/app/App.d.ts +++ b/frontend/wailsjs/go/app/App.d.ts @@ -20,6 +20,8 @@ export function DropIndex(arg1:string,arg2:string,arg3:string,arg4:string):Promi export function Environment():Promise; +export function ExecuteShellScript(arg1:string,arg2:string,arg3:string,arg4:string):Promise; + export function FindItems(arg1:string,arg2:string,arg3:string,arg4:string):Promise; export function GetIndexes(arg1:string,arg2:string,arg3:string):Promise; diff --git a/frontend/wailsjs/go/app/App.js b/frontend/wailsjs/go/app/App.js index 5552e87..885d7c2 100755 --- a/frontend/wailsjs/go/app/App.js +++ b/frontend/wailsjs/go/app/App.js @@ -30,6 +30,10 @@ export function Environment() { return window['go']['app']['App']['Environment'](); } +export function ExecuteShellScript(arg1, arg2, arg3, arg4) { + return window['go']['app']['App']['ExecuteShellScript'](arg1, arg2, arg3, arg4); +} + export function FindItems(arg1, arg2, arg3, arg4) { return window['go']['app']['App']['FindItems'](arg1, arg2, arg3, arg4); } diff --git a/internal/app/app.go b/internal/app/app.go index 684090c..1795e4a 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -26,6 +26,7 @@ type EnvironmentInfo struct { HasMongoExport bool `json:"hasMongoExport"` HasMongoDump bool `json:"hasMongoDump"` + HasMongoShell bool `json:"hasMongoShell"` HomeDirectory string `json:"homeDirectory"` DataDirectory string `json:"dataDirectory"` @@ -50,6 +51,9 @@ func NewApp(version string) *App { _, err = exec.LookPath("mongoexport") a.Env.HasMongoExport = err == nil + _, err = exec.LookPath("mongosh") + a.Env.HasMongoShell = err == nil + a.Env.HomeDirectory, err = os.UserHomeDir() if err != nil { panic(errors.New("encountered an error while getting home directory")) diff --git a/internal/app/collection_shell.go b/internal/app/collection_shell.go new file mode 100644 index 0000000..b9c2455 --- /dev/null +++ b/internal/app/collection_shell.go @@ -0,0 +1,83 @@ +package app + +import ( + "fmt" + "os" + "os/exec" + "path" + + "github.com/google/uuid" + "github.com/wailsapp/wails/v2/pkg/runtime" +) + +type ExecuteShellScriptResult struct { + Output string `json:"output"` + Status int `json:"status"` + ErrorTitle string `json:"errorTitle"` + ErrorDescription string `json:"errorDescription"` +} + +func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result ExecuteShellScriptResult) { + if !a.Env.HasMongoShell { + result.ErrorTitle = "mongosh not found" + result.ErrorDescription = "The mongosh executable is required to run a shell script. Please see https://www.mongodb.com/docs/mongodb-shell/install/" + return + } + + hosts, err := a.Hosts() + if err != nil { + result.ErrorTitle = "Could not get hosts" + result.ErrorDescription = err.Error() + return + } + + host, hostFound := hosts[hostKey] + if !hostFound { + result.ErrorTitle = "The specified host does not seem to exist" + return + } + + id, err := uuid.NewRandom() + if err != nil { + runtime.LogErrorf(a.ctx, "Shell: failed to generate a UUID: %s", err.Error()) + result.ErrorTitle = "Could not generate UUID" + result.ErrorDescription = err.Error() + return + } + + dirname := path.Join(a.Env.DataDirectory, "Shell Scripts") + fname := path.Join(dirname, fmt.Sprintf("%s.js", id.String())) + + if err := os.MkdirAll(dirname, os.ModePerm); err != nil { + runtime.LogWarningf(a.ctx, "Shell: failed to mkdir %s", err.Error()) + result.ErrorTitle = "Could not create temporary directory" + result.ErrorDescription = err.Error() + return + } + + script = fmt.Sprintf("db = connect('%s');\n\n%s", host.URI, script) + + if err := os.WriteFile(fname, []byte(script), os.ModePerm); err != nil { + runtime.LogWarningf(a.ctx, "Shell: failed to write script to %s", err.Error()) + result.ErrorTitle = "Could not create temporary script file" + result.ErrorDescription = err.Error() + return + } + + cmd := exec.Command("mongosh", "--file", fname) + stdout, err := cmd.Output() + + if exiterr, ok := err.(*exec.ExitError); ok { + result.Status = exiterr.ExitCode() + } else if err != nil { + runtime.LogWarningf(a.ctx, "Shell: failed to execute: mongosh --file %s: %s", fname, err.Error()) + result.ErrorTitle = "Could not execute script" + result.ErrorDescription = err.Error() + return + } else { + result.Status = 0 + } + + result.Output = string(stdout) + return +} From 51897adf8d9205ec0c84c3e38c797763b8f4f015 Mon Sep 17 00:00:00 2001 From: Romein van Buren Date: Sat, 24 Jun 2023 10:28:49 +0200 Subject: [PATCH 2/8] Show spinner --- frontend/src/organisms/connection/collection/shell.svelte | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/organisms/connection/collection/shell.svelte b/frontend/src/organisms/connection/collection/shell.svelte index 03581fd..ea6ab32 100644 --- a/frontend/src/organisms/connection/collection/shell.svelte +++ b/frontend/src/organisms/connection/collection/shell.svelte @@ -12,9 +12,12 @@ let result = {}; let copySucceeded = false; let timeout; + let busy = false; async function run() { + busy = true; result = await collection.executeShellScript(script); + busy = false; } async function copyErrorDescription() { @@ -34,7 +37,9 @@
- {#if result.errorTitle || result.errorDescription} + {#if busy} + + {:else if result.errorTitle || result.errorDescription} - - {:else} -
{result.output || ''}
- {/if} -
+
+ {#if busy} + + {:else if result.errorTitle || result.errorDescription} + + + + {:else} +
{result.output || ''}
+ {/if}
@@ -69,18 +69,16 @@