Browse Source

Rewrite to 3.1

master3.3
parent
commit
31de24cf5a
  1. 4
      README
  2. 11
      data/gtkbg
  3. 7
      data/login.d/00init
  4. 7
      data/logout.d/00init
  5. 2
      data/xdm
  6. 0
      desktop/__init__.py
  7. 306
      desktop/cl_desktop.py
  8. 85
      desktop/cl_wsdl_desktop.py
  9. 34
      desktop/datavars.py
  10. 20
      desktop/variables/__init__.py
  11. 60
      desktop/variables/action.py
  12. 150
      desktop/variables/desktop.py
  13. 327
      pym/cl_desktop.py
  14. 154
      pym/cl_desktop_cmd.py
  15. 111
      pym/cl_fill_desktop.py
  16. 80
      pym/cl_share_cmd.py
  17. 92
      pym/cl_vars_desktop.py
  18. 69
      scripts/cl-desktop
  19. 5
      setup.cfg
  20. 59
      setup.py

4
README

@ -4,10 +4,10 @@ INSTALL
-------
calculate-desktop needs the following library version installed, in order to run:
Python >= 2.5
Python >= 2.7
python-ldap >= 2.0.0
pyxml >= 0.8
calculate-lib >= 2.2.24
calculate-lib >= 3.0.0
To install calculate-desktop, just execute the install script 'setup.py'.
Example:

11
data/gtkbg

@ -21,6 +21,15 @@ import sys
import re
import subprocess
def select_color():
try:
if filter(re.compile(r"(cld|cldx|cldg|cmc|cls)-themes-12").search,
os.listdir('/var/db/pkg/media-gfx')):
return "#73a363"
except:
pass
return '#30648b'
if __name__ == "__main__":
if gtk.gdk.get_display():
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
@ -43,7 +52,7 @@ if __name__ == "__main__":
window.set_border_width(0)
window.modify_bg(gtk.STATE_NORMAL,
gtk.gdk.rgb_get_colormap().alloc_color('#30648b'))
gtk.gdk.rgb_get_colormap().alloc_color(select_color()))
window.show()
pid = os.fork()

7
data/login.d/00init

@ -14,7 +14,12 @@
# limitations under the License.
# set background color
xsetroot -solid rgb:30/64/8b
if ls /var/db/pkg/media-gfx/cld[-gx]*themes-12* &>/dev/null
then
xsetroot -solid rgb:73/a3/63
else
xsetroot -solid rgb:30/64/8b
fi
if [[ "`ps axeo command | grep 'xdm/xdm --logout' | grep -v grep | \
sed -n -r 's/.* USER=([^ ]+) .*/\1/p'`" == "$USER" ]];

7
data/logout.d/00init

@ -14,5 +14,10 @@
# limitations under the License.
# set background color
xsetroot -solid rgb:30/64/8b
if ls /var/db/pkg/media-gfx/cld[-gx]*themes-12* &>/dev/null
then
xsetroot -solid rgb:73/a3/63
else
xsetroot -solid rgb:30/64/8b
fi
exit 0

2
data/xdm

