ARIA2 The PORTS 〜downloader〜

# なんなの???
｢ARIA2｣と書いてますが､アニメの｢[ARIA](https://ja.wikipedia.org/wiki/ARIA_(%E3%82%A2%E3%83%8B%E3%83%A1))｣とは当然無関係ですし､ただタイトルをもじっただけの記事です(ｿﾚｦｲｲﾀｲﾀﾞｹｶﾖ

# 概要
~~｢[FreeBSD Advent Calendar 2024](https://qiita.com/advent-calendar/2024/freebsd)の余った箇所を12月25日を過ぎたあとに書いてみよう会?｣会員のワタシです(ぉぃ~~
｢aria2 を使って並列ダウンロードで高速化だ!｣と息巻いて見事 壁にぶち当たったのでなんとかしたお話です｡

## つまりどういうことなんだい??
```config:make.conf
DISABLE_SIZE=yes
FETCH_BINARY=aria2c
FETCH_ARGS=-c -s10 -x10 -k1M
```
素材のファイルを aria2 で fetch するとき､ GitHub などのプラットフォームからダウンロードするときに時折こういったことが起こります｡
```
[root@test nkf]# make
===>  License ZLIB accepted by the user
===>   ja-nkf-2.1.5_1,1 depends on file: /usr/local/sbin/pkg - found
=> nurse-nkf-v2_1_5_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://codeload.github.com/nurse/nkf/tar.gz/v2_1_5?dummy=/nurse-nkf-v2_1_5_GH0.tar.gz

12/23 17:26:37 [NOTICE] Downloading 1 item(s)

12/23 17:26:37 [NOTICE] Download complete: /usr/ports/distfiles/nkf-2_1_5.tar.gz

Download Results:
gid   |stat|avg speed  |path/URI
======+====+===========+=======================================================
f14e5c|OK  |   710KiB/s|/usr/ports/distfiles/nkf-2_1_5.tar.gz

Status Legend:
(OK):download completed.
stat: nurse-nkf-v2_1_5_GH0.tar.gz: No such file or directory
*** Error code 1

Stop.
make: stopped in /usr/ports/japanese/nkf
[root@test nkf]# 
```
このように URL のクエリに｢dummy=｣が含まれている場合､aria2 で make が認識出来ないファイル名になってダウンロードしてしまいます｡

# とりあえず調べてみた
壁を壊すにはまずどういう壁なのか調べる必要があります｡
```config:make.conf
DISABLE_SIZE=yes
FETCH_BINARY=/root/test-ports.py
FETCH_ARGS=--ARGS-test
FETCH_BEFORE_ARGS=--ARGS-BEFORE-test
FETCH_AFTER_ARGS=--ARGS-AFTER-test
```
```python:/root/test-ports.py
#!/usr/bin/python3

import sys

cmd = sys.argv
print(cmd)
exit(-1)
```
上のような設定にして引数を表示させるスクリプトを実行させるとどうなるのか試してみました｡
```
[root@test nkf]# make
===>  License ZLIB accepted by the user
===>   ja-nkf-2.1.5_1,1 depends on file: /usr/local/sbin/pkg - found
=> nurse-nkf-v2_1_5_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://codeload.github.com/nurse/nkf/tar.gz/v2_1_5?dummy=/nurse-nkf-v2_1_5_GH0.tar.gz
['/root/test-ports.py', '--ARGS-test', '--ARGS-BEFORE-test', 'https://codeload.github.com/nurse/nkf/tar.gz/v2_1_5?dummy=/nurse-nkf-v2_1_5_GH0.tar.gz', '--ARGS-AFTER-test']
=> Attempting to fetch http://distcache.FreeBSD.org/ports-distfiles/nurse-nkf-v2_1_5_GH0.tar.gz
['/root/test-ports.py', '--ARGS-test', '--ARGS-BEFORE-test', 'http://distcache.FreeBSD.org/ports-distfiles/nurse-nkf-v2_1_5_GH0.tar.gz', '--ARGS-AFTER-test']
=> Couldn't fetch it - please try to retrieve this
=> port manually into /usr/ports/distfiles/ and try again.
*** Error code 1

Stop.
make: stopped in /usr/ports/japanese/nkf
```
[フォーラム](https://forums.freebsd.org/threads/fetch-arguments.41270/)を覗いてみてふと他の FETCH 関連の変数を試してみたいと思ったので入れてみました｡
~~なるほど､こう設定するとこう動くんですねぇ〜~~

# とりあえずどうにかしてみた
```config:make.conf
DISABLE_SIZE=yes
FETCH_BINARY=/root/test-ports.py
FETCH_ARGS=--ARGS-test
FETCH_BEFORE_ARGS=--ARGS-BEFORE-test
#FETCH_AFTER_ARGS=--ARGS-AFTER-test
```
```python:/root/test-ports.py
#!/usr/bin/python3

import sys
import os
import shutil
import urllib.parse

cmd = sys.argv
print(cmd)

# set aria2
cmd[0] = shutil.which("aria2c")

purl = urllib.parse.urlparse(cmd[-1])
qs = urllib.parse.parse_qs(purl.query)
if("dummy" in qs):
    cmd[-1] = purl._replace(query="").geturl()
    cmd.extend(['-o'])
    fetched_file = os.path.basename("-".join(qs['dummy']))
    cmd.extend([fetched_file])

print(cmd)
exit(-1)
```
とりあえずクエリを抜き出してファイル名を取得し引数にセットしてあげます｡他に必要なクエリがあった場合は特に考えてないので追々困ったときn(ぉぃ
引数の末尾が URL でないとうまく機能しないので make.conf の｢FETCH_AFTER_ARGS｣は外しておきます｡
```
[root@test nkf]# make
===>  License ZLIB accepted by the user
===>   ja-nkf-2.1.5_1,1 depends on file: /usr/local/sbin/pkg - found
=> nurse-nkf-v2_1_5_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://codeload.github.com/nurse/nkf/tar.gz/v2_1_5?dummy=/nurse-nkf-v2_1_5_GH0.tar.gz
['/root/test-ports.py', '--ARGS-test', '--ARGS-BEFORE-test', 'https://codeload.github.com/nurse/nkf/tar.gz/v2_1_5?dummy=/nurse-nkf-v2_1_5_GH0.tar.gz']
['/usr/local/bin/aria2c', '--ARGS-test', '--ARGS-BEFORE-test', 'https://codeload.github.com/nurse/nkf/tar.gz/v2_1_5', '-o', 'nurse-nkf-v2_1_5_GH0.tar.gz']
=> Attempting to fetch http://distcache.FreeBSD.org/ports-distfiles/nurse-nkf-v2_1_5_GH0.tar.gz
['/root/test-ports.py', '--ARGS-test', '--ARGS-BEFORE-test', 'http://distcache.FreeBSD.org/ports-distfiles/nurse-nkf-v2_1_5_GH0.tar.gz']
['/usr/local/bin/aria2c', '--ARGS-test', '--ARGS-BEFORE-test', 'http://distcache.FreeBSD.org/ports-distfiles/nurse-nkf-v2_1_5_GH0.tar.gz']
=> Couldn't fetch it - please try to retrieve this
=> port manually into /usr/ports/distfiles/ and try again.
*** Error code 1

Stop.
make: stopped in /usr/ports/japanese/nkf
```
リスト配列の先頭に入っているスクリプトファイルパスを aria2c に置き換えてあげればだいたい意図したとおりのリスト配列になります｡

```config:make.conf
DISABLE_SIZE=yes
FETCH_BINARY=/root/aria-ports
FETCH_ARGS=-c -x10 -s10 -k1M --allow-overwrite=true
```
```python:/root/aria-ports
#!/usr/bin/python3

import sys
import os
import shutil
import subprocess
import urllib.parse

cmd = sys.argv
if len(cmd) - 1 == 0:
    print('please set cmd arguments')
    exit(-1)

# set aria2
cmd[0] = shutil.which("aria2c")

purl = urllib.parse.urlparse(cmd[-1])
qs = urllib.parse.parse_qs(purl.query)
if("dummy" in qs):
    cmd[-1] = purl._replace(query="").geturl()
    cmd.extend(['-o'])
    fetched_file = os.path.basename("-".join(qs['dummy']))
    cmd.extend([fetched_file])

aria2 = subprocess.Popen(cmd, universal_newlines=True)
aria2.wait()
exit(aria2.returncode)
```
最終的にこんな形になりました｡引数エラー処理は引数のありなし以外は基本的に aria2c へ丸投げしてやります｡

# まとめ
こんな感じで最終的に aria2 を呼び出す前に fetch するときの致命的な箇所をどうにかして aria2 を手抜きの極みでなんとかしてみたお話でした｡
とりあえずこれでうまく回ってはいますが｢Ruby にしたら?｣とか色々あるかもしれないので｢その時は勝手に書き換えてくれてもいいよ｣とは思っているので(ぉぃ