website/content/posts/installing-every-arch-package.md

91 lines
3 KiB
Markdown
Raw Normal View History

---
title: "Installing Every Arch Package"
date: 2022-01-26T21:52:58-06:00
2022-01-30 04:38:01 +00:00
draft: true
description: "Using algorithms and Julia to install as many packages as possible from the Arch Linux official repositories"
type: "post"
2022-01-30 04:38:01 +00:00
tags: ["linux", "fun", "algorithms", "computer-science"]
---
![A stupid idea on Matrix](/images/install-every-arch-package-matrix.png)
2022-01-30 00:06:23 +00:00
Challenge accepted. Let's do it!
2022-01-30 04:38:01 +00:00
First things first, let's generate a list of [all official Arch Linux packages](https://archlinux.org/packages/). Fortunately, `pacman`, the best pragmatic package manager in existence, makes this a breeze.
```sh
2022-01-30 04:38:01 +00:00
pacman -Sql
```
Great, now let's install it all!
```sh
2022-01-30 04:38:01 +00:00
pacman -Sql | xargs sudo pacman -S
```
10 seconds later, you'll find yourself with... unresolvable package conflicts detected?
2022-01-30 00:07:00 +00:00
OK, fine, let's disable dependency checking then:
```sh
2022-01-30 04:38:01 +00:00
pacman -Sql | xargs sudo pacman -Sdd
2022-01-30 00:07:00 +00:00
```
2022-01-30 00:07:00 +00:00
Nope, didn't work. We have to do something about the conflicting packages!
2022-01-30 04:38:01 +00:00
We could resolve all the conflicts manually with an hour of work... or we could write a program!
![Automation](https://imgs.xkcd.com/comics/automation.png)
2022-01-30 00:07:36 +00:00
## Time for some algorithms!
2022-01-30 04:38:01 +00:00
It's time to put our algorithms knowledge to good use. This is *just* a graph We can think of each package as a node in a graph and each conflict is an edge. Since we don't care about dependency checks (which would make for a likely broken system), we don't need to add any other edges to the graph.
2022-01-30 00:07:36 +00:00
2022-01-30 04:38:01 +00:00
For each edge, we need to pick at most one package, but not both. That sounds a lot like a [maximum independent set](https://en.wikipedia.org/wiki/Maximum_independent_set)!
2022-01-30 04:38:01 +00:00
Wait... it's NP hard though? And we have up to 12000 nodes, so we'll never be able to find the answer before the heat death of the universe, right?
2022-01-30 04:38:01 +00:00
Well, do we have 12000 *connected* nodes? No, since the largest connected component is probably only a few nodes. We aren't going to have hundreds or thousands of packages all conflicting with each other.
2022-01-30 00:06:23 +00:00
2022-01-30 04:38:01 +00:00
## Implementing this in Julia
We're going to use [Julia](https://julialang.org/) for implementing this algorithm, since Julia is Python but better. We first need to get a list of all packages:
```jl
packages = split(read(`pacman -Sql`, String))
n = length(packages)
idx = Dict(packages[i] => i for i = 1:n)
2022-01-30 00:06:23 +00:00
```
2022-01-30 04:38:01 +00:00
Now, we'll get info about each package:
```jl
struct Package
provides::Vector{String}
conflicts::Vector{String}
size::Float64
end
info = Vector{Package}()
Threads.@threads for i = 1:n
package = packages[i]
r = map(x -> split(split(x, "\n")[1]), split(read(`pacman -Si $package`, String), " : "))
push!(info, Package(r[10], r[13], parse(Float64, r[16][1])))
end
2022-01-30 00:06:23 +00:00
```
2022-01-30 04:38:01 +00:00
We need special handling for [virtual packages](https://wiki.archlinux.org/title/Pacman#Virtual_packages):
```jl
virtual = Dict{String, Vector{String}}()
for i = 1:n
for p in info[i].provides
if p not in virtual
virtual[packages[i]] = Vector{String}()
end
push!(virtual[packages[i]], packages[i])
end
end
2022-01-30 00:06:23 +00:00
```
2022-01-30 04:38:01 +00:00
We can use this to construct the graph:
```jl
graph = [Vector{Int}() for i = 1:n]
2022-01-30 00:07:00 +00:00
2022-01-30 04:38:01 +00:00
```