@ -64,7 +64,7 @@ die_xmes() {
}
gtk_background(){
if [[ -n $(env | grep RUNNING_UNDER_GDM=true) ]];
if [[ -n $(env | grep RUNNING_UNDER_GDM=true) ]] && ls /var/db/pkg/gnome-base/gdm-2* &>/dev/null;
then
/usr/bin/env python2 /usr/share/calculate/xdm/gtkbg
BG_PID=$(ps ax | sed -nr "s/^\s*([0-9]+)\s.*gtkbg$/\1/p")

0
pym/__init__.py → desktop/__init__.py

306
desktop/cl_desktop.py

@ -0,0 +1,306 @@
#-*- coding: utf-8 -*-
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from os import path
import re
import sys
import pwd
import time
import traceback
from datavars import DataVarsDesktop, DataVars, __version__,__app__
from calculate.lib.cl_template import Template, ProgressTemplate,TemplatesError
from calculate.lib.utils.files import runOsCommand
from calculate.lib.utils.common import getpathenv,appendProgramToEnvFile, \
removeProgramToEnvFile
from calculate.core.server.func import safetyWrapper
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class DesktopError(Exception):
"""Desktop Error"""
class share:
"""Общие методы"""
# Объект хранения переменных
clVars = False
def isRoot(self, printError=True):
"""Определяет является ли пользователь root"""
if os.getuid() == 0 and os.getgid() == 0:
return True
else:
if printError:
self.printERROR(_("The user is not root"))
return False
def createClVars(self, clVars=False):
"""Создает объект Vars"""
if not clVars:
clVars = DataVarsDesktop()
# Импортируем переменные
clVars.importDesktop()
# Заменяем значения переменных переменными из env файлов
clVars.flIniFile()
# Устанавливаем у объекта атрибут объект переменных
self.clVars = clVars
return True
def applyTemplatesFromSystem(self):
"""Применяем шаблоны для cистемы"""
# Cоздаем объект обработки шаблонов
clTempl = template(self.clVars)
# Объединяем шаблоны
dirsFiles = clTempl.applyTemplates()
if clTempl.getError():
self.printERROR(clTempl.getError().strip())
return False
else:
return dirsFiles
class Desktop(share):
"""Методы работы с профилем пользователя"""
# Имя пользователя
userName = ""
verbose = False
def __init__(self):
self.homeDir = ""
self.clTempl = None
self.clVars = None
# def installProg(self,dv):
# """Наложение шаблонов на систему при инсталяции"""
# # Проверяем на root
# if not self.isRoot():
# return False
# self.clVars.AppendToList("cl_merges", __app__, force=True)
# # Действие инсталяция
# self.clVars.Set("cl_action", "install", True)
# if not self.applyTemplatesFromSystem():
# raise DesktopError(_("Failed to apply install templates"))
# # Добавление программы в инсталяционную переменную
# if not appendProgramToEnvFile(__app__, self.clVars):
# self.printERROR(_("Failed to save '%s'") %__app__ + " " +\
# _("to %s") %self.clVars.Get("cl_env_path")[0])
# return False
# self.printOK(_("Install templates applied"))
# return True
#
# def uninstallProg(self):
# """Наложение шаблонов на систему при деинсталяции"""
# # Проверяем на root
# if not self.isRoot():
# return False
# # Действие деинсталяция
# self.clVars.Set("cl_action", "uninstall", True)
# if not self.applyTemplatesFromSystem():
# self.printERROR(_("Failed to apply uninstall templates"))
# return False
# # Удаление программы из инсталяционной переменной
# if not removeProgramToEnvFile(__app__, self.clVars):
# self.printERROR(_("Failed to remove '%(app)s' from %(path)s")%
# {'app':__app__,
# 'path': self.clVars.Get("cl_env_path")[0]})
# return False
# self.printOK(_("Uninstall templates applied"))
# return True
def createUserDir(self, uid, gid, userDir, mode=0700):
"""
Create user directory with need uid and gid
"""
if not path.exists(userDir):
os.makedirs(userDir)
if mode:
os.chmod(userDir,mode)
os.chown(userDir,uid,gid)
return True
else:
raise DesktopError(_("Path %s exists") %userDir)
def displayTemplatesApplied(self,dirsFiles):
"""
Display templates are applied (--verbose)
"""
self.printWARNING(_("The following files were changed")+":")
for nameF in dirsFiles[1]:
nameFile = nameF
if nameFile[:1] != "/":
nameFile = "/" + nameFile
self.printWARNING(" "*5 + nameFile)
def applyTemplatesFromUser(self):
"""Применяем шаблоны для пользователя"""
if self.clTempl:
self.closeClTemplate()
self.clTempl = ProgressTemplate(self.setProgress,self.clVars,
cltObj=False)
dirsFiles = self.clTempl.applyTemplates()
if self.clTempl.getError():
self.printERROR(self.clTempl.getError().strip())
return False
else:
if self.verbose:
self.displayTemplatesApplied(dirsFiles)
return dirsFiles
def initVars(self,datavars=None):
"""Primary variables initialization"""
if not datavars:
self.clVars = DataVarsDesktop()
self.clVars.importDesktop()
self.clVars.flIniFile()
else:
self.clVars = datavars
def closeClTemplate(self):
if self.clTempl:
if self.clTempl.cltObj:
self.clTempl.cltObj.closeFiles()
self.clTempl.closeFiles()
self.clTempl = None
def umountUserRes(self, error):
"""Отмонтируем пользовательские директории если они есть"""
self.closeClTemplate()
if error and self.homeDir:
umountPaths = self.getMountUserPaths(self.homeDir)
ret = True
for umountPath in umountPaths:
if not self.umountSleepPath(umountPath):
ret = False
break
return ret
@safetyWrapper(native_errors=(TemplatesError,DesktopError),
man_int=__("Configuration manually interrupted"),
post_action=umountUserRes)
def createHome(self, datavars=None):
"""
Creating user profile and userdir
"""
self.initVars(datavars)
self.verbose = self.clVars.Get('cl_verbose_set') == 'on'
#uid = os.getuid()
#try:
# realUserName = pwd.getpwuid(uid).pw_name
#except:
# realUserName = ""
userName = self.clVars.Get("ur_login")
#if userName != realUserName and not self.isRoot():
# return False
uidGid = False
if self.clVars.isModuleInstalled("client"):
import ipdb
ipdb.set_trace()
# domain host
domain = self.clVars.Get("client.cl_remote_host")
# authorized in domain or local
hostAuth = self.clVars.Get("client.os_remote_auth")
else:
domain = ""
hostAuth = ""
uid = self.clVars.Get('ur_uid')
gid = self.clVars.Get('ur_gid')
if not uid or not gid:
raise DesktopError(_("Failed to determine user UID"))
uid,gid = int(uid),int(gid)
self.homeDir = self.clVars.Get('ur_home_path')
rootPath = self.clVars.Get('cl_root_path')
# real path to home dir
self.homeDir = path.join(rootPath, self.homeDir[1:])
if not path.exists(self.homeDir):
self.startTask(_("Creating the home directory for %s")%self.homeDir)
self.createUserDir(uid,gid,self.homeDir)
self.endTask()
# Действие - шаблоны пользователя
self.clVars.Set("cl_action", "desktop", True)
# Применяем профили для пользователя
self.startTask(_("Setting up the user profile"),progress=True)
dirsAndFiles = self.applyTemplatesFromUser()
self.endTask()
if not dirsAndFiles:
# Отмонтируем пользовательские ресурсы в случае ошибки
raise DesktopError(_("Failed to apply user profile templates"))
self.printSUCCESS(_("User account %s is configured")%userName + " ...")
return True
def getMountUserPaths(self, homeDir=False):
"""Находит пользовательские примонтированные пути"""
# Имя пользователя
if not homeDir:
userName = self.clVars.Get("ur_login")
homeDir = self.clVars.Get("ur_home_path")
if not homeDir:
raise DesktopError(_("Failed to determine home directory"))
dirStart, dirEnd = path.split(homeDir)
mountProfileDir = path.join(dirStart, ".%s" %dirEnd)
mountRemoteProfileDir = path.join(dirStart, ".%s.remote" %dirEnd)
return filter(lambda x: x.startswith(homeDir) or\
x.startswith(mountProfileDir) or\
x.startswith(mountRemoteProfileDir),
map(lambda x: x.split(" ")[1],\
open("/proc/mounts").readlines()))
def execProg(self, cmdStrProg, inStr=False, envProg={}):
"""Выполняет внешнюю программу
Параметры:
cmdStrProg внешняя программа
inStr данные передаваемые программе на страндартный вход.
Возвращаемые параметры:
строки которые выведет внешняя программа или False в случае ошибки
"""
env_path = {"PATH":getpathenv()}
env = {}
env.update(os.environ.items() + env_path.items() + envProg.items())
retCode,programOut = runOsCommand(cmdStrProg,in_str=inStr,env_dict=env)
if not retCode:
return programOut
return False
def umountSleepPath(self, umountpath):
"""Отмонтирует путь при неудаче задержка потом повтор"""
# Задержки при отмонтированиии директории
sleeps = [0.5, 2, 5]
# Проверяем на монтирование директорию
if path.ismount(umountpath):
textLine = self.execProg("umount %s"%umountpath)
if textLine is False:
i = 0
flagError = False
while (i<len(sleeps) and textLine is False):
# Задержка перед следующей попыткой
time.sleep(sleeps[i])
# Отмонтируем Samba ресурс
if path.ismount(umountpath):
textLine = self.execProg("umount %s"%umountpath)
else:
textLine = True
break
i += 1
if textLine is False:
self.printERROR(_("Failed to unmount path %s")%
umountpath + " ...")
return False
return True

85
desktop/cl_wsdl_desktop.py

@ -0,0 +1,85 @@
# Copyright 2012 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import soaplib, sys, time, os
import threading
from soaplib.serializers.primitive import String, Integer, Any, Boolean
from soaplib.serializers.clazz import Array, ClassSerializer
from soaplib.service import rpc, DefinitionBase
from calculate.core.server.api_types import ReturnedMessage
from calculate.core.server.api_types import ChoiceValue, Table, Option, Field, \
GroupField, ViewInfo, ViewParams
from calculate.lib.datavars import VariableError,DataVarsError
from calculate.desktop.cl_desktop import DesktopError
from cl_desktop import Desktop,DataVarsDesktop
import cl_desktop
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
from calculate.core.server.decorators import Dec
from calculate.core.server.func import catchExcept
core_method = Dec.core_method
setLocalTranslate('cl_desktop3',sys.modules[__name__])
import traceback
from functools import wraps,WRAPPER_ASSIGNMENTS
__ = getLazyLocalTranslate(_)
class DesktopInfo(ClassSerializer):
"""Parameters for method install"""
ur_login = String
cl_verbose_set = String
Default = Array(String)
CheckOnly = Boolean
CheckAll = Boolean
desktopCatchExcept = catchExcept(VariableError,DataVarsError,
cl_desktop.DesktopError)
class Wsdl:
"""
cl-desktop
"""
@rpc(Integer, DesktopInfo, _returns = Array(ReturnedMessage))
@core_method(category=__('Desktop'),title=__('Configure user'),
image='applications-other',
gui=True,command='cl-desktop',
rights=['userconfigure'])
def desktop(self, sid, info):
return self.callMethod(sid,info,method_name="desktop",
logicClass=Desktop,
method="createHome")
def desktop_vars(self,dv=None):
if not dv:
dv = DataVarsDesktop()
dv.importDesktop()
dv.flIniFile()
dv.Set('cl_action','desktop',True)
dv.addGroup(None,
normal=('ur_login','cl_verbose_set',),
next_label=_("Configure"))
return dv
@rpc(Integer, ViewParams,_returns = ViewInfo)
def desktop_view (self, sid, params):
dv = self.get_cache(sid,"desktop","vars")
if not dv:
dv = self.desktop_vars()
else:
dv.processRefresh()
view = ViewInfo(dv,viewparams=params)
self.set_cache(sid, 'desktop', "vars",dv,smart=False)
return view

34
desktop/datavars.py

@ -0,0 +1,34 @@
#-*- coding: utf-8 -*-
# Copyright 2012 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
__app__ = 'calculate-desktop'
__version__ = '3.1.0'
import os
import sys
from calculate.lib.datavars import DataVars
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
class DataVarsDesktop(DataVars):
"""Variable class for desktop package"""
def importDesktop(self, **args):
"""Import desktop variables"""
self.importData()
self.importData('calculate.desktop.variables')
self.defaultModule = "desktop"

20
desktop/variables/__init__.py

@ -0,0 +1,20 @@
#-*- coding: utf-8 -*-
# Copyright 2008-2012 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import action
import desktop
section = "desktop"

60
desktop/variables/action.py

@ -0,0 +1,60 @@
#-*- coding: utf-8 -*-
# Copyright 2008-2012 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from os import path
from calculate.lib.datavars import Variable,VariableError,ReadonlyVariable
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
class VariableAcDesktopMerge(ReadonlyVariable):
"""
Action variable which has value "up" for package install and
install this package
"""
def get(self):
ret = ""
action = self.Get("cl_action")
if action in ("install","merge"):
ret = "up"
return ret
class VariableAcDesktopInstall(ReadonlyVariable):
"""
Action variable which has value "up" for install calculate-desktop
and "down" for uninstall
"""
def get(self):
ret = ""
action = self.Get("cl_action")
if action in ("install","merge"):
ret = "up"
elif action == "uninstall":
ret = "down"
return ret
class VariableAcDesktopDesktop(ReadonlyVariable):
"""
Action variable which has value "up" on user profile setup
"""
def get(self):
ret = ""
action = self.Get("cl_action")
if action in ("desktop",):
ret = "up"
return ret

150
desktop/variables/desktop.py

@ -0,0 +1,150 @@
import os
import sys
from os import path
from calculate.lib.datavars import Variable,VariableError,ReadonlyVariable
from calculate.lib.utils.files import readLinesFile
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
class VariableUrJidHost(ReadonlyVariable):
"""
Jabber host for user
"""
def get(self):
userJid = self.Get("ur_jid")
if userJid:
return userJid.partition('@')[2]
return ""
class VariableUrDomainSet(ReadonlyVariable):
"""
Flag for determining domain user or local
"""
def getUserDataInFile(self, login, filePasswd):
return filter(lambda x: x[0]==login,
map(lambda x: x.strip().split(':'),
readLinesFile(filePasswd)))
def get(self):
ret = "off"
userName = self.Get("ur_login")
if userName:
try:
passwdUserData = self.getUserDataInFile(userName, "/etc/passwd")
except:
return ret
if passwdUserData:
passwdUserData = passwdUserData[0]
try:
cacheUserData = self.getUserDataInFile(userName,
"/var/lib/calculate/calculate-client/cache/passwd")
except:
return ret
if cacheUserData:
cacheUserData = cacheUserData[0]
if cacheUserData == passwdUserData:
ret = "on"
else:
ret = "on"
return ret
class VariableClDesktopXsession(ReadonlyVariable):
"""
User current X session
"""
def get(self):
envXsessionFile = "/etc/env.d/90xsession"
xsession = os.environ.get("XSESSION",None)
desktopSession = os.environ.get("DESKTOP_SESSION",None)
if not xsession:
if os.path.exists(envXsessionFile):
xsession = \
map(lambda x:x.partition("=")[2].strip("'\""),
filter(lambda x:x.startswith("XSESSION="),
filter(lambda x:not x.startswith("#"),
open(envXsessionFile,"r"))))
if xsession:
xsession = xsession[-1]
if xsession:
if desktopSession and \
any(x in desktopSession.lower()
for x in ("kde","xfce","gnome")):
xsession = desktopSession
if "kde" in xsession.lower():
return "kde"
elif "gnome" in xsession.lower():
return "gnome"
elif "xfce" in xsession.lower():
return "xfce"
else:
return xsession.lower()
return ""
class VariableClDesktopGstData(ReadonlyVariable):
"""
GStreamer data
"""
def get(self):
# try import gst
try:
olderr = os.dup(sys.stderr.fileno())
os.close(sys.stderr.fileno())
import gst
import gst.interfaces
except ImportError:
gst = None
finally:
os.dup2(olderr,sys.stderr.fileno())
if gst is None:
return {}
outdata = {}
try:
pipeline = "alsamixer"
alsamixer = gst.element_factory_make(pipeline)
res = alsamixer.set_state(gst.STATE_PAUSED)
if res == gst.STATE_CHANGE_SUCCESS:
outdata['device_name'] = alsamixer.get_property("device-name")
outdata['long_name'] = alsamixer.get_factory().get_longname()
outdata['internal_name'] = filter(str.isalnum,
"%s (%s)"%(outdata['device_name'],
outdata['long_name']))
outdata['channels'] = []
for t in alsamixer.list_tracks():
if t.flags & gst.interfaces.MIXER_TRACK_OUTPUT:
if t.flags & gst.interfaces.MIXER_TRACK_MASTER or \
any(x in t.label
for x in ("Wave","Front","LFE","Center",
"Head","Side","Speaker",
"Surround","PCM")):
outdata['channels'].append(t.label)
if t.flags & gst.interfaces.MIXER_TRACK_MASTER:
outdata['master_channel'] = t.label
except:
pass
return outdata
class VariableClDesktopGstCard(ReadonlyVariable):
"""
Internal card name for xfce mixer
"""
def get(self):
return self.Get('cl_desktop_gst_data').get('internal_name','')
class VariableClDesktopGstMasterchannel(ReadonlyVariable):
"""
Master track name
"""
def get(self):
return self.Get('cl_desktop_gst_data').get('master_channel','')
class VariableClDesktopXfceMixer(ReadonlyVariable):
"""
List of channel for xfce-perchannel mixer
"""
def get(self):
return "\n".join(
map(lambda x:' <value type="string" value="%s" />'%x,
self.Get('cl_desktop_gst_data').get('channels',[])))

327
pym/cl_desktop.py

@ -1,327 +0,0 @@
#-*- coding: utf-8 -*-
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
__version__ = "2.2.24"
__app__ = "calculate-desktop"
import os
import re
import sys
import pwd
import time
from cl_lang import lang
from cl_template import template
from cl_datavars import DataVars
from cl_print import color_print
from client.progressbar import ProgressBar
from cl_utils import runOsCommand, getpathenv, appendProgramToEnvFile,\
removeProgramToEnvFile
lang().setLanguage(sys.modules[__name__])
class DataVarsDesktop(DataVars):
"""Хранение переменных"""
def importDesktop(self, **args):
'''Импорт переменных для десктопа'''
# Имя секции в calculate2.env
envSection = "desktop"
# импорт переменных
self.importData(envSection, ('cl_vars_desktop','cl_fill_desktop'))
class ProgressTemplate(template):
def __init__(self, vars):
template.__init__(self, vars)
self.progress = ProgressBar(_("Setting up user profile") + " ...")
def numberAllTemplates(self, number):
self.progress.setMaximum(number)
return True
def numberProcessTemplates(self,number):
self.progress.setValue(number)
return True
def close(self):
self.progress.shutdownDialog()
class share(color_print):
"""Общие методы"""
# Объект хранения переменных
clVars = False
def isRoot(self, printError=True):
"""Определяет является ли пользователь root"""
if os.getuid() == 0 and os.getgid() == 0:
return True
else:
if printError:
self.printERROR(_("The user is not root"))
return False
def createClVars(self, clVars=False):
"""Создает объект Vars"""
if not clVars:
clVars = DataVarsDesktop()
# Импортируем переменные
clVars.importDesktop()
# Заменяем значения переменных переменными из env файлов
clVars.flIniFile()
# Устанавливаем у объекта атрибут объект переменных
self.clVars = clVars
return True
def applyTemplatesFromSystem(self):
"""Применяем шаблоны для cистемы"""
# Cоздаем объект обработки шаблонов
clTempl = template(self.clVars)
# Объединяем шаблоны
dirsFiles = clTempl.applyTemplates()
if clTempl.getError():
self.printERROR(clTempl.getError().strip())
return False
else:
return dirsFiles
def printVars(self, *arg, **argv):
"""Печать существующих переменных"""
self.clVars.printVars(*arg, **argv)
class desktop(share):
"""Методы работы с профилем пользователя"""
# Имя пользователя
userName = ""
verbose = False
def installProg(self):
"""Наложение шаблонов на систему при инсталяции"""
# Проверяем на root
if not self.isRoot():
return False
self.clVars.AppendToList("cl_merges", __app__, force=True)
# Действие инсталяция
self.clVars.Set("cl_action", "install", True)
if not self.applyTemplatesFromSystem():
self.printERROR(_("Can not apply install templates"))
return False
# Добавление программы в инсталяционную переменную
if not appendProgramToEnvFile(__app__, self.clVars):
self.printERROR(_("Can not save '%s'") %__app__ + " " +\
_("to %s") %self.clVars.Get("cl_env_path")[0])
return False
self.printOK(_("Apply install templates"))
return True
def uninstallProg(self):
"""Наложение шаблонов на систему при деинсталяции"""
# Проверяем на root
if not self.isRoot():
return False
# Действие деинсталяция
self.clVars.Set("cl_action", "uninstall", True)
if not self.applyTemplatesFromSystem():
self.printERROR(_("Can not apply uninstall templates"))
return False
# Удаление программы из инсталяционной переменной
if not removeProgramToEnvFile(__app__, self.clVars):
self.printERROR(_("Can not remove '%(app)s' to %(path)s")%
{'app':__app__,
'path': self.clVars.Get("cl_env_path")[0]})
return False
self.printOK(_("Apply uninstall templates"))
return True
def existsUser(self, userName):
"""Существует ли пользователь"""
try:
pwd.getpwnam(userName).pw_gid
except:
self.printERROR(_("User %s not exists")%userName)
return False
return True
def createUserDir(self, uid, gid, userDir, mode=0700):
"""Создание пользовательской директории"""
if not os.path.exists(userDir):
os.makedirs(userDir)
if mode:
os.chmod(userDir,mode)
os.chown(userDir,uid,gid)
return True
else:
self.printERROR(_("Path %s exists") %userDir)
return False
def displayTemplatesApplied(self,dirsFiles):
"""
Display templates are applied (--verbose)
"""
self.printWARNING(_("Following files were changed")+":")
for nameF in dirsFiles[1]:
nameFile = nameF
if nameFile[:1] != "/":
nameFile = "/" + nameFile
self.printWARNING(" "*5 + nameFile)
def applyTemplatesFromUser(self, progress=False):
"""Применяем шаблоны для пользователя"""
# Cоздаем объект обработки шаблонов
if progress:
clTempl = ProgressTemplate(self.clVars)
else:
clTempl = template(self.clVars,cltObj=False)
# Объединяем шаблоны
dirsFiles = clTempl.applyTemplates()
if progress:
clTempl.close()
if clTempl.getError():
self.printERROR(clTempl.getError().strip())
return False
else:
if self.verbose:
self.displayTemplatesApplied(dirsFiles)
return dirsFiles
def createHome(self, progress=False, verbose=False):
"""Создание профиля пользователя (пользовательской директории)"""
# Имя пользователя
self.verbose = verbose
uid = os.getuid()
try:
realUserName = pwd.getpwuid(uid).pw_name
except:
realUserName = ""
userName = self.clVars.Get("ur_login")
if userName != realUserName and not self.isRoot():
return False
uidGid = False
# Домен для подключения Samba
domain = self.clVars.GetIniVar("client.cl_remote_host")
# Авторизация в домененe или локально
hostAuth = self.clVars.GetIniVar("client.os_remote_auth")
try:
passwdUsers = map(lambda x: x[0],
map(lambda x: x.split(':'),
map(lambda x: x.strip(),
open("/etc/passwd").readlines())))
except:
self.printERROR("Can not open /etc/passwd")
return False
try:
pwdInfo = pwd.getpwnam(userName)
except:
self.printERROR(_("Can not found user %s") %userName)
self.umountUserRes()
return False
uid = pwdInfo.pw_uid
gid = pwdInfo.pw_gid
homeDir = pwdInfo.pw_dir
# Создаем пользовательскую директорию
rootPath = self.clVars.Get('cl_root_path')
# Реальный путь к домашней директории
homeDir = os.path.join(rootPath, homeDir[1:])
# Домашняя директория существует
flagHomeExists = True
# Создаем домашнюю директорию если ее нет
if not os.path.exists(homeDir):
flagHomeExists = False
self.createUserDir(uid, gid, homeDir)
# Действие - шаблоны пользователя
self.clVars.Set("cl_action", "desktop", True)
# Применяем профили для пользователя
dirsAndFiles = self.applyTemplatesFromUser(progress)
if not dirsAndFiles:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.printERROR(_("Can not apply user profile"))
self.umountUserRes(homeDir)
return False
if not flagHomeExists:
self.printSUCCESS(_("Created home dir %s")%homeDir + " ...")
self.printSUCCESS(_("User account %s is configured")%userName + " ...")
return True
def getMountUserPaths(self, homeDir=False):
"""Находит пользовательские примонтированные пути"""
# Имя пользователя
if not homeDir:
userName = self.clVars.Get("ur_login")
try:
homeDir = pwd.getpwnam(userName).pw_dir
except:
homeDir = os.path.join("/home",userName)
dirStart, dirEnd = os.path.split(homeDir)
mountProfileDir = os.path.join(dirStart, ".%s" %dirEnd)
mountRemoteProfileDir = os.path.join(dirStart, ".%s.remote" %dirEnd)
return filter(lambda x: x.startswith(homeDir) or\
x.startswith(mountProfileDir) or\
x.startswith(mountRemoteProfileDir),
map(lambda x: x.split(" ")[1],\
open("/proc/mounts").readlines()))
def execProg(self, cmdStrProg, inStr=False, envProg={}):
"""Выполняет внешнюю программу
Параметры:
cmdStrProg внешняя программа
inStr данные передаваемые программе на страндартный вход.
Возвращаемые параметры:
строки которые выведет внешняя программа или False в случае ошибки
"""
env_path = {"PATH":getpathenv()}
env = {}
env.update(os.environ.items() + env_path.items() + envProg.items())
retCode,programOut = runOsCommand(cmdStrProg,in_str=inStr,env_dict=env)
if not retCode:
return programOut
return False
def umountSleepPath(self, path):
"""Отмонтирует путь при неудаче задержка потом повтор"""
# Задержки при отмонтированиии директории
sleeps = [0.5, 2, 5]
# Проверяем на монтирование директорию
if os.path.ismount(path):
textLine = self.execProg("umount %s"%path)
if textLine is False:
i = 0
flagError = False
while (i<len(sleeps) and textLine is False):
# Задержка перед следующей попыткой
time.sleep(sleeps[i])
# Отмонтируем Samba ресурс
if os.path.ismount(path):
textLine = self.execProg("umount %s"%path)
else:
textLine = True
break
i += 1
if textLine is False:
self.printERROR(_("Can not unmount path %s")%path + " ...")
return False
return True
def umountUserRes(self, homeDir=False):
"""Отмонтируем пользовательские директории если они есть"""
umountPaths = self.getMountUserPaths(homeDir)
ret = True
for umountPath in umountPaths:
if not self.umountSleepPath(umountPath):
ret = False
break
return ret

154
pym/cl_desktop_cmd.py

@ -1,154 +0,0 @@
#-*- coding: utf-8 -*-
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from cl_desktop import desktop, __app__, __version__
from cl_opt import opt
import sys
from cl_share_cmd import share_cmd
# Перевод сообщений для программы
from cl_lang import lang
lang().setLanguage(sys.modules[__name__])
# Использование программы
USAGE = _("%prog [options] user")
# Коментарии к использованию программы
COMMENT_EXAMPLES = _("Create home directory for the user_name")
# Пример использования программы
EXAMPLES = _("%prog user_name")
# Описание программы (что делает программа)
DESCRIPTION = _("Create home directory for the new user account")
# Опции командной строки
CMD_OPTIONS = [{'longOption':"verbose",
'help':_("display the template is applied")},
{'longOption':"set"},
{'longOption':"install",
'help':_("install package")},
{'longOption':"uninstall",
'help':_("uninstall package")},
{'longOption':"progress",
'help':_("show progress bar for xdm startup")}]
class desktop_cmd(share_cmd):
def __init__(self):
# Объект опций командной строки
setpos = \
filter(lambda x:x[1].get('longOption')=="set",
enumerate(CMD_OPTIONS))[0][0]
CMD_OPTIONS[setpos] = opt.variable_set[0]
self.optobj = opt(\
package=__app__,
version=__version__,
usage=USAGE,
examples=EXAMPLES,
comment_examples=COMMENT_EXAMPLES,
description=DESCRIPTION,
option_list=CMD_OPTIONS + opt.variable_view+opt.color_control,
check_values=self.checkOpts)
# Создаем объект логики
self.logicObj = desktop()
# Создаем переменные
self.logicObj.createClVars()
# Названия несовместимых опций
self.optionsNamesIncompatible = ["install", "uninstall"]
def getIncompatibleOptions(self, optObj):
"""Получаем несовместимые опции"""
retList = []
for nameOpt in self.optionsNamesIncompatible:
retList.append(getattr(optObj, nameOpt))
return retList
def _getNamesAllSetOptions(self):
"""Выдает словарь измененных опций"""
setOptDict = self.optobj.values.__dict__.items()
defaultOptDict = self.optobj.get_default_values().__dict__.items()
return dict(set(setOptDict) - set(defaultOptDict)).keys()
def getStringIncompatibleOptions(self):
"""Форматированная строка несовместимых опций разделенных ','"""
listOpt = list(set(self.optionsNamesIncompatible) &\
set(self._getNamesAllSetOptions()))
return ", ".join(map(lambda x: len(x) == 1 and "'-%s'"%x or "'--%s'"%x,\
listOpt))
def checkOpts(self, optObj, args):
"""Проверка опций командной строки"""
# Несовместимые опции
if len(filter(lambda x: x, self.getIncompatibleOptions(optObj)))>1:
errMsg = _("incompatible options")+":"+" %s"\
%self.getStringIncompatibleOptions()
self.optobj.error(errMsg)
return False
if optObj.v or optObj.filter or optObj.xml:
if args:
if len(args)>1:
errMsg = _("incorrect argument")+":" + " %s" %" ".join(args)
self.optobj.error(errMsg)
return False
userName = args[0]
# Проверка на существование пользователя
if not self.logicObj.existsUser(userName):
return False
elif optObj.install or optObj.uninstall:
if args:
errMsg = _("invalid argument") + ":" + " %s" %" ".join(args)
self.optobj.error(errMsg)
return False
else:
if not args:
errMsg = _("no such argument")+":"+" %s" %USAGE.split(" ")[-1]
self.optobj.error(errMsg)
return False
if len(args)>1:
errMsg = _("incorrect argument") + ":" + " %s" %" ".join(args)
self.optobj.error(errMsg)
return False
if not optObj.v:
if optObj.filter:
errMsg = _("incorrect option") + ":" + " %s" %"--filter" +\
": " + _("use with option '-v'")
self.optobj.error(errMsg)
return False
if optObj.xml:
errMsg = _("incorrect option") + ":" + " %s" %"--xml" +\
": " + _("use with option '-v'")
self.optobj.error(errMsg)
return False
return optObj, args
def setUserName(self, userName):
"""Установка имени пользователя"""
# Проверка на существование пользователя
if not self.logicObj.existsUser(userName):
return False
self.logicObj.clVars.Set("ur_login", userName, True)
return True
def createHome(self, optObj):
"""Создание домашней директории"""
return self.logicObj.createHome(optObj.progress, optObj.verbose)
def install(self):
"""Инсталяция программы"""
return self.logicObj.installProg()
def uninstall(self):
"""Удаление программы"""
return self.logicObj.uninstallProg()

111
pym/cl_fill_desktop.py

@ -1,111 +0,0 @@
#-*- coding: utf-8 -*-
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re
import os
class fillVars():
"""Методы определения значений переменных шаблона"""
def getUserDataInFile(self, login, filePasswd):
return filter(lambda x: x[0]==login,
map(lambda x: x.split(':'),
map(lambda x: x.strip(),
open(filePasswd).readlines())))
def get_ur_jid_host(self):
"""Host Jabber пользователя"""
userJid = self.Get("ur_jid")
if userJid:
return userJid.partition('@')[2]
return ""
def get_ac_desktop_install(self):
"""переключатель для шаблонов инсталяции и удаления программы"""
ret = ""
action = self.Get("cl_action")
if action in ("install","merge"):
ret = "up"
elif action == "uninstall":
ret = "down"
return ret
def get_ac_desktop_merge(self):
"""переключатель для шаблонов merge"""
ret = ""
action = self.Get("cl_action")
if action in ("install","merge"):
ret = "up"
return ret
def get_ac_desktop_desktop(self):
"""переключатель для шаблонов создания пользовательского профиля"""
ret = ""
action = self.Get("cl_action")
if action in ("desktop",):
ret = "up"
return ret
def get_ur_domain_set(self):
'''доменный пользователь "on", "off"'''
ret = "off"
userName = self.Get("ur_login")
if userName:
try:
passwdUserData = self.getUserDataInFile(userName, "/etc/passwd")
except:
return ret
if passwdUserData:
passwdUserData = passwdUserData[0]
try:
cacheUserData = self.getUserDataInFile(userName,
"/var/lib/calculate/calculate-client/cache/passwd")
except:
return ret
if cacheUserData:
cacheUserData = cacheUserData[0]
if cacheUserData == passwdUserData:
ret = "on"
else:
ret = "on"
return ret
def get_cl_desktop_xsession(self):
"""Current session"""
envXsessionFile = "/etc/env.d/90xsession"
xsession = os.environ.get("XSESSION",None)
desktopSession = os.environ.get("DESKTOP_SESSION",None)
if not xsession:
if os.path.exists(envXsessionFile):
xsession = \
map(lambda x:x.partition("=")[2].strip("'\""),
filter(lambda x:x.startswith("XSESSION="),
filter(lambda x:not x.startswith("#"),
open(envXsessionFile,"r"))))
if xsession:
xsession = xsession[-1]
if xsession:
if desktopSession and desktopSession.lower() != "default":
xsession = desktopSession
if "kde" in xsession.lower():
return "kde"
elif "gnome" in xsession.lower():
return "gnome"
elif "xfce" in xsession.lower():
return "xfce"
else:
return xsession.lower()
return ""

80
pym/cl_share_cmd.py

@ -1,80 +0,0 @@
#-*- coding: utf-8 -*-
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
from cl_print import color_print
from cl_utils import _error
# Перевод сообщений для программы
from cl_lang import lang
lang().setLanguage(sys.modules[__name__])
class share_cmd(color_print, _error):
"""Класс общих методов обработки опций командной строки"""
def printVars(self, optObj):
"""Печать переменных"""
if optObj.v:
varsFilter = None
varsNames = []
format = "default"
# Фильтрование переменных
if optObj.filter:
optCmd = optObj.filter
if ',' in optCmd:
varsNames = optCmd.split(",")
else:
varsFilter = optCmd
if optObj.xml:
format = "xml"
try:
v = int(optObj.v)
except:
v = 1
self.logicObj.printVars(varsFilter, varsNames, outFormat=format,
verbose=v)
def setVars(self, optObj):
"""Установка переменных"""
if optObj.set:
for val in optObj.set:
k,o,v = val.partition('=')
if self.logicObj.clVars.exists(k):
if self.logicObj.clVars.SetWriteVar(k,v) == False:
return False
else:
self.printERROR(_('variable %s not found')%k)
return False
return True
def writeVars(self, optObj):
"""Запись переменных"""
if optObj.set:
if not self.logicObj.clVars.WriteVars():
errMsg = self.getError()
if errMsg:
self.printERROR(errMsg.strip())
self.printERROR(_('Can not write template variables'))
return False
return True
def setPrintNoColor(self, optObj):
"""Установка печати сообщений без цвета"""
if optObj.color and optObj.color=="never":
color_print.colorPrint = lambda *arg : sys.stdout.write(arg[-1]) or\
sys.stdout.flush()

92
pym/cl_vars_desktop.py

@ -1,92 +0,0 @@
#-*- coding: utf-8 -*-
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#Допустимые ключи
# mode - режим переменной r-не переназначается из командной строки,
# w-переназначается из командной строки
# type - тип переменной состоит из двух элементов(что это и для чего
# это)
# value - значение переменной по умолчанию
# hide - флаг того, что данная переменная служебная и не отображается
# при печати списка значений переменных
from cl_desktop import __version__
from cl_desktop import __app__
class Data:
# имя программы
cl_name = {'value':__app__}
# версия программы
cl_ver = {'value':__version__}
#Логин пользователя
ur_login = {'mode':"r"}
#Название группы пользователя
ur_group = {'mode':"r"}
#Полное имя пользователя
ur_fullname = {'mode':"r"}
# Jabber ID пользователя
ur_jid = {'mode':"r"}
# Почтовый адрес пользователя
ur_mail = {'mode':"r"}
# Домашняя директория пользователя
ur_home_path = {'mode':"r"}
# Host Jabber пользователя
ur_jid_host = {'mode':"w"}
# переключатель для шаблонов merge
ac_desktop_merge = {}
# переключатель для шаблонов инсталяции и удаления программы
ac_desktop_install = {}
# переключатель для шаблонов создания пользовательского профиля
ac_desktop_desktop = {}
# доменный пользователь "on", "off"
ur_domain_set = {}
# user current X session
cl_desktop_xsession = {}
# lib vars
cl_env_path = {}
cl_root_path = {'mode':"w"}
hr_laptop = {}
hr_laptop_model = {}
hr_virtual = {}
os_linux_name = {}
os_linux_shortname = {}
os_linux_subname = {}
os_linux_ver = {}
os_locale_lang = {}
os_locale_language = {}
os_locale_xkb = {}
os_locale_xkbname = {}
os_net_hostname = {'mode':"w"}
os_root_type = {}
os_x11_composite = {}
os_x11_height = {'mode':"w"}
os_x11_standart = {}
os_x11_video_drv = {}
os_x11_width = {'mode':"w"}

69
scripts/cl-desktop

@ -1,69 +0,0 @@
#!/usr/bin/env python2
#-*- coding: utf-8 -*-
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#