[X2Go-Commits] python-x2go.git - build-baikal (branch) updated: 0.1.1.4-138-ge6596c5
X2Go dev team
git-admin at x2go.org
Wed Jan 8 15:28:57 CET 2014
The branch, build-baikal has been updated
via e6596c551489ab155e241299d30cc90a74fd25a1 (commit)
from 83b74e308c0b9dfd47c9f8815be2c161e21c7c54 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
-----------------------------------------------------------------------
Summary of changes:
debian/changelog | 2 +
x2go/backends/control/_stdout.py | 155 ++++++++++++++++++++++++++++++++++---
x2go/backends/terminal/_stdout.py | 1 +
x2go/session.py | 35 ++++++---
4 files changed, 171 insertions(+), 22 deletions(-)
The diff of changes is:
diff --git a/debian/changelog b/debian/changelog
index 7e942d1..e92b8d4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -43,6 +43,8 @@ python-x2go (0.1.2.0-0~x2go1) UNRELEASED; urgency=low
- Fix base64 encoded icon string.
- Fix master session recognition.
- Handle empty control session in the session list cache.
+ - Render and cache dictionary based published applications menu tree in
+ Python X2Go. Cache the tree once rendered.
* Depend on python-xlib.
-- Mike Gabriel <mike.gabriel at das-netzwerkteam.de> Sat, 28 Sep 2012 01:44:21 +0100
diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py
index b04dda3..4366f5f 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -30,11 +30,10 @@ import os
import types
import paramiko
import gevent
-
import copy
-
import string
import random
+import re
from gevent import socket
@@ -141,7 +140,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
self.sessions_rootdir = sessions_rootdir
self.ssh_rootdir = ssh_rootdir
- self._published_applications_menu = None
+ self._published_applications_menu = {}
paramiko.SSHClient.__init__(self, *args, **kwargs)
if self.add_to_known_hosts:
@@ -597,16 +596,46 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
return True
return False
- def get_published_applications(self):
+ def get_published_applications(self, lang='en', refresh=False, raw=False, very_raw=False):
"""\
Retrieve the menu tree of published applications from X2Go server.
+ The C{raw} option lets this method return a C{list} of C{dict} elements. Each C{dict} elements has a
+ C{desktop} key containing the text output of a .desktop file and an C{icon} key which contains the desktop
+ icon data base64 encoded.
+
+ The {very_raw} lets this method return the output of the C{x2gogetapps} script as is.
+
+ @param lang: locale/language identifier
+ @type lang: C{str}
+ @param refresh: force reload of the menu tree from X2Go server
+ @type refresh: C{bool}
+ @param raw: retrieve a raw output of the server list of published applications
+ @type raw: C{bool}
+ @param very_raw: retrieve a very raw output of the server list of published applications
+ @type very_raw: C{bool}
+
+ @return: an i18n capable menu tree packed as a Python dictionary
+ @rtype: C{list}
+
"""
+
if 'X2GO_PUBLISHED_APPLICATIONS' in self._x2go_server_features:
- if self._published_applications_menu is None:
+ if self._published_applications_menu is {} or not self._published_applications_menu.has_key(lang) or raw or very_raw or refresh:
+
+ ### STAGE 1: retrieve menu from server
+
self.logger('querying server (%s) for list of published applications' % self.profile_name, loglevel=log.loglevel_NOTICE)
(stdin, stdout, stderr) = self._x2go_exec_command('which x2gogetapps >/dev/null && x2gogetapps')
- _raw_menu_items = stdout.read().split('</desktop>\n')
+ _raw_output = stdout.read()
+
+ if very_raw:
+ self.logger('published applications query for %s finished, return very raw output' % self.profile_name, loglevel=log.loglevel_NOTICE)
+ return _raw_output
+
+ ### STAGE 2: dissect the text file retrieved from server, cut into single menu elements
+
+ _raw_menu_items = _raw_output.split('</desktop>\n')
_raw_menu_items = [ i.replace('<desktop>\n', '') for i in _raw_menu_items ]
_menu = []
for _raw_menu_item in _raw_menu_items:
@@ -621,11 +650,115 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
_menu_item = None
_icon_base64 = None
- self._published_applications_menu = _menu
- self.logger('published applications query for %s finished' % self.profile_name, loglevel=log.loglevel_NOTICE)
- return self._published_applications_menu
- else:
- return self._published_applications_menu
+ if raw:
+ self.logger('published applications query for %s finished, returning raw output' % self.profile_name, loglevel=log.loglevel_NOTICE)
+ return _menu
+
+
+ # STAGE 3: create menu structure in a Python dictionary
+
+ _category_map = {
+ lang: {
+ 'Multimedia': [],
+ 'Development': [],
+ 'Education': [],
+ 'Games': [],
+ 'Graphics': [],
+ 'Internet': [],
+ 'Office': [],
+ 'System': [],
+ 'Utilities': [],
+ 'Other Applications': [],
+ }
+ }
+ _empty_menus = _category_map[lang].keys()
+
+ for item in _menu:
+
+ _menu_entry_name = ''
+ _menu_entry_fallback_name = ''
+ _menu_entry_comment = ''
+ _menu_entry_fallback_comment = ''
+ _menu_entry_exec = ''
+ _menu_entry_cat = ''
+
+ lang_regio = lang
+ lang_only = lang_regio.split('_')[0]
+
+ for line in item['desktop'].split('\n'):
+ if re.match('^Name\[%s\]=.*' % lang_regio, line) or re.match('Name\[%s\]=.*' % lang_only, line):
+ _menu_entry_name = line.split("=")[1].strip()
+ elif re.match('^Comment\[%s\]=.*' % lang_regio, line) or re.match('Comment\[%s\]=.*' % lang_only, line):
+ _menu_entry_comment = line.split("=")[1].strip()
+ elif re.match('^Name=.*', line):
+ _menu_entry_fallback_name = line.split("=")[1].strip()
+ elif re.match('^Comment=.*', line):
+ _menu_entry_fallback_comment = line.split("=")[1].strip()
+ elif re.match('^Exec=.*', line):
+ _menu_entry_exec = line.split("=")[1].strip()
+ elif re.match('^Categories=.*', line):
+ if 'Audio' in line or 'Video' in line:
+ _menu_entry_cat = 'Multimedia'
+ elif 'Development' in line:
+ _menu_entry_cat = 'Development'
+ elif 'Education' in line:
+ _menu_entry_cat = 'Education'
+ elif 'Game' in line:
+ _menu_entry_cat = 'Games'
+ elif 'Graphics' in line:
+ _menu_entry_cat = 'Graphics'
+ elif 'Network' in line:
+ _menu_entry_cat = 'Internet'
+ elif 'Office' in line:
+ _menu_entry_cat = 'Office'
+ elif 'Settings' in line:
+ continue
+ elif 'System' in line:
+ _menu_entry_cat = 'System'
+ elif 'Utilities' in line:
+ _menu_entry_cat = 'Utilities'
+ else:
+ _menu_entry_cat = 'Other Applications'
+
+ if not _menu_entry_exec:
+ continue
+ else:
+ # FIXME: strip off any noted options (%f, %F, %u, %U, ...), this can be more intelligent
+ _menu_entry_exec = _menu_entry_exec.replace('%f', '').replace('%F','').replace('%u','').replace('%U','')
+
+ if not _menu_entry_cat:
+ _menu_entry_cat = 'Other Applications'
+
+ if _menu_entry_cat in _empty_menus:
+ _empty_menus.remove(_menu_entry_cat)
+
+ if not _menu_entry_name: _menu_entry_name = _menu_entry_fallback_name
+ if not _menu_entry_comment: _menu_entry_comment = _menu_entry_fallback_comment
+ if not _menu_entry_comment: _menu_entry_comment = _menu_entry_name
+
+ _menu_entry_icon = item['icon']
+
+ _category_map[lang][_menu_entry_cat].append(
+ {
+ 'name': _menu_entry_name,
+ 'comment': _menu_entry_comment,
+ 'exec': _menu_entry_exec,
+ 'icon': _menu_entry_icon,
+ }
+ )
+
+ for _cat in _empty_menus:
+ del _category_map[lang][_cat]
+
+ for _cat in _category_map[lang].keys():
+ _sorted = sorted(_category_map[lang][_cat], key=lambda k: k['name'])
+ _category_map[lang][_cat] = _sorted
+
+ self._published_applications_menu.update(_category_map)
+ self.logger('published applications query for %s finished, return menu tree' % self.profile_name, loglevel=log.loglevel_NOTICE)
+
+ return self._published_applications_menu
+
else:
# FIXME: ignoring the absence of the published applications feature for now, handle it appropriately later
pass
diff --git a/x2go/backends/terminal/_stdout.py b/x2go/backends/terminal/_stdout.py
index 2155d2c..32798af 100644
--- a/x2go/backends/terminal/_stdout.py
+++ b/x2go/backends/terminal/_stdout.py
@@ -345,6 +345,7 @@ class X2goTerminalSessionSTDOUT(object):
self.release_proxy()
try:
+
if self.control_session.get_transport() is not None:
try:
for _tunnel in [ _tun[1] for _tun in self.reverse_tunnels[self.session_info.name].values() ]:
diff --git a/x2go/session.py b/x2go/session.py
index c966ac9..1079a59 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -724,7 +724,7 @@ class X2goSession(object):
@rtype: C{str}
"""
- if self.terminal_session is not None:
+ if self.has_terminal_session():
return self.terminal_session.session_title
else:
return 'X2GO-%s' % self.get_session_name()
@@ -1225,18 +1225,27 @@ class X2goSession(object):
return self.terminal_session.is_desktop_session()
return False
- def get_published_applications(self):
+ def get_published_applications(self, lang='en', refresh=False, raw=False, very_raw=False):
"""\
Return a list of published menu items from the X2Go server
for session type published applications.
+ @param lang: locale/language identifier
+ @type lang: C{str}
+ @param refresh: force reload of the menu tree from X2Go server
+ @type refresh: C{bool}
+ @param raw: retrieve a raw output of the server list of published applications
+ @type raw: C{bool}
+ @param very_raw: retrieve a very raw output of the server list of published applications (as-is output of x2gogetapps script)
+ @type very_raw: C{bool}
+
@return: A C{list} of C{dict} elements. Each C{dict} elements has a
C{desktop} key containing the text output of a .desktop file and
an C{icon} key which contains the desktop icon data base64 encoded
@rtype: C{list}
"""
- return self.control_session.get_published_applications()
+ return self.control_session.get_published_applications(lang=lang, refresh=refresh, raw=raw, very_raw=very_raw)
def exec_published_application(self, exec_name):
"""\
@@ -1280,7 +1289,7 @@ class X2goSession(object):
try:
if self.published_applications:
- self.published_applications_menu = self.get_published_applications()
+ self.published_applications_menu = gevent.spawn(self.get_published_applications)
except:
# FIXME: test the code to see what exceptions may occur here...
raise
@@ -1303,13 +1312,13 @@ class X2goSession(object):
# only run the session startup command if we do not resume...
if _new_session:
- self.terminal_session.run_command(env=self.session_environment)
+ self.has_terminal_session() and self.terminal_session.run_command(env=self.session_environment)
if self.get_session_cmd() != 'PUBLISHED':
self.published_applications = False
if self._SUPPORTED_SOUND and self.terminal_session.params.snd_system is not 'none':
- self.terminal_session and not self.faulty and self.terminal_session.start_sound()
+ self.has_terminal_session() and not self.faulty and self.terminal_session.start_sound()
else:
self._SUPPORTED_SOUND = False
@@ -1317,7 +1326,7 @@ class X2goSession(object):
if (self._SUPPORTED_PRINTING and self.printing) or \
(self._SUPPORTED_MIMEBOX and self.allow_mimebox) or \
(self._SUPPORTED_FOLDERSHARING and self.allow_share_local_folders):
- self.terminal_session and not self.faulty and self.terminal_session.start_sshfs()
+ self.has_terminal_session() and not self.faulty and self.terminal_session.start_sshfs()
except x2go_exceptions.X2goUserException, e:
self.logger('%s' % str(e), loglevel=log.loglevel_WARN)
self.HOOK_sshfs_not_available()
@@ -1327,8 +1336,8 @@ class X2goSession(object):
try:
if self._SUPPORTED_PRINTING and self.printing:
- self.terminal_session and not self.faulty and self.terminal_session.start_printing()
- self.terminal_session and not self.faulty and self.session_environment.update({'X2GO_SPOOLDIR': self.terminal_session.get_printing_spooldir(), })
+ self.has_terminal_session() and not self.faulty and self.terminal_session.start_printing()
+ self.has_terminal_session() and not self.faulty and self.session_environment.update({'X2GO_SPOOLDIR': self.terminal_session.get_printing_spooldir(), })
except x2go_exceptions.X2goUserException, e:
self.logger('%s' % str(e), loglevel=log.loglevel_WARN)
self.HOOK_printing_not_available()
@@ -1336,8 +1345,8 @@ class X2goSession(object):
try:
if self._SUPPORTED_MIMEBOX and self.allow_mimebox:
- self.terminal_session and not self.faulty and self.terminal_session.start_mimebox(mimebox_extensions=self.mimebox_extensions, mimebox_action=self.mimebox_action)
- self.terminal_session and self.session_environment.update({'X2GO_MIMEBOX': self.terminal_session.get_mimebox_spooldir(), })
+ self.has_terminal_session() and not self.faulty and self.terminal_session.start_mimebox(mimebox_extensions=self.mimebox_extensions, mimebox_action=self.mimebox_action)
+ self.has_terminal_session() and self.session_environment.update({'X2GO_MIMEBOX': self.terminal_session.get_mimebox_spooldir(), })
except x2go_exceptions.X2goUserException, e:
self.logger('%s' % str(e), loglevel=log.loglevel_WARN)
self.HOOK_mimebox_not_available()
@@ -1471,6 +1480,8 @@ class X2goSession(object):
self.terminated = False
self.faults = False
self.session_cleanup()
+ del self.terminal_session
+ self.terminal_session = None
return True
elif self.has_control_session() and self.session_name:
@@ -1512,6 +1523,8 @@ class X2goSession(object):
self.terminated = True
self.faulty = False
self.session_cleanup()
+ del self.terminal_session
+ self.terminal_session = None
return True
elif self.has_control_session() and self.session_name:
hooks/post-receive
--
python-x2go.git (Python X2Go Client API)
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-x2go.git" (Python X2Go Client API).
More information about the x2go-commits
mailing list