mirror of
https://github.com/Maks1mS/altlinux-autorepacked.git
synced 2025-10-15 23:22:07 +03:00
Compare commits
5 Commits
250fe07bf0
...
main
Author | SHA1 | Date | |
---|---|---|---|
7750d226f4 | |||
85cda3e705 | |||
dc54853fc7 | |||
657c424bf1 | |||
233c11efec |
@@ -0,0 +1 @@
|
||||
REPO_PATH=
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.env
|
||||
.env
|
||||
venv
|
12
Dockerfile
12
Dockerfile
@@ -1,9 +1,15 @@
|
||||
FROM registry.altlinux.org/alt/python:p10
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
eepm \
|
||||
wget
|
||||
# && rm -rf /var/lib/apt/lists/*
|
||||
wget \
|
||||
apt-repo-tools \
|
||||
alien \
|
||||
pip \
|
||||
epm
|
||||
# wget -O- https://eepm.ru/epm.sh | bash /dev/stdin ei
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip --no-cache-dir install -r requirements.txt
|
||||
|
||||
COPY ./autorepacked ./autorepacked
|
||||
|
||||
|
@@ -1,91 +0,0 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import re
|
||||
|
||||
|
||||
def _get_file(directory):
|
||||
files_and_dirs = os.listdir(directory)
|
||||
files = [f for f in files_and_dirs if os.path.isfile(os.path.join(directory, f))]
|
||||
return os.path.join(directory, files[0]) if files else None
|
||||
|
||||
class BaseProvider:
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
DOWNLOAD_URL = ''
|
||||
_name = ''
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
|
||||
def get_version(self):
|
||||
url = subprocess.run([
|
||||
'epm',
|
||||
'--silent',
|
||||
'tool',
|
||||
'eget',
|
||||
'--get-real-url',
|
||||
self.get_download_url(),
|
||||
], stdout=subprocess.PIPE).stdout.decode('utf-8')
|
||||
|
||||
pattern = r'\d+\.\d+\.\d+'
|
||||
match = re.search(pattern, url)
|
||||
if match:
|
||||
return match.group()
|
||||
else:
|
||||
return "not found"
|
||||
|
||||
def get_download_url(self):
|
||||
return self.DOWNLOAD_URL
|
||||
|
||||
def download(self):
|
||||
download_directory = tempfile.mkdtemp()
|
||||
repacked_directory = tempfile.mkdtemp()
|
||||
|
||||
subprocess.run(
|
||||
args=[
|
||||
'epm',
|
||||
'--silent',
|
||||
'tool',
|
||||
'eget',
|
||||
'-q',
|
||||
self.get_download_url(),
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
cwd=download_directory,
|
||||
).stdout.decode('utf-8')
|
||||
|
||||
file = _get_file(download_directory)
|
||||
|
||||
subprocess.run(
|
||||
args=[
|
||||
'epm',
|
||||
'--silent',
|
||||
'-y',
|
||||
'repack',
|
||||
file,
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
cwd=repacked_directory,
|
||||
).stdout.decode('utf-8')
|
||||
|
||||
shutil.rmtree(download_directory)
|
||||
|
||||
file = _get_file(repacked_directory)
|
||||
|
||||
subprocess.run(
|
||||
args=[
|
||||
'epm',
|
||||
'--silent',
|
||||
'repo',
|
||||
'pkgadd',
|
||||
self.config.get('repo_path'),
|
||||
file,
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
cwd=repacked_directory,
|
||||
).stdout.decode('utf-8')
|
||||
|
||||
shutil.rmtree(repacked_directory)
|
80
autorepacked/common_providers/base_provider.py
Normal file
80
autorepacked/common_providers/base_provider.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import re
|
||||
|
||||
from autorepacked import utils
|
||||
|
||||
|
||||
def _get_file(directory):
|
||||
files_and_dirs = os.listdir(directory)
|
||||
files = [f for f in files_and_dirs if os.path.isfile(os.path.join(directory, f))]
|
||||
return os.path.join(directory, files[0]) if files else None
|
||||
|
||||
|
||||
class BaseProvider:
|
||||
disabled = False
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
DOWNLOAD_URL = ''
|
||||
_name = ''
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
|
||||
def get_version(self):
|
||||
url = utils.eget([
|
||||
'--get-real-url',
|
||||
self.get_download_url(),
|
||||
])
|
||||
|
||||
pattern = r'\d+\.\d+\.\d+'
|
||||
match = re.search(pattern, url)
|
||||
if match:
|
||||
return match.group()
|
||||
else:
|
||||
return "not found"
|
||||
|
||||
def get_download_url(self):
|
||||
return self.DOWNLOAD_URL
|
||||
|
||||
def get_download_name(self):
|
||||
return ""
|
||||
|
||||
def download(self):
|
||||
download_directory = tempfile.mkdtemp()
|
||||
repacked_directory = tempfile.mkdtemp()
|
||||
|
||||
args = []
|
||||
|
||||
download_name = self.get_download_name()
|
||||
|
||||
if download_name:
|
||||
args += ["-O", download_name]
|
||||
|
||||
args += [self.get_download_url()]
|
||||
|
||||
utils.eget(args, cwd=download_directory)
|
||||
|
||||
file = _get_file(download_directory)
|
||||
|
||||
utils.epm([
|
||||
'-y',
|
||||
'repack',
|
||||
file,
|
||||
], cwd=repacked_directory)
|
||||
|
||||
shutil.rmtree(download_directory)
|
||||
|
||||
file = _get_file(repacked_directory)
|
||||
|
||||
utils.epm([
|
||||
'repo',
|
||||
'pkgadd',
|
||||
self.config.get('repo_path'),
|
||||
file,
|
||||
], cwd=repacked_directory)
|
||||
|
||||
shutil.rmtree(repacked_directory)
|
35
autorepacked/common_providers/github_releases_provider.py
Normal file
35
autorepacked/common_providers/github_releases_provider.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import re
|
||||
|
||||
from autorepacked import utils
|
||||
from autorepacked.common_providers.base_provider import BaseProvider
|
||||
|
||||
|
||||
class GithubReleasesProvider(BaseProvider):
|
||||
_repo = ''
|
||||
|
||||
def _last_release_url(self):
|
||||
return utils.eget([
|
||||
'--get-real-url',
|
||||
f'https://github.com/{self._repo}/releases/latest'
|
||||
])
|
||||
|
||||
def _last_tag_name(self):
|
||||
return self.get_version()
|
||||
|
||||
def _get_release_filename(self):
|
||||
return ''
|
||||
|
||||
def get_version(self):
|
||||
url = self._last_release_url()
|
||||
|
||||
pattern = r'\d+\.\d+\.\d+'
|
||||
match = re.search(pattern, url)
|
||||
if match:
|
||||
return match.group()
|
||||
else:
|
||||
return "not found"
|
||||
|
||||
def get_download_url(self):
|
||||
return (f"https://github.com/"
|
||||
f"{self._repo}/releases/download/"
|
||||
f"{self._last_tag_name()}/{self._get_release_filename()}")
|
35
autorepacked/common_providers/snap_provider.py
Normal file
35
autorepacked/common_providers/snap_provider.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import json
|
||||
import urllib
|
||||
|
||||
from autorepacked.common_providers.base_provider import BaseProvider
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
class SnapProvider(BaseProvider):
|
||||
_package_name = "package"
|
||||
_channel = "stable"
|
||||
_arch = "amd64"
|
||||
|
||||
def _get_snap_info(self):
|
||||
request = Request(
|
||||
f"http://api.snapcraft.io/v2/snaps/info/{self._package_name}",
|
||||
headers={"Content-Type": "application/json", "Snap-Device-Series": "16"},
|
||||
)
|
||||
response = urlopen(request).read()
|
||||
return json.loads(response)
|
||||
|
||||
def get_download_name(self):
|
||||
return f"{self._package_name}-{self.get_version()}.snap"
|
||||
|
||||
def get_version(self):
|
||||
snap_info = self._get_snap_info()
|
||||
for channel_map in snap_info["channel-map"]:
|
||||
if (channel_map["channel"]["name"] == self._channel
|
||||
and channel_map["channel"]["architecture"] == self._arch):
|
||||
return channel_map['version']
|
||||
|
||||
def get_download_url(self):
|
||||
snap_info = self._get_snap_info()
|
||||
for channel_map in snap_info["channel-map"]:
|
||||
if (channel_map["channel"]["name"] == self._channel
|
||||
and channel_map["channel"]["architecture"] == self._arch):
|
||||
return channel_map['download']['url']
|
123
autorepacked/main.py
Normal file
123
autorepacked/main.py
Normal file
@@ -0,0 +1,123 @@
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import importlib
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import BackgroundTasks, FastAPI
|
||||
import uvicorn
|
||||
from fastapi_utils.tasks import repeat_every
|
||||
|
||||
from autorepacked import utils
|
||||
from autorepacked.common_providers.base_provider import BaseProvider
|
||||
from autorepacked.config import Config
|
||||
|
||||
|
||||
def create_repo(config: Config):
|
||||
utils.epm([
|
||||
'repo',
|
||||
'create',
|
||||
config.get('repo_path')
|
||||
])
|
||||
|
||||
|
||||
def update_cache():
|
||||
utils.epm(['update'])
|
||||
|
||||
def update_epm():
|
||||
utils.epm(['ei'])
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
await update_repeat()
|
||||
yield
|
||||
|
||||
|
||||
config = Config()
|
||||
app = FastAPI(lifespan=lifespan, root_path=config.get('root_path'))
|
||||
|
||||
update_task_started = False
|
||||
|
||||
|
||||
def update():
|
||||
json_file_path = os.path.join(config.get('repo_path'), 'data.json')
|
||||
if not os.path.exists(json_file_path):
|
||||
with open(json_file_path, 'w') as data_file:
|
||||
json.dump({'versions': {}}, data_file, indent=4)
|
||||
with open(json_file_path, 'r') as data_file:
|
||||
repo_data = json.load(data_file)
|
||||
|
||||
global update_task_started
|
||||
|
||||
if 'last_version_check' in repo_data:
|
||||
last_version_check = datetime.datetime.fromisoformat(repo_data['last_version_check'])
|
||||
|
||||
if datetime.datetime.now() - datetime.timedelta(minutes=5) < last_version_check:
|
||||
update_task_started = False
|
||||
return
|
||||
|
||||
update_cache()
|
||||
update_epm()
|
||||
|
||||
providers_path = os.path.join(os.getcwd(), 'autorepacked/providers')
|
||||
modules = os.listdir(providers_path)
|
||||
|
||||
versions = repo_data['versions']
|
||||
need_update_index = False
|
||||
for module_name in modules:
|
||||
module = importlib.import_module(f'providers.{module_name}')
|
||||
if hasattr(module, 'get_provider'):
|
||||
provider = module.get_provider(config) # type: BaseProvider
|
||||
if not provider.disabled:
|
||||
name = provider.get_name()
|
||||
print(f"request version of {name}")
|
||||
version = provider.get_version()
|
||||
if name not in versions or versions[name] != version:
|
||||
print(f'{name} has new version {version}')
|
||||
versions[name] = version
|
||||
provider.download()
|
||||
need_update_index = True
|
||||
|
||||
repo_data['versions'] = versions
|
||||
|
||||
current_date = datetime.datetime.utcnow()
|
||||
|
||||
if need_update_index:
|
||||
utils.epm(
|
||||
args=[
|
||||
'repo',
|
||||
'index',
|
||||
config.get('repo_path'),
|
||||
]
|
||||
)
|
||||
repo_data['last_index_update'] = current_date.isoformat()
|
||||
|
||||
repo_data['last_version_check'] = current_date.isoformat()
|
||||
|
||||
with open(json_file_path, 'w') as data_file:
|
||||
json.dump(repo_data, data_file, indent=4)
|
||||
|
||||
update_task_started = False
|
||||
|
||||
|
||||
@app.post("/update")
|
||||
def update_method(background_tasks: BackgroundTasks):
|
||||
global update_task_started
|
||||
if not update_task_started:
|
||||
update_task_started = True
|
||||
background_tasks.add_task(update)
|
||||
return {'status': 'OK'}
|
||||
|
||||
|
||||
@repeat_every(seconds=60 * 60 * 4)
|
||||
def update_repeat():
|
||||
global update_task_started
|
||||
if not update_task_started:
|
||||
update_task_started = True
|
||||
update()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
create_repo(config)
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
@@ -1,4 +1,4 @@
|
||||
from autorepacked.base_provider import BaseProvider
|
||||
from autorepacked.common_providers.base_provider import BaseProvider
|
||||
|
||||
|
||||
class CodeProvider(BaseProvider):
|
||||
|
@@ -1,4 +1,4 @@
|
||||
from autorepacked.base_provider import BaseProvider
|
||||
from autorepacked.common_providers.base_provider import BaseProvider
|
||||
|
||||
|
||||
class DiscordProvider(BaseProvider):
|
||||
|
@@ -1,30 +1,17 @@
|
||||
import subprocess
|
||||
|
||||
from autorepacked.base_provider import BaseProvider
|
||||
from autorepacked.common_providers.github_releases_provider import GithubReleasesProvider
|
||||
|
||||
|
||||
class RustdeskProvider(BaseProvider):
|
||||
class RustdeskProvider(GithubReleasesProvider):
|
||||
_name = 'rustdesk'
|
||||
_release_url = 'https://github.com/rustdesk/rustdesk/releases'
|
||||
_release_file = '[0-9]/rustdesk-[0-9].[0-9].[0-9].deb'
|
||||
|
||||
def get_download_url(self):
|
||||
url = subprocess.run(
|
||||
args=[
|
||||
'epm',
|
||||
'--silent',
|
||||
'tool',
|
||||
'eget',
|
||||
'--list',
|
||||
'--latest',
|
||||
'--get-real-url',
|
||||
self._release_url,
|
||||
self._release_file,
|
||||
],
|
||||
stdout=subprocess.PIPE
|
||||
).stdout.decode('utf-8')
|
||||
_repo = 'rustdesk/rustdesk'
|
||||
|
||||
return url
|
||||
def _get_release_filename(self):
|
||||
return f'rustdesk-{self.get_version()}.deb'
|
||||
|
||||
def get_version(self):
|
||||
# pin version due to error in start
|
||||
return '1.1.9'
|
||||
|
||||
|
||||
def get_provider(config):
|
||||
|
12
autorepacked/providers/singularityapp/__init__.py
Normal file
12
autorepacked/providers/singularityapp/__init__.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from autorepacked.common_providers.snap_provider import SnapProvider
|
||||
|
||||
|
||||
class SingularityApp(SnapProvider):
|
||||
disabled = True
|
||||
|
||||
_name = 'singularityapp'
|
||||
_package_name = 'singularityapp'
|
||||
|
||||
|
||||
def get_provider(config):
|
||||
return SingularityApp(config)
|
20
autorepacked/providers/trezor_suite/__init__.py
Normal file
20
autorepacked/providers/trezor_suite/__init__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from autorepacked.common_providers.github_releases_provider import GithubReleasesProvider
|
||||
|
||||
|
||||
class TrezorSuiteProvider(GithubReleasesProvider):
|
||||
_name = 'trezor-suite'
|
||||
|
||||
_repo = 'trezor/trezor-suite'
|
||||
|
||||
def _last_tag_name(self):
|
||||
return f'v{self.get_version()}'
|
||||
|
||||
def _get_release_filename(self):
|
||||
return f'Trezor-Suite-{self.get_version()}-linux-x86_64.AppImage'
|
||||
|
||||
def get_download_name(self):
|
||||
return f"trezor-suite-{self.get_version()}-linux-x86_64.AppImage"
|
||||
|
||||
|
||||
def get_provider(config):
|
||||
return TrezorSuiteProvider(config)
|
21
autorepacked/providers/ultimaker_cura/__init__.py
Normal file
21
autorepacked/providers/ultimaker_cura/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from autorepacked.common_providers.github_releases_provider import GithubReleasesProvider
|
||||
|
||||
|
||||
class UltimakerCuraProvider(GithubReleasesProvider):
|
||||
_name = 'ultimaker-cura'
|
||||
|
||||
_repo = 'Ultimaker/Cura'
|
||||
|
||||
def _get_release_filename(self):
|
||||
return f'UltiMaker-Cura-{self.get_version()}-linux.AppImage'
|
||||
|
||||
def get_download_name(self):
|
||||
return f"ultimaker-cura-{self.get_version()}-linux-x86_64.AppImage"
|
||||
|
||||
def get_version(self):
|
||||
# pin version due to error in start
|
||||
return '5.4.0'
|
||||
|
||||
|
||||
def get_provider(config):
|
||||
return UltimakerCuraProvider(config)
|
18
autorepacked/utils.py
Normal file
18
autorepacked/utils.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import subprocess
|
||||
|
||||
|
||||
def run(args, cwd=None):
|
||||
return subprocess.run(
|
||||
args=args,
|
||||
cwd=cwd,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout.decode('utf-8')
|
||||
|
||||
|
||||
def epm(args, cwd=None):
|
||||
return run(["epm"] + args, cwd=cwd)
|
||||
|
||||
|
||||
def eget(args, cwd=None):
|
||||
return epm(["tool", "eget"] + args, cwd=cwd)
|
||||
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
fastapi==0.109.0
|
||||
uvicorn==0.26.0
|
||||
fastapi-utils==0.2.1
|
Reference in New Issue
Block a user