Skip to content

Instantly share code, notes, and snippets.

@otykhonruk
Last active November 24, 2021 15:37
Show Gist options
  • Save otykhonruk/e52986ab3397f90f49b2af8aa67cfcb9 to your computer and use it in GitHub Desktop.
Save otykhonruk/e52986ab3397f90f49b2af8aa67cfcb9 to your computer and use it in GitHub Desktop.

Requirements: Python 3.9+

Running: python3 -m vpm < input.txt

DEPEND TELNET TCPIP NETCARD
DEPEND TCPIP NETCARD
DEPEND DNS TCPIP NETCARD
DEPEND BROWSER TCPIP HTML
INSTALL NETCARD
INSTALL TELNET
INSTALL foo
REMOVE NETCARD
INSTALL BROWSER
INSTALL DNS
LIST
REMOVE TELNET
REMOVE NETCARD
REMOVE DNS
REMOVE NETCARD
INSTALL NETCARD
REMOVE TCPIP
REMOVE BROWSER
REMOVE TCPIP
LIST
END
# Vintra package manager
import sys
from graphlib import TopologicalSorter # Python 3.9+
def collect_dependencies(dependencies, *pkgs):
"""
Returns iterator over dependencies in sorted order.
Uses graphlib.TopologicalSorter from Python 3.9+
"""
ts = TopologicalSorter()
candidates = set(pkgs)
while candidates:
pkg = candidates.pop()
if pkg in dependencies:
deps = dependencies[pkg]
ts.add(pkg, *deps)
candidates.update(deps)
return ts.static_order()
class PackageManager:
def __init__(self):
self.dependencies = {}
self.installed = set()
self.auto_installed = set()
def depend(self, pkg, *items):
"""
Package item1 depends on package item2 (and item3 or any additional packages).
"""
self.dependencies[pkg] = items
def install(self, item):
"""
Installs item1 and any other packages required by item1
"""
if item in self.installed:
print(f'\t{item} is already installed')
return
deps = list(collect_dependencies(self.dependencies, item))[:-1]
for pkg in deps:
if pkg not in self.auto_installed and pkg not in self.installed:
# perform actual install
self.auto_installed.add(pkg)
print(f'\t{pkg} successfully installed')
print(f'\t{item} successfully installed')
self.installed.add(item)
def remove(self, pkg):
"""
Removes item1 and, if possible, packages required by item1.
"""
if not (pkg in self.installed or pkg in self.auto_installed):
print(f'\t{pkg} is not installed')
return
deps = set(collect_dependencies(self.dependencies, *(self.installed - {pkg})))
if pkg in deps:
print(f'\t{pkg} is still needed')
return
self.installed.remove(pkg)
print(f'\t{pkg} successfully removed')
pkg_deps = list(collect_dependencies(self.dependencies, pkg))
for p in pkg_deps[:-1]:
if p not in deps and p not in self.installed:
print(f'\t{p} is no longer needed')
self.auto_installed.remove(p)
print(f'\t{p} successfully removed')
def list(self):
"""
Lists the names of all currently installed packages.
"""
for pkg in self.installed.union(self.auto_installed):
print(f'\t{pkg}')
def end(self):
"""
Marks the end of input, when used in a line by itself.
"""
pass
def process_input(package_manager=None, stream=sys.stdin):
pm = package_manager or PackageManager()
for line in stream:
if words := line.split():
cmd, *args = words
try:
print(line, end='')
getattr(pm, cmd.swapcase())(*args)
except AttributeError:
print(f'ERROR: Unknown command {cmd}')
if __name__ == '__main__':
process_input()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment