# Qt5.15.6で動かない…だと…(Archlinuxで複数パッケージをダウングレードするワンライナー)

Arch Linuxをいつものように使っていて、あるときいくつかのアプリケーションが動かないことに気がつきました。
今回は動かなかったfcitx5を代表例として、ターミナルから起動させてみました。

```bash:terminal
$ fcitx5-configtool
Cannot mix incompatible Qt library (5.15.5) with this library (5.15.6)
[1]    41884 IOT instruction (core dumped)  fcitx5-configtool
```

> 互換性のない Qt ライブラリ (5.15.5) をこのライブラリ (5.15.6) と混在させることはできません。

どうやら、Qt5のライブラリに`5.15.(5|6)`が混在するせいで、うまく動かないようです。
ですので、Qt5のライブラリで`5.15.6`をグレードダウンさせて、`5.15.5`に統一することで解決します。

## TL;DR

解決手段として、AURに`downgrade`というツールがありますので、そちらを使用します。
また、ダウングレードするパッケージ量が多いので、パッケージの指定方法をワンラインで解決してみました。

```bash:terminal
paru -S downgrade     # downgradeをAURヘルパーでインストールします。
paru -Qs qt5 | rg '5.15.6' | sed -r "s/local\///g" | awk -F'[ ]' '{print $1}' | tr '\n' ' ' > pkglist.txt && sudo downgrade `cat pkglist.txt` && rm pkglist.txt
```

---

**今回のコマンドで、注意してほしいこと。**
- AURヘルパーには`paru`を使用していますが、ほかのAURヘルパーでも問題なく動くかと思います。
- `downgrade`でのダウングレードバージョンの指定方法は、`fzf`でインクリメントサーチすることになるので、パッケージの数だけ都度指定する必要があります。
- `downgrade`ではダウングレードしたパッケージを`pacman.conf`の`IgnorPkg`に追加する機能もありますが、コマンド終了後に`pacman.conf`を確認した方が良いです。
    - `IgnorePkg`への指定されているパッケージリストが以下のように酷いことになります。コマンドが終了したら、削除することをお勧めします。

<!-- textlint-disable -->
![downgrade_IgnorePkg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/936194/0b44ff5b-c933-ded9-c5fe-155da69519c9.png)
<!-- textlint-enable -->

あとは、ワンラインで何をやっているのかの解説になります。
よろしければ最後までお付き合いください。


## downgradeについて

Arch Linuxにおけるパッケージ管理ツールである`pacman`は最新のパッケージの更新のみで、ダウングレードやバージョン指定のインストールなどには対応していません。
もし不具合などでパッケージのダウングレードをしたい場合は、インストール時に`/var/lib/pacman/local`下へキャッシュされるパッケージを`sudo pacman -U`を使用して解決できます。
そのうえで`/etc/pacman.conf`の`IgnorePkg`へ、更新を無効にするパッケージ名を追記することでダウングレードが完了します。

このダウングレード作業が1～2回くらいならどうってことはないのですが、10を超えてくると作業量はたいへんなものになってしまいます。
それをお手軽にパッケージ指定して解決できるのが、この`downgrade`です。

https://github.com/archlinux-downgrade/downgrade

処理的には`pacman`をラップして、ローカルキャッシュとALA（Arch Linux Archive）と呼ばれるオンラインで保管されている過去バージョンのパッケージを`fzf`で検索してダウングレードを行います。
ダウングレード完了後はインタラクティブに`IgnorePkg`へ追記するか確認してくれるので、必要であれば`y`を選択して追記してもらいましょう。

今回はダウングレードするパッケージをすべて`IgnorePkg`へ追記してもらいました。

## 対象のパッケージを絞り込む

`pacman`やそれをラップしているAURヘルパーでは`-Qs`でインストール済みのパッケージを検索できます。
今回はタイプ量が減るので`paru`から検索してみました。

その検索結果にはデフォルトで、以下のようなフォーマットで出力されます。

```
local/パッケージ名 パッケージバージョン パッケージグループ
    パッケージ説明
```

