1
0
mirror of https://github.com/garraflavatra/rolens.git synced 2025-01-18 13:07:58 +00:00

Added functionality to save and import shell scripts (#37)

This commit is contained in:
Romein van Buren 2023-07-19 20:01:15 +02:00
parent ae5002d356
commit 9d577ac429
Signed by: romein
GPG Key ID: 0EFF8478ADDF6C49
8 changed files with 176 additions and 39 deletions

View File

@ -24,8 +24,5 @@ export function looseJsonIsValid(json) {
}
export function stringCouldBeID(string) {
if (looseJsonIsValid(string)) {
return false;
}
return /^[a-zA-Z0-9_-]{1,}$/.test(string);
}

View File

@ -12,6 +12,8 @@
import Stats from './stats.svelte';
import Update from './update.svelte';
export let host;
export let database;
export let collection;
export let tab = 'stats';
@ -47,6 +49,8 @@
this={view.component}
visible={tab === view.key}
on:performFind={catchQuery}
{host}
{database}
{collection}
/>
</div>

View File

@ -6,6 +6,7 @@
import Shell from '../shell.svelte';
import Stats from './stats.svelte';
export let host;
export let database;
export let tab = 'stats';
@ -28,7 +29,7 @@
{#each Object.values(tabs) as view}
<div class="container" class:hidden={tab !== view.key}>
<svelte:component this={view.component} visible={tab === view.key} {database} />
<svelte:component this={view.component} visible={tab === view.key} {host} {database} />
</div>
{/each}
{/key}

View File

@ -64,11 +64,20 @@
{#if activeCollKey}
{#key activeCollKey}
<CollectionView collection={$hostTree[activeHostKey]?.databases[activeDbKey]?.collections?.[activeCollKey]} bind:tab={collTab} />
<CollectionView
host={$hostTree[activeHostKey]}
database={$hostTree[activeHostKey]?.databases[activeDbKey]}
collection={$hostTree[activeHostKey]?.databases[activeDbKey]?.collections?.[activeCollKey]}
bind:tab={collTab}
/>
{/key}
{:else if activeDbKey}
{#key activeDbKey}
<DatabaseView database={$hostTree[activeHostKey]?.databases[activeDbKey]} bind:tab={dbTab} />
<DatabaseView
host={$hostTree[activeHostKey]}
database={$hostTree[activeHostKey]?.databases[activeDbKey]}
bind:tab={dbTab}
/>
{/key}
{:else if activeHostKey}
{#key activeHostKey}

View File

@ -2,6 +2,7 @@
import BlankState from '$components/blankstate.svelte';
import CodeEditor from '$components/codeeditor.svelte';
import Icon from '$components/icon.svelte';
import { OpenShellScript, SaveShellScript } from '$wails/go/app/App';
import { javascript } from '@codemirror/lang-javascript';
import { onDestroy, onMount } from 'svelte';
@ -19,7 +20,7 @@
let busy = false;
let editor;
async function run() {
async function runScript() {
busy = true;
if (collection) {
@ -35,6 +36,36 @@
busy = false;
}
async function loadScript() {
const _script = await OpenShellScript();
if (_script) {
script = _script;
editor.dispatch({
changes: {
from: 0,
to: editor.state.doc.length,
insert: script,
},
selection: {
from: 0,
anchor: 0,
to: 0,
head: 0,
},
});
}
}
async function saveScript() {
await SaveShellScript(
host?.key || '',
database?.key || '',
collection?.key || '',
script,
false // not temporary
);
}
async function copyErrorDescription() {
await navigator.clipboard.writeText(result.errorDescription);
copySucceeded = true;
@ -86,10 +117,19 @@
</div>
<div class="controls">
<button class="button" on:click={run}>
<button class="button" on:click={runScript}>
<Icon name="play" /> Run
</button>
<div class="field inline">
<button class="button secondary" on:click={loadScript}>
<Icon name="upload" /> Load script…
</button>
<button class="button secondary" on:click={saveScript}>
<Icon name="save" /> Save as…
</button>
</div>
{#key result}
<div class="status flash-green">
{#if result?.status}
@ -145,6 +185,7 @@
.controls {
margin-top: 0.5rem;
display: flex;
gap: 0.2rem;
align-items: center;
grid-column: 1 / 3;
}

4
frontend/wailsjs/go/app/App.d.ts generated vendored
View File

@ -40,6 +40,8 @@ export function OpenConnection(arg1:string):Promise<app.OpenConnectionResult>;
export function OpenDatabase(arg1:string,arg2:string):Promise<app.OpenDatabaseResult>;
export function OpenShellScript():Promise<string>;
export function PerformDump(arg1:string):Promise<boolean>;
export function PerformFindExport(arg1:string,arg2:string,arg3:string,arg4:string):Promise<boolean>;
@ -62,6 +64,8 @@ export function ReportSharedStateVariable(arg1:string,arg2:string):Promise<void>
export function SaveQuery(arg1:string):Promise<string>;
export function SaveShellScript(arg1:string,arg2:string,arg3:string,arg4:string,arg5:boolean):Promise<app.SaveShellScriptResult>;
export function SavedQueries():Promise<map[string]app.SavedQuery>;
export function Settings():Promise<app.Settings>;

View File

@ -70,6 +70,10 @@ export function OpenDatabase(arg1, arg2) {
return window['go']['app']['App']['OpenDatabase'](arg1, arg2);
}
export function OpenShellScript() {
return window['go']['app']['App']['OpenShellScript']();
}
export function PerformDump(arg1) {
return window['go']['app']['App']['PerformDump'](arg1);
}
@ -114,6 +118,10 @@ export function SaveQuery(arg1) {
return window['go']['app']['App']['SaveQuery'](arg1);
}
export function SaveShellScript(arg1, arg2, arg3, arg4, arg5) {
return window['go']['app']['App']['SaveShellScript'](arg1, arg2, arg3, arg4, arg5);
}
export function SavedQueries() {
return window['go']['app']['App']['SavedQueries']();
}

View File

@ -20,6 +20,13 @@ type ExecuteShellScriptResult struct {
ErrorDescription string `json:"errorDescription"`
}
type SaveShellScriptResult struct {
Host Host `json:"host"`
Fname string `json:"filename"`
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"
@ -27,8 +34,40 @@ func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result
return
}
saveRes := a.SaveShellScript(hostKey, dbKey, collKey, script, true)
if (saveRes.ErrorTitle != "") || (saveRes.ErrorDescription != "") {
result.ErrorTitle = saveRes.ErrorTitle
result.ErrorDescription = saveRes.ErrorDescription
return
}
var outbuf, errbuf strings.Builder
cmd := exec.Command("mongosh", "--file", saveRes.Fname, saveRes.Host.URI)
cmd.Stdout = &outbuf
cmd.Stderr = &errbuf
err := cmd.Run()
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", saveRes.Fname, err.Error())
result.ErrorTitle = "mongosh failure"
result.ErrorDescription = err.Error()
return
} else {
result.Status = 0
}
os.Remove(saveRes.Fname)
result.Output = outbuf.String()
result.Stderr = errbuf.String()
return
}
func (a *App) SaveShellScript(hostKey, dbKey, collKey, script string, temp bool) (result SaveShellScriptResult) {
hosts, err := a.Hosts()
if err != nil {
runtime.LogWarningf(a.ctx, "Shell: could not get hosts: %s", err.Error())
result.ErrorTitle = "Could not get hosts"
result.ErrorDescription = err.Error()
return
@ -36,10 +75,12 @@ func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result
host, hostFound := hosts[hostKey]
if !hostFound {
runtime.LogWarningf(a.ctx, "Shell: host %s does not exist", host)
result.ErrorTitle = "The specified host does not seem to exist"
return
}
result.Host = host
id, err := uuid.NewRandom()
if err != nil {
runtime.LogErrorf(a.ctx, "Shell: failed to generate a UUID: %s", err.Error())
@ -48,14 +89,35 @@ func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result
return
}
dirname := path.Join(a.Env.DataDirectory, "Shell Scripts")
fname := path.Join(dirname, fmt.Sprintf("%s.mongosh.js", id.String()))
if temp {
dirname, err := os.MkdirTemp(os.TempDir(), "rolens-script")
if err != nil {
runtime.LogErrorf(a.ctx, "Shell: failed to create temporary directory: %s", err.Error())
result.ErrorTitle = "Could not generate temporary directory for script"
result.ErrorDescription = err.Error()
return
}
result.Fname = path.Join(dirname, fmt.Sprintf("%s.mongosh.js", id.String()))
} else {
result.Fname, err = runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
DefaultFilename: "New Script.js",
DefaultDirectory: path.Join(a.Env.DataDirectory, "Shell Scripts"),
Title: "Save MongoDB Shell Script",
CanCreateDirectories: true,
Filters: []runtime.FileFilter{
{
DisplayName: "MongoDB Shell Script (*.js)",
Pattern: "*.js",
},
},
})
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
if err != nil {
runtime.LogErrorf(a.ctx, "Shell: failed to save script: %s", err.Error())
result.ErrorTitle = "Could not save shell script"
result.ErrorDescription = err.Error()
return
}
}
scriptHeader := fmt.Sprintf("// Namespace: %s.%s\n", dbKey, collKey)
@ -77,35 +139,46 @@ func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result
scriptHeader = scriptHeader + fmt.Sprintf("coll = db.getCollection('%s');\n", collKey)
}
scriptHeader = scriptHeader + "\n// Start of user script\n"
script = scriptHeader + script
scriptHeader = scriptHeader + "\n"
script = scriptHeader + strings.TrimLeft(strings.TrimRight(script, " \t\n"), "\n")
if err := os.WriteFile(fname, []byte(script), os.ModePerm); err != nil {
runtime.LogWarningf(a.ctx, "Shell: failed to write script to %s", err.Error())
if err := os.WriteFile(result.Fname, []byte(script), os.ModePerm); err != nil {
runtime.LogWarningf(a.ctx, "Shell: failed to write script to %s: %s", result.Fname, err.Error())
result.ErrorTitle = "Could not create temporary script file"
result.ErrorDescription = err.Error()
return
}
var outbuf, errbuf strings.Builder
cmd := exec.Command("mongosh", "--file", fname, host.URI)
cmd.Stdout = &outbuf
cmd.Stderr = &errbuf
err = cmd.Run()
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 = "mongosh failure"
result.ErrorDescription = err.Error()
return
} else {
result.Status = 0
}
os.Remove(fname)
result.Output = outbuf.String()
result.Stderr = errbuf.String()
return
}
func (a *App) OpenShellScript() string {
dir := path.Join(a.Env.DataDirectory, "Shell Scripts")
os.MkdirAll(dir, os.ModePerm)
fname, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
DefaultDirectory: path.Join(a.Env.DataDirectory, "Shell Scripts"),
Title: "Load a MongoDB Shell Script",
CanCreateDirectories: true,
Filters: []runtime.FileFilter{
{
DisplayName: "MongoDB Shell Script (*.js)",
Pattern: "*.js",
},
},
})
if err != nil {
runtime.LogWarningf(a.ctx, "Shell: error opening script: %s", err.Error())
return ""
}
script, err := os.ReadFile(fname)
if err != nil {
runtime.LogWarningf(a.ctx, "Shell: error reading script %s: %s", fname, err.Error())
return ""
}
return string(script)
}