Disable the PSQL tool for Windows, the 'fcntl' module is not working on Windows.

This commit is contained in:
Nikhil Mohite 2021-06-01 20:04:43 +05:30 committed by Akshay Joshi
parent 9ac08c263b
commit e0eac875b6
18 changed files with 175 additions and 101 deletions

View File

@ -851,7 +851,8 @@ def utils():
app_version_int=config.APP_VERSION_INT, app_version_int=config.APP_VERSION_INT,
pg_libpq_version=pg_libpq_version, pg_libpq_version=pg_libpq_version,
support_ssh_tunnel=config.SUPPORT_SSH_TUNNEL, support_ssh_tunnel=config.SUPPORT_SSH_TUNNEL,
logout_url=_get_logout_url() logout_url=_get_logout_url(),
platform=sys.platform
), ),
200, {'Content-Type': MIMETYPE_APP_JS}) 200, {'Content-Type': MIMETYPE_APP_JS})

View File

@ -6,6 +6,7 @@
# This software is released under the PostgreSQL Licence # This software is released under the PostgreSQL Licence
# #
########################################################################## ##########################################################################
import sys
from flask_babelex import gettext from flask_babelex import gettext
from pgadmin.utils.constants import PREF_LABEL_DISPLAY,\ from pgadmin.utils.constants import PREF_LABEL_DISPLAY,\
PREF_LABEL_KEYBOARD_SHORTCUTS, PREF_LABEL_TABS_SETTINGS, \ PREF_LABEL_KEYBOARD_SHORTCUTS, PREF_LABEL_TABS_SETTINGS, \
@ -505,6 +506,7 @@ def register_browser_preferences(self):
) )
) )
if sys.platform != 'win32':
self.open_in_new_tab = self.preference.register( self.open_in_new_tab = self.preference.register(
'tab_settings', 'new_browser_tab_open', 'tab_settings', 'new_browser_tab_open',
gettext("Open in new browser tab"), 'select2', None, gettext("Open in new browser tab"), 'select2', None,
@ -514,7 +516,8 @@ def register_browser_preferences(self):
{'label': gettext('Schema Diff'), 'value': 'schema_diff'}, {'label': gettext('Schema Diff'), 'value': 'schema_diff'},
{'label': gettext('ERD Tool'), 'value': 'erd_tool'}, {'label': gettext('ERD Tool'), 'value': 'erd_tool'},
{'label': gettext('PSQL Tool'), 'value': 'psql_tool'}], {'label': gettext('PSQL Tool'), 'value': 'psql_tool'}],
help_str=gettext('Select Query Tool, Debugger, Schema Diff, ERD Tool ' help_str=gettext(
'Select Query Tool, Debugger, Schema Diff, ERD Tool '
'or PSQL Tool from the drop-down to set ' 'or PSQL Tool from the drop-down to set '
'open in new browser tab for that particular module.' 'open in new browser tab for that particular module.'
), ),
@ -533,9 +536,31 @@ def register_browser_preferences(self):
'text', '%DATABASE%/%USERNAME%@%SERVER%', 'text', '%DATABASE%/%USERNAME%@%SERVER%',
category_label=PREF_LABEL_DISPLAY, category_label=PREF_LABEL_DISPLAY,
help_str=gettext( help_str=gettext(
'Supported placeholders are %DATABASE%, %USERNAME%, and %SERVER%. ' 'Supported placeholders are %DATABASE%, %USERNAME%, '
'Users can provide any string with or without placeholders of' 'and %SERVER%. Users can provide any string with or without'
' their choice. The blank title will be revert back to the' ' placeholders of their choice. The blank title will be revert'
' default title with placeholders.' ' back to the default title with placeholders.'
) )
) )
else:
self.open_in_new_tab = self.preference.register(
'tab_settings', 'new_browser_tab_open',
gettext("Open in new browser tab"), 'select2', None,
category_label=PREF_LABEL_OPTIONS,
options=[{'label': gettext('Query Tool'), 'value': 'qt'},
{'label': gettext('Debugger'), 'value': 'debugger'},
{'label': gettext('Schema Diff'), 'value': 'schema_diff'},
{'label': gettext('ERD Tool'), 'value': 'erd_tool'}],
help_str=gettext(
'Select Query Tool, Debugger, Schema Diff, ERD Tool '
'or PSQL Tool from the drop-down to set '
'open in new browser tab for that particular module.'
),
select2={
'multiple': True, 'allowClear': False,
'tags': True, 'first_empty': False,
'selectOnClose': False, 'emptyOptions': True,
'tokenSeparators': [','],
'placeholder': gettext('Select open new tab...')
}
)