この検索結果を標準入力で`ripgrep`に渡して、検索対象のバージョンを指定します。
これは`grep`でも可能ですね。皆さんもターミナルで検索するときは良くやると思います。

```bash:terminal
$ paru -Qs qt5 | rg '5.15.6'
local/qt5-base 5.15.6+kde+r184-1 (qt qt5)
local/qt5-doc 5.15.6-1 (qt qt5)
local/qt5-examples 5.15.6-1 (qt qt5)
        ⋮
        ⋮
        ⋮
```

これで`paru`からの検索結果をバージョン指定して、パッケージリストの一行目のパッケージ名やバージョンが書いてある部分だけのリストを取得できました。

## 必要なところだけを抽出して整形する

とりあえず、`local/`の部分は不要ですので、`sed`コマンドを使用してここを削除してしまいましょう。

```bash:terminal
$ paru -Qs qt5 | rg '5.15.6' | sed -r 's/local\///'
qt5-base 5.15.6+kde+r184-1 (qt qt5)
qt5-doc 5.15.6-1 (qt qt5)
qt5-examples 5.15.6-1 (qt qt5)
        ⋮
        ⋮
        ⋮
```

こんな風に出力されたと思います。
あと欲しいのはスペースで区切られた最初の部分ですので、`awk`コマンドを使用して1フィールド目のパッケージ名を抽出します。

```bash:terminal
$ paru -Qs qt5 | rg '5.15.6' | sed -r 's/local\///' | awk -F '[ ]' '{print $1}'
qt5-base
qt5-doc
qt5-examples
    ⋮
    ⋮
    ⋮
```


## downgradeに引数として渡す

`pacman`だと、`<`を使用して先ほどまでの処理できたリストの形式でファイル読み込みができます。
同じように`downgrade`でもできると思ったのですが、どうやら駄目みたいです。

とりあえず改行がない状態にして、ファイルリストをスペースで区切られた形に整形して引数として渡せるようにしてみます。

```bash:terminal
$ paru -Qs qt5 | rg '5.15.6' | sed -r "s/local\///g" | awk -F'[ ]' '{print $1}' | tr '\n' ' '
qt5-base qt5-doc qt5-examples …
```

ここからいろいろ試して、標準入力で`downgrade`の引数に渡そうとしたのですが、うまくいきませんでした。
ですのでリダイレクトでファイルを作成してしまって、それをコマンド置換を使用して`cat`で出力したものを引数に渡すという方法に落ち付きました。

```bash:terminal
paru -Qs qt5 | rg '5.15.6' | sed -r "s/local\///g" | awk -F'[ ]' '{print $1}' | tr '\n' ' ' > pkglist.txt && sudo downgrade `cat pkglist.txt` && rm pkglist.txt
```

ここまでの出力内容をリダイレクトで`pkglist.txt`を作成し、`downgrade`に引数で渡すのは`cat`コマンド置換でファイル内容を出力させます。
これで`downgrade`にファイルリストを渡せたので`downgrade`の処理が終了したあとに、作成してしまった`pkglist.txt`を削除すればワンラインとしてのコマンドは終了です。

あとは冒頭で説明した通り`pacman.conf`の`IgnorePkg`がすごいことになるので、コメントアウトされた`IgnorePkg`の部分を削除すれば完全に終了です。

そんな感じにTwitterで困っていたら、「`xargs`を使えば解決できるのでは？」というアドバイスをもらったのですが、こちらも完全解決にはなりませんでした。
パッケージをダウングレードするかの確認と、ダウングレード後の`IgnorePkg`への追加確認で使用される部分は標準入力で呼び出されると正常に処理できないようです。


## まとめ

やはりLinuxでターミナル操作をメインにしていると、(Vim|Neovim)でのテキスト編集が一番フィットすると思います。
さらに言えば、ワンラインで一気に処理されるのはカッコイイですよね！

ただ、最後まで標準入力を使用するパイプで簡潔できなかったのは悔しいところですね…。
ワンラインという操作は今回が、ほとんど初めてみたいな感じだったので拙いところがあったかもしれません。

こうするとできるかも、みたいなコメントがあれば歓迎します。

ここまでお読みいただきありがとうございました。