diff --git a/spug_api/apps/repository/utils.py b/spug_api/apps/repository/utils.py index ed9895b..e9c0099 100644 --- a/spug_api/apps/repository/utils.py +++ b/spug_api/apps/repository/utils.py @@ -142,12 +142,12 @@ class Helper: if env: env = dict(env.items()) env.update(os.environ) - command = 'set -e\n' + command task = subprocess.Popen(command, env=env, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while True: message = task.stdout.readline() if not message: break - self.send_info('local', message.decode()) + message = message.decode().rstrip('\r\n') + self.send_info('local', message + '\r\n') if task.wait() != 0: self.send_error('local', f'exit code: {task.returncode}') diff --git a/spug_web/src/pages/deploy/repository/Console.js b/spug_web/src/pages/deploy/repository/Console.js index ec98171..906b94d 100644 --- a/spug_web/src/pages/deploy/repository/Console.js +++ b/spug_web/src/pages/deploy/repository/Console.js @@ -3,21 +3,25 @@ * Copyright (c) * Released under the AGPL-3.0 License. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { observer } from 'mobx-react'; import { FullscreenOutlined, FullscreenExitOutlined, LoadingOutlined } from '@ant-design/icons'; +import { FitAddon } from 'xterm-addon-fit'; +import { Terminal } from 'xterm'; import { Modal, Steps } from 'antd'; import { X_TOKEN, human_time } from 'libs'; import styles from './index.module.less'; import store from './store'; export default observer(function Console() { + const el = useRef() const [fullscreen, setFullscreen] = useState(false); const [step, setStep] = useState(0); const [status, setStatus] = useState('process') useEffect(() => { - store.outputs = [`${human_time()} 建立连接... `] + const term = initialTerm() + term.write(`${human_time()} 建立连接... `) let index = 0; const token = store.record.spug_version; const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; @@ -29,17 +33,24 @@ export default observer(function Console() { } else { index += 1; const {data, step, status} = JSON.parse(e.data); - if (data !== undefined) store.outputs.push(data); + if (data !== undefined) term.write(data); if (step !== undefined) setStep(step); if (status !== undefined) setStatus(status); } } - return () => { - socket.close(); - store.outputs = [] - } + return () => socket.close(); }, []) + function initialTerm() { + const fitPlugin = new FitAddon() + const term = new Terminal({disableStdin: true}) + term.loadAddon(fitPlugin) + term.setOption('theme', {background: '#fafafa', foreground: '#000', selection: '#999'}) + term.open(el.current) + fitPlugin.fit() + return term + } + function handleClose() { store.fetchRecords(); store.logVisible = false @@ -74,7 +85,9 @@ export default observer(function Console() { -
{store.outputs}
+
+
+
) }) diff --git a/spug_web/src/pages/deploy/repository/index.module.less b/spug_web/src/pages/deploy/repository/index.module.less index 83600df..6b487a5 100644 --- a/spug_web/src/pages/deploy/repository/index.module.less +++ b/spug_web/src/pages/deploy/repository/index.module.less @@ -19,9 +19,7 @@ .out { margin-top: 24px; - min-height: 40px; - max-height: 300px; - padding: 10px 15px; + padding: 8px 0 0 15px; border: 1px solid #d9d9d9; border-radius: 4px; background-color: #fafafa; diff --git a/spug_web/src/pages/deploy/repository/store.js b/spug_web/src/pages/deploy/repository/store.js index 9b75d05..f6e704e 100644 --- a/spug_web/src/pages/deploy/repository/store.js +++ b/spug_web/src/pages/deploy/repository/store.js @@ -10,7 +10,6 @@ class Store { @observable records = []; @observable record = {}; @observable deploy = {}; - @observable outputs = []; @observable isFetching = false; @observable formVisible = false; @observable addVisible = false;