View File

@ -66,6 +66,7 @@ define([
}]); }]);
// show psql tool same as query tool. // show psql tool same as query tool.
if(pgAdmin['enable_psql'] && pgAdmin['platform'] != 'win32') {
pgAdmin.Browser.add_menus([{ pgAdmin.Browser.add_menus([{
name: 'show_psql_tool', node: this.type, module: this, name: 'show_psql_tool', node: this.type, module: this,
applies: ['context'], callback: 'show_psql_tool', applies: ['context'], callback: 'show_psql_tool',
@ -74,6 +75,7 @@ define([
}]); }]);
} }
} }
}
}, },
hasId: false, hasId: false,

View File

@ -210,7 +210,7 @@ define('pgadmin.browser.node', [
icon: 'fa fa-search', enable: enable, icon: 'fa fa-search', enable: enable,
}]); }]);
if(pgAdmin['enable_psql']) { if(pgAdmin['enable_psql'] && pgAdmin['platform'] != 'win32') {
// show psql tool same as query tool. // show psql tool same as query tool.
pgAdmin.Browser.add_menus([{ pgAdmin.Browser.add_menus([{
name: 'show_psql_tool', node: this.type, module: this, name: 'show_psql_tool', node: this.type, module: this,

View File

@ -59,7 +59,7 @@ let _defaultToolBarButtons = [
} }
]; ];
if(pgAdmin['enable_psql']) { if(pgAdmin['enable_psql'] && pgAdmin['platform'] != 'win32') {
_defaultToolBarButtons.unshift({ _defaultToolBarButtons.unshift({
label: gettext('PSQL Tool'), label: gettext('PSQL Tool'),
ariaLabel: gettext('PSQL Tool'), ariaLabel: gettext('PSQL Tool'),
@ -119,7 +119,7 @@ export function initializeToolbar(panel, wcDocker) {
pgAdmin.DataGrid.show_filtered_row({mnuid: 4}, pgAdmin.Browser.tree.selected()); pgAdmin.DataGrid.show_filtered_row({mnuid: 4}, pgAdmin.Browser.tree.selected());
else if ('name' in data && data.name === gettext('Search objects')) else if ('name' in data && data.name === gettext('Search objects'))
pgAdmin.SearchObjects.show_search_objects('', pgAdmin.Browser.tree.selected()); pgAdmin.SearchObjects.show_search_objects('', pgAdmin.Browser.tree.selected());
else if ('name' in data && data.name === gettext('PSQL Tool')){ else if ('name' in data && data.name === gettext('PSQL Tool') && pgAdmin['platform'] != 'win32'){
var input = {}, var input = {},
t = pgAdmin.Browser.tree, t = pgAdmin.Browser.tree,
i = input.item || t.selected(), i = input.item || t.selected(),

View File

@ -54,6 +54,8 @@ define('pgadmin.browser.utils',
/* GET PSQL Tool related config */ /* GET PSQL Tool related config */
pgAdmin['enable_psql'] = '{{ current_app.config.get('ENABLE_PSQL') }}' == 'True'; pgAdmin['enable_psql'] = '{{ current_app.config.get('ENABLE_PSQL') }}' == 'True';
pgAdmin['allow_psql_shell_commands'] = '{{ current_app.config.get('ALLOW_PSQL_SHELL_COMMANDS') }}' == 'True';
pgAdmin['platform'] = '{{platform}}';
// Define list of nodes on which Query tool option doesn't appears // Define list of nodes on which Query tool option doesn't appears
var unsupported_nodes = pgAdmin.unsupported_nodes = [ var unsupported_nodes = pgAdmin.unsupported_nodes = [

View File

@ -1,35 +1,35 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import fcntl
import os import os
import pty
import re import re
import select import select
import struct import struct
import termios
import config import config
from sys import platform as _platform
import eventlet.green.subprocess as subprocess import eventlet.green.subprocess as subprocess
from config import PG_DEFAULT_DRIVER from config import PG_DEFAULT_DRIVER
from flask import Response, url_for, request from flask import Response, url_for, request
from flask import render_template, copy_current_request_context, \ from flask import render_template, copy_current_request_context, \
current_app as app current_app as app
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import login_required, current_user from flask_security import login_required, current_user
from pgadmin.browser.utils import underscore_unescape from pgadmin.browser.utils import underscore_unescape, underscore_escape
from pgadmin.utils import PgAdminModule from pgadmin.utils import PgAdminModule
from pgadmin.utils.constants import MIMETYPE_APP_JS from pgadmin.utils.constants import MIMETYPE_APP_JS
from pgadmin.utils.driver import get_driver from pgadmin.utils.driver import get_driver
from ... import socketio as sio from ... import socketio as sio
from pgadmin.utils import get_complete_file_path from pgadmin.utils import get_complete_file_path
from pgadmin.utils.ajax import internal_server_error
if _platform != 'win32':
import fcntl
import termios
import pty
session_input = dict() session_input = dict()
session_input_cursor = dict() session_input_cursor = dict()
session_last_cmd = dict() session_last_cmd = dict()
pdata = dict() pdata = dict()
cdata = dict() cdata = dict()
_NODES_SQL = 'nodes.sql'
class PSQLModule(PgAdminModule): class PSQLModule(PgAdminModule):
@ -225,8 +225,10 @@ def start_process(data):
""" """
@copy_current_request_context @copy_current_request_context
def read_and_forward_pty_output(sid, data): def read_and_forward_pty_output(sid, data):
max_read_bytes = 1024 * 20 max_read_bytes = 1024 * 20
if _platform != 'win32':
p, parent, fd = create_pty_terminal(connection_data) p, parent, fd = create_pty_terminal(connection_data)
while p and p.poll() is None: while p and p.poll() is None:
@ -246,6 +248,12 @@ def start_process(data):
timeout) timeout)
read_terminal_data(parent, data_ready, max_read_bytes, sid) read_terminal_data(parent, data_ready, max_read_bytes, sid)
else:
sio.emit(
'conn_error',
{
'error': 'PSQL tool not supported.',
}, namespace='/pty', room=request.sid)
# Check user is authenticated and PSQL is enabled in config. # Check user is authenticated and PSQL is enabled in config.
if current_user.is_authenticated and config.ENABLE_PSQL: if current_user.is_authenticated and config.ENABLE_PSQL:
@ -255,6 +263,8 @@ def start_process(data):
if data['db']: if data['db']:
db = underscore_unescape(data['db']).replace('\\', "\\\\") db = underscore_unescape(data['db']).replace('\\', "\\\\")
data['db'] = db
conn, manager = _get_connection(int(data['sid']), data) conn, manager = _get_connection(int(data['sid']), data)
psql_utility = manager.utility('sql') psql_utility = manager.utility('sql')
connection_data = get_connection_str(psql_utility, db, connection_data = get_connection_str(psql_utility, db,
@ -348,15 +358,15 @@ def get_conn_str(manager, db):
""" """
manager.export_password_env('PGPASSWORD') manager.export_password_env('PGPASSWORD')
conn_attr =\ conn_attr =\
"host={0} port={1} dbname={2} user={3} sslmode={4} " \ 'host={0} port={1} dbname={2} user={3} sslmode={4} ' \
"sslcompression={5} " \ 'sslcompression={5} ' \
"".format( ''.format(
manager.local_bind_host if manager.use_ssh_tunnel else manager.local_bind_host if manager.use_ssh_tunnel else
manager.host, manager.host,
manager.local_bind_port if manager.use_ssh_tunnel else manager.local_bind_port if manager.use_ssh_tunnel else
manager.port, manager.port,
db if db != '' else 'postgres', underscore_unescape(db) if db != '' else 'postgres',
manager.user if manager.user else 'postgres', underscore_unescape(manager.user) if manager.user else 'postgres',
manager.ssl_mode, manager.ssl_mode,
True if manager.sslcompression else False, True if manager.sslcompression else False,
) )
@ -423,7 +433,6 @@ def invalid_cmd():
:rtype: :rtype:
""" """
session_last_cmd[request.sid]['invalid_cmd'] = True session_last_cmd[request.sid]['invalid_cmd'] = True
for i in range(len(session_input[request.sid])): for i in range(len(session_input[request.sid])):
os.write(app.config['sessions'][request.sid], os.write(app.config['sessions'][request.sid],
'\b \b'.encode()) '\b \b'.encode())
@ -455,6 +464,7 @@ def check_valid_cmd(user_input):
if stop_execution: if stop_execution:
session_last_cmd[request.sid]['invalid_cmd'] = True session_last_cmd[request.sid]['invalid_cmd'] = True
# Remove already added command from terminal. # Remove already added command from terminal.
for i in range(len(user_input)): for i in range(len(user_input)):
os.write(app.config['sessions'][request.sid], os.write(app.config['sessions'][request.sid],
@ -482,6 +492,7 @@ def enter_key_press(data):
# contains \! in input. # contains \! in input.
is_new_connection = session_last_cmd[request.sid][ is_new_connection = session_last_cmd[request.sid][
'is_new_connection'] 'is_new_connection']
if user_input.startswith('\\!') and re.match("^\\\!$", user_input) and len( if user_input.startswith('\\!') and re.match("^\\\!$", user_input) and len(
user_input) == 2 and not config.ALLOW_PSQL_SHELL_COMMANDS \ user_input) == 2 and not config.ALLOW_PSQL_SHELL_COMMANDS \
and not is_new_connection: and not is_new_connection:
@ -490,7 +501,8 @@ def enter_key_press(data):
not config.ALLOW_PSQL_SHELL_COMMANDS and\ not config.ALLOW_PSQL_SHELL_COMMANDS and\
not session_last_cmd[request.sid]['is_new_connection']: not session_last_cmd[request.sid]['is_new_connection']:
check_valid_cmd(user_input) check_valid_cmd(user_input)
elif user_input == '\q' or user_input == 'q\\q': elif user_input == '\q' or user_input == 'q\\q' or \
user_input in ['exit', 'exit;']:
# If user enter \q to terminate the PSQL, emit the msg to # If user enter \q to terminate the PSQL, emit the msg to
# notify user connection is terminated. # notify user connection is terminated.
sio.emit('pty-output', sio.emit('pty-output',
@ -501,6 +513,7 @@ def enter_key_press(data):
' tool.'), ' tool.'),
'error': True}, 'error': True},
namespace='/pty', room=request.sid) namespace='/pty', room=request.sid)
os.write(app.config['sessions'][request.sid], os.write(app.config['sessions'][request.sid],
'\n'.encode()) '\n'.encode())

View File

@ -54,7 +54,7 @@ export function initialize(gettext, url_for, $, _, pgAdmin, csrfToken, Browser)
}]; }];
this.enable_psql_tool = pgAdmin['enable_psql']; this.enable_psql_tool = pgAdmin['enable_psql'];
if(pgAdmin['enable_psql']) { if(pgAdmin['enable_psql'] && pgAdmin['platform'] != 'win32') {
pgBrowser.add_menus(menus); pgBrowser.add_menus(menus);
} }

View File

@ -23,6 +23,7 @@
require( require(
['sources/generated/psql_tool'], ['sources/generated/psql_tool'],
function(pgBrowser) { function(pgBrowser) {
if (self.pgAdmin['platform'] != 'win32') {
const term = self.pgAdmin.Browser.psql.psql_terminal(); const term = self.pgAdmin.Browser.psql.psql_terminal();
<!--Addon for fitAddon, webLinkAddon, SearchAddon --> <!--Addon for fitAddon, webLinkAddon, SearchAddon -->
const fitAddon = self.pgAdmin.Browser.psql.psql_Addon(term); const fitAddon = self.pgAdmin.Browser.psql.psql_Addon(term);
@ -53,6 +54,9 @@ require(
const wait_ms = 50;; const wait_ms = 50;;
window.onresize = debounce(fitToscreen, wait_ms) window.onresize = debounce(fitToscreen, wait_ms)
} else {
document.getElementById('psql-terminal').innterHTML = 'PSQL not supported'
}
}); });
{% endblock %} {% endblock %}

View File

@ -1,5 +1,6 @@
import uuid import uuid
import config import config
import sys
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict from regression import parent_node_dict
@ -24,6 +25,8 @@ class PSQLBackend(BaseTestGenerator):
self.server_con = server_utils.connect_server(self, self.sid) self.server_con = server_utils.connect_server(self, self.sid)
def runTest(self): def runTest(self):
if sys.platform == 'win32':
self.skipTest('PSQL disabled for windows')
# Fetch flask client to access current user and other cookies. # Fetch flask client to access current user and other cookies.
flask_client = app.test_client() flask_client = app.test_client()
flask_client.get('/') flask_client.get('/')

View File

@ -1,5 +1,6 @@
import uuid import uuid
import random import random
import sys
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict from regression import parent_node_dict
@ -16,6 +17,8 @@ class PSQLPanel(BaseTestGenerator):
self.theme = 'standard' self.theme = 'standard'
def runTest(self): def runTest(self):
if sys.platform == 'win32':
self.skipTest('PSQL disabled for windows')
trans_id = random.randint(1, 9999999) trans_id = random.randint(1, 9999999)
url = '/psql/panel/{trans_id}?sgid={sgid}&sid={sid}&did={did}' \ url = '/psql/panel/{trans_id}?sgid={sgid}&sid={sid}&did={did}' \
'&server_type=pg&db={db_name}&theme={theme}'.\ '&server_type=pg&db={db_name}&theme={theme}'.\

View File

@ -1,5 +1,6 @@
import uuid import uuid
import config import config
import sys
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict from regression import parent_node_dict
@ -17,6 +18,8 @@ class PSQLSocketDisabled(BaseTestGenerator):
config.ENABLE_PSQL = False config.ENABLE_PSQL = False
def runTest(self): def runTest(self):
if sys.platform == 'win32':
self.skipTest('PSQL disabled for windows')
self.test_client = socketio.test_client(app, namespace='/pty') self.test_client = socketio.test_client(app, namespace='/pty')
self.assertTrue(self.test_client.is_connected('/pty')) self.assertTrue(self.test_client.is_connected('/pty'))
received = self.test_client.get_received('/pty') received = self.test_client.get_received('/pty')

View File

@ -1,5 +1,6 @@
import uuid import uuid
import config import config
import sys
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict from regression import parent_node_dict
@ -24,6 +25,8 @@ class PSQLInput(BaseTestGenerator):
self.server_con = server_utils.connect_server(self, self.sid) self.server_con = server_utils.connect_server(self, self.sid)
def runTest(self): def runTest(self):
if sys.platform == 'win32':
self.skipTest('PSQL disabled for windows')
# Fetch flask client to access current user and other cookies. # Fetch flask client to access current user and other cookies.
flask_client = app.test_client() flask_client = app.test_client()
flask_client.get('/') flask_client.get('/')

View File

@ -1,5 +1,6 @@
import uuid import uuid
import config import config
import sys
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict from regression import parent_node_dict
@ -24,6 +25,8 @@ class PSQLResizeTerminal(BaseTestGenerator):
self.server_con = server_utils.connect_server(self, self.sid) self.server_con = server_utils.connect_server(self, self.sid)
def runTest(self): def runTest(self):
if sys.platform == 'win32':
self.skipTest('PSQL disabled for windows')
# Fetch flask client to access current user and other cookies. # Fetch flask client to access current user and other cookies.
flask_client = app.test_client() flask_client = app.test_client()
flask_client.get('/') flask_client.get('/')

View File

@ -1,5 +1,6 @@
import uuid import uuid
import config import config
import sys
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict from regression import parent_node_dict
@ -17,6 +18,8 @@ class PSQLSocketConnect(BaseTestGenerator):
config.ENABLE_PSQL = True config.ENABLE_PSQL = True
def runTest(self): def runTest(self):
if sys.platform == 'win32':
self.skipTest('PSQL disabled for windows')
self.test_client = socketio.test_client(app, namespace='/pty') self.test_client = socketio.test_client(app, namespace='/pty')
self.assertTrue(self.test_client.is_connected('/pty')) self.assertTrue(self.test_client.is_connected('/pty'))
received = self.test_client.get_received('/pty') received = self.test_client.get_received('/pty')

View File

@ -1,5 +1,6 @@
import uuid import uuid
import config import config
import sys
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict from regression import parent_node_dict
@ -17,6 +18,8 @@ class PSQLSocketDisconnect(BaseTestGenerator):
config.ENABLE_PSQL = True config.ENABLE_PSQL = True
def runTest(self): def runTest(self):
if sys.platform == 'win32':
self.skipTest('PSQL disabled for windows')
# Fetch flask client to access current user and other cookies. # Fetch flask client to access current user and other cookies.
flask_test_client = app.test_client() flask_test_client = app.test_client()
flask_test_client.get('/') flask_test_client.get('/')

View File

@ -1,5 +1,6 @@
import uuid import uuid
import config import config
import sys
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict from regression import parent_node_dict
@ -21,6 +22,8 @@ class PSQLStartProcess(BaseTestGenerator):
self.server_con = server_utils.connect_server(self, self.sid) self.server_con = server_utils.connect_server(self, self.sid)
def runTest(self): def runTest(self):
if sys.platform == 'win32':
self.skipTest('PSQL disabled for windows')
# Fetch flask client to access current user and other cookies. # Fetch flask client to access current user and other cookies.
flask_client = app.test_client() flask_client = app.test_client()
flask_client.get('/') flask_client.get('/')

View File

@ -1,5 +1,6 @@
import uuid import uuid
import config import config
import sys
from pgadmin.utils.route import BaseTestGenerator from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict from regression import parent_node_dict
@ -17,6 +18,8 @@ class PSQLStartProcessFail(BaseTestGenerator):
config.ENABLE_PSQL = True config.ENABLE_PSQL = True
def runTest(self): def runTest(self):
if sys.platform == 'win32':
self.skipTest('PSQL disabled for windows')
self.test_client = socketio.test_client(app, namespace='/pty') self.test_client = socketio.test_client(app, namespace='/pty')
self.assertTrue(self.test_client.is_connected('/pty')) self.assertTrue(self.test_client.is_connected('/pty'))
received = self.test_client.get_received('/pty') received = self.test_client.get_received('/pty')