- Rewrited
- Add multi-lang support
---
Current languages:
- English
- Russian
This commit is contained in:
trueold89 2024-03-25 07:50:38 +03:00
commit 2280b74221
Signed by: trueold89
GPG Key ID: C122E85DD49E6B30
11 changed files with 267 additions and 84 deletions

BIN
.ex.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
.ex.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
old/
VoidServiceControl/main.py
__pycache__
.idea
.venv
probe.py

View File

@ -1,17 +1,30 @@
# Void Service Control (VSC)
## A simple script that will allow you to manage runit services in Void Linux
- [Installation](#install)
- [Usage](#usage)
- [Build from sources](#build-from_sources)
- [Example (Screenshot)](#example)
### Install:
**You can install vsc using pip:**
From [git.orudo.ru](https://git.orudo.ru/trueold89/void-service-control/releases):
```bash
$ pip install https://git.orudo.ru/trueold89/void-service-control/releases/download/0.2/VoidServiceControl-0.2.tar.gz
```
or pypi
```bash
$ pip install void-service-control
```
---
or by downloading the pre-built binary from the **[releases](https://git.orudo.ru/trueold89/void-service-control/releases)** page
**Or by downloading the pre-built binary / xbps-package from the **[releases](https://git.orudo.ru/trueold89/void-service-control/releases)** page**
***
@ -29,15 +42,40 @@ $ vsc e <service_name>
$ vsc d <service_name>
```
**Print help**
**Print help:**
```bash
$ vsc --help
```
*All commands require root privileges*
### Build from sources
**Clone repo:**
```bash
$ git clone https://git.orudo.ru/trueold89/void-service-control.git --depth=1 && cd void-service-control
```
**Install deps:**
```bash
$ pip install setuptools
```
**Build sdist:**
```bash
$ python3 setup.py sdist
```
**Install:**
```bash
$ pip install dist/*
```
*Last command require root privileges*
***
## Example:
![](.ex.png)
![](.ex.jpg)

View File

View File

@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
import importlib.resources
import json
from enum import Enum
from os import listdir as ls
from subprocess import run as execute
from subprocess import PIPE
from sys import argv
from VoidServiceControl.env import *
class Help(Exception):
def __str__(self) -> str:
"""
Returns the program usage help
:return: Program usage help
"""
return lang.messages["help"]
def Su() -> None:
"""
Checks if the user has administrator rights
"""
user = execute('whoami', shell=True, text=True, stdout=PIPE).stdout[:-1]
if user != 'root':
raise PermissionError(lang.errors["su"])
# Types of service actions
class Action(Enum):
ENABLE = ["enable", "e", "on", "up"]
DISABLE = ["disable", "d", "off", "down"]
# Types of run arguments
class Arg(Enum):
HELP = ["--help", "-h", "help"]
@classmethod
def all(cls) -> list[str]:
"""
Returns all types of run arguments
:return: All types of run arguments list
"""
return cls.HELP.value + cls.__action()
@classmethod
def __action(cls) -> list[str]:
"""
Returns all types of service actions
:return: All types of service actions list
"""
actions = list(map(lambda action: action.value, Action))
out = []
for lst in actions:
out.extend(lst)
return out
class Args(object):
def __init__(self) -> None:
self.__arguments = argv[1:]
self.__check()
def __check(self) -> None:
"""
Checks the arguments
"""
if len(self.__arguments) == 0:
raise TypeError(lang.errors["usage"])
if len(self.__arguments) != 2 and self.__arguments[0] not in Arg.HELP.value:
raise TypeError(lang.errors["usage"])
if self.__arguments[0] in Arg.HELP.value:
raise Help()
if self.__arguments[0] not in Arg.all():
raise TypeError(lang.errors["args"])
def __action(self) -> Action:
"""
Returns the action to the service
:return: Service action
"""
actions = list(Action)
for action in actions:
if self.__arguments[0] in action.value:
return action
def __iter__(self):
yield self.__action()
yield self.__arguments[1]
class Service(object):
__enabled = False
def __init__(self, name: str) -> None:
self.__name = name
self.__check()
def __check(self) -> None:
"""
Checks if the service exists and is enabled
"""
all_services = ls(SV_PATH)
enabled_services = ls(ENABLED_PATH)
if self.__name not in all_services:
raise ValueError(lang.errors["ne"].format(self.getname()))
if self.__name in enabled_services:
self.__enabled = True
def getname(self) -> str:
"""
Returns the service name
:return: Service name
"""
return self.__name
def enable(self) -> None:
"""
Enable the service
"""
if self.__enabled:
raise ValueError(lang.errors["enabled"].format(self.getname()))
execute(f'ln -s {SV_PATH}/{self.__name} {ENABLED_PATH}/', shell=True)
def disable(self):
"""
Disable the service
"""
if not self.__enabled:
raise ValueError(lang.errors["disabled"].format(self.getname()))
execute(f'rm {ENABLED_PATH}/{self.__name}', shell=True)
class Interface(object):
def __init__(self, service: str) -> None:
self.service = Service(service)
def action(self, action: Action) -> None:
"""
Performs an action on the service
:param action: Action on the service
"""
match action:
case Action.ENABLE:
self.service.enable()
print(lang.messages["enabled"].format(self.service.getname()))
case Action.DISABLE:
self.service.disable()
print(lang.messages["disabled"].format(self.service.getname()))
class Translate(object):
def __init__(self, language: str):
"""
:param language: Language (ex. en_US)
"""
self.lang = language
self.errors = self.__translation["errors"]
self.messages = self.__translation["messages"]
@property
def __translation(self):
try:
with importlib.resources.open_text(__package__, f"{self.lang}.json", "utf-8") as json_file:
return json.loads(json_file.read())
except FileNotFoundError:
with importlib.resources.open_text(__package__, f"en_US.json", "utf-8") as json_file:
return json.loads(json_file.read())
lang = Translate(LANG)

View File

@ -0,0 +1 @@
{"errors": {"su": "Error: Access denied", "usage": "Bad usage", "args": "Error: Invalid args", "ne": "Error: Service '{}' doesn't exists", "enabled": "Error: Service '{}' already enabled", "disabled": "Error: Service '{}' already disabled"}, "messages": {"enabled": "Service '{}' successfully enabled", "disabled": "Service '{}' successfully disabled", "help": "Usage:\n---\nvsc {e/enable/on/up} <service_name> - Run service and add it to autostart\nvsc {d/disable/off/down <service_name> - Stop service and remove it from autostart"}}

22
VoidServiceControl/env.py Normal file
View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from os import environ
# Edit these lines if you are using custom paths to Runit services
SV_PATH = '/etc/sv'
ENABLED_PATH = '/var/service'
# Lang settings
def lang() -> str:
"""
Get system lang
:return: system lang
"""
try:
return environ["LANG"][:5]
except KeyError:
return "en_US"
LANG = lang()

View File

@ -0,0 +1 @@
{"errors": {"su": "\u041e\u0448\u0438\u0431\u043a\u0430: \u0414\u043e\u0441\u0442\u0443\u043f \u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d", "usage": "\u041e\u0448\u0438\u0431\u043a\u0430: \u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435", "args": "\u041e\u0448\u0438\u0431\u043a\u0430: \u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b", "ne": "\u041e\u0448\u0438\u0431\u043a\u0430: \u0421\u0435\u0440\u0432\u0438\u0441 '{}' \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442", "enabled": "\u041e\u0448\u0438\u0431\u043a\u0430: \u0421\u0435\u0440\u0432\u0438\u0441 '{}' \u0443\u0436\u0435 \u0432\u043a\u043b\u044e\u0447\u0435\u043d", "disabled": "\u041e\u0448\u0438\u0431\u043a\u0430: \u0421\u0435\u0440\u0432\u0438\u0441 '{}' \u0443\u0436\u0435 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d"}, "messages": {"enabled": "\u0421\u0435\u0440\u0432\u0438\u0441 '{}' \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0435\u043d", "disabled": "\u0421\u0435\u0440\u0432\u0438\u0441 '{}' \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d", "help": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435:\n---\nvsc {e/enable/on/up} <\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435_\u0441\u0435\u0440\u0432\u0438\u0441\u0430> - \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0430\u0432\u0442\u043e\u0437\u0430\u043f\u0443\u0441\u043a\nvsc {d/disable/off/down <\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435_\u0441\u0435\u0440\u0432\u0438\u0441\u0430> - \u0412\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437 \u0430\u0432\u0442\u043e\u0437\u0430\u043f\u0443\u0441\u043a\u0430"}}

18
setup.py Normal file
View File

@ -0,0 +1,18 @@
from setuptools import setup
setup(
name='VoidServiceControl',
version='0.2',
url='https://git.orudo.ru/trueold89/void-service-control',
author='trueold89',
author_email='trueold89@orudo.ru',
description="A simple script that will allow you to manage runit services in Void Linux",
packages=['VoidServiceControl'],
long_description=open('README.md').read(),
entry_points={
"console_scripts": ["vsc = VoidServiceControl.main:main"]
},
package_data={
'VoidServiceControl': ['*.json'],
},
)

81
vsc.py
View File

@ -1,81 +0,0 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Import
import os, subprocess, sys
# Const
SV_PATH = '/etc/sv'
ENABLED_PATH = '/var/service'
# Access
def su():
out = subprocess.run('whoami', shell=True, text=True, stdout=subprocess.PIPE)
user = out.stdout[:-1]
if user == 'root':
return True
else:
return False
# Print help message
def helpmsg():
print('''
Usage:
---
vsc {e/enable/on/up} <service_name> - Run service and add it to autostart
vsc {d/disable/off/down <service_name> - Stop service and remove it from autostart
---
''')
sys.exit(1)
# Check exec args
def args_check():
args = sys.orig_argv[2:]
if len(args) == 2:
return args
elif len(args) == 1 and args[0] in ['--h','--help']:
helpmsg()
else:
return False
# Check availability
def availability(service, action):
all = os.listdir(SV_PATH)
enabled = os.listdir(ENABLED_PATH)
all = service in all
if all == False:
raise Exception(f"Service '{service}' doesn't exist")
if service in enabled:
if action == 'on':
raise Exception(f"Service '{service}' already enabled")
elif action == 'off':
return True
else:
if action == 'off':
raise Exception(f"Service '{service}' already disabled")
elif action == 'on':
return True
# Main
def main():
try:
args = args_check()
if args == False:
raise Exception('Bad usage. See --help')
if su() == False:
raise Exception('Access denied')
action, service = args
if action in ['enable','e','on','up']:
if availability(service,'on'):
subprocess.run(f'ln -s {SV_PATH}/{service} {ENABLED_PATH}/', shell=True)
print(f"Service '{service}' successfully enabled")
if action in ['disable','d','off','down']:
if availability(service,'off'):
subprocess.run(f'rm {ENABLED_PATH}/{service}', shell=True)
print(f"Service '{service}' successfully disabled")
except Exception as ex:
print(ex)
sys.exit(0)
if __name__ == '__main__':
main()