New package manager for 1.2
This commit is contained in:
parent
80faf9c740
commit
364c8e2910
@ -1,46 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import toaru_package
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
if not os.getuid() == 0:
|
||||
print(f"{sys.argv[0]}: must be root")
|
||||
sys.exit(1)
|
||||
|
||||
toaru_package.fetch_manifest()
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Available packages:")
|
||||
packages = sorted(toaru_package.manifest['packages'].keys())
|
||||
for k in packages:
|
||||
print(f" - {k}","(installed)" if k in toaru_package.installed_packages else "")
|
||||
sys.exit(0)
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
if arg.startswith("--"):
|
||||
if arg == "--dryrun":
|
||||
toaru_package.dryrun = True
|
||||
print("(Simulating installation.)")
|
||||
if arg == "--gui":
|
||||
toaru_package.is_gui = True
|
||||
else:
|
||||
toaru_package.process_package(arg)
|
||||
|
||||
toaru_package.calculate_upgrades()
|
||||
|
||||
for package in toaru_package.packages_to_install:
|
||||
if package in toaru_package.upgrade_packages:
|
||||
print(f"Upgrading {package}...")
|
||||
toaru_package.install_package(package)
|
||||
elif package in toaru_package.install_packages:
|
||||
print(f"Installing {package}...")
|
||||
toaru_package.install_package(package)
|
||||
|
||||
if not toaru_package.upgrade_packages and not toaru_package.install_packages:
|
||||
print(f"{sys.argv[0]}: up to date")
|
||||
|
||||
toaru_package.write_status()
|
1
hdd/bin/msk
Symbolic link
1
hdd/bin/msk
Symbolic link
@ -0,0 +1 @@
|
||||
msk.py
|
@ -17,8 +17,8 @@ char * __kernel_version_format = "%d.%d.%d-%s";
|
||||
|
||||
/* Version numbers X.Y.Z */
|
||||
int __kernel_version_major = 1;
|
||||
int __kernel_version_minor = 1;
|
||||
int __kernel_version_lower = 2;
|
||||
int __kernel_version_minor = 2;
|
||||
int __kernel_version_lower = 0;
|
||||
|
||||
/* Kernel build suffix, which doesn't necessarily
|
||||
* mean anything, but can be used to distinguish
|
||||
|
@ -1,37 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import tarfile
|
||||
import json
|
||||
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
|
||||
with tarfile.open(sys.argv[1], 'r:gz') as package:
|
||||
try:
|
||||
manifest_inf = package.getmember('manifest.json')
|
||||
manifest_br = package.extractfile(manifest_inf)
|
||||
manifest_str = manifest_br.read()
|
||||
except KeyError:
|
||||
print("Invalid MSK package: missing manifest")
|
||||
sys.exit(1)
|
||||
|
||||
manifest = json.loads(manifest_str)
|
||||
print(manifest['package'])
|
||||
print('.'.join([str(x) for x in manifest['version']]))
|
||||
|
||||
print("contents:")
|
||||
for member in package.getnames():
|
||||
if not member.startswith('./'):
|
||||
continue
|
||||
print(member.replace('./','/',1))
|
||||
|
||||
print("Going to extract to /")
|
||||
members = [member for member in package.getmembers() if member.name.startswith('./')]
|
||||
package.extractall('/',members=members)
|
||||
|
||||
if os.path.exists('/tmp/.wallpaper.pid'):
|
||||
with open('/tmp/.wallpaper.pid','r') as f:
|
||||
pid = int(f.read().strip())
|
||||
if pid:
|
||||
os.kill(pid, signal.SIGUSR1)
|
0
userspace/py/bin/migrate.py
Normal file → Executable file
0
userspace/py/bin/migrate.py
Normal file → Executable file
266
userspace/py/bin/msk.py
Executable file
266
userspace/py/bin/msk.py
Executable file
@ -0,0 +1,266 @@
|
||||
#!/usr/bin/python3.6
|
||||
"""
|
||||
Misaka Package Manager
|
||||
|
||||
Fetches and installs packages in compressed tarballs.
|
||||
"""
|
||||
|
||||
import glob
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
|
||||
server_url = 'http://toaruos.org/packages'
|
||||
var_dir = '/var/msk'
|
||||
manifest_path = f'{var_dir}/manifest.json'
|
||||
manifest_url = f'{server_url}/manifest.json'
|
||||
index_path = f'{var_dir}/index.json'
|
||||
local_cache = f'{var_dir}/cache'
|
||||
|
||||
is_gui = False
|
||||
|
||||
def fetch(url, destination, check=False):
|
||||
"""Fetch a package or other file from `url` and write it to `destination`."""
|
||||
if is_gui:
|
||||
args = ['fetch','-m','-o',destination,url]
|
||||
_fetch = subprocess.Popen(args, stdout=subprocess.PIPE)
|
||||
_progress = subprocess.Popen(['progress-bar.py',f'Fetching {os.path.basename(url)}...'], stdin=_fetch.stdout)
|
||||
_fetch.stdout.close()
|
||||
_progress.wait()
|
||||
else:
|
||||
args = ['fetch','-v','-o',destination,url]
|
||||
subprocess.call(args)
|
||||
if check:
|
||||
sha = hashlib.sha512()
|
||||
with open(destination,'rb') as f:
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
sha.update(chunk)
|
||||
if sha.hexdigest() != check:
|
||||
return False
|
||||
return True
|
||||
|
||||
def try_fetch(url, destination):
|
||||
"""Make multiple attempts to download a file with an integrity checksum."""
|
||||
attempts = 0
|
||||
while attempts < 3:
|
||||
if fetch(url, destination, check=True):
|
||||
return True
|
||||
else:
|
||||
attempts += 1
|
||||
return False
|
||||
|
||||
def extract_package(path, quiet=True):
|
||||
with tarfile.open(path, 'r:gz') as package:
|
||||
try:
|
||||
manifest_inf = package.getmember('manifest.json')
|
||||
manifest_br = package.extractfile(manifest_inf)
|
||||
manifest_str = manifest_br.read()
|
||||
except KeyError:
|
||||
if not quiet:
|
||||
print("Invalid MSK:", path)
|
||||
return False
|
||||
|
||||
manifest = json.loads(manifest_str)
|
||||
if not quiet:
|
||||
print(manifest['package'])
|
||||
print('.'.join([str(x) for x in manifest['version']]))
|
||||
|
||||
print("contents:")
|
||||
for member in package.getnames():
|
||||
if not member.startswith('./'):
|
||||
continue
|
||||
print(member.replace('./','/',1))
|
||||
|
||||
print("Going to extract to /")
|
||||
|
||||
members = [member for member in package.getmembers() if member.name.startswith('./')]
|
||||
package.extractall('/',members=members)
|
||||
|
||||
def signal_desktop(pid_file='/tmp/.wallpaper.pid'):
|
||||
if os.path.exists(pid_file):
|
||||
with open(pid_file,'r') as f:
|
||||
pid = int(f.read().strip())
|
||||
if pid:
|
||||
os.kill(pid, signal.SIGUSR1)
|
||||
|
||||
def version_str(version_lst):
|
||||
return '.'.join([str(x) for x in version_lst])
|
||||
|
||||
def needs_var_dir():
|
||||
if not os.path.exists(var_dir):
|
||||
os.makedirs(var_dir)
|
||||
|
||||
def needs_local_cache():
|
||||
needs_var_dir()
|
||||
if not os.path.exists(local_cache):
|
||||
os.makedirs(local_cache)
|
||||
|
||||
def fetch_manifest():
|
||||
needs_var_dir()
|
||||
fetch(manifest_url, manifest_path)
|
||||
|
||||
def get_manifest():
|
||||
if not os.path.exists(manifest_path):
|
||||
fetch_manifest()
|
||||
with open(manifest_path, 'r') as f:
|
||||
return json.loads(f.read())
|
||||
|
||||
def get_local_index():
|
||||
if not os.path.exists(index_path):
|
||||
return {}
|
||||
else:
|
||||
with open(index_path, 'r') as f:
|
||||
return json.loads(f.read())
|
||||
|
||||
def commit_local_index(index):
|
||||
needs_var_dir()
|
||||
with open(index_path,'w') as f:
|
||||
f.write(json.dumps(index))
|
||||
|
||||
def resolve_dependencies(packages, local_index, manifest, output=None):
|
||||
if not output:
|
||||
output = []
|
||||
for package in packages:
|
||||
for dep in manifest[package]['depends']:
|
||||
if not dep in packages and dep not in output and dep not in local_index:
|
||||
output = resolve_dependencies([dep], local_index, manifest, output)
|
||||
output.append(package)
|
||||
return output
|
||||
|
||||
def show_usage():
|
||||
print(f"""msk - Download and install packages.
|
||||
|
||||
usage: {sys.argv[0]} install PACKAGE [PACKAGE ...]
|
||||
{sys.argv[0]} update
|
||||
{sys.argv[0]} remove PACKAGE [PACKAGE ...] (* unimplemented)
|
||||
{sys.argv[0]} list
|
||||
{sys.argv[0]} list-all
|
||||
{sys.argv[0]} help
|
||||
""")
|
||||
return 1
|
||||
|
||||
def update_manifest():
|
||||
fetch_manifest()
|
||||
return 0
|
||||
|
||||
def remove_packages():
|
||||
print("(Unimplemented)")
|
||||
return 1
|
||||
|
||||
def fetch_package(name, manifest):
|
||||
package = manifest[name]
|
||||
fetch(f"{server_url}/{package['file']}", f"{local_cache}/{package['file']}", check=package['checksum'])
|
||||
|
||||
def install_fetched_package(name, manifest, local_index, install_candidates):
|
||||
package = manifest[name]
|
||||
|
||||
# Extract tarball
|
||||
extract_package(f"{local_cache}/{package['file']}")
|
||||
|
||||
# Remove the extracted package
|
||||
os.remove(f"{local_cache}/{package['file']}")
|
||||
|
||||
# Update the index to mark the package as installed
|
||||
if not name in local_index:
|
||||
local_index[name] = {}
|
||||
local_index[name].update(manifest[name])
|
||||
if name in install_candidates:
|
||||
local_index[name]['status'] = 'I' # Installed directly.
|
||||
else:
|
||||
if 'status' not in local_index[name]:
|
||||
local_index[name]['status'] = 'i' # Installed as a dependency
|
||||
|
||||
def install_packages():
|
||||
needs_local_cache()
|
||||
local_index = get_local_index()
|
||||
if local_index is None:
|
||||
print("Failed to build a local index.")
|
||||
return 1
|
||||
manifest = get_manifest()
|
||||
if manifest is None:
|
||||
print("Failed to obtain manifest.")
|
||||
return 1
|
||||
|
||||
# Verify the requested package names are valid
|
||||
packages = sys.argv[2:]
|
||||
install_candidates = []
|
||||
for package in packages:
|
||||
if package in local_index:
|
||||
continue
|
||||
if package not in manifest:
|
||||
print("Package not found:", package)
|
||||
continue
|
||||
install_candidates.append(package)
|
||||
|
||||
# Nothing was valid or the input was empty...
|
||||
if not install_candidates:
|
||||
print("Nothing to install.")
|
||||
return 1
|
||||
|
||||
# Go through each package and calculate dependency tree.
|
||||
all_packages = resolve_dependencies(install_candidates, local_index, manifest)
|
||||
|
||||
# If the set of packages we are installing differs from what
|
||||
# was requested (and valid), warn the user before continuing
|
||||
# (this just means there were dependencies to also install)
|
||||
if set(all_packages) != set(install_candidates):
|
||||
print("Going to install:", ", ".join(all_packages))
|
||||
if input("Continue? [y/N] ") not in ['y','Y','yes','YES']:
|
||||
print("Stopping.")
|
||||
return 1
|
||||
|
||||
# Download all of the requested packages
|
||||
for name in all_packages:
|
||||
print(f"Downloading {name}...")
|
||||
fetch_package(name, manifest)
|
||||
|
||||
# Install the packages
|
||||
for name in all_packages:
|
||||
print(f"Installing {package['file']}...")
|
||||
install_fetched_package(name, manifest, local_index, install_candidates)
|
||||
|
||||
# Commit
|
||||
commit_local_index(local_index)
|
||||
|
||||
# Signal desktop for menu changes
|
||||
signal_desktop()
|
||||
|
||||
return 0
|
||||
|
||||
def list_installed_packages():
|
||||
local_index = get_local_index()
|
||||
for name, package in local_index.items():
|
||||
print(f"{name} {version_str(package['version'])} - {package['friendly-name']}")
|
||||
return 0
|
||||
|
||||
def list_all_packages():
|
||||
local_index = get_local_index()
|
||||
manifest = get_manifest()
|
||||
for name, package in manifest.items():
|
||||
info = " " if name not in local_index else local_index[name]['status']
|
||||
print(f"{info} {name} {version_str(package['version'])} - {package['friendly-name']}")
|
||||
return 0
|
||||
|
||||
__commands = {
|
||||
'update': update_manifest,
|
||||
'help': show_usage,
|
||||
'install': install_packages,
|
||||
'remove': remove_packages,
|
||||
'list': list_installed_packages,
|
||||
'list-all': list_all_packages,
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit(show_usage())
|
||||
|
||||
if sys.argv[1] in __commands:
|
||||
sys.exit(__commands[sys.argv[1]]())
|
||||
else:
|
||||
print("Unrecognized command:", sys.argv[1])
|
||||
sys.exit(1)
|
||||
|
@ -13,7 +13,7 @@ import cairo
|
||||
import yutani
|
||||
import text_region
|
||||
import toaru_fonts
|
||||
import toaru_package
|
||||
import msk
|
||||
|
||||
from menu_bar import MenuBarWidget, MenuEntryAction, MenuEntrySubmenu, MenuEntryDivider, MenuWindow
|
||||
from icon_cache import get_icon
|
||||
@ -31,19 +31,23 @@ hilight_gradient_top = (93/255,163/255,236/255)
|
||||
hilight_gradient_bottom = (56/255,137/255,220/55)
|
||||
hilight_border_bottom = (47/255,106/255,167/255)
|
||||
|
||||
_local_index = None
|
||||
_manifest = None
|
||||
|
||||
package_height = 50
|
||||
|
||||
def install(name):
|
||||
toaru_package.process_package(name)
|
||||
toaru_package.calculate_upgrades()
|
||||
msk.needs_local_cache()
|
||||
all_packages = msk.resolve_dependencies([name], _local_index, _manifest)
|
||||
|
||||
for package in toaru_package.packages_to_install:
|
||||
if package in toaru_package.upgrade_packages or package in toaru_package.install_packages:
|
||||
toaru_package.install_package(package)
|
||||
for name in all_packages:
|
||||
msk.fetch_package(name, _manifest)
|
||||
|
||||
toaru_package.write_status()
|
||||
for name in all_packages:
|
||||
msk.install_fetched_package(name, _manifest, _local_index, [name])
|
||||
|
||||
toaru_package.packages_to_install = []
|
||||
toaru_package.upgrade_packages = []
|
||||
toaru_package.install_packages = []
|
||||
msk.commit_local_index(_local_index)
|
||||
msk.signal_desktop()
|
||||
|
||||
class Package(object):
|
||||
|
||||
@ -55,17 +59,24 @@ class Package(object):
|
||||
|
||||
@property
|
||||
def installed(self):
|
||||
return self.name in toaru_package.installed_packages
|
||||
return self.name in _local_index
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return _manifest[self.name]['description'].replace('\n',' ')
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
a,b,c= toaru_package.manifest['packages'][self.name]['version']
|
||||
a,b,c= _manifest[self.name]['version']
|
||||
return f"{a}.{b}.{c}"
|
||||
|
||||
@property
|
||||
def friendly_name(self):
|
||||
return _manifest[self.name]['friendly-name']
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
check = "☐" if not self.installed else "☑"
|
||||
return f"{check} <b>{self.name}</b> - {self.version}"
|
||||
return f"<h2><b>{self.friendly_name}</b> - {self.version}</h2>\n{self.description}"
|
||||
|
||||
def do_action(self):
|
||||
if self.installed:
|
||||
@ -135,20 +146,20 @@ class PackageManagerWindow(yutani.Window):
|
||||
self.hilighted = None
|
||||
|
||||
def load_packages(self):
|
||||
self.packages = sorted([Package(name) for name in toaru_package.manifest['packages'].keys()],key=lambda x: x.name)
|
||||
self.packages = sorted([Package(name) for name in _manifest.keys()],key=lambda x: x.name)
|
||||
|
||||
def redraw_buf(self,clips=None):
|
||||
if self.buf:
|
||||
self.buf.destroy()
|
||||
w = self.width - self.decorator.width()
|
||||
self.buf = yutani.GraphicsBuffer(w,len(self.packages)*24)
|
||||
self.buf = yutani.GraphicsBuffer(w,len(self.packages)*package_height)
|
||||
|
||||
surface = self.buf.get_cairo_surface()
|
||||
ctx = cairo.Context(surface)
|
||||
|
||||
if clips:
|
||||
for clip in clips:
|
||||
ctx.rectangle(clip.x,clip.y,w,24)
|
||||
ctx.rectangle(clip.x,clip.y,w,package_height)
|
||||
ctx.clip()
|
||||
|
||||
ctx.rectangle(0,0,surface.get_width(),surface.get_height())
|
||||
@ -160,7 +171,8 @@ class PackageManagerWindow(yutani.Window):
|
||||
for f in self.packages:
|
||||
f.y = offset_y
|
||||
if not clips or f in clips:
|
||||
tr = text_region.TextRegion(4,offset_y+4,w-4,20)
|
||||
tr = text_region.TextRegion(54,offset_y+4,w-54,package_height-4)
|
||||
tr.line_height = 20
|
||||
if f.hilight:
|
||||
gradient = cairo.LinearGradient(0,0,0,18)
|
||||
gradient.add_color_stop_rgba(0.0,*hilight_gradient_top,1.0)
|
||||
@ -168,26 +180,30 @@ class PackageManagerWindow(yutani.Window):
|
||||
ctx.rectangle(0,offset_y+4,w,1)
|
||||
ctx.set_source_rgb(*hilight_border_top)
|
||||
ctx.fill()
|
||||
ctx.rectangle(0,offset_y+4+20-1,w,1)
|
||||
ctx.rectangle(0,offset_y+package_height-1,w,1)
|
||||
ctx.set_source_rgb(*hilight_border_bottom)
|
||||
ctx.fill()
|
||||
ctx.save()
|
||||
ctx.translate(0,offset_y+4+1)
|
||||
ctx.rectangle(0,0,w,20-2)
|
||||
ctx.rectangle(0,0,w,package_height-6)
|
||||
ctx.set_source(gradient)
|
||||
ctx.fill()
|
||||
ctx.restore()
|
||||
tr.font.font_color = 0xFFFFFFFF
|
||||
else:
|
||||
ctx.rectangle(0,offset_y+4,w,20)
|
||||
ctx.rectangle(0,offset_y+4,w,package_height-4)
|
||||
ctx.set_source_rgb(1,1,1)
|
||||
ctx.fill()
|
||||
tr.font.font_color = 0xFF000000
|
||||
if f.installed:
|
||||
package_icon = get_icon('package',48)
|
||||
ctx.set_source_surface(package_icon,2,1+offset_y)
|
||||
ctx.paint()
|
||||
tr.set_richtext(f.text)
|
||||
tr.set_one_line()
|
||||
tr.set_ellipsis()
|
||||
tr.draw(self.buf)
|
||||
offset_y += 24
|
||||
offset_y += package_height
|
||||
|
||||
def draw(self):
|
||||
surface = self.get_cairo_surface()
|
||||
@ -275,7 +291,7 @@ class PackageManagerWindow(yutani.Window):
|
||||
|
||||
for f in self.packages:
|
||||
if offset_y > h: break
|
||||
if y >= offset_y and y < offset_y + 24:
|
||||
if y >= offset_y and y < offset_y + package_height:
|
||||
if not f.hilight:
|
||||
redraw.append(f)
|
||||
if self.hilighted:
|
||||
@ -285,7 +301,7 @@ class PackageManagerWindow(yutani.Window):
|
||||
self.hilighted = f
|
||||
hit = True
|
||||
break
|
||||
offset_y += 24
|
||||
offset_y += package_height
|
||||
|
||||
if not hit:
|
||||
if self.hilighted:
|
||||
@ -316,8 +332,9 @@ if __name__ == '__main__':
|
||||
d = yutani.Decor()
|
||||
|
||||
try:
|
||||
toaru_package.fetch_manifest()
|
||||
toaru_package.is_gui = True
|
||||
msk.is_gui = True
|
||||
_manifest = msk.get_manifest()
|
||||
_local_index = msk.get_local_index()
|
||||
packages = []
|
||||
except:
|
||||
packages = [NoPackages()]
|
||||
|
@ -13,7 +13,6 @@ import cairo
|
||||
import yutani
|
||||
import text_region
|
||||
import toaru_fonts
|
||||
import toaru_package
|
||||
|
||||
from color_picker import ColorPickerWindow
|
||||
|
||||
|
@ -1,182 +0,0 @@
|
||||
"""
|
||||
Library for managing get-py packages.
|
||||
"""
|
||||
import json
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import hashlib
|
||||
import os
|
||||
import stat
|
||||
|
||||
url = 'http://toaruos.org'
|
||||
|
||||
MANIFEST_PATH = '/tmp/.manifest.json'
|
||||
INSTALLED_PATH = '/tmp/.installed.json'
|
||||
|
||||
installed_packages = []
|
||||
packages_to_install = []
|
||||
upgrade_packages = []
|
||||
install_packages = []
|
||||
dryrun = False
|
||||
manifest = None
|
||||
is_gui = False
|
||||
|
||||
|
||||
def compare_version(left,right):
|
||||
if left[0] > right[0]: return True
|
||||
if left[0] == right[0] and left[1] > right[1]: return True
|
||||
if left[0] == right[0] and left[1] == right[1] and left[2] > right[2]: return True
|
||||
return False
|
||||
|
||||
def fetch_file(path, output, check=False, url=url, gui=False):
|
||||
loop = 0
|
||||
while loop < 3:
|
||||
if gui:
|
||||
args = ['fetch', '-m', '-o', output]
|
||||
args.append(f'{url}/{path}')
|
||||
fetch = subprocess.Popen(args, stdout=subprocess.PIPE)
|
||||
progress = subprocess.Popen(['progress-bar.py',f"Fetching {path}..."], stdin=fetch.stdout)
|
||||
fetch.stdout.close()
|
||||
progress.wait()
|
||||
else:
|
||||
args = ['fetch','-o',output]
|
||||
if check:
|
||||
args.append('-v')
|
||||
args.append(f'{url}/{path}')
|
||||
subprocess.call(args)
|
||||
if check:
|
||||
s = hashlib.sha512()
|
||||
with open(output,'rb') as f:
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
s.update(chunk)
|
||||
if s.hexdigest() != check:
|
||||
if loop == 2:
|
||||
print("Too many bad checksums, bailing.")
|
||||
else:
|
||||
print("Bad checksum, trying again...")
|
||||
loop += 1
|
||||
continue
|
||||
break
|
||||
|
||||
def process_package(name):
|
||||
if not name in manifest['packages']:
|
||||
raise ValueError((f"Unknown package: {name}"))
|
||||
package = manifest['packages'][name]
|
||||
if 'deps' in package:
|
||||
for dep in package['deps']:
|
||||
if dep not in packages_to_install:
|
||||
process_package(dep)
|
||||
packages_to_install.append(name)
|
||||
|
||||
def install_file(file,source):
|
||||
print(f"- Retrieving file {file[0]}","and checking hash" if file[2] else "")
|
||||
if not dryrun:
|
||||
fetch_file(file[0],file[1],file[2],source,is_gui)
|
||||
|
||||
def install_icon(steps):
|
||||
if not os.path.exists('/usr/share/icons/external'):
|
||||
subprocess.call(['mount','tmpfs','x','/usr/share/icons/external'])
|
||||
if not os.path.exists('/usr/share/menus'):
|
||||
subprocess.call(['mount','tmpfs','x','/usr/share/menus'])
|
||||
if not steps[2] in ['accessories','games','demo','graphics','settings']:
|
||||
return
|
||||
if not os.path.exists(f'/usr/share/menus/{steps[2]}'):
|
||||
os.mkdir(f'/usr/share/menus/{steps[2]}')
|
||||
fetch_file(steps[3],f'/usr/share/icons/external/{steps[4]}.png')
|
||||
with open(f'/usr/share/menus/{steps[2]}/{steps[4]}.desktop','w') as f:
|
||||
f.write(f"{steps[4]},{steps[5]},{steps[1]}\n")
|
||||
pid = None
|
||||
|
||||
if os.path.exists('/tmp/.wallpaper.pid'):
|
||||
with open('/tmp/.wallpaper.pid','r') as f:
|
||||
pid = int(f.read().strip())
|
||||
if pid:
|
||||
os.kill(pid, signal.SIGUSR1)
|
||||
|
||||
def run_install_step(step):
|
||||
if step[0] == 'ln':
|
||||
print(f"- Linking {step[2]} -> {step[1]}")
|
||||
if not dryrun:
|
||||
os.symlink(step[1],step[2])
|
||||
elif step[0] == 'tmpfs':
|
||||
print(f"- Mounting tmpfs at {step[1]}")
|
||||
if not dryrun:
|
||||
subprocess.call(['mount','tmpfs','x',step[1]])
|
||||
elif step[0] == 'ext2':
|
||||
print(f"- Mounting ext2 image {step[1]} at {step[2]}")
|
||||
if not dryrun:
|
||||
subprocess.call(['mount','ext2',step[1] + ',nocache',step[2]])
|
||||
elif step[0] == 'chmodx':
|
||||
print(f"- Making {step[1]} executable")
|
||||
if not dryrun:
|
||||
current = os.stat(step[1]).st_mode
|
||||
os.chmod(step[1],current | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
elif step[0] == 'ungz':
|
||||
print(f"- Decompressing {step[1]}")
|
||||
if not dryrun:
|
||||
subprocess.call(['ungz',step[1]])
|
||||
elif step[0] == 'mkdir':
|
||||
print(f"- Creating directory {step[1]}")
|
||||
if not dryrun:
|
||||
if not os.path.exists(step[1]):
|
||||
os.mkdir(step[1])
|
||||
elif step[0] == 'menu':
|
||||
print(f"- Installing shortcut {step[1]} in {step[2]}")
|
||||
if not dryrun:
|
||||
install_icon(step)
|
||||
else:
|
||||
print("Unknown step:",step)
|
||||
|
||||
def install_package(name):
|
||||
if not name in manifest['packages']:
|
||||
print(f"Unknown package: {arg}")
|
||||
sys.exit(1)
|
||||
package = manifest['packages'][name]
|
||||
if 'pre_steps' in package:
|
||||
for step in package['pre_steps']:
|
||||
run_install_step(step)
|
||||
if 'files' in package:
|
||||
url_source = url
|
||||
if 'source' in package:
|
||||
source = package['source']
|
||||
if source not in manifest['sources']:
|
||||
print(f"Bad source '{source}', will try locally.")
|
||||
url_source = manifest['sources'][source]
|
||||
for file in package['files']:
|
||||
install_file(file,url_source)
|
||||
if 'post_steps' in package:
|
||||
for step in package['post_steps']:
|
||||
run_install_step(step)
|
||||
installed_packages[name] = package['version']
|
||||
|
||||
def calculate_upgrades():
|
||||
for name in packages_to_install:
|
||||
if name in installed_packages:
|
||||
if compare_version(manifest['packages'][name]['version'],installed_packages[name]):
|
||||
upgrade_packages.append(name)
|
||||
else:
|
||||
install_packages.append(name)
|
||||
|
||||
def write_status():
|
||||
if not dryrun:
|
||||
with open(INSTALLED_PATH,'w') as f:
|
||||
json.dump(installed_packages, f)
|
||||
|
||||
def fetch_manifest():
|
||||
global manifest
|
||||
global installed_packages
|
||||
fetch_file('manifest.json',MANIFEST_PATH)
|
||||
|
||||
with open(MANIFEST_PATH) as f:
|
||||
manifest = json.load(f)
|
||||
|
||||
try:
|
||||
with open(INSTALLED_PATH) as f:
|
||||
installed_packages = json.load(f)
|
||||
except:
|
||||
installed_packages = {}
|
||||
|
||||
if not 'packages' in manifest:
|
||||
raise ValueError("invalid manifest file")
|
||||
|
Loading…
Reference in New Issue
Block a user