Add table of contents to readme
type: documentation
This commit is contained in:
parent
66d44155f0
commit
1f5b829742
13
.github/workflows/rust.yaml
vendored
13
.github/workflows/rust.yaml
vendored
|
@ -26,13 +26,18 @@ jobs:
|
||||||
cargo --version
|
cargo --version
|
||||||
cargo clippy --version
|
cargo clippy --version
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --verbose
|
run: cargo build --all --verbose
|
||||||
- name: Test
|
- name: Test
|
||||||
run: cargo test --verbose
|
run: cargo test --all --verbose
|
||||||
- name: Clippy
|
- name: Clippy
|
||||||
run: cargo clippy
|
run: cargo clippy --all
|
||||||
- name: Format
|
- name: Format
|
||||||
run: cargo fmt -- --check
|
run: cargo fmt --all -- --check
|
||||||
- name: Lint
|
- name: Lint
|
||||||
if: matrix.os != 'windows-latest'
|
if: matrix.os != 'windows-latest'
|
||||||
run: "! grep --color -REn 'FIXME|TODO|XXX' src"
|
run: "! grep --color -REn 'FIXME|TODO|XXX' src"
|
||||||
|
- name: Readme
|
||||||
|
if: matrix.os != 'windows-latest'
|
||||||
|
run: |
|
||||||
|
cargo run --package update-readme toc
|
||||||
|
git diff --no-ext-diff --quiet --exit-code
|
||||||
|
|
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -139,7 +139,6 @@ dependencies = [
|
||||||
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"md5 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"md5 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -518,6 +517,15 @@ name = "unicode-xid"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "update-readme"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"structopt 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
|
15
Cargo.toml
15
Cargo.toml
|
@ -33,13 +33,8 @@ walkdir = "2"
|
||||||
version = "1"
|
version = "1"
|
||||||
features = ["derive"]
|
features = ["derive"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[workspace]
|
||||||
glob = "0.3.0"
|
members = [
|
||||||
regex = "1.3.3"
|
# generate table of contents and table of supported BEPs in README.md
|
||||||
|
"bin/update-readme"
|
||||||
# generates the table of supported BEPs in README.md
|
]
|
||||||
# not an example, but included as an example and not
|
|
||||||
# a binary because examples can use dev dependencies
|
|
||||||
[[example]]
|
|
||||||
name = "generate-bep-table"
|
|
||||||
path = "bin/generate-bep-table.rs"
|
|
||||||
|
|
85
README.md
85
README.md
|
@ -1,5 +1,53 @@
|
||||||
# intermodal: a 40' shipping container for the Internet
|
# intermodal: a 40' shipping container for the Internet
|
||||||
|
|
||||||
|
## Manual
|
||||||
|
|
||||||
|
- [General](#general)
|
||||||
|
- [Semantic Versioning](#semantic-versioning)
|
||||||
|
- [Unstable Features](#unstable-features)
|
||||||
|
- [Colored Output](#colored-output)
|
||||||
|
- [Bittorrent](#bittorrent)
|
||||||
|
- [BEP Support](#bep-support)
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
### Semantic Versioning
|
||||||
|
|
||||||
|
Intermodal follows [semantic versioning](https://semver.org/).
|
||||||
|
|
||||||
|
In particular:
|
||||||
|
|
||||||
|
- v0.0.X: Breaking changes may be introduced at any time.
|
||||||
|
- v0.X.Y: Breaking changes may only be introduced with a minor version number
|
||||||
|
bump.
|
||||||
|
- vX.Y.Z: Breaking changes may only be introduced with a major version number
|
||||||
|
bump
|
||||||
|
|
||||||
|
### Unstable Features
|
||||||
|
|
||||||
|
To avoid premature stabilization and excessive version churn, unstable features
|
||||||
|
are unavailable unless the `--unstable` / `-u` flag is passed. Unstable
|
||||||
|
features may be changed or removed at any time.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ imdl torrent stats --input tmp
|
||||||
|
error: Feature `torrent stats subcommand` cannot be used without passing the `--unstable` flag
|
||||||
|
$ imdl --unstable torrent stats tmp
|
||||||
|
Torrents processed: 0
|
||||||
|
Read failed: 0
|
||||||
|
Decode failed: 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Colored Output
|
||||||
|
|
||||||
|
Intermodal features colored help, error, and informational output. Colored
|
||||||
|
output is disabled if Intermodal detects that it is not printing to a TTY.
|
||||||
|
|
||||||
|
To disable colored output, set the `NO_COLOR` environment variable to any
|
||||||
|
value or pass `--use-color never` on the command line.
|
||||||
|
|
||||||
|
To force colored output, pass `--use-color always` on the command line.
|
||||||
|
|
||||||
## Bittorrent
|
## Bittorrent
|
||||||
|
|
||||||
### BEP Support
|
### BEP Support
|
||||||
|
@ -67,40 +115,3 @@
|
||||||
| [53](http://bittorrent.org/beps/bep_0053.html) | :x: | Magnet URI extension - Select specific file indices for download |
|
| [53](http://bittorrent.org/beps/bep_0053.html) | :x: | Magnet URI extension - Select specific file indices for download |
|
||||||
| [54](http://bittorrent.org/beps/bep_0054.html) | :heavy_minus_sign: | The lt_donthave extension |
|
| [54](http://bittorrent.org/beps/bep_0054.html) | :heavy_minus_sign: | The lt_donthave extension |
|
||||||
| [55](http://bittorrent.org/beps/bep_0055.html) | :heavy_minus_sign: | Holepunch extension |
|
| [55](http://bittorrent.org/beps/bep_0055.html) | :heavy_minus_sign: | Holepunch extension |
|
||||||
|
|
||||||
## General Functionality
|
|
||||||
|
|
||||||
### Colored Output
|
|
||||||
|
|
||||||
Intermodal features colored help, error, and informational output. Colored
|
|
||||||
output is disabled if Intermodal detects that it is not printing to a TTY.
|
|
||||||
|
|
||||||
To disable colored output, set the `NO_COLOR` environment variable to any
|
|
||||||
valu or pass `--use-color never` on the command line.
|
|
||||||
|
|
||||||
To force colored output, pass `--use-color always` on the command line.
|
|
||||||
|
|
||||||
## Semantic Versioning and Unstable Features
|
|
||||||
|
|
||||||
Intermodal follows [semantic versioning](https://semver.org/).
|
|
||||||
|
|
||||||
In particular:
|
|
||||||
|
|
||||||
- v0.0.X: Breaking changes may be introduced at any time.
|
|
||||||
- v0.X.Y: Breaking changes may only be introduced with a minor version number
|
|
||||||
bump.
|
|
||||||
- vX.Y.Z: Breaking changes may only be introduced with a major version number
|
|
||||||
bump
|
|
||||||
|
|
||||||
To avoid premature stabilization and excessive version churn, unstable features
|
|
||||||
are unavailable unless the `--unstable` / `-u` flag is passed. Unstable
|
|
||||||
features may be changed or removed at any time.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ imdl torrent stats --input tmp
|
|
||||||
error: Feature `torrent stats subcommand` cannot be used without passing the `--unstable` flag
|
|
||||||
$ imdl --unstable torrent stats tmp
|
|
||||||
Torrents processed: 0
|
|
||||||
Read failed: 0
|
|
||||||
Decode failed: 0
|
|
||||||
```
|
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
use std::{
|
|
||||||
error::Error,
|
|
||||||
fmt::{self, Display, Formatter},
|
|
||||||
fs,
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
use glob::glob;
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
const README: &str = "README.md";
|
|
||||||
|
|
||||||
struct Bep {
|
|
||||||
number: usize,
|
|
||||||
title: String,
|
|
||||||
status: Status,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Status {
|
|
||||||
Unknown,
|
|
||||||
NotApplicable,
|
|
||||||
Supported,
|
|
||||||
NotSupported,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Status {
|
|
||||||
type Err = String;
|
|
||||||
|
|
||||||
fn from_str(text: &str) -> Result<Self, Self::Err> {
|
|
||||||
match text {
|
|
||||||
"x" => Ok(Self::NotSupported),
|
|
||||||
"+" => Ok(Self::Supported),
|
|
||||||
"-" => Ok(Self::NotApplicable),
|
|
||||||
"?" => Ok(Self::Unknown),
|
|
||||||
":x:" => Ok(Self::NotSupported),
|
|
||||||
":white_check_mark:" => Ok(Self::Supported),
|
|
||||||
":heavy_minus_sign:" => Ok(Self::NotApplicable),
|
|
||||||
":grey_question:" => Ok(Self::Unknown),
|
|
||||||
_ => Err(format!("invalid status: {}", text)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Status {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Unknown => write!(f, ":grey_question:"),
|
|
||||||
Self::NotApplicable => write!(f, ":heavy_minus_sign:"),
|
|
||||||
Self::Supported => write!(f, ":white_check_mark:"),
|
|
||||||
Self::NotSupported => write!(f, ":x:"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
let title_re = Regex::new("(?m)^:Title: (?P<title>.*)$")?;
|
|
||||||
|
|
||||||
let mut beps = Vec::new();
|
|
||||||
|
|
||||||
for result in glob("tmp/bittorrent.org/beps/bep_*.rst")? {
|
|
||||||
let path = result?;
|
|
||||||
|
|
||||||
let number = path
|
|
||||||
.file_stem()
|
|
||||||
.unwrap()
|
|
||||||
.to_string_lossy()
|
|
||||||
.split('_')
|
|
||||||
.nth(1)
|
|
||||||
.unwrap()
|
|
||||||
.parse::<usize>()?;
|
|
||||||
|
|
||||||
if number == 1000 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let rst = fs::read_to_string(path)?;
|
|
||||||
|
|
||||||
let title = title_re
|
|
||||||
.captures(&rst)
|
|
||||||
.unwrap()
|
|
||||||
.name("title")
|
|
||||||
.unwrap()
|
|
||||||
.as_str()
|
|
||||||
.trim()
|
|
||||||
.to_owned();
|
|
||||||
|
|
||||||
beps.push(Bep {
|
|
||||||
status: Status::Unknown,
|
|
||||||
number,
|
|
||||||
title,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
beps.sort_by_key(|bep| bep.number);
|
|
||||||
|
|
||||||
let table_re = Regex::new(
|
|
||||||
r"(?mx)
|
|
||||||
^[|]\ BEP.*
|
|
||||||
(
|
|
||||||
\n
|
|
||||||
[|]
|
|
||||||
.*
|
|
||||||
)*
|
|
||||||
",
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let readme = fs::read_to_string(README)?;
|
|
||||||
|
|
||||||
let parts = table_re.split(&readme).into_iter().collect::<Vec<&str>>();
|
|
||||||
|
|
||||||
assert_eq!(parts.len(), 2);
|
|
||||||
|
|
||||||
let before = parts[0];
|
|
||||||
let after = parts[1];
|
|
||||||
let original = table_re
|
|
||||||
.captures(&readme)
|
|
||||||
.unwrap()
|
|
||||||
.get(0)
|
|
||||||
.unwrap()
|
|
||||||
.as_str()
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
let row_re = Regex::new(
|
|
||||||
r"(?x)
|
|
||||||
^
|
|
||||||
\|
|
|
||||||
\s*
|
|
||||||
\[
|
|
||||||
(?P<number>[0-9]+)
|
|
||||||
\]
|
|
||||||
.*
|
|
||||||
\s*
|
|
||||||
\|
|
|
||||||
(?P<status>.*)
|
|
||||||
\|
|
|
||||||
(?P<title>.*)
|
|
||||||
\|
|
|
||||||
$
|
|
||||||
",
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut originals = Vec::new();
|
|
||||||
|
|
||||||
for row in original.lines().skip(2) {
|
|
||||||
let captures = row_re.captures(row).unwrap();
|
|
||||||
originals.push(Bep {
|
|
||||||
number: captures.name("number").unwrap().as_str().parse()?,
|
|
||||||
status: captures.name("status").unwrap().as_str().trim().parse()?,
|
|
||||||
title: captures.name("title").unwrap().as_str().to_owned(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(originals.len(), beps.len());
|
|
||||||
|
|
||||||
let mut lines = Vec::new();
|
|
||||||
|
|
||||||
let width = beps.iter().map(|bep| bep.title.len()).max().unwrap_or(0);
|
|
||||||
|
|
||||||
lines.push(format!(
|
|
||||||
"| BEP | Status | {:width$} |",
|
|
||||||
"Title",
|
|
||||||
width = width
|
|
||||||
));
|
|
||||||
|
|
||||||
lines.push(format!(
|
|
||||||
"|:----------------------------------------------:|:------------------:|:{:-<width$}-|",
|
|
||||||
"",
|
|
||||||
width = width
|
|
||||||
));
|
|
||||||
|
|
||||||
for (bep, original) in beps.into_iter().zip(originals) {
|
|
||||||
assert_eq!(bep.number, original.number);
|
|
||||||
lines.push(format!(
|
|
||||||
"| [{:02}](http://bittorrent.org/beps/bep_{:04}.html) | {:18} | {:width$} |",
|
|
||||||
bep.number,
|
|
||||||
bep.number,
|
|
||||||
original.status.to_string(),
|
|
||||||
bep.title,
|
|
||||||
width = width
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let table = lines.join("\n");
|
|
||||||
|
|
||||||
let readme = &[before.trim(), "", &table, "", after.trim(), ""].join("\n");
|
|
||||||
|
|
||||||
fs::write(README, readme)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
11
bin/update-readme/Cargo.toml
Normal file
11
bin/update-readme/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "update-readme"
|
||||||
|
version = "0.0.0"
|
||||||
|
authors = ["Casey Rodarmor <casey@rodarmor.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
glob = "0.3.0"
|
||||||
|
regex = "1.3.3"
|
||||||
|
structopt = "0.3"
|
7
bin/update-readme/src/bep.rs
Normal file
7
bin/update-readme/src/bep.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
|
pub(crate) struct Bep {
|
||||||
|
pub(crate) number: usize,
|
||||||
|
pub(crate) title: String,
|
||||||
|
pub(crate) status: Status,
|
||||||
|
}
|
15
bin/update-readme/src/common.rs
Normal file
15
bin/update-readme/src/common.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// stdlib
|
||||||
|
pub(crate) use std::{
|
||||||
|
error::Error,
|
||||||
|
fmt::{self, Display, Formatter},
|
||||||
|
fs,
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
// crates.io
|
||||||
|
pub(crate) use glob::glob;
|
||||||
|
pub(crate) use regex::Regex;
|
||||||
|
pub(crate) use structopt::StructOpt;
|
||||||
|
|
||||||
|
// local
|
||||||
|
pub(crate) use crate::{bep::Bep, opt::Opt, status::Status};
|
10
bin/update-readme/src/main.rs
Normal file
10
bin/update-readme/src/main.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
mod bep;
|
||||||
|
mod common;
|
||||||
|
mod opt;
|
||||||
|
mod status;
|
||||||
|
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
Opt::from_args().run()
|
||||||
|
}
|
188
bin/update-readme/src/opt.rs
Normal file
188
bin/update-readme/src/opt.rs
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
|
const README: &str = "README.md";
|
||||||
|
|
||||||
|
const HEADING_PATTERN: &str = "(?m)^(?P<MARKER>#+) (?P<TEXT>.*)$";
|
||||||
|
|
||||||
|
const TOC_PATTERN: &str = "(?ms)## Manual.*## General";
|
||||||
|
|
||||||
|
#[derive(StructOpt)]
|
||||||
|
pub(crate) enum Opt {
|
||||||
|
SupportedBeps,
|
||||||
|
Toc,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Opt {
|
||||||
|
pub(crate) fn run(self) -> Result<(), Box<dyn Error>> {
|
||||||
|
match self {
|
||||||
|
Self::Toc => Self::update_toc(),
|
||||||
|
Self::SupportedBeps => Self::update_supported_beps(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_toc() -> Result<(), Box<dyn Error>> {
|
||||||
|
let readme = fs::read_to_string(README)?;
|
||||||
|
|
||||||
|
let header_re = Regex::new(HEADING_PATTERN)?;
|
||||||
|
|
||||||
|
let mut toc = Vec::new();
|
||||||
|
for captures in header_re.captures_iter(&readme).skip(2) {
|
||||||
|
let marker = captures.name("MARKER").unwrap().as_str();
|
||||||
|
let text = captures.name("TEXT").unwrap().as_str();
|
||||||
|
let level = marker.len();
|
||||||
|
let indentation = " ".repeat((level - 2) * 2);
|
||||||
|
let slug = text.to_lowercase().replace(' ', "-");
|
||||||
|
toc.push(format!("{}- [{}](#{})", indentation, text, slug));
|
||||||
|
}
|
||||||
|
|
||||||
|
let toc = toc.join("\n");
|
||||||
|
|
||||||
|
let toc_re = Regex::new(TOC_PATTERN)?;
|
||||||
|
|
||||||
|
let readme = toc_re.replace(
|
||||||
|
&readme,
|
||||||
|
format!("## Manual\n\n{}\n\n## General", toc).as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
|
fs::write(README, readme.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_supported_beps() -> Result<(), Box<dyn Error>> {
|
||||||
|
let title_re = Regex::new("(?m)^:Title: (?P<title>.*)$")?;
|
||||||
|
|
||||||
|
let mut beps = Vec::new();
|
||||||
|
|
||||||
|
for result in glob("tmp/bittorrent.org/beps/bep_*.rst")? {
|
||||||
|
let path = result?;
|
||||||
|
|
||||||
|
let number = path
|
||||||
|
.file_stem()
|
||||||
|
.unwrap()
|
||||||
|
.to_string_lossy()
|
||||||
|
.split('_')
|
||||||
|
.nth(1)
|
||||||
|
.unwrap()
|
||||||
|
.parse::<usize>()?;
|
||||||
|
|
||||||
|
if number == 1000 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rst = fs::read_to_string(path)?;
|
||||||
|
|
||||||
|
let title = title_re
|
||||||
|
.captures(&rst)
|
||||||
|
.unwrap()
|
||||||
|
.name("title")
|
||||||
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
.trim()
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
beps.push(Bep {
|
||||||
|
status: Status::Unknown,
|
||||||
|
number,
|
||||||
|
title,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
beps.sort_by_key(|bep| bep.number);
|
||||||
|
|
||||||
|
let table_re = Regex::new(
|
||||||
|
r"(?mx)
|
||||||
|
^[|]\ BEP.*
|
||||||
|
(
|
||||||
|
\n
|
||||||
|
[|]
|
||||||
|
.*
|
||||||
|
)*
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let readme = fs::read_to_string(README)?;
|
||||||
|
|
||||||
|
let parts = table_re.split(&readme).collect::<Vec<&str>>();
|
||||||
|
|
||||||
|
assert_eq!(parts.len(), 2);
|
||||||
|
|
||||||
|
let before = parts[0];
|
||||||
|
let after = parts[1];
|
||||||
|
let original = table_re
|
||||||
|
.captures(&readme)
|
||||||
|
.unwrap()
|
||||||
|
.get(0)
|
||||||
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
let row_re = Regex::new(
|
||||||
|
r"(?x)
|
||||||
|
^
|
||||||
|
\|
|
||||||
|
\s*
|
||||||
|
\[
|
||||||
|
(?P<number>[0-9]+)
|
||||||
|
\]
|
||||||
|
.*
|
||||||
|
\s*
|
||||||
|
\|
|
||||||
|
(?P<status>.*)
|
||||||
|
\|
|
||||||
|
(?P<title>.*)
|
||||||
|
\|
|
||||||
|
$
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut originals = Vec::new();
|
||||||
|
|
||||||
|
for row in original.lines().skip(2) {
|
||||||
|
let captures = row_re.captures(row).unwrap();
|
||||||
|
originals.push(Bep {
|
||||||
|
number: captures.name("number").unwrap().as_str().parse()?,
|
||||||
|
status: captures.name("status").unwrap().as_str().trim().parse()?,
|
||||||
|
title: captures.name("title").unwrap().as_str().to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(originals.len(), beps.len());
|
||||||
|
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
|
let width = beps.iter().map(|bep| bep.title.len()).max().unwrap_or(0);
|
||||||
|
|
||||||
|
lines.push(format!(
|
||||||
|
"| BEP | Status | {:width$} |",
|
||||||
|
"Title",
|
||||||
|
width = width
|
||||||
|
));
|
||||||
|
|
||||||
|
lines.push(format!(
|
||||||
|
"|:----------------------------------------------:|:------------------:|:{:-<width$}-|",
|
||||||
|
"",
|
||||||
|
width = width
|
||||||
|
));
|
||||||
|
|
||||||
|
for (bep, original) in beps.into_iter().zip(originals) {
|
||||||
|
assert_eq!(bep.number, original.number);
|
||||||
|
lines.push(format!(
|
||||||
|
"| [{:02}](http://bittorrent.org/beps/bep_{:04}.html) | {:18} | {:width$} |",
|
||||||
|
bep.number,
|
||||||
|
bep.number,
|
||||||
|
original.status.to_string(),
|
||||||
|
bep.title,
|
||||||
|
width = width
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let table = lines.join("\n");
|
||||||
|
|
||||||
|
let readme = &[before.trim(), "", &table, after.trim()].join("\n");
|
||||||
|
|
||||||
|
fs::write(README, readme.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
37
bin/update-readme/src/status.rs
Normal file
37
bin/update-readme/src/status.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
|
pub(crate) enum Status {
|
||||||
|
Unknown,
|
||||||
|
NotApplicable,
|
||||||
|
Supported,
|
||||||
|
NotSupported,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Status {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(text: &str) -> Result<Self, Self::Err> {
|
||||||
|
match text.replace('\\', "").as_str() {
|
||||||
|
"x" => Ok(Self::NotSupported),
|
||||||
|
"+" => Ok(Self::Supported),
|
||||||
|
"-" => Ok(Self::NotApplicable),
|
||||||
|
"?" => Ok(Self::Unknown),
|
||||||
|
":x:" => Ok(Self::NotSupported),
|
||||||
|
":white_check_mark:" => Ok(Self::Supported),
|
||||||
|
":heavy_minus_sign:" => Ok(Self::NotApplicable),
|
||||||
|
":grey_question:" => Ok(Self::Unknown),
|
||||||
|
_ => Err(format!("invalid status: {}", text)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Status {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Unknown => write!(f, ":grey_question:"),
|
||||||
|
Self::NotApplicable => write!(f, ":heavy_minus_sign:"),
|
||||||
|
Self::Supported => write!(f, ":white_check_mark:"),
|
||||||
|
Self::NotSupported => write!(f, ":x:"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
justfile
17
justfile
|
@ -29,8 +29,21 @@ preview-readme:
|
||||||
dev-deps:
|
dev-deps:
|
||||||
brew install grip
|
brew install grip
|
||||||
|
|
||||||
generate-bep-table:
|
# update readme table of contents
|
||||||
cargo run --example generate-bep-table
|
update-toc:
|
||||||
|
cargo run --package update-readme toc
|
||||||
|
|
||||||
|
# update readme table of supported BEPs
|
||||||
|
update-supported-beps:
|
||||||
|
cargo run --package update-readme supported-beps
|
||||||
|
|
||||||
|
check:
|
||||||
|
cargo test --all
|
||||||
|
cargo clippy --all
|
||||||
|
cargo fmt --all -- --check
|
||||||
|
! grep --color -REn 'FIXME|TODO|XXX' src
|
||||||
|
cargo run --package update-readme toc
|
||||||
|
git diff --no-ext-diff --quiet --exit-code
|
||||||
|
|
||||||
# retrieve large collection of torrents from the Internet Archive
|
# retrieve large collection of torrents from the Internet Archive
|
||||||
get-torrents:
|
get-torrents:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user