mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-09 00:34:16 +02:00
Modernize runtime compatibility and initialize Bearhub fork
This commit is contained in:
10
README.md
10
README.md
@@ -1,4 +1,12 @@
|
|||||||
[](https://github.com/vinifmor/bauh/releases/) [](https://pypi.org/project/bauh) [](https://aur.archlinux.org/packages/bauh) [](https://aur.archlinux.org/packages/bauh-staging) [](https://github.com/vinifmor/bauh/blob/master/LICENSE) [](https://ko-fi.com/vinifmor)
|
[](https://github.com/spalencsar/bearhub/blob/master/LICENSE)
|
||||||
|
|
||||||
|
# Bearhub
|
||||||
|
|
||||||
|
**Bearhub** is a community-maintained fork of [bauh](https://github.com/vinifmor/bauh), focused on keeping the application working on current Linux systems, especially modern Arch Linux and Python versions.
|
||||||
|
|
||||||
|
The original project was created by Vinicius Moreira. This fork continues from that codebase under the original license and keeps the history and authorship intact.
|
||||||
|
|
||||||
|
At the moment, parts of the documentation below still refer to the original `bauh` command name, paths, package names, and screenshots. Those references are historical and will be updated incrementally as the fork evolves.
|
||||||
|
|
||||||
**bauh** (baoo), formerly known as [fpakman](https://github.com/vinifmor/fpakman), is a graphical interface for managing your Linux software (packages/applications). It currently supports the following formats: AppImage, Debian and Arch Linux packages (including AUR), Flatpak, Snap and Web applications.
|
**bauh** (baoo), formerly known as [fpakman](https://github.com/vinifmor/fpakman), is a graphical interface for managing your Linux software (packages/applications). It currently supports the following formats: AppImage, Debian and Arch Linux packages (including AUR), Flatpak, Snap and Web applications.
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
@@ -93,7 +93,7 @@ class CategoriesDownloader(Thread):
|
|||||||
self.logger.info(self._msg('Downloading category definitions from {}'.format(self.url_categories_file)))
|
self.logger.info(self._msg('Downloading category definitions from {}'.format(self.url_categories_file)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
timestamp = datetime.utcnow().timestamp()
|
timestamp = datetime.now(timezone.utc).timestamp()
|
||||||
res = self.http_client.get(self.url_categories_file)
|
res = self.http_client.get(self.url_categories_file)
|
||||||
except requests.exceptions.ConnectionError:
|
except requests.exceptions.ConnectionError:
|
||||||
self.logger.error(self._msg('[{}] Could not download categories. The internet connection seems to be off.'.format(self.id_)))
|
self.logger.error(self._msg('[{}] Could not download categories. The internet connection seems to be off.'.format(self.id_)))
|
||||||
@@ -139,13 +139,13 @@ class CategoriesDownloader(Thread):
|
|||||||
timestamp_str = f.read()
|
timestamp_str = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
categories_timestamp = datetime.fromtimestamp(float(timestamp_str))
|
categories_timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.error(self._msg("An exception occurred when trying to parse the categories file timestamp from '{}'. The categories file should be re-downloaded.".format(categories_ts_path)))
|
self.logger.error(self._msg("An exception occurred when trying to parse the categories file timestamp from '{}'. The categories file should be re-downloaded.".format(categories_ts_path)))
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
should_download = (categories_timestamp + timedelta(hours=self.expiration) <= datetime.utcnow())
|
should_download = (categories_timestamp + timedelta(hours=self.expiration) <= datetime.now(timezone.utc))
|
||||||
|
|
||||||
if should_download:
|
if should_download:
|
||||||
self.logger.info(self._msg("Cached categories file '{}' has expired. A new one should be downloaded.".format(self.categories_path)))
|
self.logger.info(self._msg("Cached categories file '{}' has expired. A new one should be downloaded.".format(self.categories_path)))
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
@@ -66,7 +66,10 @@ def size_to_byte(size: Union[float, int, str], unit: str, logger: Optional[Logge
|
|||||||
return final_size * (base ** 5)
|
return final_size * (base ** 5)
|
||||||
|
|
||||||
|
|
||||||
def datetime_as_milis(date: datetime = datetime.utcnow()) -> int:
|
def datetime_as_milis(date: Optional[datetime] = None) -> int:
|
||||||
|
if date is None:
|
||||||
|
date = datetime.now(timezone.utc)
|
||||||
|
|
||||||
return int(round(date.timestamp() * 1000))
|
return int(round(date.timestamp() * 1000))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=Applications (bauh)
|
Name=Applications (Bearhub)
|
||||||
Name[pt]=Aplicativos (bauh)
|
Name[pt]=Aplicativos (bauh)
|
||||||
Name[es]=Aplicaciones (bauh)
|
Name[es]=Aplicaciones (bauh)
|
||||||
Name[ca]=Aplicacions (bauh)
|
Name[ca]=Aplicacions (bauh)
|
||||||
@@ -17,5 +17,5 @@ Comment[de]=Anwendungen installieren und entfernen (AppImage, Arch, Flatpak, Sna
|
|||||||
Comment[ca]=Instal·lar i eliminar aplicacions (AppImage, Arch, Flatpak, Snap, Web)
|
Comment[ca]=Instal·lar i eliminar aplicacions (AppImage, Arch, Flatpak, Snap, Web)
|
||||||
Comment[ru]=Установка и удаление приложений (AppImage, Arch, Flatpak, Snap, Web)
|
Comment[ru]=Установка и удаление приложений (AppImage, Arch, Flatpak, Snap, Web)
|
||||||
Comment[tr]=Uygulama yükle/kaldır (AppImage, Arch, Flatpak, Snap, Web)
|
Comment[tr]=Uygulama yükle/kaldır (AppImage, Arch, Flatpak, Snap, Web)
|
||||||
Exec=/usr/bin/bauh
|
Exec=/usr/bin/bearhub
|
||||||
Icon=bauh
|
Icon=bauh
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=Applications (bauh-tray)
|
Name=Applications (Bearhub tray)
|
||||||
Name[pt]=Aplicativos (bauh-bandeja)
|
Name[pt]=Aplicativos (bauh-bandeja)
|
||||||
Name[es]=Aplicaciones (bauh-bandeja)
|
Name[es]=Aplicaciones (bauh-bandeja)
|
||||||
Name[ca]=Aplicacions (bauh-safata)
|
Name[ca]=Aplicacions (bauh-safata)
|
||||||
@@ -17,5 +17,5 @@ Comment[de]=Anwendungen installieren und entfernen (AppImage, Arch, Flatpak, Sna
|
|||||||
Comment[ca]=Instal·lar i eliminar aplicacions (AppImage, Arch, Flatpak, Snap, Web)
|
Comment[ca]=Instal·lar i eliminar aplicacions (AppImage, Arch, Flatpak, Snap, Web)
|
||||||
Comment[ru]=Установка и удаление приложений (AppImage, Arch, Flatpak, Snap, Web)
|
Comment[ru]=Установка и удаление приложений (AppImage, Arch, Flatpak, Snap, Web)
|
||||||
Comment[tr]=Uygulama yükle/kaldır (AppImage, Arch, Flatpak, Snap, Web)
|
Comment[tr]=Uygulama yükle/kaldır (AppImage, Arch, Flatpak, Snap, Web)
|
||||||
Exec=/usr/bin/bauh-tray
|
Exec=/usr/bin/bearhub-tray
|
||||||
Icon=bauh
|
Icon=bauh
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import os
|
|||||||
import tarfile
|
import tarfile
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Optional, Generator
|
from typing import Optional, Generator
|
||||||
@@ -73,13 +73,13 @@ class DatabaseUpdater(Thread):
|
|||||||
dbs_ts_str = f.read()
|
dbs_ts_str = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
dbs_timestamp = datetime.fromtimestamp(float(dbs_ts_str))
|
dbs_timestamp = datetime.fromtimestamp(float(dbs_ts_str), tz=timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.error('Could not parse the databases timestamp: {}'.format(dbs_ts_str))
|
self.logger.error('Could not parse the databases timestamp: {}'.format(dbs_ts_str))
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
update = dbs_timestamp + timedelta(minutes=db_exp) <= datetime.utcnow()
|
update = dbs_timestamp + timedelta(minutes=db_exp) <= datetime.now(timezone.utc)
|
||||||
self.logger.info('Finished. Took {0:.2f} seconds'.format(time.time() - ti))
|
self.logger.info('Finished. Took {0:.2f} seconds'.format(time.time() - ti))
|
||||||
return update
|
return update
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ class DatabaseUpdater(Thread):
|
|||||||
self._update_task_progress(10, self.i18n['appimage.update_database.downloading'])
|
self._update_task_progress(10, self.i18n['appimage.update_database.downloading'])
|
||||||
self.logger.info('Retrieving AppImage databases')
|
self.logger.info('Retrieving AppImage databases')
|
||||||
|
|
||||||
database_timestamp = datetime.utcnow().timestamp()
|
database_timestamp = datetime.now(timezone.utc).timestamp()
|
||||||
try:
|
try:
|
||||||
res = self.http_client.get(URL_COMPRESSED_DATABASES, session=False)
|
res = self.http_client.get(URL_COMPRESSED_DATABASES, session=False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -356,13 +356,13 @@ class AppImageSuggestionsDownloader(Thread):
|
|||||||
timestamp_str = f.read()
|
timestamp_str = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
suggestions_timestamp = datetime.fromtimestamp(float(timestamp_str))
|
suggestions_timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.error(f'Could not parse the cached AppImage suggestions timestamp: {timestamp_str}')
|
self.logger.error(f'Could not parse the cached AppImage suggestions timestamp: {timestamp_str}')
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
update = suggestions_timestamp + timedelta(hours=exp_hours) <= datetime.utcnow()
|
update = suggestions_timestamp + timedelta(hours=exp_hours) <= datetime.now(timezone.utc)
|
||||||
return update
|
return update
|
||||||
|
|
||||||
def read(self) -> Generator[str, None, None]:
|
def read(self) -> Generator[str, None, None]:
|
||||||
@@ -372,7 +372,7 @@ class AppImageSuggestionsDownloader(Thread):
|
|||||||
|
|
||||||
self.logger.info("Checking if AppImage suggestions should be downloaded")
|
self.logger.info("Checking if AppImage suggestions should be downloaded")
|
||||||
if self.should_download(self.config):
|
if self.should_download(self.config):
|
||||||
suggestions_timestamp = datetime.utcnow().timestamp()
|
suggestions_timestamp = datetime.now(timezone.utc).timestamp()
|
||||||
suggestions_str = self.download()
|
suggestions_str = self.download()
|
||||||
|
|
||||||
Thread(target=self.cache_suggestions, args=(suggestions_str, suggestions_timestamp), daemon=True).start()
|
Thread(target=self.cache_suggestions, args=(suggestions_str, suggestions_timestamp), daemon=True).start()
|
||||||
@@ -466,7 +466,7 @@ class AppImageSuggestionsDownloader(Thread):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if should_download:
|
if should_download:
|
||||||
suggestions_timestamp = datetime.utcnow().timestamp()
|
suggestions_timestamp = datetime.now(timezone.utc).timestamp()
|
||||||
suggestions_str = self.download()
|
suggestions_str = self.download()
|
||||||
self.taskman.update_progress(self.task_id, 70, None)
|
self.taskman.update_progress(self.task_id, 70, None)
|
||||||
|
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ def read_repository_from_info(name: str) -> Optional[str]:
|
|||||||
|
|
||||||
repository = None
|
repository = None
|
||||||
|
|
||||||
for o in new_subprocess(['grep', '-Po', "Repository\s+:\s+\K.+"], stdin=info.stdout).stdout:
|
for o in new_subprocess(['grep', '-Po', r"Repository\s+:\s+\K.+"], stdin=info.stdout).stdout:
|
||||||
if o:
|
if o:
|
||||||
line = o.decode().strip()
|
line = o.decode().strip()
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ def read_provides(name: str) -> Set[str]:
|
|||||||
|
|
||||||
provides = None
|
provides = None
|
||||||
|
|
||||||
for out in new_subprocess(['grep', '-Po', 'Provides\s+:\s\K(.+)'], stdin=dep_info.stdout).stdout:
|
for out in new_subprocess(['grep', '-Po', r'Provides\s+:\s\K(.+)'], stdin=dep_info.stdout).stdout:
|
||||||
if out:
|
if out:
|
||||||
provided_names = [p.strip() for p in out.decode().strip().split(' ') if p]
|
provided_names = [p.strip() for p in out.decode().strip().split(' ') if p]
|
||||||
|
|
||||||
@@ -372,7 +372,7 @@ def read_dependencies(name: str) -> Set[str]:
|
|||||||
raise PackageNotFoundException(name)
|
raise PackageNotFoundException(name)
|
||||||
|
|
||||||
depends_on = set()
|
depends_on = set()
|
||||||
for out in new_subprocess(['grep', '-Po', 'Depends\s+On\s+:\s\K(.+)'], stdin=dep_info.stdout).stdout:
|
for out in new_subprocess(['grep', '-Po', r'Depends\s+On\s+:\s\K(.+)'], stdin=dep_info.stdout).stdout:
|
||||||
if out:
|
if out:
|
||||||
line = out.decode().strip()
|
line = out.decode().strip()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
@@ -90,13 +90,13 @@ class RepositorySuggestionsDownloader(Thread):
|
|||||||
timestamp_str = f.read()
|
timestamp_str = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
suggestions_timestamp = datetime.fromtimestamp(float(timestamp_str))
|
suggestions_timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
self._log.error(f'Could not parse the Arch cached suggestions timestamp: {timestamp_str}')
|
self._log.error(f'Could not parse the Arch cached suggestions timestamp: {timestamp_str}')
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
update = suggestions_timestamp + timedelta(hours=exp_hours) <= datetime.utcnow()
|
update = suggestions_timestamp + timedelta(hours=exp_hours) <= datetime.now(timezone.utc)
|
||||||
|
|
||||||
if update:
|
if update:
|
||||||
self._log.info("The cached suggestions file is no longer valid")
|
self._log.info("The cached suggestions file is no longer valid")
|
||||||
@@ -166,7 +166,7 @@ class RepositorySuggestionsDownloader(Thread):
|
|||||||
suggestions = parse(res.text, self._log, 'Arch')
|
suggestions = parse(res.text, self._log, 'Arch')
|
||||||
|
|
||||||
if suggestions:
|
if suggestions:
|
||||||
self._save(text=res.text, timestamp=datetime.utcnow().timestamp())
|
self._save(text=res.text, timestamp=datetime.now(timezone.utc).timestamp())
|
||||||
else:
|
else:
|
||||||
self._log.warning(f"Could not parse any Arch suggestion from {self._file_suggestions_ts}")
|
self._log.warning(f"Could not parse any Arch suggestion from {self._file_suggestions_ts}")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import re
|
|||||||
import shutil
|
import shutil
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -71,8 +71,8 @@ class AURIndexUpdater(Thread):
|
|||||||
timestamp_str = f.read()
|
timestamp_str = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
index_timestamp = datetime.fromtimestamp(float(timestamp_str))
|
index_timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc)
|
||||||
return (index_timestamp + timedelta(hours=exp_hours)) <= datetime.utcnow()
|
return (index_timestamp + timedelta(hours=exp_hours)) <= datetime.now(timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return True
|
return True
|
||||||
@@ -81,7 +81,7 @@ class AURIndexUpdater(Thread):
|
|||||||
self.logger.info('Indexing AUR packages')
|
self.logger.info('Indexing AUR packages')
|
||||||
self.taskman.update_progress(self.task_id, 5, self.i18n['arch.task.aur.index.substatus.download'])
|
self.taskman.update_progress(self.task_id, 5, self.i18n['arch.task.aur.index.substatus.download'])
|
||||||
try:
|
try:
|
||||||
index_ts = datetime.utcnow().timestamp()
|
index_ts = datetime.now(timezone.utc).timestamp()
|
||||||
res = self.http_client.get(URL_INDEX)
|
res = self.http_client.get(URL_INDEX)
|
||||||
|
|
||||||
if res and res.text:
|
if res and res.text:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import traceback
|
import traceback
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from json import JSONDecodeError
|
from json import JSONDecodeError
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -52,14 +52,14 @@ class ApplicationIndexer:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
timestamp = datetime.fromtimestamp(float(timestamp_str))
|
timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
self._log.error(f'Could not parse the Debian applications index timestamp: {timestamp_str} '
|
self._log.error(f'Could not parse the Debian applications index timestamp: {timestamp_str} '
|
||||||
f'({self._file_timestamp_path})')
|
f'({self._file_timestamp_path})')
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
expired = timestamp + timedelta(minutes=exp_minutes) <= datetime.utcnow()
|
expired = timestamp + timedelta(minutes=exp_minutes) <= datetime.now(timezone.utc)
|
||||||
|
|
||||||
if expired:
|
if expired:
|
||||||
self._log.info("Debian applications index has expired. A new one must be generated.")
|
self._log.info("Debian applications index has expired. A new one must be generated.")
|
||||||
@@ -122,7 +122,7 @@ class ApplicationIndexer:
|
|||||||
raise ApplicationIndexError()
|
raise ApplicationIndexError()
|
||||||
|
|
||||||
if update_timestamp:
|
if update_timestamp:
|
||||||
index_timestamp = datetime.utcnow().timestamp()
|
index_timestamp = datetime.now(timezone.utc).timestamp()
|
||||||
try:
|
try:
|
||||||
with open(self._file_timestamp_path, 'w+') as f:
|
with open(self._file_timestamp_path, 'w+') as f:
|
||||||
f.write(str(index_timestamp))
|
f.write(str(index_timestamp))
|
||||||
@@ -140,7 +140,7 @@ class ApplicationsMapper:
|
|||||||
def __init__(self, logger: Logger, workers: int = 10):
|
def __init__(self, logger: Logger, workers: int = 10):
|
||||||
self._log = logger
|
self._log = logger
|
||||||
self._re_desktop_file = re.compile(r'(.+):\s+(/usr/share/applications/.+\.desktop)')
|
self._re_desktop_file = re.compile(r'(.+):\s+(/usr/share/applications/.+\.desktop)')
|
||||||
self._re_desktop_file_fields = re.compile('(Exec|TryExec|Icon|Categories|NoDisplay|Terminal)\s*=\s*(.+)')
|
self._re_desktop_file_fields = re.compile(r'(Exec|TryExec|Icon|Categories|NoDisplay|Terminal)\s*=\s*(.+)')
|
||||||
self._workers = workers
|
self._workers = workers
|
||||||
|
|
||||||
def _read_file(self, file_path: str) -> Optional[str]:
|
def _read_file(self, file_path: str) -> Optional[str]:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
@@ -95,13 +95,13 @@ class DebianSuggestionsDownloader(Thread):
|
|||||||
timestamp_str = f.read()
|
timestamp_str = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
suggestions_timestamp = datetime.fromtimestamp(float(timestamp_str))
|
suggestions_timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
self._log.error(f'Could not parse the Debian cached suggestions timestamp: {timestamp_str}')
|
self._log.error(f'Could not parse the Debian cached suggestions timestamp: {timestamp_str}')
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
update = suggestions_timestamp + timedelta(hours=exp_hours) <= datetime.utcnow()
|
update = suggestions_timestamp + timedelta(hours=exp_hours) <= datetime.now(timezone.utc)
|
||||||
return update
|
return update
|
||||||
|
|
||||||
def _save(self, text: str, timestamp: float):
|
def _save(self, text: str, timestamp: float):
|
||||||
@@ -184,7 +184,7 @@ class DebianSuggestionsDownloader(Thread):
|
|||||||
suggestions = parse(res.text, self._log, 'Debian')
|
suggestions = parse(res.text, self._log, 'Debian')
|
||||||
|
|
||||||
if suggestions:
|
if suggestions:
|
||||||
self._save(text=res.text, timestamp=datetime.utcnow().timestamp())
|
self._save(text=res.text, timestamp=datetime.now(timezone.utc).timestamp())
|
||||||
else:
|
else:
|
||||||
self._log.warning("No Debian suggestions to cache")
|
self._log.warning("No Debian suggestions to cache")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Optional, Set
|
from typing import Optional, Set
|
||||||
@@ -149,14 +149,14 @@ class SynchronizePackages(Thread):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
last_timestamp = datetime.fromtimestamp(float(timestamp_str))
|
last_timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(f'Could not parse the packages synchronization timestamp: {timestamp_str} '
|
logger.error(f'Could not parse the packages synchronization timestamp: {timestamp_str} '
|
||||||
f'({PACKAGE_SYNC_TIMESTAMP_FILE})')
|
f'({PACKAGE_SYNC_TIMESTAMP_FILE})')
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
expired = last_timestamp + timedelta(minutes=period) <= datetime.utcnow()
|
expired = last_timestamp + timedelta(minutes=period) <= datetime.now(timezone.utc)
|
||||||
|
|
||||||
if expired:
|
if expired:
|
||||||
logger.info("Packages synchronization is outdated")
|
logger.info("Packages synchronization is outdated")
|
||||||
@@ -176,7 +176,7 @@ class SynchronizePackages(Thread):
|
|||||||
self._taskman.update_progress(self._id, 99, None)
|
self._taskman.update_progress(self._id, 99, None)
|
||||||
|
|
||||||
if updated:
|
if updated:
|
||||||
index_timestamp = datetime.utcnow().timestamp()
|
index_timestamp = datetime.now(timezone.utc).timestamp()
|
||||||
finish_msg = None
|
finish_msg = None
|
||||||
try:
|
try:
|
||||||
with open(PACKAGE_SYNC_TIMESTAMP_FILE, 'w+') as f:
|
with open(PACKAGE_SYNC_TIMESTAMP_FILE, 'w+') as f:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
@@ -60,7 +60,7 @@ class FlatpakManager(SoftwareManager, SettingsController):
|
|||||||
if app.runtime and app.latest_version is None:
|
if app.runtime and app.latest_version is None:
|
||||||
app.latest_version = app.version
|
app.latest_version = app.version
|
||||||
|
|
||||||
expired_data = api_data and api_data.get('expires_at') and api_data['expires_at'] <= datetime.utcnow()
|
expired_data = api_data and api_data.get('expires_at') and api_data['expires_at'] <= datetime.now(timezone.utc)
|
||||||
|
|
||||||
data_loader: Optional[FlatpakAsyncDataLoader] = None
|
data_loader: Optional[FlatpakAsyncDataLoader] = None
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from bauh.gems.flatpak.constants import FLATHUB_URL
|
|||||||
|
|
||||||
RE_SEVERAL_SPACES = re.compile(r'\s+')
|
RE_SEVERAL_SPACES = re.compile(r'\s+')
|
||||||
RE_COMMIT = re.compile(r'(Latest commit|Commit)\s*:\s*(.+)')
|
RE_COMMIT = re.compile(r'(Latest commit|Commit)\s*:\s*(.+)')
|
||||||
RE_REQUIRED_RUNTIME = re.compile(f'Required\s+runtime\s+.+\(([\w./]+)\)\s*.+\s+remote\s+([\w+./]+)')
|
RE_REQUIRED_RUNTIME = re.compile(r'Required\s+runtime\s+.+\(([\w./]+)\)\s*.+\s+remote\s+([\w+./]+)')
|
||||||
OPERATION_UPDATE_SYMBOLS = {'i', 'u'}
|
OPERATION_UPDATE_SYMBOLS = {'i', 'u'}
|
||||||
|
|
||||||
|
|
||||||
@@ -56,12 +56,20 @@ def get_fields(app_id: str, branch: str, fields: List[str]) -> List[str]:
|
|||||||
if branch:
|
if branch:
|
||||||
cmd.append(branch)
|
cmd.append(branch)
|
||||||
|
|
||||||
info = new_subprocess(cmd).stdout
|
info = run_cmd(' '.join(cmd), print_error=False)
|
||||||
|
|
||||||
|
if not info:
|
||||||
|
return []
|
||||||
|
|
||||||
res = []
|
res = []
|
||||||
for o in new_subprocess(('grep', '-E', '({}):.+'.format('|'.join(fields)), '-o'), stdin=info).stdout:
|
for line in info.splitlines():
|
||||||
if o:
|
if not line or ':' not in line:
|
||||||
res.append(o.decode().split(':')[-1].strip())
|
continue
|
||||||
|
|
||||||
|
field_name, field_value = line.split(':', 1)
|
||||||
|
|
||||||
|
if field_name.strip() in fields:
|
||||||
|
res.append(field_value.strip())
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@@ -97,11 +105,14 @@ def list_installed(version: Tuple[str, ...]) -> List[dict]:
|
|||||||
apps = []
|
apps = []
|
||||||
|
|
||||||
if version < VERSION_1_2:
|
if version < VERSION_1_2:
|
||||||
app_list = new_subprocess(('flatpak', 'list', '-d'), lang=None)
|
app_list = run_cmd('flatpak list -d', print_error=False, lang=None)
|
||||||
|
|
||||||
for o in app_list.stdout:
|
if not app_list:
|
||||||
if o:
|
return apps
|
||||||
data = o.decode().strip().split('\t')
|
|
||||||
|
for line in app_list.splitlines():
|
||||||
|
if line:
|
||||||
|
data = line.strip().split('\t')
|
||||||
ref_split = data[0].split('/')
|
ref_split = data[0].split('/')
|
||||||
runtime = 'runtime' in data[5]
|
runtime = 'runtime' in data[5]
|
||||||
|
|
||||||
@@ -121,11 +132,14 @@ def list_installed(version: Tuple[str, ...]) -> List[dict]:
|
|||||||
else:
|
else:
|
||||||
name_col = '' if version < VERSION_1_3 else 'name,'
|
name_col = '' if version < VERSION_1_3 else 'name,'
|
||||||
cols = f'application,ref,arch,branch,description,origin,options,{name_col}version'
|
cols = f'application,ref,arch,branch,description,origin,options,{name_col}version'
|
||||||
app_list = new_subprocess(('flatpak', 'list', f'--columns={cols}'), lang=None)
|
app_list = run_cmd(f'flatpak list --columns={cols}', print_error=False, lang=None)
|
||||||
|
|
||||||
for o in app_list.stdout:
|
if not app_list:
|
||||||
if o:
|
return apps
|
||||||
data = o.decode().strip().split('\t')
|
|
||||||
|
for line in app_list.splitlines():
|
||||||
|
if line:
|
||||||
|
data = line.strip().split('\t')
|
||||||
runtime = 'runtime' in data[6]
|
runtime = 'runtime' in data[6]
|
||||||
|
|
||||||
if version < VERSION_1_3:
|
if version < VERSION_1_3:
|
||||||
@@ -237,14 +251,17 @@ def fill_updates(version: Tuple[str, ...], installation: str, res: Dict[str, Set
|
|||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
else:
|
else:
|
||||||
updates = new_subprocess(('flatpak', 'update', f'--{installation}', '--no-deps')).stdout
|
|
||||||
|
|
||||||
reg = r'[0-9]+\.\s+.+'
|
reg = r'[0-9]+\.\s+.+'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for o in new_subprocess(('grep', '-E', reg, '-o', '--color=never'), stdin=updates).stdout:
|
output = run_cmd(f'flatpak update --{installation} --no-deps', ignore_return_code=True, print_error=False)
|
||||||
if o:
|
|
||||||
line_split = o.decode().strip().split('\t')
|
if not output:
|
||||||
|
return
|
||||||
|
|
||||||
|
for line in output.splitlines():
|
||||||
|
if re.match(reg, line):
|
||||||
|
line_split = line.strip().split('\t')
|
||||||
|
|
||||||
if len(line_split) >= 5:
|
if len(line_split) >= 5:
|
||||||
if version >= VERSION_1_5:
|
if version >= VERSION_1_5:
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class WebApplicationManager(SoftwareManager, SettingsController):
|
|||||||
|
|
||||||
def get_accept_language_header(self) -> str:
|
def get_accept_language_header(self) -> str:
|
||||||
try:
|
try:
|
||||||
syslocale = locale.getdefaultlocale()
|
syslocale = locale.getlocale()
|
||||||
|
|
||||||
if syslocale:
|
if syslocale:
|
||||||
locale_split = syslocale[0].split('_')
|
locale_split = syslocale[0].split('_')
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import tarfile
|
import tarfile
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
@@ -245,12 +245,12 @@ class EnvironmentUpdater:
|
|||||||
env_ts_str = f.read()
|
env_ts_str = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
env_timestamp = datetime.fromtimestamp(float(env_ts_str))
|
env_timestamp = datetime.fromtimestamp(float(env_ts_str), tz=timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.error(f"Could not parse environment settings file timestamp: {env_ts_str}")
|
self.logger.error(f"Could not parse environment settings file timestamp: {env_ts_str}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
expired = env_timestamp + timedelta(hours=settings_exp) <= datetime.utcnow()
|
expired = env_timestamp + timedelta(hours=settings_exp) <= datetime.now(timezone.utc)
|
||||||
|
|
||||||
if expired:
|
if expired:
|
||||||
self.logger.info("Environment settings file has expired. It should be re-downloaded")
|
self.logger.info("Environment settings file has expired. It should be re-downloaded")
|
||||||
@@ -314,7 +314,7 @@ class EnvironmentUpdater:
|
|||||||
self._finish_task_download_settings()
|
self._finish_task_download_settings()
|
||||||
return
|
return
|
||||||
|
|
||||||
cache_timestamp = datetime.utcnow().timestamp()
|
cache_timestamp = datetime.now(timezone.utc).timestamp()
|
||||||
with open(ENVIRONMENT_SETTINGS_CACHED_FILE, 'w+') as f:
|
with open(ENVIRONMENT_SETTINGS_CACHED_FILE, 'w+') as f:
|
||||||
f.write(yaml.safe_dump(settings))
|
f.write(yaml.safe_dump(settings))
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -68,12 +68,12 @@ class SuggestionsManager:
|
|||||||
timestamp_str = f.read()
|
timestamp_str = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sugs_timestamp = datetime.fromtimestamp(float(timestamp_str))
|
sugs_timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.error(f"Could not parse the cached suggestions file timestamp: {timestamp_str}")
|
self.logger.error(f"Could not parse the cached suggestions file timestamp: {timestamp_str}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
expired = sugs_timestamp + timedelta(days=exp) <= datetime.utcnow()
|
expired = sugs_timestamp + timedelta(days=exp) <= datetime.now(timezone.utc)
|
||||||
|
|
||||||
if expired:
|
if expired:
|
||||||
self.logger.info("Cached suggestions file has expired.")
|
self.logger.info("Cached suggestions file has expired.")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ class SuggestionsLoader(Thread):
|
|||||||
self.suggestions = self.manager.read_cached(check_file=False)
|
self.suggestions = self.manager.read_cached(check_file=False)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
timestamp = datetime.utcnow().timestamp()
|
timestamp = datetime.now(timezone.utc).timestamp()
|
||||||
self.suggestions = self.manager.download()
|
self.suggestions = self.manager.download()
|
||||||
|
|
||||||
if self.suggestions:
|
if self.suggestions:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import inspect
|
import inspect
|
||||||
|
import importlib
|
||||||
import os
|
import os
|
||||||
import pkgutil
|
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from typing import List, Generator
|
from typing import List, Generator
|
||||||
|
|
||||||
@@ -49,11 +49,14 @@ def load_managers(locale: str, context: ApplicationContext, config: dict, defaul
|
|||||||
logger.warning(f"gem '{f.name}' could not be loaded because it was marked as forbidden in '{FORBIDDEN_GEMS_FILE}'")
|
logger.warning(f"gem '{f.name}' could not be loaded because it was marked as forbidden in '{FORBIDDEN_GEMS_FILE}'")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
loader = pkgutil.find_loader(f'bauh.gems.{f.name}.controller')
|
module_name = f'bauh.gems.{f.name}.controller'
|
||||||
|
|
||||||
if loader:
|
try:
|
||||||
module = loader.load_module()
|
module = importlib.import_module(module_name)
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
module = None
|
||||||
|
|
||||||
|
if module:
|
||||||
manager_class = find_manager(module)
|
manager_class = find_manager(module)
|
||||||
|
|
||||||
if manager_class:
|
if manager_class:
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class DefaultMemoryCache(MemoryCache):
|
|||||||
|
|
||||||
def _add(self, key: str, val: object):
|
def _add(self, key: str, val: object):
|
||||||
if key:
|
if key:
|
||||||
self._cache[key] = {'val': val, 'expires_at': datetime.datetime.utcnow() + datetime.timedelta(seconds=self.expiration_time) if self.expiration_time > 0 else None}
|
self._cache[key] = {'val': val, 'expires_at': datetime.datetime.now(UTC) + datetime.timedelta(seconds=self.expiration_time) if self.expiration_time > 0 else None}
|
||||||
|
|
||||||
def add_non_existing(self, key: str, val: object):
|
def add_non_existing(self, key: str, val: object):
|
||||||
if key and self. is_enabled():
|
if key and self. is_enabled():
|
||||||
@@ -46,7 +46,7 @@ class DefaultMemoryCache(MemoryCache):
|
|||||||
if val:
|
if val:
|
||||||
expiration = val.get('expires_at')
|
expiration = val.get('expires_at')
|
||||||
|
|
||||||
if expiration and expiration <= datetime.datetime.utcnow():
|
if expiration and expiration <= datetime.datetime.now(UTC):
|
||||||
if lock:
|
if lock:
|
||||||
self.lock.acquire()
|
self.lock.acquire()
|
||||||
|
|
||||||
@@ -86,3 +86,4 @@ class DefaultMemoryCacheFactory(MemoryCacheFactory):
|
|||||||
|
|
||||||
def new(self, expiration: Optional[int] = None) -> MemoryCache:
|
def new(self, expiration: Optional[int] = None) -> MemoryCache:
|
||||||
return DefaultMemoryCache(expiration if expiration is not None else self.expiration_time)
|
return DefaultMemoryCache(expiration if expiration is not None else self.expiration_time)
|
||||||
|
UTC = datetime.timezone.utc
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ def get_locale_keys(key: str = None, locale_dir: str = resource.get_path('locale
|
|||||||
|
|
||||||
if key is None:
|
if key is None:
|
||||||
try:
|
try:
|
||||||
current_locale = locale.getdefaultlocale()
|
current_locale = locale.getlocale()
|
||||||
|
|
||||||
if current_locale is None or current_locale[0] is None:
|
if current_locale is None or current_locale[0] is None:
|
||||||
current_locale = ('en', 'UTF-8')
|
current_locale = ('en', 'UTF-8')
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ requires = ["setuptools", "wheel"]
|
|||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "bauh"
|
name = "bearhub"
|
||||||
description = "Graphical interface to manage Linux applications (AppImage, Arch / AUR, Flatpak, Snap and Web)"
|
description = "Community-maintained fork of bauh focused on modern Linux compatibility"
|
||||||
license = {file = "LICENSE"}
|
license = {file = "LICENSE"}
|
||||||
requires-python = ">=3.6"
|
requires-python = ">=3.6"
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [{name = "Vinicius Moreira", email = "vinicius_fmoreira@hotmail.com"}]
|
authors = [
|
||||||
|
{name = "Vinicius Moreira", email = "vinicius_fmoreira@hotmail.com"},
|
||||||
|
{name = "Bearhub maintainers"}
|
||||||
|
]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
'Topic :: Utilities',
|
'Topic :: Utilities',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
@@ -36,12 +39,12 @@ web = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
bauh = "bauh.app:main"
|
bearhub = "bauh.app:main"
|
||||||
bauh-tray = "bauh.app:tray"
|
bearhub-tray = "bauh.app:tray"
|
||||||
bauh-cli = "bauh.cli.app:main"
|
bearhub-cli = "bauh.cli.app:main"
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Repository = "https://github.com/vinifmor/bauh"
|
Repository = "https://github.com/spalencsar/bearhub"
|
||||||
|
|
||||||
[tool.setuptools]
|
[tool.setuptools]
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
|
|||||||
19
setup.py
19
setup.py
@@ -4,13 +4,14 @@ import os
|
|||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
DESCRIPTION = (
|
DESCRIPTION = (
|
||||||
"Graphical interface to manage Linux applications (AppImage, Arch / AUR, Flatpak, Snap and Web)"
|
"Community-maintained fork of bauh focused on modern Linux compatibility"
|
||||||
)
|
)
|
||||||
|
|
||||||
AUTHOR = "Vinicius Moreira"
|
AUTHOR = "Vinicius Moreira"
|
||||||
AUTHOR_EMAIL = "vinicius_fmoreira@hotmail.com"
|
AUTHOR_EMAIL = "vinicius_fmoreira@hotmail.com"
|
||||||
NAME = 'bauh'
|
DIST_NAME = 'bearhub'
|
||||||
URL = "https://github.com/vinifmor/" + NAME
|
APP_PACKAGE = 'bauh'
|
||||||
|
URL = "https://github.com/spalencsar/" + DIST_NAME
|
||||||
|
|
||||||
file_dir = os.path.dirname(os.path.abspath(__file__))
|
file_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
@@ -21,12 +22,12 @@ else:
|
|||||||
requirements = [line.strip() for line in f.readlines() if line]
|
requirements = [line.strip() for line in f.readlines() if line]
|
||||||
|
|
||||||
|
|
||||||
with open(file_dir + '/{}/__init__.py'.format(NAME), 'r') as f:
|
with open(file_dir + '/{}/__init__.py'.format(APP_PACKAGE), 'r') as f:
|
||||||
exec(f.readlines()[0])
|
exec(f.readlines()[0])
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name=NAME,
|
name=DIST_NAME,
|
||||||
version=eval('__version__'),
|
version=eval('__version__'),
|
||||||
description=DESCRIPTION,
|
description=DESCRIPTION,
|
||||||
long_description=DESCRIPTION,
|
long_description=DESCRIPTION,
|
||||||
@@ -35,14 +36,14 @@ setup(
|
|||||||
python_requires=">=3.5",
|
python_requires=">=3.5",
|
||||||
url=URL,
|
url=URL,
|
||||||
packages=find_packages(exclude=["tests.*", "tests"]),
|
packages=find_packages(exclude=["tests.*", "tests"]),
|
||||||
package_data={NAME: ["view/resources/locale/*", "view/resources/img/*", "view/resources/style/*", 'view/resources/style/*/img/*', "gems/*/resources/img/*", "gems/*/resources/locale/*", "desktop/*"]},
|
package_data={APP_PACKAGE: ["view/resources/locale/*", "view/resources/img/*", "view/resources/style/*", 'view/resources/style/*/img/*', "gems/*/resources/img/*", "gems/*/resources/locale/*", "desktop/*"]},
|
||||||
install_requires=requirements,
|
install_requires=requirements,
|
||||||
test_suite="tests",
|
test_suite="tests",
|
||||||
entry_points={
|
entry_points={
|
||||||
"console_scripts": [
|
"console_scripts": [
|
||||||
"{name}={name}.app:main".format(name=NAME),
|
"bearhub=bauh.app:main",
|
||||||
"{name}-tray={name}.app:tray".format(name=NAME),
|
"bearhub-tray=bauh.app:tray",
|
||||||
"{name}-cli={name}.cli.app:main".format(name=NAME)
|
"bearhub-cli=bauh.cli.app:main"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
|
|||||||
Reference in New Issue
Block a user