[NO TESTS] WIP

This commit is contained in:
Reid 'arrdem' McKenzie 2021-09-07 02:21:34 -06:00
parent 95e546ac55
commit 13d7f07b03
2 changed files with 141 additions and 0 deletions

View file

@ -0,0 +1,94 @@
import os
import re
import sys
def main(opts, args):
"""Usage: python rollback.py date
Parse /var/log/pacman.log, enumerating package transactions since the
specified date and building a plan for restoring the state of your system to
what it was at the specified date.
Assumes:
- /var/log/pacman.log has not been truncated
- /var/cache/pacman/pkg has not been flushed and still contains all required
packages
- The above paths are Arch default and have not been customized
- That it is not necessary to remove any "installed" packages
Note: no attempt is made to inspect the dependency graph of packages to be
downgraded to detect when a package is already transitively listed for
downgrading. This can create some annoying errors where eg. systemd will be
downgraded, meaning libsystemd will also be downgraded, but pacman considers
explicitly listing the downgrade of libsystemd when it will already be
transitively downgraded an error.
"""
date, = args
print("Attempting to roll back package state to that of {0}...\n"
.format(date),
file=sys.stderr)
# These patterns can't be collapsed because we want to select different
# version identifying strings depending on which case we're in. Not ideal,
# but it works.
# Ex. [2017-04-01 09:51] [ALPM] upgraded filesystem (2016.12-2 -> 2017.03-2)
upgraded_pattern = re.compile(
".*? upgraded (?P<name>\w+) \((?P<from>[^ ]+) -> (?P<to>[^\)]+)\)")
# Ex: [2018-02-23 21:18] [ALPM] downgraded emacs (25.3-3 -> 25.3-2)
downgraded_pattern = re.compile(
".*? downgraded (?P<name>\w+) \((?P<to>[^ ]+) -> (?P<from>[^\)]+)\)")
# Ex: [2017-03-31 07:05] [ALPM] removed gdm (3.22.3-1)
removed_pattern = re.compile(
".*? removed (?P<name>\w+) \((?P<from>[^ ]+)\)")
checkpoint = {}
flag = False
with open("/var/log/pacman.log") as logfile:
for line in logfile:
if date in line:
flag = True
elif not flag:
continue
match = re.match(upgraded_pattern, line)\
or re.match(downgraded_pattern, line)\
or re.match(removed_pattern, line)
if match:
package = match.group("name")
from_rev = match.group("from")
if package not in checkpoint:
checkpoint[package] = from_rev
continue
print("Checkpoint state:")
for k in checkpoint.keys():
print("{0} -> {1}".format(k, checkpoint[k]), file=sys.stderr)
pkgcache = "/var/cache/pacman/pkg"
pkgs = os.listdir(pkgcache)
pkgnames = ["{0}-{1}".format(k, v) for k, v in checkpoint.items()]
selected_pkgs = set([os.path.join(pkgcache, p)
for n in pkgnames
for p in pkgs
if n in p])
print("Suggested incantation:\n", file=sys.stderr)
print("sudo pacman --noconfirm -U {}"
.format("\\\n ".join(selected_pkgs)))
if __name__ == "__main__":
main(None, sys.argv[1:])

View file

@ -0,0 +1,47 @@
# An Asynchronous, Distributed Task Engine
This document presents a design without reference implementation for a distributed programming system;
sometimes called a workflow engine.
It is intended to provide architectural level clarity allowing for the development of alternative designs or implementations as may suit.
## Problem Statement
In building, operating and maintaining distributed systems (many computers in concert) engineers face a tooling gap.
Within the confines of a single computer, we have shells (`bash`, `csh`, `zsh`, `oil` etc.)
and a suite of small programs which mesh together well enough for the completion of small tasks with ad-hoc automation.
This is an enormous tooling win, as it allows small tasks to be automated at least for a time with a minimum of effort and with tools close to hand.
In interacting with networks, communicating between computers is difficult with traditional tools and communication failure becomes an ever-present concern.
Traditional automation tools such as shells are inadequate for this environment because achieving network communication is excessively difficult.
In a distributed environment it cannot be assumed that a single machine can remain available to execute automation;
This requires an approach to automation which allows for the incremental execution of single tasks at a time with provisions for relocation and recovery should failure occur.
It also cannot be assumed that a single machine is sufficiently available to receive and process incoming events such as callbacks.
A distributed system is needed to wrangle distributed systems.
## Design Considerations
- Timeouts are everywhere
- Sub-Turing/boundable
-
## Architectural Overview
### Events
Things that will happen, or time out.
### Actions
Things the workflow will do, or time out.
### Bindings
Data the workflow either was given or computed.
### Conditionals
Decisions the workflow may make.
### Functions
A convenient way to talk about fragments of control flow graph.
### Tracing & Reporting