cargo-atcoderの代替品を作った

[cargo-atcoder を使って Rust での AtCoder ライフを超快適にする](https://qiita.com/maguro_tuna/items/316068eeb8c5b9b31ed8)

この記事で紹介されている[cargo-atcoder](https://github.com/tanakh/cargo-atcoder)の代替品として[cargo-compete](https://github.com/qryxip/cargo-compete)を作りました。これを書いている時点でv0.5.0です。

インストール方法と使い方は[日本語README](https://github.com/qryxip/cargo-compete/blob/master/README-ja.md)を見てください。バイナリでの配布もしています。

![READMEのGIF](https://user-images.githubusercontent.com/14125495/91647583-511c6c80-ea97-11ea-941c-884070a3182a.gif)

cargo-atcoderで作ったパッケージをマイグレートするために[`cargo compete migrate cargo-atcoder`](https://github.com/qryxip/cargo-compete/blob/master/README-ja.md#cargo-compete-migrate-cargo-atcoder)というコマンドも用意しています。

## 動機

- 自分用に作った競プロツールを腐らせるのがもったいなかった。cargo-competeはそれを流用して作った
- 以下で紹介する機能が欲しかった/捨てるのが惜しかった
    - cargo-atcoderに乗り換えることはそこそこ本気で考えていて、[いくつかコントリビュート](https://github.com/tanakh/cargo-atcoder/pulls?q=is%3Apr+author%3Aqryxip)もしたが、自分用のものを用意した方が早そうと思った

## 機能

cargo-atcoderにはない機能として以下のものがあります。

- AtCoderのほかCodeforcesとyukicoderに対応

- AtCoderではDropboxからのダウンロードに対応

    ただし自分で認証したJSONをディレクトリに放り込んで..という形になります。

    ![Record](https://user-images.githubusercontent.com/14125495/91647905-c722d280-ea9b-11ea-88e8-e8c81b3ce555.gif)

    問題ページをPDFで保存しておけば、航空機内でAtCoderができます。ただインターネットが使えないのもそうですが紙とペンを出すスペースがあるとも限らないので、低難易度の問題を解くのに留めたほうが良いでしょう。

- テストケースはこのようなYAMLとして保存され、手軽に編集できます。

    - <code>[match](https://docs.rs/snowchains_core/0.4/snowchains_core/testsuite/enum.Match.html)</code>が`Float: { .. }`の場合、数値っぽい文字列は浮動小数点数として比較されます。サンプルケース取得時にそれっぽいキーワードとそれっぽい数値から自動で判定されます。
    - <code>[cases\[\].out](https://docs.rs/snowchains_core/0.4/snowchains_core/testsuite/struct.PartialBatchTestCase.html#structfield.out)</code>は省略可能です。省略した場合REやTLEしない限りすべてのUTF-8の出力が通ります。
    - <code>[extend](https://docs.rs/snowchains_core/0.4.1/snowchains_core/testsuite/struct.BatchTestSuite.html#structfield.extend)</code>を使うことで大きな入出力データはテキストファイルにするということが可能です。「フルの」テストケースを取得するときはテキストファイルとして保存され、保存先が`extend`に書かれます。

    ```yaml:a.yml
    ---
    type: Batch
    timelimit: 2s
    match: Lines

    cases:
      - name: sample1
        in: |
          1
          2 3
          test
        out: |
          6 test
      - name: sample2
        in: |
          72
          128 256
          myonmyon
        out: |
          456 myonmyon

    extend:
      - type: Text
        path: "./a"
        in: /in/*.txt
        out: /out/*.txt
    ```

- 問題ページとファイルを開く機能

    問題ページをブラウザで開くのはもちろん、ソースコードと上記のテストファイルを任意のエディタで開くことができます。 (`jq`が必要です。無い場合はパッケージマネージャで入れるか、Windowsなら[GitHub Releases](https://github.com/stedolan/jq/releases)等からダウンロードして`$PATH`内に置いてください)

    ```toml:compete.toml
    # Open files with the command (`jq` command)
    #
    # VSCode:
    # `["code", ..]`一発で記述できるだろうと思っていたがそうではなかった
    #open = '["bash", "-c"] + ["code -a " + .manifest_dir + " && code " + (.paths | map([.src, .test_suite]) | flatten | join(" "))]'
    # Emacs:
    #open = '["emacsclient", "-n"] + (.paths | map([.src, .test_suite]) | flatten)'
    ```

- ~~パッケージを[ワークスペース](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html)で管理し、~~ビルドキャッシュを共有

    AtCoderでは2020年のジャッジアップデートでRustが1.42.0にアップデートされ、[39個のクレート](https://github.com/rust-lang-ja/atcoder-rust-resources/wiki/2020-Update)が使えるようになりました。 また、サードパーティのクレートを含んだ実行バイナリをbase64でエンコードして提出する「バイナリ提出」もその是非はともかく**今のところ**明示的に容認されてます。しかしcargo-atcoderではコンテストに対応するパッケージ一つにつき一つのビルドキャッシュを使うため、クレートの数を控えるかコンテスト開始前にビルドを行っておく必要があるという問題がありました。

    cargo-competeではパッケージをワークスペースで管理することでこの問題を解決ししていました... v0.4.7までは。というのもワークスペースで管理していると、数百のパッケージがあったときにrust-analyzer等の開発ツールに負荷がかかってしまっていました。 (この924はwarningの個数です)

    ![Screenshot](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245660/a82d3df3-9733-b0e3-b415-9cb7eab44ef7.png)

    v0.5.0からは[`.cargo/config.toml`](https://doc.rust-lang.org/cargo/reference/config.html)で`target`ディレクトリだけを共有し、各パッケージのワークスペースは分離されます。ただし各`bin`のリネームは従来のままです。(e.g. `src/bin/a.rs` → `abc170-a`)

- コンテストへの参加登録

    コンテストの問題一覧が404の場合、コンテストの開始時間を見て開始してたら参加登録を試みます。

- AtCoder上のいくつかの古い問題に対応

    全部ではありませんが古い問題のうちいくつかのパターンに対応しています。

## Q&A

### `cargo compete new`が開始前のコンテストに使えない

cargo-competeではビルドキャッシュを共有する限り"warmup"が不要なため、問題が見えない場合に番号を推測するといった機能は付けてません。

### `cargo compete gen-binary`は?

今のところありません。バイナリ提出の場合<code>[resources/exec-base64-encoded-binary.rs.liquid](https://github.com/qryxip/cargo-compete/blob/master/resources/exec-base64-encoded-binary.rs.liquid)</code>に`source_code`と`base64`のパラメータを与えたものが提出されます。ただしそれはファイルシステム上に置かれません。

ojやatcoder-toolsと併用することも、想定していないことはないですがバイナリ提出する人の人数を考えると共通集合は空に近いと考えているためです。

### そもそも使い方がわからない

[README-ja](https://github.com/qryxip/cargo-compete/blob/master/README-ja.md)と`--help`を見てわからなければ、Qiitaのコメント欄か[Gitterの部屋](https://gitter.im/cargo-compete/community)も立てたのでこちらかにでも。

使い方を誤ったときでも人間が解釈可能なエラーメッセージが発生するはずなので、「エラーが意味不明」のようなものでも報告していただけると幸いです。 不具合によるものかもしれないし、そもそも適切なメッセージが出ないのは不具合なので。