mirror of
https://github.com/naruxde/revpipyload.git
synced 2025-11-08 23:23:52 +01:00
autoreloaddelay implementiert
Update der IpAclManager-Klasse
This commit is contained in:
@@ -68,6 +68,9 @@ Methods</h3>
|
|||||||
<td><a style="color:#0000FF" href="#IpAclManager.__get_regex_acl">__get_regex_acl</a></td>
|
<td><a style="color:#0000FF" href="#IpAclManager.__get_regex_acl">__get_regex_acl</a></td>
|
||||||
<td>Gibt formatierten RegEx-String zurueck.</td>
|
<td>Gibt formatierten RegEx-String zurueck.</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
|
<td><a style="color:#0000FF" href="#IpAclManager.__iter__">__iter__</a></td>
|
||||||
|
<td>Gibt einzelne ACLs als <class 'tuple'> aus.</td>
|
||||||
|
</tr><tr>
|
||||||
<td><a style="color:#0000FF" href="#IpAclManager.__set_acl">__set_acl</a></td>
|
<td><a style="color:#0000FF" href="#IpAclManager.__set_acl">__set_acl</a></td>
|
||||||
<td>Uebernimmt neue ACL-Liste fuer die Ausertung der Level.</td>
|
<td>Uebernimmt neue ACL-Liste fuer die Ausertung der Level.</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
@@ -86,11 +89,17 @@ Static Methods</h3>
|
|||||||
<a NAME="IpAclManager.__init__" ID="IpAclManager.__init__"></a>
|
<a NAME="IpAclManager.__init__" ID="IpAclManager.__init__"></a>
|
||||||
<h3 style="background-color:#FFFFFF;color:#FF0000">
|
<h3 style="background-color:#FFFFFF;color:#FF0000">
|
||||||
IpAclManager (Constructor)</h3>
|
IpAclManager (Constructor)</h3>
|
||||||
<b>IpAclManager</b>(<i>acl=None, minlevel=0, maxlevel=0</i>)
|
<b>IpAclManager</b>(<i>minlevel, maxlevel, acl=None</i>)
|
||||||
<p>
|
<p>
|
||||||
Init IpAclManager class.
|
Init IpAclManager class.
|
||||||
</p><dl>
|
</p><dl>
|
||||||
<dt><i>acl</i></dt>
|
<dt><i>minlevel</i></dt>
|
||||||
|
<dd>
|
||||||
|
Smallest access level (min. 0)
|
||||||
|
</dd><dt><i>maxlevel</i></dt>
|
||||||
|
<dd>
|
||||||
|
Biggest access level (max. 9)
|
||||||
|
</dd><dt><i>acl</i></dt>
|
||||||
<dd>
|
<dd>
|
||||||
ACL Liste fuer Berechtigungen als <class 'str'>
|
ACL Liste fuer Berechtigungen als <class 'str'>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -108,6 +117,12 @@ IpAclManager.__get_regex_acl</h3>
|
|||||||
<p>
|
<p>
|
||||||
Gibt formatierten RegEx-String zurueck.
|
Gibt formatierten RegEx-String zurueck.
|
||||||
return RegEx Code als <class 'str'>
|
return RegEx Code als <class 'str'>
|
||||||
|
</p><a NAME="IpAclManager.__iter__" ID="IpAclManager.__iter__"></a>
|
||||||
|
<h3 style="background-color:#FFFFFF;color:#FF0000">
|
||||||
|
IpAclManager.__iter__</h3>
|
||||||
|
<b>__iter__</b>(<i></i>)
|
||||||
|
<p>
|
||||||
|
Gibt einzelne ACLs als <class 'tuple'> aus.
|
||||||
</p><a NAME="IpAclManager.__set_acl" ID="IpAclManager.__set_acl"></a>
|
</p><a NAME="IpAclManager.__set_acl" ID="IpAclManager.__set_acl"></a>
|
||||||
<h3 style="background-color:#FFFFFF;color:#FF0000">
|
<h3 style="background-color:#FFFFFF;color:#FF0000">
|
||||||
IpAclManager.__set_acl</h3>
|
IpAclManager.__set_acl</h3>
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ Static Methods</h3>
|
|||||||
<a NAME="SaveXMLRPCServer.__init__" ID="SaveXMLRPCServer.__init__"></a>
|
<a NAME="SaveXMLRPCServer.__init__" ID="SaveXMLRPCServer.__init__"></a>
|
||||||
<h3 style="background-color:#FFFFFF;color:#FF0000">
|
<h3 style="background-color:#FFFFFF;color:#FF0000">
|
||||||
SaveXMLRPCServer (Constructor)</h3>
|
SaveXMLRPCServer (Constructor)</h3>
|
||||||
<b>SaveXMLRPCServer</b>(<i>addr, logRequests=True, allow_none=False, use_builtin_types=False, ipacl=IpAclManager()</i>)
|
<b>SaveXMLRPCServer</b>(<i>addr, logRequests=True, allow_none=False, use_builtin_types=False, ipacl=None</i>)
|
||||||
<p>
|
<p>
|
||||||
Init SaveXMLRPCServer class.
|
Init SaveXMLRPCServer class.
|
||||||
</p><a NAME="SaveXMLRPCServer._dispatch" ID="SaveXMLRPCServer._dispatch"></a>
|
</p><a NAME="SaveXMLRPCServer._dispatch" ID="SaveXMLRPCServer._dispatch"></a>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
helper.IpAclManager.__get_acl?6()
|
helper.IpAclManager.__get_acl?6()
|
||||||
helper.IpAclManager.__get_regex_acl?6()
|
helper.IpAclManager.__get_regex_acl?6()
|
||||||
|
helper.IpAclManager.__iter__?6()
|
||||||
helper.IpAclManager.__set_acl?6(value)
|
helper.IpAclManager.__set_acl?6(value)
|
||||||
helper.IpAclManager.acl?7
|
helper.IpAclManager.acl?7
|
||||||
helper.IpAclManager.get_acllevel?4(ipaddress)
|
helper.IpAclManager.get_acllevel?4(ipaddress)
|
||||||
helper.IpAclManager.loadacl?4(str_acl)
|
helper.IpAclManager.loadacl?4(str_acl)
|
||||||
helper.IpAclManager.regex_acl?7
|
helper.IpAclManager.regex_acl?7
|
||||||
helper.IpAclManager?1(acl=None, minlevel=0, maxlevel=0)
|
helper.IpAclManager?1(minlevel, maxlevel, acl=None)
|
||||||
helper._setuprt?5(pid, evt_exit)
|
helper._setuprt?5(pid, evt_exit)
|
||||||
helper._zeroprocimg?5()
|
helper._zeroprocimg?5()
|
||||||
helper.refullmatch?4(regex, string)
|
helper.refullmatch?4(regex, string)
|
||||||
@@ -90,4 +91,4 @@ xrpcserver.SaveXMLRPCServer.isAlive?4()
|
|||||||
xrpcserver.SaveXMLRPCServer.register_function?4(acl_level, function, name=None)
|
xrpcserver.SaveXMLRPCServer.register_function?4(acl_level, function, name=None)
|
||||||
xrpcserver.SaveXMLRPCServer.start?4()
|
xrpcserver.SaveXMLRPCServer.start?4()
|
||||||
xrpcserver.SaveXMLRPCServer.stop?4()
|
xrpcserver.SaveXMLRPCServer.stop?4()
|
||||||
xrpcserver.SaveXMLRPCServer?1(addr, logRequests=True, allow_none=False, use_builtin_types=False, ipacl=IpAclManager())
|
xrpcserver.SaveXMLRPCServer?1(addr, logRequests=True, allow_none=False, use_builtin_types=False, ipacl=None)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE Project SYSTEM "Project-5.1.dtd">
|
<!DOCTYPE Project SYSTEM "Project-5.1.dtd">
|
||||||
<!-- eric project file for project revpipyload -->
|
<!-- eric project file for project revpipyload -->
|
||||||
<!-- Saved: 2018-03-08, 10:56:15 -->
|
<!-- Saved: 2018-04-03, 20:12:25 -->
|
||||||
<!-- Copyright (C) 2018 Sven Sager, akira@narux.de -->
|
<!-- Copyright (C) 2018 Sven Sager, akira@narux.de -->
|
||||||
<Project version="5.1">
|
<Project version="5.1">
|
||||||
<Language>en_US</Language>
|
<Language>en_US</Language>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<ProgLanguage mixed="0">Python3</ProgLanguage>
|
<ProgLanguage mixed="0">Python3</ProgLanguage>
|
||||||
<ProjectType>Console</ProjectType>
|
<ProjectType>Console</ProjectType>
|
||||||
<Description>Dieser Loader wird über das Init-System geladen und führt das angegebene Pythonprogramm aus. Es ist für den RevolutionPi gedacht um automatisch das SPS-Programm zu starten.</Description>
|
<Description>Dieser Loader wird über das Init-System geladen und führt das angegebene Pythonprogramm aus. Es ist für den RevolutionPi gedacht um automatisch das SPS-Programm zu starten.</Description>
|
||||||
<Version>0.6.0</Version>
|
<Version>0.6.1</Version>
|
||||||
<Author>Sven Sager</Author>
|
<Author>Sven Sager</Author>
|
||||||
<Email>akira@narux.de</Email>
|
<Email>akira@narux.de</Email>
|
||||||
<Eol index="1"/>
|
<Eol index="1"/>
|
||||||
|
|||||||
@@ -16,17 +16,28 @@ class IpAclManager():
|
|||||||
|
|
||||||
"""Verwaltung fuer IP Adressen und deren ACL Level."""
|
"""Verwaltung fuer IP Adressen und deren ACL Level."""
|
||||||
|
|
||||||
def __init__(self, acl=None, minlevel=0, maxlevel=0):
|
def __init__(self, minlevel, maxlevel, acl=None):
|
||||||
"""Init IpAclManager class.
|
"""Init IpAclManager class.
|
||||||
@param acl ACL Liste fuer Berechtigungen als <class 'str'>"""
|
|
||||||
if minlevel > maxlevel:
|
@param minlevel Smallest access level (min. 0)
|
||||||
raise ValueError("minlevel is smaller than maxlevel")
|
@param maxlevel Biggest access level (max. 9)
|
||||||
|
@param acl ACL Liste fuer Berechtigungen als <class 'str'>
|
||||||
|
|
||||||
|
"""
|
||||||
|
if type(minlevel) != int:
|
||||||
|
raise ValueError("parameter minlevel must be <class 'int'>")
|
||||||
|
if type(maxlevel) != int:
|
||||||
|
raise ValueError("parameter maxlevel must be <class 'int'>")
|
||||||
if minlevel < 0:
|
if minlevel < 0:
|
||||||
raise ValueError("minlevel must be 0 or more")
|
raise ValueError("minlevel must be 0 or more")
|
||||||
|
if maxlevel > 9:
|
||||||
|
raise ValueError("maxlevel maximum is 9")
|
||||||
|
if minlevel > maxlevel:
|
||||||
|
raise ValueError("minlevel is smaller than maxlevel")
|
||||||
|
|
||||||
self.__dict_acl = {}
|
self.__dict_acl = {}
|
||||||
self.__dict_ips = {}
|
self.__dict_regex = {}
|
||||||
self.__rawacl = ""
|
self.__dict_knownips = {}
|
||||||
self.__re_ipacl = "(([\\d\\*]{1,3}\\.){3}[\\d\\*]{1,3},[" \
|
self.__re_ipacl = "(([\\d\\*]{1,3}\\.){3}[\\d\\*]{1,3},[" \
|
||||||
+ str(minlevel) + "-" + str(maxlevel) + "] ?)*"
|
+ str(minlevel) + "-" + str(maxlevel) + "] ?)*"
|
||||||
|
|
||||||
@@ -34,10 +45,18 @@ class IpAclManager():
|
|||||||
if acl is not None:
|
if acl is not None:
|
||||||
self.__set_acl(acl)
|
self.__set_acl(acl)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""Gibt einzelne ACLs als <class 'tuple'> aus."""
|
||||||
|
for aclip in sorted(self.__dict_acl):
|
||||||
|
yield (aclip, self.__dict_acl[aclip])
|
||||||
|
|
||||||
def __get_acl(self):
|
def __get_acl(self):
|
||||||
"""Getter fuer den rohen ACL-String.
|
"""Getter fuer den rohen ACL-String.
|
||||||
return ACLs als <class 'str'>"""
|
return ACLs als <class 'str'>"""
|
||||||
return self.__rawacl
|
str_acl = ""
|
||||||
|
for aclip in sorted(self.__dict_acl):
|
||||||
|
str_acl += "{},{} ".format(aclip, self.__dict_acl[aclip])
|
||||||
|
return str_acl.strip()
|
||||||
|
|
||||||
def __get_regex_acl(self):
|
def __get_regex_acl(self):
|
||||||
"""Gibt formatierten RegEx-String zurueck.
|
"""Gibt formatierten RegEx-String zurueck.
|
||||||
@@ -50,32 +69,34 @@ class IpAclManager():
|
|||||||
if type(value) != str:
|
if type(value) != str:
|
||||||
raise ValueError("parameter acl must be <class 'str'>")
|
raise ValueError("parameter acl must be <class 'str'>")
|
||||||
|
|
||||||
|
value = value.strip()
|
||||||
if not refullmatch(self.__re_ipacl, value):
|
if not refullmatch(self.__re_ipacl, value):
|
||||||
raise ValueError("acl format ist not okay - 1.2.3.4,0 5.6.7.8,1")
|
raise ValueError("acl format ist not okay - 1.2.3.4,0 5.6.7.8,1")
|
||||||
|
|
||||||
# Klassenwerte übernehmen
|
# Klassenwerte übernehmen
|
||||||
self.__dict_acl = {}
|
self.__dict_acl = {}
|
||||||
self.__dict_ips = {}
|
self.__dict_regex = {}
|
||||||
self.__rawacl = value
|
self.__dict_knownips = {}
|
||||||
|
|
||||||
# Liste neu füllen mit regex Strings
|
# Liste neu füllen mit regex Strings
|
||||||
for ip_level in value.split():
|
for ip_level in value.split():
|
||||||
ip, level = ip_level.split(",", 1)
|
ip, level = ip_level.split(",", 1)
|
||||||
ip = ip.replace(".", "\\.").replace("*", "\\d{1,3}")
|
|
||||||
self.__dict_acl[ip] = int(level)
|
self.__dict_acl[ip] = int(level)
|
||||||
|
self.__dict_regex[ip] = \
|
||||||
|
ip.replace(".", "\\.").replace("*", "\\d{1,3}")
|
||||||
|
|
||||||
def get_acllevel(self, ipaddress):
|
def get_acllevel(self, ipaddress):
|
||||||
"""Prueft IP gegen ACL List und gibt ACL-Wert aus.
|
"""Prueft IP gegen ACL List und gibt ACL-Wert aus.
|
||||||
@param ipaddress zum pruefen
|
@param ipaddress zum pruefen
|
||||||
@return <class 'int'> ACL Wert oder -1 wenn nicht gefunden"""
|
@return <class 'int'> ACL Wert oder -1 wenn nicht gefunden"""
|
||||||
# Bei bereits aufgelösten IPs direkt ACL auswerten
|
# Bei bereits aufgelösten IPs direkt ACL auswerten
|
||||||
if ipaddress in self.__dict_ips:
|
if ipaddress in self.__dict_knownips:
|
||||||
return self.__dict_ips[ipaddress]
|
return self.__dict_knownips[ipaddress]
|
||||||
|
|
||||||
for aclip in sorted(self.__dict_acl, reverse=True):
|
for aclip in sorted(self.__dict_acl, reverse=True):
|
||||||
if refullmatch(aclip, ipaddress):
|
if refullmatch(self.__dict_regex[aclip], ipaddress):
|
||||||
# IP und Level merken
|
# IP und Level merken
|
||||||
self.__dict_ips[ipaddress] = self.__dict_acl[aclip]
|
self.__dict_knownips[ipaddress] = self.__dict_acl[aclip]
|
||||||
|
|
||||||
# Level zurückgeben
|
# Level zurückgeben
|
||||||
return self.__dict_acl[aclip]
|
return self.__dict_acl[aclip]
|
||||||
@@ -86,10 +107,10 @@ class IpAclManager():
|
|||||||
"""Laed ACL String und gibt erfolg zurueck.
|
"""Laed ACL String und gibt erfolg zurueck.
|
||||||
@param str_acl ACL als <class 'str'>
|
@param str_acl ACL als <class 'str'>
|
||||||
@return True, wenn erfolgreich uebernommen"""
|
@return True, wenn erfolgreich uebernommen"""
|
||||||
if refullmatch(self.__re_ipacl, str_acl):
|
if not refullmatch(self.__re_ipacl, str_acl):
|
||||||
self.__set_acl(str_acl)
|
return False
|
||||||
return True
|
self.__set_acl(str_acl)
|
||||||
return False
|
return True
|
||||||
|
|
||||||
acl = property(__get_acl, __set_acl)
|
acl = property(__get_acl, __set_acl)
|
||||||
regex_acl = property(__get_regex_acl)
|
regex_acl = property(__get_regex_acl)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class RevPiPlc(Thread):
|
|||||||
self._procplc = None
|
self._procplc = None
|
||||||
self._pversion = pversion
|
self._pversion = pversion
|
||||||
self.autoreload = False
|
self.autoreload = False
|
||||||
|
self.autoreloaddelay = 5 * 2
|
||||||
self.exitcode = None
|
self.exitcode = None
|
||||||
self.gid = 65534
|
self.gid = 65534
|
||||||
self.uid = 65534
|
self.uid = 65534
|
||||||
@@ -131,44 +132,54 @@ class RevPiPlc(Thread):
|
|||||||
_setuprt(self._procplc.pid, self._evt_exit)
|
_setuprt(self._procplc.pid, self._evt_exit)
|
||||||
|
|
||||||
# Überwachung starten
|
# Überwachung starten
|
||||||
|
delaycounter = self.autoreloaddelay
|
||||||
while not self._evt_exit.is_set():
|
while not self._evt_exit.is_set():
|
||||||
|
|
||||||
# Auswerten
|
# Auswerten
|
||||||
self.exitcode = self._procplc.poll()
|
self.exitcode = self._procplc.poll()
|
||||||
|
|
||||||
if self.exitcode is not None:
|
if self.exitcode is not None:
|
||||||
if self.exitcode > 0:
|
if delaycounter == self.autoreloaddelay:
|
||||||
# PLC Python Programm abgestürzt
|
if self.exitcode > 0:
|
||||||
proginit.logger.error(
|
# PLC Python Programm abgestürzt
|
||||||
"plc program crashed - exitcode: {}".format(
|
proginit.logger.error(
|
||||||
self.exitcode
|
"plc program crashed - exitcode: {}".format(
|
||||||
|
self.exitcode
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
if self.zeroonerror:
|
||||||
if self.zeroonerror:
|
_zeroprocimg()
|
||||||
_zeroprocimg()
|
proginit.logger.warning(
|
||||||
proginit.logger.warning(
|
"set piControl0 to ZERO after "
|
||||||
"set piControl0 to ZERO after PLC program error")
|
"PLC program error"
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# PLC Python Programm sauber beendet
|
# PLC Python Programm sauber beendet
|
||||||
proginit.logger.info("plc program did a clean exit")
|
proginit.logger.info("plc program did a clean exit")
|
||||||
if self.zeroonexit:
|
if self.zeroonexit:
|
||||||
_zeroprocimg()
|
_zeroprocimg()
|
||||||
proginit.logger.info(
|
proginit.logger.info(
|
||||||
"set piControl0 to ZERO after PLC program returns "
|
"set piControl0 to ZERO after "
|
||||||
"clean exitcode")
|
"PLC program returns clean exitcode"
|
||||||
|
)
|
||||||
|
|
||||||
if not self._evt_exit.is_set() and self.autoreload:
|
if not self._evt_exit.is_set() and self.autoreload:
|
||||||
# Prozess neu starten
|
if delaycounter > 0:
|
||||||
self._procplc = self._spopen(lst_proc)
|
delaycounter -= 1
|
||||||
if self.exitcode == 0:
|
|
||||||
proginit.logger.warning(
|
|
||||||
"restart plc program after clean exit"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
proginit.logger.warning(
|
delaycounter = self.autoreloaddelay
|
||||||
"restart plc program after crash"
|
|
||||||
)
|
# Prozess neu starten
|
||||||
|
self._procplc = self._spopen(lst_proc)
|
||||||
|
if self.exitcode == 0:
|
||||||
|
proginit.logger.warning(
|
||||||
|
"restart plc program after clean exit"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
proginit.logger.warning(
|
||||||
|
"restart plc program after crash"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ from time import asctime
|
|||||||
from xmlrpc.client import Binary
|
from xmlrpc.client import Binary
|
||||||
from xrpcserver import SaveXMLRPCServer
|
from xrpcserver import SaveXMLRPCServer
|
||||||
|
|
||||||
pyloadversion = "0.6.0"
|
pyloadversion = "0.6.1"
|
||||||
|
|
||||||
|
|
||||||
class RevPiPyLoad():
|
class RevPiPyLoad():
|
||||||
@@ -305,6 +305,7 @@ class RevPiPyLoad():
|
|||||||
self.pythonversion
|
self.pythonversion
|
||||||
)
|
)
|
||||||
th_plc.autoreload = bool(self.autoreload)
|
th_plc.autoreload = bool(self.autoreload)
|
||||||
|
th_plc.autoreloaddelay = self.autoreloaddelay
|
||||||
th_plc.gid = int(self.plcgid)
|
th_plc.gid = int(self.plcgid)
|
||||||
th_plc.uid = int(self.plcuid)
|
th_plc.uid = int(self.plcuid)
|
||||||
th_plc.rtlevel = int(self.rtlevel)
|
th_plc.rtlevel = int(self.rtlevel)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class SaveXMLRPCServer(SimpleXMLRPCServer):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, addr, logRequests=True, allow_none=False,
|
self, addr, logRequests=True, allow_none=False,
|
||||||
use_builtin_types=False, ipacl=IpAclManager()):
|
use_builtin_types=False, ipacl=None):
|
||||||
"""Init SaveXMLRPCServer class."""
|
"""Init SaveXMLRPCServer class."""
|
||||||
proginit.logger.debug("enter SaveXMLRPCServer.__init__()")
|
proginit.logger.debug("enter SaveXMLRPCServer.__init__()")
|
||||||
|
|
||||||
@@ -34,7 +34,10 @@ class SaveXMLRPCServer(SimpleXMLRPCServer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Klassenvariablen
|
# Klassenvariablen
|
||||||
self.aclmgr = ipacl
|
if ipacl is None:
|
||||||
|
self.aclmgr = IpAclManager(0, 0)
|
||||||
|
else:
|
||||||
|
self.aclmgr = ipacl
|
||||||
self.funcacls = {}
|
self.funcacls = {}
|
||||||
self.requestacl = -1
|
self.requestacl = -1
|
||||||
self.tpe = futures.ThreadPoolExecutor(max_workers=1)
|
self.tpe = futures.ThreadPoolExecutor(max_workers=1)
|
||||||
|
|||||||
3
setup.py
3
setup.py
@@ -27,11 +27,12 @@ setup(
|
|||||||
|
|
||||||
license="LGPLv3",
|
license="LGPLv3",
|
||||||
name="revpipyload",
|
name="revpipyload",
|
||||||
version="0.6.0",
|
version="0.6.1",
|
||||||
|
|
||||||
scripts=["data/revpipyload"],
|
scripts=["data/revpipyload"],
|
||||||
|
|
||||||
install_requires=["revpimodio2"],
|
install_requires=["revpimodio2"],
|
||||||
|
python_requires=">=3.2",
|
||||||
|
|
||||||
data_files=[
|
data_files=[
|
||||||
("/etc/avahi/services", [
|
("/etc/avahi/services", [
|
||||||
|
|||||||
Reference in New Issue
Block a user