parent
7b8d2939e7
commit
4f531e31ff
@ -1,56 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014-2016 Mir Calculate. 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 printing import Print
|
||||
from palette import TextState
|
||||
from info import Terminal
|
||||
|
||||
Colors = TextState.Colors
|
||||
|
||||
from converter import ConsoleCodes256Converter, XmlConverter
|
||||
from output import XmlOutput, ColorTerminal16Output, TerminalPositionOutput, \
|
||||
ColorTerminal256Output
|
||||
|
||||
|
||||
def convert_console_to_xml(s):
|
||||
"""Преобразовать вывод консоли в xml для внутреннего использования"""
|
||||
return ConsoleCodes256Converter(output=XmlOutput()).transform(s)
|
||||
|
||||
|
||||
def get_color_print():
|
||||
"""
|
||||
Получить объект для вывода текста в цвете
|
||||
"""
|
||||
return Print(output=XmlOutput())
|
||||
|
||||
|
||||
def get_terminal_output():
|
||||
return (ColorTerminal256Output()
|
||||
if Terminal().colors > 16
|
||||
else ColorTerminal16Output())
|
||||
|
||||
|
||||
def get_terminal_print(printfunc=lambda x: x):
|
||||
"""
|
||||
Получить объект для вывода в терминал
|
||||
"""
|
||||
# TODO: возвращать объект 256 или 16 терминал в зависимости от параметров
|
||||
return Print(output=get_terminal_output(),
|
||||
position_controller=TerminalPositionOutput(),
|
||||
printfunc=printfunc)
|
||||
|
||||
|
||||
def convert_xml_to_terminal(s):
|
||||
return XmlConverter(output=get_terminal_output()).transform(s)
|
@ -1,119 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014-2016 Mir Calculate. 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 output import BaseOutput, BasePositionOutput
|
||||
from calculate.lib.utils.text import _uu8
|
||||
|
||||
|
||||
class Print(object):
|
||||
"""
|
||||
Упрощенное получение строки при помощи Output объектов """
|
||||
|
||||
def __init__(self, output=BaseOutput(),
|
||||
position_controller=BasePositionOutput(),
|
||||
printfunc=lambda x: x):
|
||||
self.output = output
|
||||
self.position_controller = position_controller
|
||||
self.buffer = []
|
||||
if isinstance(printfunc, file):
|
||||
self.printfunc = printfunc.write
|
||||
self.flush = printfunc.flush
|
||||
else:
|
||||
self.printfunc = printfunc
|
||||
self.flush = lambda: None
|
||||
|
||||
@property
|
||||
def bold(self):
|
||||
self.buffer.append(self.output.setBold())
|
||||
return self
|
||||
|
||||
@property
|
||||
def underline(self):
|
||||
self.buffer.append(self.output.setUnderline())
|
||||
return self
|
||||
|
||||
def foreground(self, color):
|
||||
self.buffer.append(self.output.setForeground(color))
|
||||
return self
|
||||
|
||||
def background(self, color):
|
||||
self.buffer.append(self.output.setBackground(color))
|
||||
return self
|
||||
|
||||
@property
|
||||
def invert(self):
|
||||
self.buffer.append(self.output.setInvert())
|
||||
return self
|
||||
|
||||
@property
|
||||
def halflight(self):
|
||||
self.buffer.append(self.output.setHalfbright())
|
||||
return self
|
||||
|
||||
def up(self, count):
|
||||
self.buffer.append(self.position_controller.moveCursorUp(count))
|
||||
return self
|
||||
|
||||
def down(self, count):
|
||||
self.buffer.append(self.position_controller.moveCursorDown(count))
|
||||
return self
|
||||
|
||||
def right(self, count):
|
||||
self.buffer.append(self.position_controller.moveCursorRight(count))
|
||||
return self
|
||||
|
||||
def left(self, count):
|
||||
self.buffer.append(self.position_controller.moveCursorLeft(count))
|
||||
return self
|
||||
|
||||
@property
|
||||
def clear_line(self):
|
||||
self.buffer.append(self.position_controller.clearLine(whole_line=True))
|
||||
return self
|
||||
|
||||
def __call__(self, s, *args, **kwargs):
|
||||
if args or kwargs:
|
||||
s = s.format(*args, **kwargs)
|
||||
self.buffer.append(self.output.outputText(s))
|
||||
self.buffer.append(self.output.endText())
|
||||
try:
|
||||
return self.printfunc("".join(_uu8(*filter(None, self.buffer))))
|
||||
finally:
|
||||
self.buffer = []
|
||||
|
||||
def clone(self):
|
||||
obj = PrintClone(self.output.clone(),
|
||||
self.position_controller,
|
||||
self.printfunc)
|
||||
obj.output.pushState()
|
||||
return obj
|
||||
|
||||
|
||||
class PrintClone(Print):
|
||||
def __init__(self, output=BaseOutput(),
|
||||
position_controller=BasePositionOutput(),
|
||||
printfunc=lambda x: x):
|
||||
super(PrintClone, self).__init__(output, position_controller, printfunc)
|
||||
|
||||
def __call__(self, s, *args, **kwargs):
|
||||
s = s.format(*args, **kwargs)
|
||||
self.buffer.append(self.output.outputText(s))
|
||||
self.buffer.append(self.output.endText())
|
||||
self.output.popState()
|
||||
self.output.pushState()
|
||||
try:
|
||||
return self.printfunc("".join(filter(None, self.buffer)))
|
||||
finally:
|
||||
self.buffer = []
|
@ -1,75 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014-2016 Mir Calculate. 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 dbus
|
||||
from os import path
|
||||
from xml.etree import ElementTree
|
||||
|
||||
|
||||
def get_dbus_path_tree(bus_name, bus=None):
|
||||
"""
|
||||
Получить список путей объектов по имени шины
|
||||
"""
|
||||
if not bus:
|
||||
bus = dbus.SessionBus()
|
||||
|
||||
def get_child(objpath):
|
||||
obj = bus.get_object(bus_name, objpath)
|
||||
yield objpath
|
||||
if obj:
|
||||
for node in ElementTree.fromstring(obj.Introspect()):
|
||||
nodepath = path.join(objpath, node.get('name', ''))
|
||||
if node.tag == 'node':
|
||||
for child in get_child(nodepath):
|
||||
yield child
|
||||
|
||||
try:
|
||||
for x in get_child('/'):
|
||||
yield x
|
||||
except dbus.DBusException:
|
||||
pass
|
||||
|
||||
def run_dbus_core(hostname, port):
|
||||
if hostname in ("127.0.0.1", "localhost"):
|
||||
try:
|
||||
from ip import check_port
|
||||
if not check_port(hostname, port):
|
||||
bus = dbus.SystemBus()
|
||||
DBUS_INTERFACE="org.calculate.CoreInterface"
|
||||
DBUS_NAME="org.calculate.Core"
|
||||
DBUS_OBJECT="/Core"
|
||||
try:
|
||||
remote_object = bus.get_object(DBUS_NAME, DBUS_OBJECT)
|
||||
remote_object.Start(port)
|
||||
except dbus.DBusException:
|
||||
pass
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def get_dbus_hostname():
|
||||
try:
|
||||
bus = dbus.SystemBus()
|
||||
DBUS_INTERFACE="org.calculate.CoreInterface"
|
||||
DBUS_NAME="org.calculate.Core"
|
||||
DBUS_OBJECT="/Core"
|
||||
try:
|
||||
remote_object = bus.get_object(DBUS_NAME, DBUS_OBJECT)
|
||||
return str(remote_object.ServerHostname())
|
||||
except dbus.DBusException:
|
||||
pass
|
||||
except ImportError:
|
||||
pass
|
||||
return ""
|
File diff suppressed because it is too large
Load Diff
@ -1,555 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2008-2016 Mir Calculate. 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 files import (process, checkUtils, readFile, listDirectory,
|
||||
getRunCommands, getProgPath, FilesError)
|
||||
import device
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import fcntl
|
||||
import socket
|
||||
import math
|
||||
import ctypes
|
||||
from os import path
|
||||
import select
|
||||
import time
|
||||
|
||||
from calculate.lib.cl_lang import setLocalTranslate
|
||||
_ = lambda x: x
|
||||
setLocalTranslate('cl_lib3', sys.modules[__name__])
|
||||
|
||||
PROCFS_NET_PATH = "/proc/net/dev"
|
||||
|
||||
# From linux/sockios.h
|
||||
SIOCGIFINDEX = 0x8933
|
||||
SIOCGIFFLAGS = 0x8913
|
||||
SIOCSIFFLAGS = 0x8914
|
||||
SIOCSIFHWADDR = 0x8924
|
||||
SIOCSIFADDR = 0x8916
|
||||
SIOCSIFNETMASK = 0x891C
|
||||
SIOCETHTOOL = 0x8946
|
||||
|
||||
SIOCGIFADDR = 0x8915
|
||||
SIOCGIFNETMASK = 0x891B
|
||||
SIOCGIFHWADDR = 0x8927
|
||||
|
||||
# Resources allocated
|
||||
IFF_RUNNING = 0x40
|
||||
IFF_MASTER = 0x400
|
||||
IFF_SLAVE = 0x800
|
||||
|
||||
# ip digit from 0|1-255|254 (template)
|
||||
IP_DIG = "[%s-9]|(?:1[0-9]|[1-9])[0-9]|2[0-4][0-9]|25[0-%s]"
|
||||
# ip net 0-32
|
||||
IP_NET_SUFFIX = "[0-9]|[12][0-9]|3[012]"
|
||||
# ip digs 1-254,0-254,0-255
|
||||
IP_DIGS = {'dig1_254': IP_DIG % (1, 4), 'dig0_254': IP_DIG % (0, 4),
|
||||
'dig0_255': IP_DIG % (0, 5), }
|
||||
# ip addr 10.0.0.12
|
||||
IP_ADDR = "(%(dig1_254)s)\.(%(dig0_254)s)\.(%(dig0_254)s)\.(%(dig1_254)s)" % \
|
||||
IP_DIGS
|
||||
IP_MASK = "(%(dig0_255)s)\.(%(dig0_255)s)\.(%(dig0_255)s)\.(%(dig0_255)s)" % \
|
||||
IP_DIGS
|
||||
# ip addr for net 10.0.0.0
|
||||
IP_NET = "(%(dig1_254)s)\.(%(dig0_254)s)\.(%(dig0_254)s)\.(%(dig0_254)s)" % \
|
||||
IP_DIGS
|
||||
# ip and net 192.168.0.0/16
|
||||
IP_ADDR_NET = "(%(ipaddr)s)/((%(ipnet)s))" % {'ipaddr': IP_NET,
|
||||
'ipnet': IP_NET_SUFFIX}
|
||||
|
||||
reIp = re.compile("^{0}$".format(IP_ADDR))
|
||||
reNetSuffix = re.compile("^{0}$".format(IP_NET_SUFFIX))
|
||||
reNet = re.compile("^{0}$".format(IP_ADDR_NET))
|
||||
reMask = re.compile("^{0}$".format(IP_MASK))
|
||||
|
||||
|
||||
def checkIp(ip):
|
||||
"""Check ip"""
|
||||
return reIp.match(ip)
|
||||
|
||||
|
||||
def checkNetSuffix(netSuffix):
|
||||
"""Check net suffix"""
|
||||
return reNetSuffix.match(netSuffix)
|
||||
|
||||
|
||||
def checkNet(net):
|
||||
"""Check net"""
|
||||
if not reNet.match(net):
|
||||
return False
|
||||
ip, op, cidr = net.partition('/')
|
||||
mask = strIpToIntIp(cidrToMask(int(cidr)))
|
||||
return (strIpToIntIp(ip) & mask) == (strIpToIntIp(ip))
|
||||
|
||||
|
||||
maskDigs = map(lambda x: str(x),
|
||||
(0b10000000, 0b11000000, 0b11100000, 0b11110000,
|
||||
0b11111000, 0b11111100, 0b11111110, 0b11111111))
|
||||
|
||||
|
||||
def checkMask(mask):
|
||||
"""Check net"""
|
||||
if not mask:
|
||||
return False
|
||||
if mask.count('.') != 3:
|
||||
return False
|
||||
zero = False
|
||||
for dig in mask.split('.'):
|
||||
if zero or not dig in maskDigs:
|
||||
if dig == "0":
|
||||
zero = True
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def getIpAndMask(interface="eth0"):
|
||||
"""Get ip and mask from interface"""
|
||||
ifconfig = process('/sbin/ifconfig', interface)
|
||||
res = re.search(r"inet addr:(\S+)\s.*Mask:(\S+)", ifconfig.read(), re.S)
|
||||
if res:
|
||||
return res.groups()
|
||||
else:
|
||||
return "", ""
|
||||
|
||||
|
||||
def strIpToIntIp(addr):
|
||||
"""Convert ip specified by string to integer"""
|
||||
addr = addr.split('.')
|
||||
return ((int(addr[0]) << 24) |
|
||||
(int(addr[1]) << 16) |
|
||||
(int(addr[2]) << 8) |
|
||||
(int(addr[3])))
|
||||
|
||||
def intIpToStrIp(addr):
|
||||
"""Convert ip specified by integer to string"""
|
||||
return "{0}.{1}.{2}.{3}".format(
|
||||
addr >> 24, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff)
|
||||
|
||||
|
||||
def numMaskToCidr(netmask):
|
||||
"""
|
||||
Convert integer mask to cidr
|
||||
"""
|
||||
neg_net = ctypes.c_uint32(~netmask).value
|
||||
return 32 - int(math.log(neg_net, 2)) - 1 if neg_net else 32
|
||||
|
||||
|
||||
def maskToCidr(mask):
|
||||
"""Convert mask specified by str to net"""
|
||||
mask = strIpToIntIp(mask)
|
||||
return numMaskToCidr(mask)
|
||||
|
||||
|
||||
def cidrToMask(cidr):
|
||||
"""Convert net to mask specified by str"""
|
||||
return intIpToStrIp((2 ** cidr - 1) << (32 - cidr))
|
||||
|
||||
|
||||
def getIpNet(ip, mask=None, cidr=None):
|
||||
"""Get net (xx.xx.xx.xx/xx) by ip address and mask"""
|
||||
ip = strIpToIntIp(ip)
|
||||
if not mask is None:
|
||||
net = maskToCidr(mask)
|
||||
else:
|
||||
net = int(cidr)
|
||||
mask = cidrToMask(net)
|
||||
mask = strIpToIntIp(mask)
|
||||
return "{ip}/{net}".format(ip=intIpToStrIp(ip & mask),
|
||||
net=net)
|
||||
|
||||
|
||||
def isIpInNet(checkip, *ipnets):
|
||||
"""Check is ip in specified nets"""
|
||||
return map(lambda x: x[0],
|
||||
filter(lambda x: strIpToIntIp(checkip) & x[2] == strIpToIntIp(
|
||||
x[1]) & x[2],
|
||||
map(lambda x: (
|
||||
x[0], x[1][0],
|
||||
strIpToIntIp(cidrToMask(int(x[1][1])))),
|
||||
map(lambda x: (x, x.partition('/')[0::2]),
|
||||
ipnets))))
|
||||
|
||||
def isUsingNetworkManager():
|
||||
try:
|
||||
p = process("/usr/bin/nmcli", "general", "status")
|
||||
return p.success()
|
||||
except FilesError:
|
||||
return False
|
||||
|
||||
def isNMDhcp(interface="eth0"):
|
||||
p = process("/usr/bin/nmcli", "-g", "ipv4.method", "connection", "show", "eth0")
|
||||
if p.success():
|
||||
if "auto" in p.read():
|
||||
return True
|
||||
return False
|
||||
|
||||
def isDhcpIp(interface="eth0"):
|
||||
"""Get ip by dhcp or static"""
|
||||
# dhclients (dhcpcd, dhclient (dhcp), udhcpc (busybox)
|
||||
if isUsingNetworkManager() and isNMDhcp(interface):
|
||||
return True
|
||||
commands = getRunCommands()
|
||||
dhcpProgs = ("dhcpcd", "dhclient", "udhcpc")
|
||||
if filter(lambda x: interface in x and any(prog in x for prog in dhcpProgs),
|
||||
commands):
|
||||
return True
|
||||
else:
|
||||
# если запущен демон dhcpcd
|
||||
if filter(lambda x: "dhcpcd\x00-q" in x, commands):
|
||||
curIp = getIp(interface)
|
||||
dhcpcd = getProgPath('/sbin/dhcpcd')
|
||||
leaseIp = \
|
||||
map(lambda x: x.group(1),
|
||||
filter(None,
|
||||
map(re.compile('^ip_address=(.*)$').search,
|
||||
process(dhcpcd, '-U', interface))))
|
||||
if not curIp or leaseIp and leaseIp[0] == curIp:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def getRouteTable(onlyIface=()):
|
||||
"""Get route table, exclude specifed iface"""
|
||||
ipProg = checkUtils('/sbin/ip')
|
||||
routes = process(ipProg, "route")
|
||||
if onlyIface:
|
||||
filterRe = re.compile("|".join(map(lambda x: r"dev %s" % x, onlyIface)))
|
||||
routes = filter(filterRe.search, routes)
|
||||
for line in routes:
|
||||
network, op, line = line.partition(" ")
|
||||
routeParams = map(lambda x: x.strip(), line.split())
|
||||
# (network,{'via':value,'dev':value})
|
||||
if network:
|
||||
yield (network, dict(zip(routeParams[0::2], routeParams[1::2])))
|
||||
|
||||
|
||||
def getInterfaces():
|
||||
"""
|
||||
Get available interfaces (discard which hasn't device)
|
||||
"""
|
||||
|
||||
def filter_ethernet(x):
|
||||
# exclude loopback
|
||||
if device.sysfs.read(x, "type").strip() != "1":
|
||||
return False
|
||||
# physical device
|
||||
if device.sysfs.exists(x, "device"):
|
||||
return True
|
||||
# exclude bridges
|
||||
if device.sysfs.exists(x, "brport"):
|
||||
return False
|
||||
if device.sysfs.exists(x, "bridge"):
|
||||
return False
|
||||
# exclude bonding
|
||||
if device.sysfs.exists(x, "bonding"):
|
||||
return False
|
||||
if device.sysfs.exists(x, "bonding_slave"):
|
||||
return False
|
||||
# exclude slave devices
|
||||
if any(device.sysfs.glob(x, "lower_*")):
|
||||
return False
|
||||
return True
|
||||
|
||||
return sorted(path.basename(x)
|
||||
for x in device.sysfs.listdir(
|
||||
device.sysfs.Path.ClassNet, fullpath=True)
|
||||
if filter_ethernet(x))
|
||||
|
||||
def getMaster(iface):
|
||||
master_path = [device.sysfs.Path.ClassNet, iface, "master"]
|
||||
if device.sysfs.exists(*master_path):
|
||||
return path.split(device.sysfs.realpath(*master_path))[-1]
|
||||
return None
|
||||
|
||||
def getIp(iface):
|
||||
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00' * 14)
|
||||
try:
|
||||
res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
|
||||
except IOError:
|
||||
return ""
|
||||
finally:
|
||||
sockfd.close()
|
||||
ip = struct.unpack('16sH2x4s8x', res)[2]
|
||||
return socket.inet_ntoa(ip)
|
||||
|
||||
def checkFlag(iface, flag):
|
||||
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00' * 14)
|
||||
try:
|
||||
res = fcntl.ioctl(sockfd, SIOCGIFFLAGS, ifreq)
|
||||
except IOError:
|
||||
return False
|
||||
finally:
|
||||
sockfd.close()
|
||||
return bool(struct.unpack('16sH2x4s8x', res)[1] & flag)
|
||||
|
||||
def getPlugged(iface):
|
||||
return checkFlag(iface, IFF_RUNNING)
|
||||
|
||||
def isSlaveInterface(iface):
|
||||
return checkFlag(iface, IFF_SLAVE)
|
||||
|
||||
def isMasterInterface(iface):
|
||||
return checkFlag(iface, IFF_MASTER)
|
||||
|
||||
def getMask(iface):
|
||||
"""
|
||||
Get mask for interface
|
||||
"""
|
||||
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00' * 14)
|
||||
try:
|
||||
res = fcntl.ioctl(sockfd, SIOCGIFNETMASK, ifreq)
|
||||
except IOError:
|
||||
return 0
|
||||
finally:
|
||||
sockfd.close()
|
||||
netmask = socket.ntohl(struct.unpack('16sH2xI8x', res)[2])
|
||||
return numMaskToCidr(netmask)
|
||||
|
||||
def isWireless(iface):
|
||||
"""
|
||||
Является ли данное устройство беспроводным
|
||||
"""
|
||||
return device.sysfs.exists(device.sysfs.Path.ClassNet, iface, "wireless")
|
||||
|
||||
def getMac(iface):
|
||||
"""
|
||||
Get mac for interface
|
||||
"""
|
||||
sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
ifreq = struct.pack('16sH14s', iface, socket.AF_UNIX, '\x00' * 14)
|
||||
try:
|
||||
res = fcntl.ioctl(sockfd, SIOCGIFHWADDR, ifreq)
|
||||
except IOError:
|
||||
return ""
|
||||
address = struct.unpack('16sH14s', res)[2]
|
||||
mac = struct.unpack('6B8x', address)
|
||||
sockfd.close()
|
||||
return ":".join(['%02X' % i for i in mac])
|
||||
|
||||
|
||||
def getOperState(iface):
|
||||
"""
|
||||
Get interface state up or down
|
||||
"""
|
||||
if device.sysfs.read(device.sysfs.Path.ClassNet, iface, "operstate") == "down":
|
||||
return "down"
|
||||
return "up"
|
||||
|
||||
|
||||
def isOpenPort(ip, port):
|
||||
"""
|
||||
Test if an [ip:port] is open
|
||||
"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.connect((ip, int(port)))
|
||||
s.shutdown(2)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class IPError(Exception):
|
||||
"""Error received on work with ip"""
|
||||
pass
|
||||
|
||||
|
||||
class Pinger(object):
|
||||
# ICMP parameters
|
||||
ICMP_ECHO = 8 # Echo request (per RFC792)
|
||||
ICMP_MAX_RECV = 2048 # Max size of incoming buffer
|
||||
|
||||
def checksum(self, source_string):
|
||||
"""
|
||||
A port of the functionality of in_cksum() from ping.c
|
||||
Ideally this would act on the string as a series of 16-bit ints (host
|
||||
packed), but this works.
|
||||
Network data is big-endian, hosts are typically little-endian
|
||||
"""
|
||||
countTo = (int(len(source_string) / 2)) * 2
|
||||
sum = 0
|
||||
count = 0
|
||||
|
||||
# Handle bytes in pairs (decoding as short ints)
|
||||
while count < countTo:
|
||||
if sys.byteorder == "little":
|
||||
loByte = ord(source_string[count])
|
||||
hiByte = ord(source_string[count + 1])
|
||||
else:
|
||||
loByte = ord(source_string[count + 1])
|
||||
hiByte = ord(source_string[count])
|
||||
sum += hiByte * 256 + loByte
|
||||
count += 2
|
||||
|
||||
# Handle last byte if applicable (odd-number of bytes)
|
||||
# Endianness should be irrelevant in this case
|
||||
if countTo < len(source_string): # Check for odd length
|
||||
loByte = ord(source_string[len(source_string) - 1])
|
||||
sum += loByte
|
||||
|
||||
# Truncate sum to 32 bits (a variance from ping.c,which
|
||||
sum &= 0xffffffff
|
||||
# uses signed ints, but overflow is unlikely in ping)
|
||||
|
||||
sum = (sum >> 16) + (sum & 0xffff) # Add high 16 bits to low 16 bits
|
||||
sum += (sum >> 16) # Add carry from above (if any)
|
||||
answer = ~sum & 0xffff # Invert and truncate to 16 bits
|
||||
answer = socket.htons(answer)
|
||||
|
||||
return answer
|
||||
|
||||
def ping(self, destIP, timeout, numDataBytes):
|
||||
"""
|
||||
Returns either the delay (in ms) or None on timeout.
|
||||
"""
|
||||
delay = None
|
||||
|
||||
try: # One could use UDP here, but it's obscure
|
||||
mySocket = socket.socket(socket.AF_INET, socket.SOCK_RAW,
|
||||
socket.getprotobyname("icmp"))
|
||||
except socket.error as e:
|
||||
raise IPError(_("failed. (socket error: '%s')" % e.args[1]))
|
||||
|
||||
my_ID = os.getpid() & 0xFFFF
|
||||
|
||||
sentTime = self.send_one_ping(mySocket, destIP, my_ID, 0,
|
||||
numDataBytes)
|
||||
if sentTime is None:
|
||||
mySocket.close()
|
||||
return delay
|
||||
|
||||
recvTime, dataSize, iphSrcIP, icmpSeqNumber, iphTTL = \
|
||||
self.receive_one_ping(mySocket, my_ID, timeout)
|
||||
|
||||
mySocket.close()
|
||||
|
||||
if recvTime:
|
||||
delay = (recvTime - sentTime) * 1000
|
||||
return (dataSize, socket.inet_ntoa(struct.pack("!I", iphSrcIP)),
|
||||
iphTTL, delay)
|
||||
else:
|
||||
raise IPError(_("Request timed out"))
|
||||
|
||||
def send_one_ping(self, mySocket, destIP, myID, mySeqNumber, numDataBytes):
|
||||
"""
|
||||
Send one ping to the given >destIP<.
|
||||
"""
|
||||
try:
|
||||
destIP = socket.gethostbyname(destIP)
|
||||
except socket.gaierror as e:
|
||||
raise IPError(e.strerror)
|
||||
|
||||
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
|
||||
myChecksum = 0
|
||||
|
||||
# Make a dummy heder with a 0 checksum.
|
||||
header = struct.pack(
|
||||
"!BBHHH", self.ICMP_ECHO, 0, myChecksum, myID, mySeqNumber
|
||||
)
|
||||
|
||||
padBytes = []
|
||||
startVal = 0x42
|
||||
for i in range(startVal, startVal + numDataBytes):
|
||||
padBytes += [(i & 0xff)] # Keep chars in the 0-255 range
|
||||
data = bytes(padBytes)
|
||||
|
||||
# Calculate the checksum on the data and the dummy header.
|
||||
# Checksum is in network order
|
||||
myChecksum = self.checksum(header + data)
|
||||
|
||||
# Now that we have the right checksum, we put that in. It's just easier
|
||||
# to make up a new header than to stuff it into the dummy.
|
||||
header = struct.pack(
|
||||
"!BBHHH", self.ICMP_ECHO, 0, myChecksum, myID, mySeqNumber
|
||||
)
|
||||
|
||||
packet = header + data
|
||||
|
||||
sendTime = time.time()
|
||||
|
||||
try:
|
||||
# Port number is irrelevant for ICMP
|
||||
mySocket.sendto(packet, (destIP, 1))
|
||||
except socket.error as e:
|
||||
raise IPError("General failure (%s)" % (e.args[1]))
|
||||
|
||||
return sendTime
|
||||
|
||||
def receive_one_ping(self, mySocket, myID, timeout):
|
||||
"""
|
||||
Receive the ping from the socket. Timeout = in ms
|
||||
"""
|
||||
timeLeft = timeout / 1000.0
|
||||
|
||||
while True: # Loop while waiting for packet or timeout
|
||||
startedSelect = time.time()
|
||||
whatReady = select.select([mySocket], [], [], timeLeft)
|
||||
howLongInSelect = (time.time() - startedSelect)
|
||||
if isinstance(whatReady[0], list) and not whatReady[0]: # Timeout
|
||||
return None, 0, 0, 0, 0
|
||||
|
||||
timeReceived = time.time()
|
||||
|
||||
recPacket, addr = mySocket.recvfrom(self.ICMP_MAX_RECV)
|
||||
|
||||
ipHeader = recPacket[:20]
|
||||
iphVersion, iphTypeOfSvc, iphLength, \
|
||||
iphID, iphFlags, iphTTL, iphProtocol, \
|
||||
iphChecksum, iphSrcIP, iphDestIP = struct.unpack(
|
||||
"!BBHHHBBHII", ipHeader
|
||||
)
|
||||
|
||||
icmpHeader = recPacket[20:28]
|
||||
icmpType, icmpCode, icmpChecksum, \
|
||||
icmpPacketID, icmpSeqNumber = struct.unpack(
|
||||
"!BBHHH", icmpHeader
|
||||
)
|
||||
|
||||
if icmpPacketID == myID: # Our packet
|
||||
dataSize = len(recPacket) - 28
|
||||
return timeReceived, dataSize, iphSrcIP, icmpSeqNumber, iphTTL
|
||||
|
||||
timeLeft = timeLeft - howLongInSelect
|
||||
if timeLeft <= 0:
|
||||
return None, 0, 0, 0, 0
|
||||
|
||||
def check_port(target, port, timeout=5):
|
||||
"""
|
||||
Проверить порт (port) на хосте (target)
|
||||
:param target: хост
|
||||
:param port: порт
|
||||
:param timeout: таймаут
|
||||
:return: True - порт открыт, False - нет хоста, порт закрыт, firewall
|
||||
"""
|
||||
try:
|
||||
targetIP = socket.gethostbyname(target)
|
||||
except socket.gaierror:
|
||||
return False
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(timeout)
|
||||
try:
|
||||
s.connect((targetIP, port))
|
||||
s.close()
|
||||
except (socket.error, socket.timeout):
|
||||
return False
|
||||
return True
|
@ -1,438 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2008-2016 Mir Calculate. 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 types
|
||||
from calculate.lib import cl_overriding
|
||||
import re
|
||||
import sys
|
||||
from itertools import *
|
||||
|
||||
from calculate.lib.cl_lang import setLocalTranslate
|
||||
|
||||
_ = lambda x: x
|
||||
setLocalTranslate('cl_lib3', sys.modules[__name__])
|
||||
|
||||
_u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t
|
||||
_uu = lambda *tt: tuple(_u(t) for t in tt)
|
||||
_u8 = lambda t: t.encode('UTF-8', 'replace') if isinstance(t, unicode) else t
|
||||
_uu8 = lambda *tt: tuple(_u8(t) for t in tt)
|
||||
|
||||
|
||||
def columnMatrix(*cols):
|
||||
"""
|
||||
Split columns text to matrix
|
||||
"""
|
||||
|
||||
def splitter(s, wid):
|
||||
"""Split string by width and \\n"""
|
||||
for part in _u(s).split('\n'):
|
||||
if wid > 0:
|
||||
while part:
|
||||
p, part = part[:wid], part[wid:]
|
||||
yield p
|
||||
else:
|
||||
yield part
|
||||
|
||||
return izip_longest(
|
||||
*starmap(splitter,
|
||||
izip_longest(islice(cols, 0, None, 2),
|
||||
islice(cols, 1, None, 2))),
|
||||
fillvalue="")
|
||||
|
||||
|
||||
def columnStr(*cols):
|
||||
"""
|
||||
Get string for write, data by columns
|
||||
|
||||
Parameters:
|
||||
cols list(tuple(text,width))
|
||||
|
||||
Return:
|
||||
string for display
|
||||
|
||||
Example: columnStr( "Some text", 10, "Next column", 20 )
|
||||
"""
|
||||
|
||||
def generateStrings(*cols):
|
||||
colWidth = list(islice(cols, 1, None, 2))
|
||||
for line in map(lambda x: izip_longest(colWidth, x),
|
||||
columnMatrix(*cols)):
|
||||
yield " ".join(("{0:%d}" % (width or 1)).format(s) for \
|
||||
width, s in line)
|
||||
|
||||
return "\n".join(generateStrings(*cols))
|
||||
|
||||
|
||||
def justify(s, width):
|
||||
"""
|
||||
Выровнить текст по ширине
|
||||
|
||||
Параметры:
|
||||
s выводимая строка
|
||||
width ширина на которую надо выровнить строку
|
||||
|
||||
Возвращаямые параметры:
|
||||
Выровненная строка
|
||||
"""
|
||||
# если подана строка без пробелов - прекратить обработку
|
||||
if s.find(' ') == -1:
|
||||
return s
|
||||
pos = 0
|
||||
# переводим в юникод для правильного вычисления длины
|
||||
try:
|
||||
s = s.decode('utf-8')
|
||||
# пропуск если это не utf-8
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
# пока длина строки меньше указанной
|
||||
while len(s) < width:
|
||||
# находим очередной пробел
|
||||
pos = s.find(' ', pos)
|
||||
# если не найден искать сначала
|
||||
if pos == -1:
|
||||
pos = s.find(' ')
|
||||
# вставить в позицию еще один пробел
|
||||
s = s[:pos] + ' ' + s[pos:]
|
||||
# оставить удвоенный пробел
|
||||
pos += 3
|
||||
# вернуть строку в utf8 если она пришла в utf8
|
||||
return s.encode('utf-8')
|
||||
|
||||
|
||||
class tableReport(object):
|
||||
"""Display data in table"""
|
||||
|
||||
def __init__(self, title, headerList, dataList, colSpan=1):
|
||||
|
||||
# title
|
||||
self.title = title
|
||||
# elements list for first table row
|
||||
self.headerList = headerList
|
||||
# row list (each row is list)
|
||||
self.dataList = map(lambda x: map(lambda y: str(y).expandtabs(),
|
||||
map(lambda y: y or "", x)),
|
||||
dataList)
|
||||
# calculate columns list
|
||||
self.columnsWidth = self.getColumsnWidth()
|
||||
self.vertChar = colSpan * " " + "|" + colSpan * " "
|
||||
self.crossChar = colSpan * "-" + "+" + colSpan * "-"
|
||||
self.colSpan = colSpan
|
||||
self.align = "<" + "^" * (len(headerList) - 2) + "<"
|
||||
|
||||
def setAutosize(self, colNum=-1, maxSize=None, forceMax=False):
|
||||
"""
|
||||
Set width for specified column
|
||||
"""
|
||||
if maxSize is None:
|
||||
maxSize = get_term_size()[1]
|
||||
if not maxSize:
|
||||
maxSize = 80
|
||||
spanSize = self.colSpan * 2 + 1
|
||||
if colNum < 0:
|
||||
colNum += len(self.columnsWidth)
|
||||
currentSize = sum(map(lambda x: x + spanSize, self.columnsWidth)) + 1
|
||||
if currentSize < maxSize and not forceMax:
|
||||
return
|
||||
excludeSize = sum(map(lambda x: x[1] + spanSize,
|
||||
filter(lambda x: x[0] != colNum,
|
||||
enumerate(
|
||||
self.columnsWidth)))) + spanSize + 1
|
||||
if maxSize - excludeSize > 5:
|
||||
self.columnsWidth[colNum] = maxSize - excludeSize
|
||||
|
||||
def getColumsnWidth(self):
|
||||
"""Находит максимальную ширину каждой колонки
|
||||
|
||||
результат список ширин колонок
|
||||
"""
|
||||
columnsWidth = []
|
||||
for s in self.headerList:
|
||||
columnsWidth.append(len(_u(s)))
|
||||
lenCol = len(self.headerList)
|
||||
maxLenCol = lenCol
|
||||
# Вычисляем максимальное количество столбцов
|
||||
for s in self.dataList:
|
||||
lenS = len(s)
|
||||
if maxLenCol < lenS:
|
||||
maxLenCol = lenS
|
||||
if maxLenCol > lenCol:
|
||||
appCol = maxLenCol - lenCol
|
||||
# Добавляем элементы в список ширин
|
||||
for i in range(appCol):
|
||||
columnsWidth.append(0)
|
||||
# Вычисляем ширину столбцов
|
||||
for e in self.dataList:
|
||||
for i, s in enumerate(e):
|
||||
lenS = len(_u(s))+1
|
||||
if columnsWidth[i] < lenS:
|
||||
columnsWidth[i] = lenS
|
||||
return columnsWidth
|
||||
|
||||
def createFormatStr(self, listStr, offset=0):
|
||||
"""Создает список (текст, ширина ...)"""
|
||||
return chain(*izip_longest(listStr,
|
||||
map(lambda x:x-offset, self.columnsWidth),
|
||||
fillvalue=""))
|
||||
|
||||
def printFunc(self, s):
|
||||
"""
|
||||
Overriding print
|
||||
"""
|
||||
cl_overriding.printSUCCESS(s, printBR=False)
|
||||
|
||||
def line_printer(self, s):
|
||||
"""
|
||||
Вывод используется для отображения "линий" таблицы
|
||||
"""
|
||||
self.printFunc(s)
|
||||
|
||||
def head_printer(self, s):
|
||||
"""
|
||||
Вывод используется для отображения текста в шапке
|
||||
"""
|
||||
self.printFunc(s)
|
||||
|
||||
def body_printer(self, s):
|
||||
"""
|
||||
Вывод используется для отображения текста в таблице
|
||||
"""
|
||||
self.printFunc(s)
|
||||
|
||||
def default_printer(self, s):
|
||||
self.printFunc(s)
|
||||
|
||||
def printReport(self, printRows=True):
|
||||
"""Напечатать данные в табличном виде"""
|
||||
if self.title:
|
||||
self.printFunc(self.title)
|
||||
listStrSep = []
|
||||
for lenCol in self.columnsWidth:
|
||||
listStrSep.append("-" * lenCol)
|
||||
printData = [[self.crossChar, self.line_printer,
|
||||
columnMatrix(*self.createFormatStr(listStrSep))],
|
||||
[self.vertChar, self.head_printer,
|
||||
columnMatrix(*self.createFormatStr(self.headerList))],
|
||||
[self.crossChar, self.line_printer,
|
||||
columnMatrix(*self.createFormatStr(listStrSep))]]
|
||||
for s in self.dataList:
|
||||
printData.append([self.vertChar, self.body_printer,
|
||||
columnMatrix(*self.createFormatStr(s, 1))])
|
||||
printData.append([self.crossChar, self.line_printer,
|
||||
columnMatrix(*self.createFormatStr(listStrSep))])
|
||||
last_col = len(self.headerList) - 1
|
||||
|
||||
for char, _print, row in printData:
|
||||
for line in row:
|
||||
self.line_printer(char[self.colSpan:])
|
||||
for i, width, txt in izip(count(),
|
||||
self.columnsWidth, line):
|
||||
if _print == self.body_printer:
|
||||
align = "<"
|
||||
offset = " "
|
||||
if width:
|
||||
width -= 1
|
||||
else:
|
||||
align = "^"
|
||||
offset = ""
|
||||
_print((u"%s{0:%s%d}" % (offset, align, width)).format(txt))
|
||||
if i < last_col:
|
||||
self.line_printer(char)
|
||||
self.line_printer(char[:-self.colSpan + 1])
|
||||
self.default_printer('\n')
|
||||
if printRows:
|
||||
self.printFunc("(%s %s)" % (len(self.dataList), _("rows")))
|
||||
|
||||
|
||||
class MultiReplace:
|
||||
"""MultiReplace function object
|
||||
|
||||
Usage:
|
||||
replacer = MultiReplace({'str':'efg','in':'asd'})
|
||||
s = replacer("string")
|
||||
"""
|
||||
|
||||
def __init__(self, repl_dict):
|
||||
# string to string mapping; use a regular expression
|
||||
keys = repl_dict.keys()
|
||||
keys.sort(reverse=True) # lexical order
|
||||
pattern = u"|".join([re.escape(key) for key in keys])
|
||||
self.pattern = re.compile(pattern)
|
||||
self.dict = repl_dict
|
||||
|
||||
def replace(self, s):
|
||||
# apply replacement dictionary to string
|
||||
def repl(match, get=self.dict.get):
|
||||
item = match.group(0)
|
||||
return get(item, item)
|
||||
|
||||
return self.pattern.sub(repl, s)
|
||||
|
||||
__call__ = replace
|
||||
|
||||
|
||||
def str2dict(s):
|
||||
"""Convert string to dictionary:
|
||||
|
||||
String format:
|
||||
{'key1':'value1','key2':'val\'ue2'}
|
||||
"""
|
||||
value = r'(?:\\\\|\\\'|[^\'])'
|
||||
pair = r"""
|
||||
\s*' # begin key
|
||||
(%(v)s*)
|
||||
' # end key
|
||||
\s*:\s* # delimeter key/value
|
||||
' # begin value
|
||||
(%(v)s*)
|
||||
'\s* # end value
|
||||
""" % {"v": value}
|
||||
reDict = re.compile(pair, re.X)
|
||||
reMatchDict = re.compile("""
|
||||
^{ # begin dict
|
||||
((%(v)s,)* # many pair with comma at end
|
||||
%(v)s)? # pair without comma
|
||||
}$ # end dict
|
||||
""" % {'v': pair}, re.X)
|
||||
if reMatchDict.match(s.strip()):
|
||||
d = dict(reDict.findall(s))
|
||||
replaceSlash = MultiReplace({'\\\\': '\\', '\\\'': '\''})
|
||||
for i in d.keys():
|
||||
d[i] = replaceSlash(d[i])
|
||||
return d
|
||||
else:
|
||||
cl_overriding.printERROR(_("wrong dict value: %s" % s))
|
||||
cl_overriding.exit(1)
|
||||
|
||||
|
||||
def str2list(s):
|
||||
"""Convert string to list:
|
||||
|
||||
String format:
|
||||
['value1','val\'ue2']
|
||||
"""
|
||||
value = r'(?:\\\\|\\\'|[^\'])'
|
||||
element = r"""
|
||||
\s*' # begin value
|
||||
(%(v)s*)
|
||||
'\s* # end value
|
||||
""" % {"v": value}
|
||||
reList = re.compile(element, re.X)
|
||||
reMatchList = re.compile("""
|
||||
^\[ # begin dict
|
||||
((%(v)s,)* # many elements with comma at end
|
||||
%(v)s)? # element without comma
|
||||
\]$ # end dict
|
||||
""" % {'v': element}, re.X)
|
||||
if reMatchList.match(s.strip()):
|
||||
replaceSlash = MultiReplace({'\\\\': '\\', '\\\'': '\''})
|
||||
return [replaceSlash(i) for i in reList.findall(s)]
|
||||
else:
|
||||
cl_overriding.printERROR(_("wrong list value: %s" % s))
|
||||
cl_overriding.exit(1)
|
||||
|
||||
|
||||
def list2str(list):
|
||||
"""Convert list to string
|
||||
|
||||
Return string with escaped \ and '.
|
||||
"""
|
||||
replaceSlash = MultiReplace({'\\': '\\\\', '\'': '\\\''})
|
||||
return "[%s]" % ','.join(["'%s'" % replaceSlash(str(i))
|
||||
for i in list])
|
||||
|
||||
|
||||
def dict2str(dict):
|
||||
"""Convert dictionry to string
|
||||
|
||||
Return string with escaped \ and '.
|
||||
"""
|
||||
replaceSlash = MultiReplace({'\\': '\\\\', '\'': '\\\''})
|
||||
return '{%s}' % ','.join(["'%s':'%s'" % (str(k), replaceSlash(str(v))) \
|
||||
for (k, v) in dict.items()])
|
||||
|
||||
|
||||
def convertStrListDict(val):
|
||||
"""Convert data between string, list, dict"""
|
||||
# if val is list
|
||||
if isinstance(val, types.ListType):
|
||||
return list2str(val)
|
||||
# if val is dictionary
|
||||
elif isinstance(val, types.DictType):
|
||||
return dict2str(val)
|
||||
# else it is string
|
||||
else:
|
||||
# detect dictionary
|
||||
if re.match("^{.*}$", val):
|
||||
return str2dict(val)
|
||||
# detect list
|
||||
elif re.match("^\[.*\]$", val):
|
||||
return str2list(val)
|
||||
# else is simple string
|
||||
else:
|
||||
return val
|
||||
|
||||
|
||||
def formatListOr(lst):
|
||||
"""Convert list to string like this: [1,2,3] -> 1,2 or 3"""
|
||||
lststr = map(lambda x: str(x), lst)
|
||||
return (" %s " % _("or")).join(filter(lambda x: x,
|
||||
[", ".join(map(lambda x: x or "''",
|
||||
lststr[:-1])),
|
||||
"".join(lststr[-1:])]))
|
||||
|
||||
|
||||
def get_term_size(fd=sys.stdout.fileno()):
|
||||
"""
|
||||
Get terminal size
|
||||
"""
|
||||
try:
|
||||
import struct
|
||||
import fcntl
|
||||
import termios
|
||||
except ImportError:
|
||||
struct, fcntl, termios = None, None, None
|
||||
return None, None
|
||||
|
||||
try:
|
||||
s = struct.pack("HHHH", 0, 0, 0, 0)
|
||||
data = fcntl.ioctl(fd, termios.TIOCGWINSZ, s)
|
||||
height, width = struct.unpack('4H', data)[:2]
|
||||
return height, width
|
||||
except Exception:
|
||||
return None, None
|
||||
|
||||
|
||||
def simplify_profiles(profiles, drop_words=("amd64", "x86")):
|
||||
"""
|
||||
Упростить названия профилей (удалить одинаковое начало и конец в строках)
|
||||
:param profiles: список названий профилей
|
||||
:param drop_words: список слов из профилей, которые можно отбросить
|
||||
если профиль один
|
||||
:return: список упрощенных названий профилей
|
||||
"""
|
||||
if len(profiles) < 2:
|
||||
if len(profiles) == 1:
|
||||
return ["/".join(filter(lambda x: x not in drop_words,
|
||||
profiles[0].split('/')))]
|
||||
return profiles
|
||||
matrix = [x.split('/') for x in profiles]
|
||||
# удаляем одинаковые начальные и конечные поля
|
||||
matrix = zip(*reversed(list(dropwhile(lambda x: x.count(x[0]) == len(x),
|
||||
(reversed(list(dropwhile(
|
||||
lambda x: x.count(x[0]) == len(x),
|
||||
izip_longest(*matrix,
|
||||
fillvalue="")))))))))
|
||||
return ["/".join(filter(None, x)) for x in matrix]
|
@ -1,541 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2016 Mir Calculate. 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 calculate.lib.utils.files import readFile
|
||||
from collections import Mapping, deque
|
||||
from os import path
|
||||
import json
|
||||
from functools import wraps
|
||||
import fnmatch
|
||||
import tools
|
||||
|
||||
|
||||
class VFSError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class VFSErrorNotFound(VFSError):
|
||||
pass
|
||||
|
||||
|
||||
class VFSErrorExists(VFSError):
|
||||
pass
|
||||
|
||||
|
||||
class VFSErrorBadsymlink(VFSError):
|
||||
pass
|
||||
|
||||
|
||||
class VFSErrorCycliclink(VFSErrorBadsymlink):
|
||||
pass
|
||||
|
||||
|
||||
class VFSErrorNotImplemented(VFSError):
|
||||
pass
|
||||
|
||||
|
||||
class VFSErrorRestoreFailed(VFSError):
|
||||
pass
|
||||
|
||||
|
||||
class VFS(tools.GenericFs):
|
||||
"""
|
||||
Виртуальная файловая система
|
||||
"""
|
||||
|
||||
def __init__(self, vfs=None):
|
||||
if isinstance(vfs, VFS):
|
||||
self.root = vfs.root
|
||||
else:
|
||||
self.root = VFSRoot()
|
||||
|
||||
def get(self, fn):
|
||||
r = self.root
|
||||
for dn in (x for x in fn.split('/') if x):
|
||||
r = r[dn]
|
||||
return r
|
||||
|
||||
def walk(self, sort=False):
|
||||
deq = deque((self.root,))
|
||||
if sort:
|
||||
sortfunc = lambda z: sorted(z, key=lambda y: y.name, reverse=True)
|
||||
else:
|
||||
sortfunc = iter
|
||||
while deq:
|
||||
d = deq.pop()
|
||||
if isinstance(d, VFSDirectory):
|
||||
for x in sortfunc(d):
|
||||
deq.append(x)
|
||||
yield d
|
||||
|
||||
def read(self, fn):
|
||||
return self.get(fn).read()
|
||||
|
||||
def write(self, fn, data):
|
||||
return self.get(fn).write(data)
|
||||
|
||||
def listdir(self, fn, fullpath=False):
|
||||
return self.get(fn).listdir(fullpath=fullpath)
|
||||
|
||||
def lexists(self, fn):
|
||||
try:
|
||||
self.get(fn)
|
||||
return True
|
||||
except VFSErrorNotFound:
|
||||
return False
|
||||
|
||||
def dereflink(self, obj):
|
||||
objs = [obj]
|
||||
while isinstance(obj, VFSLink):
|
||||
obj = obj.deref()
|
||||
if obj in objs:
|
||||
raise VFSErrorCycliclink(obj.fullname())
|
||||
return obj
|
||||
|
||||
def _glob(self, pathname):
|
||||
paths = deque(x for x in pathname.split("/") if x)
|
||||
pat = paths.popleft()
|
||||
SEPARATOR = (None, None)
|
||||
deq = deque([("/", self.root), SEPARATOR])
|
||||
while deq:
|
||||
dirname, d = deq.popleft()
|
||||
if d is None:
|
||||
if paths:
|
||||
pat = paths.popleft()
|
||||
deq.append(SEPARATOR)
|
||||
continue
|
||||
else:
|
||||
break
|
||||
if d.isdir():
|
||||
dirname = path.join(dirname, d.name)
|
||||
for x in d:
|
||||
if fnmatch.fnmatch(x.name, pat):
|
||||
if not paths:
|
||||
yield (path.join(dirname, x.name), x)
|
||||
else:
|
||||
deq.append((dirname, x))
|
||||
|
||||
def glob(self, pathname):
|
||||
return (x for x, y in self._glob(pathname))
|
||||
|
||||
def realglob(self, pathname):
|
||||
return [y.fullname() for x, y in self._glob(pathname)]
|
||||
|
||||
def exists(self, fn):
|
||||
try:
|
||||
obj = self.get(fn)
|
||||
if isinstance(obj, VFSLink):
|
||||
obj = self.dereflink(obj)
|
||||
return True
|
||||
except (VFSErrorNotFound, VFSErrorBadsymlink):
|
||||
return False
|
||||
|
||||
def realpath(self, fn):
|
||||
bestpath = fn
|
||||
obj = None
|
||||
try:
|
||||
obj = self.get(fn)
|
||||
if isinstance(obj, VFSLink):
|
||||
obj = self.dereflink(obj)
|
||||
return obj.fullname()
|
||||
except VFSErrorBadsymlink:
|
||||
if isinstance(obj, VFSLink):
|
||||
bestpath = obj.symlink()
|
||||
except VFSErrorNotFound:
|
||||
pass
|
||||
return path.normpath(bestpath)
|
||||
|
||||
# serialization
|
||||
def dump(self):
|
||||
return self.root.dump()
|
||||
|
||||
def restore(self, dumpdata):
|
||||
self.root = self.root.restore(dumpdata)
|
||||
|
||||
|
||||
class SafeVFS(VFS):
|
||||
"""
|
||||
Виртуатльная файловая система, не возвращающая ошибок при обращении к
|
||||
отсутстующему файлу
|
||||
"""
|
||||
def exists(self, fn):
|
||||
return self.lexists(fn)
|
||||
|
||||
def read(self, fn):
|
||||
try:
|
||||
return super(SafeVFS, self).read(fn)
|
||||
except VFSError:
|
||||
return ""
|
||||
|
||||
def listdir(self, fn, fullpath=False):
|
||||
try:
|
||||
return super(SafeVFS, self).listdir(fn, fullpath)
|
||||
except VFSError:
|
||||
return []
|
||||
|
||||
|
||||
class VFSObject(object):
|
||||
def __init__(self, name):
|
||||
self.parent = None
|
||||
self.name = name
|
||||
|
||||
def dump(self):
|
||||
raise NotImplemented()
|
||||
|
||||
def fullname(self):
|
||||
if self.parent:
|
||||
dirname = self.parent.fullname()
|
||||
dirname = "" if dirname == "/" else dirname
|
||||
return "%s/%s" % (dirname, self.name)
|
||||
else:
|
||||
return self.name
|
||||
|
||||
def read(self):
|
||||
raise NotImplemented()
|
||||
|
||||
def write(self, data):
|
||||
raise NotImplemented()
|
||||
|
||||
def listdir(self, fullpath=False):
|
||||
raise NotImplemented()
|
||||
|
||||
def isdir(self):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def restore(cls, data):
|
||||
for clsobj in (VFSFile, VFSLink, VFSDirectory, VFSRoot):
|
||||
obj = clsobj.restore(data)
|
||||
if obj is not None:
|
||||
return obj
|
||||
raise VFSErrorRestoreFailed(data)
|
||||
|
||||
|
||||
class VFSDirectory(VFSObject, Mapping):
|
||||
def __init__(self, name, *args):
|
||||
super(VFSDirectory, self).__init__(name)
|
||||
self.children = {}
|
||||
for o in args:
|
||||
self.append(o)
|
||||
|
||||
def dump(self):
|
||||
return ['d', self.name, [x.dump() for x in self]]
|
||||
|
||||
def isdir(self):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def restore(cls, data):
|
||||
if data[0] == "d":
|
||||
objtype, name, objdata = data
|
||||
d = cls(name)
|
||||
for x in objdata:
|
||||
d.append(VFSObject.restore(x))
|
||||
return d
|
||||
|
||||
def __contains__(self, item):
|
||||
return item.name in self.children
|
||||
|
||||
def append(self, obj):
|
||||
if obj in self:
|
||||
raise VFSErrorExists("{dirn}/{name}".format(name=obj.name,
|
||||
dirn=self.fullname()))
|
||||
self.children[obj.name] = obj
|
||||
obj.parent = self
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.children.values())
|
||||
|
||||
def __len__(self):
|
||||
return len(self.children)
|
||||
|
||||
def __getitem__(self, item):
|
||||
if item == ".":
|
||||
return self
|
||||
if item == "..":
|
||||
return self.parent
|
||||
try:
|
||||
return self.children[item]
|
||||
except KeyError:
|
||||
raise VFSErrorNotFound(item)
|
||||
|
||||
def listdir(self, fullpath=False):
|
||||
if fullpath:
|
||||
dirname = self.fullname()
|
||||
else:
|
||||
dirname = ""
|
||||
return [path.join(dirname, x.name) for x in self.children.values()]
|
||||
|
||||
def read(self):
|
||||
raise VFSErrorNotImplemented("Directory does not support reading")
|
||||
|
||||
def write(self, data):
|
||||
raise VFSErrorNotImplemented("Directory does not support writing")
|
||||
|
||||
def __eq__(self, obj):
|
||||
return self is obj
|
||||
|
||||
def __ne__(self, obj):
|
||||
return self is not obj
|
||||
|
||||
|
||||
class VFSRoot(VFSDirectory):
|
||||
def __init__(self, *args):
|
||||
super(VFSRoot, self).__init__("/", *args)
|
||||
|
||||
def __getitem__(self, item):
|
||||
if item == "..":
|
||||
return self
|
||||
return super(VFSRoot, self).__getitem__(item)
|
||||
|
||||
def dump(self):
|
||||
return ['/', self.name, [x.dump() for x in self]]
|
||||
|
||||
@classmethod
|
||||
def restore(cls, data):
|
||||
if data[0] == "/":
|
||||
objtype, name, objdata = data
|
||||
d = cls()
|
||||
for x in objdata:
|
||||
d.append(VFSObject.restore(x))
|
||||
return d
|
||||
|
||||
|
||||
class VFSFile(VFSObject):
|
||||
def __init__(self, name, data=""):
|
||||
super(VFSFile, self).__init__(name)
|
||||
self.data = data
|
||||
|
||||
def dump(self):
|
||||
return ['r', self.name, self.read()]
|
||||
|
||||
@classmethod
|
||||
def restore(cls, data):
|
||||
if data[0] == "r":
|
||||
objtype, name, objdata = data
|
||||
return cls(name, objdata)
|
||||
|
||||
def read(self):
|
||||
return self.data
|
||||
|
||||
def write(self, data):
|
||||
self.data = data
|
||||
|
||||
def listdir(self, fullpath=False):
|
||||
raise VFSErrorNotImplemented("File does not support listing")
|
||||
|
||||
def __getitem__(self, item):
|
||||
raise VFSErrorNotImplemented("File does not support listing")
|
||||
|
||||
|
||||
def detect_cyclic(f):
|
||||
@wraps(f)
|
||||
def wrapper(self, *args, **kw):
|
||||
if self.deref_start:
|
||||
raise VFSErrorCycliclink(self.fullname())
|
||||
self.deref_start = True
|
||||
try:
|
||||
return f(self, *args, **kw)
|
||||
finally:
|
||||
self.deref_start = False
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class VFSLink(VFSObject):
|
||||
def __init__(self, name, target):
|
||||
super(VFSLink, self).__init__(name)
|
||||
self.name = name
|
||||
self._target = target
|
||||
self.deref_start = False
|
||||
|
||||
@classmethod
|
||||
def restore(cls, data):
|
||||
if data[0] == "l":
|
||||
objtype, name, objdata = data
|
||||
return cls(name, objdata)
|
||||
|
||||
def dump(self):
|
||||
return ['l', self.name, self.symlink()]
|
||||
|
||||
def symlink(self):
|
||||
return self._target
|
||||
|
||||
def get_root(self):
|
||||
r = self.parent
|
||||
while r.parent:
|
||||
r = r.parent
|
||||
return r
|
||||
|
||||
def deref(self):
|
||||
r = self.parent
|
||||
if r is None:
|
||||
raise VFSErrorBadsymlink(self._target)
|
||||
if self._target.startswith("/"):
|
||||
r = self.get_root()
|
||||
for dn in (x for x in self._target.split('/') if x):
|
||||
try:
|
||||
r = r[dn]
|
||||
except VFSErrorNotFound:
|
||||
raise VFSErrorBadsymlink(self._target)
|
||||
return r
|
||||
|
||||
@detect_cyclic
|
||||
def _isdir(self):
|
||||
return self.deref().isdir()
|
||||
|
||||
def isdir(self):
|
||||
try:
|
||||
return self._isdir()
|
||||
except VFSErrorBadsymlink:
|
||||
return False
|
||||
|
||||
def __iter__(self):
|
||||
if self.isdir():
|
||||
return iter(self.deref())
|
||||
else:
|
||||
raise VFSErrorNotImplemented("Symlink is not directory")
|
||||
|
||||
@detect_cyclic
|
||||
def read(self):
|
||||
return self.deref().read()
|
||||
|
||||
@detect_cyclic
|
||||
def write(self, data):
|
||||
return self.deref().write(data)
|
||||
|
||||
@detect_cyclic
|
||||
def listdir(self, fullpath=False):
|
||||
return self.deref().listdir()
|
||||
|
||||
@detect_cyclic
|
||||
def __getitem__(self, item):
|
||||
return self.deref().__getitem__(item)
|
||||
|
||||
|
||||
class VFSImporter(object):
|
||||
"""
|
||||
Имортёр файловой системы
|
||||
"""
|
||||
|
||||
def __init__(self, dn, prefix="/"):
|
||||
self.importdn = dn
|
||||
self.prefix = prefix
|
||||
|
||||
def importfs(self):
|
||||
vfs = VFS()
|
||||
dn = self.importdn
|
||||
|
||||
r = vfs.root
|
||||
for dns in (x for x in path.relpath(dn, self.prefix).split('/') if x):
|
||||
d = VFSDirectory(dns)
|
||||
r.append(d)
|
||||
r = d
|
||||
|
||||
for root, dnames, fnames in os.walk(dn):
|
||||
vroot = path.join("/", path.relpath(root, self.prefix))
|
||||
r = vfs.get(vroot)
|
||||
remove_dirs = deque()
|
||||
remove_files = deque()
|
||||
for dn in dnames:
|
||||
fdn = path.join(root, dn)
|
||||
if path.islink(fdn):
|
||||
self.import_link(r, dn, fdn)
|
||||
else:
|
||||
self.import_directory(r, dn, fdn)
|
||||
if not self.filter_dirs(root, dn):
|
||||
remove_dirs.append(dn)
|
||||
for fn in fnames:
|
||||
ffn = path.join(root, fn)
|
||||
if path.islink(ffn):
|
||||
self.import_link(r, fn, ffn)
|
||||
else:
|
||||
self.import_file(r, fn, ffn)
|
||||
if not self.filter_dirs(root, dn):
|
||||
remove_dirs.append(dn)
|
||||
while remove_dirs:
|
||||
dnames.remove(remove_dirs.popleft())
|
||||
while remove_files:
|
||||
fnames.remove(remove_files.popleft())
|
||||
return vfs
|
||||
|
||||
def filter_dirs(self, root, dn):
|
||||
return True
|
||||
|
||||
def filter_files(self, root, fn):
|
||||
return True
|
||||
|
||||
def import_link(self, dirobj, fn, ffn):
|
||||
target = os.readlink(ffn)
|
||||
dirobj.append(VFSLink(fn, target))
|
||||
|
||||
def import_file(self, dirobj, fn, ffn):
|
||||
dirobj.append(VFSFile(fn))
|
||||
|
||||
def import_directory(self, dirobj, dn, fdn):
|
||||
dirobj.append(VFSDirectory(dn))
|
||||
|
||||
|
||||
class VFSDevfsImporter(VFSImporter):
|
||||
"""
|
||||
Импортер /dev
|
||||
"""
|
||||
|
||||
def __init__(self, dn="/dev", prefix="/"):
|
||||
super(VFSDevfsImporter, self).__init__(dn, prefix)
|
||||
|
||||
def filter_dirs(self, root, dn):
|
||||
if dn == "shm":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class VFSSysfsImporter(VFSImporter):
|
||||
"""
|
||||
Импортёр /sys
|
||||
"""
|
||||
|
||||
def __init__(self, dn="/sys", prefix="/"):
|
||||
super(VFSSysfsImporter, self).__init__(dn, prefix)
|
||||
|
||||
def import_file(self, dirobj, fn, ffn):
|
||||
if fn in ("version", "vendor", "model", "board_name",
|
||||
"board_vendor", "refcnt", "boardname", "size",
|
||||
"removable",
|
||||
"type", "operstate"):
|
||||
dirobj.append(VFSFile(fn, readFile(ffn)))
|
||||
else:
|
||||
dirobj.append(VFSFile(fn))
|
||||
|
||||
|
||||
class VFSJsonKeeper(object):
|
||||
"""
|
||||
Сохранение и загрузыка виртуальной файловой системы
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def save(f, vfs):
|
||||
json.dump(vfs.dump(), f)
|
||||
|
||||
@staticmethod
|
||||
def load(f):
|
||||
vfs = VFS()
|
||||
vfs.restore(json.load(f))
|
||||
return vfs
|
||||
|
||||
|
||||
VFSKeeper = VFSJsonKeeper
|
@ -1,44 +0,0 @@
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2011-2016 Mir Calculate. 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 calculate.lib.datavars import ReadonlyVariable
|
||||
|
||||
import X11
|
||||
import locale
|
||||
import env
|
||||
import hardware
|
||||
import linux
|
||||
import net
|
||||
import user
|
||||
import system
|
||||
import action
|
||||
from calculate.lib.cl_lang import setLocalTranslate
|
||||
setLocalTranslate('cl_lib3',sys.modules[__name__])
|
||||
|
||||
section = "main"
|
||||
|
||||
class VariableClName(ReadonlyVariable):
|
||||
"""
|
||||
Package name
|
||||
"""
|
||||
value = "calculate-core"
|
||||
|
||||
class VariableClVer(ReadonlyVariable):
|
||||
"""
|
||||
Package version
|
||||
"""
|
||||
value = "3.6.7"
|
@ -1,354 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2008-2016 Mir Calculate. 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
|
||||
import os
|
||||
from os import path
|
||||
import re
|
||||
import platform
|
||||
from calculate.lib.datavars import (Variable, SimpleDataVars, ReadonlyVariable,
|
||||
VariableError, VariableInterface)
|
||||
|
||||
from calculate.lib.utils.portage import (isPkgInstalled, searchProfile,
|
||||
RepositorySubstituting, RepositoryPath)
|
||||
from calculate.lib.utils.files import readFile, pathJoin
|
||||
from calculate.lib.configparser import ConfigParser
|
||||
from calculate.lib.utils.tools import unique, drop_slash
|
||||
import env
|
||||
|
||||
_ = lambda x: x
|
||||
from calculate.lib.cl_lang import setLocalTranslate
|
||||
|
||||
setLocalTranslate('cl_lib3', sys.modules[__name__])
|
||||
|
||||
|
||||
class Linux(VariableInterface):
|
||||
dictLinuxName = {"CLD": "Calculate Linux Desktop",
|
||||
"CLDX": "Calculate Linux Desktop",
|
||||
"CLDG": "Calculate Linux Desktop",
|
||||
"CDS": "Calculate Directory Server",
|
||||
"CLS": "Calculate Linux Scratch",
|
||||
"CSS": "Calculate Scratch Server",
|
||||
"CMC": "Calculate Media Center",
|
||||
"Gentoo": "Gentoo"}
|
||||
|
||||
dictLinuxSubName = {"CLD": "KDE", "CLDX": "XFCE", "CLDG": "GNOME"}
|
||||
|
||||
dictNameSystem = {'CDS': 'server',
|
||||
'CLD': 'desktop',
|
||||
'CLDG': 'desktop',
|
||||
'CLDX': 'desktop',
|
||||
'CLS': 'desktop',
|
||||
'CMC': 'desktop',
|
||||
'CSS': 'server'}
|
||||
|
||||
def getFullNameByShort(self, shortname):
|
||||
"""Get full distributive name by short name"""
|
||||
subname = self.dictLinuxSubName.get(shortname, '')
|
||||
if subname:
|
||||
subname = " %s" % subname
|
||||
return "%s%s" % (self.dictLinuxName.get(shortname, ''), subname)
|
||||
|
||||
def getShortnameByMakeprofile(self, systemroot):
|
||||
"""Get shortname by symlink of make.profile"""
|
||||
makeprofile = self.Get('cl_make_profile')
|
||||
if path.exists(makeprofile):
|
||||
link = os.readlink(makeprofile)
|
||||
re_make_profile_link = re.compile(
|
||||
'/calculate/(desktop|server)/(%s)/' %
|
||||
"|".join(self.dictLinuxName.keys()), re.S)
|
||||
shortname_search = re_make_profile_link.search(link)
|
||||
if shortname_search:
|
||||
return shortname_search.groups()[1]
|
||||
return None
|
||||
|
||||
def getShortnameByIni(self, systemroot):
|
||||
"""Get shortname by calculate.ini file"""
|
||||
inifile = path.join(systemroot, 'etc/calculate/calculate.ini')
|
||||
if path.exists(inifile):
|
||||
with open(inifile) as f:
|
||||
data = f.readlins()
|
||||
short_name_list = filter(
|
||||
None, map(lambda x: (len(x.split("=")) == 2 and
|
||||
x.split("=")[0] == "calculate" and
|
||||
x.split("=")[1].strip()), data))
|
||||
if short_name_list:
|
||||
return short_name_list[0]
|
||||
|
||||
def detectOtherShortname(self, systemroot):
|
||||
"""Detect other system. Now only Gentoo."""
|
||||
gentoo_file = path.join(systemroot, "etc/gentoo-release")
|
||||
if path.exists(gentoo_file):
|
||||
return "Gentoo"
|
||||
if all(map(lambda x: path.lexists(path.join(systemroot, x)),
|
||||
['bin', 'var', 'lib', 'etc'])):
|
||||
return "Linux"
|
||||
return None
|
||||
|
||||
def getVersionFromOverlay(self, systemroot):
|
||||
"""
|
||||
Get version from overlay calculate-release
|
||||
"""
|
||||
overlay_path = drop_slash(RepositoryPath.Calculate)
|
||||
release_file = 'profiles/calculate-release'
|
||||
return readFile(path.join(systemroot, overlay_path, release_file))
|
||||
|
||||
def getVersionFromMetapackage(self, systemroot, shortname):
|
||||
"""Get version from meta package"""
|
||||
for pkg in ("app-misc/calculate-meta", "app-misc/%s-meta" % shortname):
|
||||
calc_meta = isPkgInstalled(pkg, systemroot)
|
||||
if calc_meta:
|
||||
return calc_meta[0]['PV']
|
||||
return None
|
||||
|
||||
def getVersionFromCalculateIni(self, systemroot):
|
||||
"""Get version from calculate ini"""
|
||||
pathname = path.join(systemroot,
|
||||
'etc/calculate/calculate.ini')
|
||||
if path.exists(pathname):
|
||||
with open(pathname) as f:
|
||||
data = f.readlines()
|
||||
ver_list = filter(
|
||||
None, map(lambda x:
|
||||
(len(x.split("=")) == 2 and
|
||||
x.split("=")[0] == "linuxver" and
|
||||
x.split("=")[1].strip()), data))
|
||||
if ver_list:
|
||||
re_ver = re.compile("^(\d+\.)*\d$", re.S)
|
||||
re_res = filter(re_ver.search, ver_list)
|
||||
if re_res:
|
||||
return re_res[0]
|
||||
|
||||
def getVersionFromGentooFiles(self, systemroot):
|
||||
"""Get version from gentoo files"""
|
||||
gentoo_file = path.join(systemroot, "etc/gentoo-release")
|
||||
re_ver = re.compile("^(\d+\.)*\d+$", re.S)
|
||||
if path.exists(gentoo_file):
|
||||
gentoo_link = self.Get('cl_make_profile')
|
||||
if path.islink(gentoo_link):
|
||||
vers = filter(re_ver.search,
|
||||
os.readlink(gentoo_link).split('/'))
|
||||
if vers:
|
||||
return vers[-1]
|
||||
|
||||
def getVersionFromUname(self):
|
||||
"""Get version from uname"""
|
||||
re_ver = re.search("^(\d+\.)*\d", platform.release(), re.S)
|
||||
if re_ver:
|
||||
return re_ver.group()
|
||||
|
||||
|
||||
class VariableOsLinuxShortname(Variable, Linux):
|
||||
"""
|
||||
Short system name (Example:CLD)
|
||||
"""
|
||||
systemRoot = "/"
|
||||
|
||||
def get(self):
|
||||
return (self.getShortnameByMakeprofile(self.systemRoot) or
|
||||
self.getShortnameByIni(self.systemRoot) or
|
||||
self.detectOtherShortname(self.systemRoot) or
|
||||
"Linux")
|
||||
|
||||
|
||||
class VariableOsLinuxName(Variable, Linux):
|
||||
"""
|
||||
Full system name
|
||||
"""
|
||||
source_variable = "os_linux_shortname"
|
||||
|
||||
def get(self):
|
||||
linux_short_name = self.Get(self.source_variable)
|
||||
return self.dictLinuxName.get(linux_short_name, "Linux")
|
||||
|
||||
|
||||
class VariableOsLinuxSubname(Variable, Linux):
|
||||
"""
|
||||
Subname of linux (KDE, GNOME, XFCE and etc)
|
||||
"""
|
||||
source_variable = "os_linux_shortname"
|
||||
|
||||
def get(self):
|
||||
linux_short_name = self.Get(self.source_variable)
|
||||
return self.dictLinuxSubName.get(linux_short_name, "")
|
||||
|
||||
|
||||
class VariableOsLinuxSystem(Variable, Linux):
|
||||
"""
|
||||
System of linux (desktop or server)
|
||||
"""
|
||||
source_variable = "os_linux_shortname"
|
||||
|
||||
def get(self):
|
||||
short_name = self.Get(self.source_variable)
|
||||
return self.dictNameSystem.get(short_name, "")
|
||||
|
||||
|
||||
class VariableOsLinuxVer(Variable, Linux):
|
||||
"""
|
||||
Version of system (get by metapackage,calculate.ini,gentoo files or 0)
|
||||
"""
|
||||
systemRoot = "/"
|
||||
|
||||
def get(self):
|
||||
"""Get system version"""
|
||||
linux_short_name = self.Get("os_linux_shortname")
|
||||
return (self.getVersionFromOverlay(self.systemRoot) or
|
||||
self.getVersionFromMetapackage(
|
||||
self.systemRoot, linux_short_name) or
|
||||
self.getVersionFromCalculateIni(self.systemRoot) or
|
||||
self.getVersionFromGentooFiles(self.systemRoot) or
|
||||
self.getVersionFromUname() or "0")
|
||||
|
||||
|
||||
class VariableOsLinuxBuild(Variable, Linux):
|
||||
"""
|
||||
Build of system
|
||||
"""
|
||||
|
||||
|
||||
class VariableOsLinuxFilesnum(Variable, Linux):
|
||||
systemRoot = "/"
|
||||
|
||||
def get(self):
|
||||
"""Depricated variable which contains count files.
|
||||
Get files count. Count files discard because it to long
|
||||
operation. This value is already count by calculate-builder and
|
||||
is placed in calculate3.env"""
|
||||
return str(0)
|
||||
# return str(countFiles(self.systemRoot))
|
||||
|
||||
|
||||
class VariableOsLinuxFiles(Variable, Linux):
|
||||
systemRoot = "/"
|
||||
|
||||
def get(self):
|
||||
"""Get files count. Count files discard because it to long
|
||||
operation. This value is already count by calculate-builder and
|
||||
is placed in calculate.env"""
|
||||
return self.Get('os_linux_filesnum')
|
||||
# return str(countFiles(self.systemRoot))
|
||||
|
||||
|
||||
class VariableOsLinuxPkglist(Variable):
|
||||
type = "list"
|
||||
|
||||
def generate_shortnames(self, make_profile):
|
||||
repos = RepositorySubstituting(self)
|
||||
for fn in searchProfile(make_profile, "calculate.env",
|
||||
repository_sub=repos):
|
||||
config = ConfigParser(strict=False)
|
||||
config.read(fn, encoding="utf-8")
|
||||
value = SimpleDataVars.unserialize("string",
|
||||
config.get('main',
|
||||
'os_linux_shortname',
|
||||
raw=True,
|
||||
fallback=''))
|
||||
yield value.encode('utf-8')
|
||||
|
||||
def get(self):
|
||||
make_profile = self.Get('cl_make_profile')
|
||||
if path.exists(make_profile):
|
||||
return list(unique(filter(None,
|
||||
self.generate_shortnames(make_profile))))
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
class VariableClProfileSystem(ReadonlyVariable):
|
||||
"""
|
||||
Профиль системы (симлинк /etc/make.profile')
|
||||
"""
|
||||
|
||||
def get(self):
|
||||
try:
|
||||
make_profile = self.Get('cl_make_profile')
|
||||
return path.normpath(
|
||||
path.join(path.dirname(make_profile),
|
||||
os.readlink(make_profile)))
|
||||
except:
|
||||
raise VariableError(_("Failed to determine the system profile"))
|
||||
|
||||
|
||||
class VariableClProfileName(ReadonlyVariable):
|
||||
source_var = "cl_profile_system"
|
||||
|
||||
def get(self):
|
||||
make_profile = self.Get(self.source_var)
|
||||
distro, o, name = make_profile.partition('/profiles/')
|
||||
if not o:
|
||||
return make_profile
|
||||
distro = path.basename(distro)
|
||||
return "%s:%s" % (distro, name)
|
||||
|
||||
|
||||
class LinuxDataVars(SimpleDataVars):
|
||||
class VariableOsArchMachine(ReadonlyVariable):
|
||||
systemRoot = '/'
|
||||
|
||||
def get(self):
|
||||
if path.exists(path.join(self.systemRoot, 'lib64')):
|
||||
return 'x86_64'
|
||||
else:
|
||||
return 'i686'
|
||||
|
||||
def variables(self):
|
||||
os_arch_machine = self.VariableOsArchMachine(systemRoot=self.systemRoot)
|
||||
|
||||
return [env.VariableClMakeProfile(systemRoot=self.systemRoot),
|
||||
VariableClProfileName(systemRoot=self.systemRoot),
|
||||
VariableClProfileSystem(systemRoot=self.systemRoot),
|
||||
env.VariableClChrootPath(),
|
||||
os_arch_machine,
|
||||
VariableOsLinuxShortname(systemRoot=self.systemRoot),
|
||||
VariableOsLinuxName(systemRoot=self.systemRoot),
|
||||
VariableOsLinuxSubname(systemRoot=self.systemRoot),
|
||||
VariableOsLinuxFilesnum(systemRoot=self.systemRoot),
|
||||
env.VariableClEmergeConfig(systemRoot=self.systemRoot),
|
||||
VariableOsLinuxFiles(systemRoot=self.systemRoot),
|
||||
VariableOsLinuxSystem(systemRoot=self.systemRoot),
|
||||
VariableOsLinuxVer(systemRoot=self.systemRoot),
|
||||
VariableOsLinuxBuild(systemRoot=self.systemRoot)]
|
||||
|
||||
def __init__(self, systemRoot="/", cache=None):
|
||||
self.systemRoot = systemRoot
|
||||
SimpleDataVars.__init__(self, *self.variables())
|
||||
self.init_variables()
|
||||
if cache is None:
|
||||
makeprofile = self.Get('cl_make_profile')
|
||||
if os.path.exists(makeprofile):
|
||||
inifile = path.join(systemRoot, os.path.dirname(makeprofile),
|
||||
os.readlink(makeprofile))
|
||||
self.flIniFileFrom(inifile, system_root=systemRoot)
|
||||
self.flCalculateEnv(systemRoot)
|
||||
else:
|
||||
self.cache = cache
|
||||
|
||||
def flCalculateEnv(self, systemRoot):
|
||||
env_data = dict(env._envData)
|
||||
for inifile in (env_data['system'],
|
||||
env_data['custom']):
|
||||
self.flIniFileFrom(path.join(systemRoot, drop_slash(inifile)),
|
||||
system_root=systemRoot)
|
||||
|
||||
def init_variables(self):
|
||||
self['cl_chroot_path'] = self.systemRoot
|
||||
return True
|
||||
|
||||
def change_root(self, dn, new_root='/'):
|
||||
if dn.startswith(self.systemRoot):
|
||||
return pathJoin(new_root, dn[len(self.systemRoot):])
|
||||
return dn
|
Loading…
Reference in new issue