Commit f9df9aa4 authored by sebt3's avatar sebt3
Browse files

Merge branch 'master' into 'master'

Code cleanup

See merge request sebt3/dbpinstaller!1
parents 0408b8f8 48078764
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# documentation files
apidocs/
# dbpinstaller files
cache/
conf/
Copyright 2021 Sébastien Huss<sebastien.huss@gmail.com>
Copyright 2021 Sébastien Huss<sebastien.huss@gmail.com> Benjamin Vogt<benjamin99.vogt@web.de>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
......
......@@ -11,8 +11,54 @@ Features:
That's absolutely all :P
## Dependency
## Install
On debian base system (included in the dbp):
Run `pip install .` or `python3 -m pip install .` in the repository directory.
## Usage
*dbpInstaller* can be executed using either `./dbpInstaller.sh` or `python3 -m dbpinstaller`.
You can print usage information by running `./dbpInstaller.sh --help`.
You should see something like:
```
sudo apt install python3-xdg python3-pydbus python3-gi python3-apt
usage: dbpinstaller [-h] [-d dest]
{install,cards,update,upgrade,list,installed} ...
install DBP packages.
optional arguments:
-h, --help show this help message and exit
-d dest, --dest dest SD-Card to use
action:
{install,cards,update,upgrade,list,installed}
action to perform
install install packages
cards List available cards
update Update the cache
upgrade Upgrade installed packages
list List known packages
installed List installed packages
```
As you can see, *dbpInstaller* utilizes subcommands, which may have
their own arguments. Use `./dbpInstaller.sh <subcommand> --help` for more specific usage information.
## Api documentation
To generate the api documentation, run the following commands:
1. `pip install pydoctor`
2. `./generate_docs.py`
Afterwards, open `apidocs/index.html` to view them.
## Contributors
The following users contributed to this project:
- @sebt3 (creator)
- @bennr01
This diff is collapsed.
#!/usr/bin/env python3
import os
import urllib.request
import argparse
import apt
from md5 import md5
from dbpd import dbpd
from repocache import RepoCache
from findcard import findcard
from installerui import installerUI
class dbpInstaller(installerUI):
dbpd = dbpd()
cache = RepoCache()
def setPackage(self, pck_id):
super().setPackage(pck_id)
pck = self.cache.getPackage(pck_id)
if pck != None:
self.current_pck = pck_id
installed={}
for p in self.dbpd.getPackagesList():
if p['id'] == pck_id:
installed=p
super().setUIPackage(pck, installed)
def onDownloadOk(self, *args):
self.downloadTo(self.installTarget.get_model()[self.installTarget.get_active_iter()][1])
super().onDownloadOk()
def onUpdate(self, *args):
pkgList = self.dbpd.getPackagesList()
self.cache.update()
super().setInstalledList(pkgList, self.cache)
super().setAvailList(self.cache.getPackagesList(), self.cache, pkgList)
print('Cache Updated')
super().onUpdate()
def updateInfo(self):
ret = super().updateInfo()
for p in self.dbpd.getPackagesList():
if ret['target']=='' or len(ret['pcks'])==0:
ret['target']=p['path'].split("/dragonbox/packages/")[0]
elif ret['target'] != p['path'].split("/dragonbox/packages/")[0]:
print("WARNING: "+p['id']+" is installed on "+p['path'].split("/dragonbox/packages/")[0]+" but will use "+ret['target']+" for this update")
pck = self.cache.getPackage(p['id'])
if pck != None:
if pck['version'] != p['version']:
ret['pcks'].append(p['id'])
elif pck['md5sum'] != md5(p['path']):
print("WARNING: "+p['path']+" doesn't match the expected md5sum, redownloading")
ret['pcks'].append(p['id'])
return ret
def downloadTo(self, target):
try:
x = os.stat(target+'/dragonbox')
except FileNotFoundError as err:
os.mkdir(target+'/dragonbox')
try:
x = os.stat(target+'/dragonbox/packages')
except FileNotFoundError as err:
os.mkdir(target+'/dragonbox/packages')
if len(self.debToInstall):
os.system('pkexec apt-get -y install '+(' '.join(self.debToInstall)))
for i in self.dbpToInstall:
pck = self.cache.getPackage(i)
print('Downloading: '+pck['download']+' to '+target+'/dragonbox/packages/'+i+'.dbp ...')
urllib.request.urlretrieve(pck['download'], target+'/dragonbox/packages/'+i+'.dbp')
def parsePackages(self, pkgs):
self.dbpToInstall = []
self.debToInstall = []
toLook = pkgs.copy()
while len(toLook)>0:
name = toLook.pop()
self.dbpToInstall.append(name)
pck = self.cache.getPackage(name)
if 'dependency[deb]' in pck:
for p in pck['dependency[deb]'].split(';'):
if p!='':
self.debToInstall.append(p)
if 'dependency[dbp]' in pck:
for p in pck['dependency[dbp]'].split(';'):
if p!='':
toLook.append(p)
# make sure the list containt uniq items
self.dbpToInstall = list(set(self.dbpToInstall))
debToInstall = list(set(self.debToInstall))
self.debToInstall = []
cache = apt.Cache()
for p in debToInstall:
if not cache[p].is_installed:
self.debToInstall.append(p)
def downloadWindow(self, pkgs):
self.parsePackages(pkgs)
super().downloadWindow(pkgs)
def onReadme(self, *args):
pck = self.cache.getPackage(self.current_pck)
os.system("xdg-open "+pck['readme'])
def __init__(self, *args, **kw):
super().__init__()
parser = argparse.ArgumentParser(description='install DBP packages.')
parser.add_argument('-i', '--install', dest='packages', metavar='pck', type=str, nargs='+', help='Install the packages from a list of package id')
parser.add_argument('-d', '--dest', dest='dest', metavar='dest', type=str, help='SD-Card to use')
parser.add_argument('-c', '--cards', dest='cards', action='store_const', const=True, default=False, help='List available cards')
parser.add_argument('-u', '--update', dest='update', action='store_const', const=True, default=False, help='Update the cache')
parser.add_argument('-U', '--upgrade', dest='upgrade', action='store_const', const=True, default=False, help='Upgrade installed packages')
parser.add_argument('-l', '--list', dest='dolist', action='store_const', const=True, default=False, help='List known packages')
parser.add_argument('-I', '--installed', dest='installed', action='store_const', const=True, default=False, help='List installed packages')
cmd = parser.parse_args()
self.setCards(findcard())
pkgList = self.dbpd.getPackagesList()
super().setInstalledList(pkgList, self.cache)
super().setAvailList(self.cache.getPackagesList(), self.cache, pkgList)
if (cmd.update):
self.cache.update()
print("Cache updated.")
if cmd.dolist:
for p in self.cache.getPackagesList():
print(p)
elif cmd.installed:
for p in self.dbpd.getPackagesList():
print(p)
elif cmd.cards:
for c in findcard():
print(c['name'])
elif cmd.upgrade:
info = self.updateInfo()
if len(info['pcks'])>0:
self.parsePackages(info['pcks'])
self.downloadTo(info['target'])
else:
print("No package to upgrade")
elif cmd.packages !=None and len(cmd.packages)>0:
pcks=[]
ok=True
target=''
if cmd.dest != None:
for c in findcard():
if c['name'] == cmd.dest:
target = c['path']
if target=='':
ok = False
print('ERROR: SD-Card "'+cmd.dest+'" is not found. Available:')
for c in findcard():
print(c['name'])
for p in cmd.packages:
if self.cache.getPackage(p) == None:
ok=False
print('ERROR: Package '+p+' is unknown')
else:
pcks.append(p)
if ok and target!='':
self.parsePackages(pcks)
self.downloadTo(target)
elif ok:
self.downloadQuit = True
self.downloadWindow(pcks)
self.main()
elif not cmd.update:
self.downWindow.set_transient_for(self.mainWindow)
self.mainWindow.show_all()
self.main()
if __name__ == '__main__':
dbpInstaller()
......@@ -6,4 +6,4 @@ mkdir -p $XDG_CONFIG_HOME
export XDG_CACHE_HOME=$(dirname $0)/cache
mkdir -p $XDG_CACHE_HOME
export PYTHONPATH=$(dirname $0)/libs
python3 ./dbpInstaller.py "$@"
python3 -m dbpinstaller "$@"
#!/usr/bin/env python3
from pydbus import SystemBus
class dbpd():
inited = False
def __init__(self, *args, **kw):
super(dbpd, self).__init__(*args, **kw)
try:
self.daemon = SystemBus().get('de.dragonbox.PackageDaemon', '/de/dragonbox/PackageDaemon')
except Exception as e:
print(e)
else:
self.inited = True
def getPackagesList(self):
ret=[]
if self.inited:
for i in self.daemon.PackageList():
ret.append({"id": i[1], "path": i[0], "version": i[3]})
return ret
if __name__ == '__main__':
print(dbpd().getPackagesList())
"""
This package contains the dbpinstaller code.
"""
"""
The __main__ entry point.
"""
from .cli import main
if __name__ == "__main__":
main()
"""
This module contains the CLI functions.
"""
import argparse
import sys
from .mounts import find_mounts
from .installer import DbpInstaller
from .ui import launch_ui
def main():
"""
The main function.
"""
parser = argparse.ArgumentParser(
prog="dbpinstaller",
description='install DBP packages.',
)
# general arguments
parser.add_argument(
'-d',
'--dest',
dest='dest',
metavar='dest',
type=str,
help='SD-Card to use',
)
# start setting up subcommand parsers
subparsers = parser.add_subparsers(
title="action",
help="action to perform",
dest="action",
required=False, # so we can have a default subcommand
)
# install subcommand
install_parser = subparsers.add_parser( # noqa: F841
"install",
help="install packages",
)
install_parser.add_argument(
'packages',
metavar='pck',
type=str,
nargs='+',
help='Install the packages from a list of package id',
)
install_parser.add_argument(
"-u",
"--update",
action="store_true",
help="Update the cache first",
)
# 'cards' subcommand (list SD cards)
card_parser = subparsers.add_parser( # noqa: F841
"cards",
help='List available cards',
)
# update subcommand
update_parser = subparsers.add_parser( # noqa: F841
'update',
help='Update the cache',
)
# upgrade subcommand
upgrade_parser = subparsers.add_parser( # noqa: F841
'upgrade',
help='Upgrade installed packages',
)
upgrade_parser.add_argument(
"-u",
"--update",
action="store_true",
help="Update the cache first",
)
# list subcommand
list_parser = subparsers.add_parser( # noqa: F841
"list",
help='List known packages',
)
# installed subcommand (perhaps change to argument for list?)
install_subparser = subparsers.add_parser( # noqa: F841
'installed',
help='List installed packages',
)
cmd = parser.parse_args()
installer = DbpInstaller()
if cmd.action == "update":
installer.update()
print("Cache updated.")
elif cmd.action == "list":
for p in installer.list_packages():
print(p)
elif cmd.action == "installed":
for p in installer.list_installed():
print(p)
elif cmd.action == "cards":
for c in find_mounts():
print(c.name)
elif cmd.action == "upgrade":
# update cache first
if cmd.update:
installer.update()
if installer.upgrade_all():
print("Packages upgraded.")
else:
print("No package to upgrade")
elif cmd.action == "install":
# update cache first
if cmd.update:
installer.update()
pcks = []
ok = True
target = ''
if cmd.dest is not None:
for c in find_mounts():
if c.name == cmd.dest:
target = c.path
if target == '':
ok = False
print(
'ERROR: SD-Card {} is not found. Available:'.format(
cmd.dest,
),
)
for c in find_mounts():
print(c.name)
for p in cmd.packages:
if installer.get_package(p) is None:
ok = False
print('ERROR: Package ' + p + ' is unknown')
else:
pcks.append(p)
if ok and target != '':
installer.parse_packages(pcks)
installer.download_to(target)
elif ok:
launch_ui(installer, download=pcks)
else:
sys.exit(1)
elif cmd.action is None:
# launch the UI instead
launch_ui(installer)
#!/usr/bin/env python3
"""
This package contains the interface to the package daemon.
"""
from pydbus import SystemBus
class Dbpd(object):
"""
Interface to the package daemon.
"""
def __init__(self):
try:
self.daemon = SystemBus().get(
'de.dragonbox.PackageDaemon',
'/de/dragonbox/PackageDaemon',
)
except Exception as e:
self.daemon = None
print(e)
@property
def inited(self):
"""
True if a connection to the daemon has been established.
@return: whether a connection to the package daemon was established.
@rtype: L{bool}
"""
return self.daemon is not None