Skip to content

Commit

Permalink
Merge pull request #134 from nikomatsakis/main
Browse files Browse the repository at this point in the history
link tracking issues
  • Loading branch information
nikomatsakis authored Sep 17, 2024
2 parents 45a1fac + fc6b535 commit daa642d
Show file tree
Hide file tree
Showing 35 changed files with 427 additions and 175 deletions.
50 changes: 50 additions & 0 deletions mdbook-goals/src/gh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use std::fmt::Display;

use crate::re::TRACKING_ISSUE;

#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct IssueId {
/// Something like `rust-lang/rust-project-goals`
pub repository: String,

/// Something like `22`
pub number: u64,
}

impl IssueId {
pub fn new(repository: &(impl Display + ?Sized), number: u64) -> Self {
Self {
repository: repository.to_string(),
number,
}
}
}

impl std::fmt::Debug for IssueId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self}")
}
}

impl std::fmt::Display for IssueId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[{repository}#{number}]",
repository = self.repository,
number = self.number,
)
}
}

impl std::str::FromStr for IssueId {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let Some(c) = TRACKING_ISSUE.captures(s) else {
anyhow::bail!("invalid issue-id")
};

Ok(IssueId::new(&c[1], c[2].parse()?))
}
}
35 changes: 31 additions & 4 deletions mdbook-goals/src/goal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{collections::BTreeSet, path::PathBuf};
use anyhow::Context;
use regex::Regex;

use crate::gh::IssueId;
use crate::re::USERNAME;
use crate::team::{self, TeamName};
use crate::util::{commas, markdown_files};
Expand All @@ -15,6 +16,7 @@ use crate::{
};

/// Data parsed from a goal file in the expected format
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct GoalDocument {
/// Path relative to the current directory (`book.toml`)
pub path: PathBuf,
Expand All @@ -37,17 +39,21 @@ pub struct GoalDocument {
}

/// Metadata loaded from the goal header
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Metadata {
#[allow(unused)]
pub title: String,
pub short_title: String,
pub owners: String,
pub status: Status,
pub tracking_issue: Option<IssueId>,
pub table: Table,
}

pub const TRACKING_ISSUE_ROW: &str = "Tracking issue";

/// Identifies a particular ask for a set of Rust teams
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct PlanItem {
pub text: String,
pub owners: String,
Expand All @@ -66,7 +72,7 @@ pub enum ParsedOwners {
}

/// Identifies a particular ask for a set of Rust teams
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct TeamAsk {
/// Path to the markdown file containing this ask (appropriate for a link)
pub link_path: Arc<PathBuf>,
Expand Down Expand Up @@ -153,6 +159,16 @@ impl GoalDocument {
Status::NotAccepted => false,
}
}

/// Modify the goal document on disk to link to the given issue number in the metadata.
pub(crate) fn link_issue(&self, number: IssueId) -> anyhow::Result<()> {
let mut metadata_table = self.metadata.table.clone();
metadata_table.add_key_value_row(TRACKING_ISSUE_ROW, &number);
self.metadata
.table
.overwrite_in_path(&self.path, &metadata_table)?;
Ok(())
}
}

/// Format a set of team asks into a table, with asks separated by team and grouped by kind.
Expand Down Expand Up @@ -240,7 +256,7 @@ pub fn format_goal_table(goals: &[&GoalDocument]) -> anyhow::Result<String> {
Ok(util::format_table(&table))
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub enum Status {
Flagship,
Accepted,
Expand Down Expand Up @@ -308,6 +324,15 @@ fn extract_metadata(sections: &[Section]) -> anyhow::Result<Option<Metadata>> {

let status = Status::try_from(status_row[1].as_str())?;

let issue = match first_table
.rows
.iter()
.find(|row| row[0] == TRACKING_ISSUE_ROW)
{
Some(r) => Some(r[1].parse()?),
None => None,
};

Ok(Some(Metadata {
title: title.to_string(),
short_title: if let Some(row) = short_title_row {
Expand All @@ -317,6 +342,8 @@ fn extract_metadata(sections: &[Section]) -> anyhow::Result<Option<Metadata>> {
},
owners: owners_row[1].to_string(),
status,
tracking_issue: issue,
table: first_table.clone(),
}))
}

Expand Down
4 changes: 4 additions & 0 deletions mdbook-goals/src/json.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub(super) fn generate_json() {

}

1 change: 1 addition & 0 deletions mdbook-goals/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{io, path::PathBuf};
use structopt::StructOpt;
use walkdir::WalkDir;

mod gh;
mod goal;
mod markwaydown;
mod mdbook_preprocessor;
Expand Down
59 changes: 57 additions & 2 deletions mdbook-goals/src/markwaydown.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Arguably the worst markdown parser ever. Extracts exactly the things we care about.

use std::path::Path;
use std::{fmt::Display, path::Path};

use crate::util;

#[derive(Debug)]
pub struct Section {
Expand All @@ -10,7 +12,7 @@ pub struct Section {
pub tables: Vec<Table>,
}

#[derive(Debug)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Table {
pub line_num: usize,
pub header: Vec<String>,
Expand Down Expand Up @@ -150,3 +152,56 @@ fn categorize_line(line: &str) -> CategorizeLine {
CategorizeLine::Other
}
}

impl Table {
/// For a "key-value" table (like metadata), find an existing row
/// where the first column (the "key") is `row_key` and modify its second column (the "value")
/// to be `row_value`. If no row exists with key `row_key`, then add a new row.
pub fn add_key_value_row(&mut self, row_key: &str, row_value: &impl Display) {
assert_eq!(self.header.len(), 2);

match self.rows.iter_mut().find(|row| row[0] == row_key) {
Some(row) => {
row[1] = row_value.to_string();
}

None => {
self.rows
.push(vec![row_key.to_string(), row_value.to_string()]);
}
}
}

/// Modify `path` to replace the lines containing this table with `new_table`.
pub fn overwrite_in_path(&self, path: &Path, new_table: &Table) -> anyhow::Result<()> {
let full_text = std::fs::read_to_string(path)?;

let mut new_lines = vec![];
new_lines.extend(
full_text
.lines()
.take(self.line_num - 1)
.map(|s| s.to_string()),
);

let table_text = {
let mut new_rows = vec![new_table.header.clone()];
new_rows.extend(new_table.rows.iter().cloned());
util::format_table(&new_rows)
};
new_lines.push(table_text);

new_lines.extend(
full_text
.lines()
.skip(self.line_num - 1)
.skip(2 + self.rows.len())
.map(|s| s.to_string()),
);

let new_text = new_lines.join("\n");
std::fs::write(path, new_text)?;

Ok(())
}
}
4 changes: 4 additions & 0 deletions mdbook-goals/src/re.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ lazy_static! {
lazy_static! {
pub static ref USERNAME: Regex = Regex::new(r"@([-a-zA-Z0-9])+").unwrap();
}

lazy_static! {
pub static ref TRACKING_ISSUE: Regex = Regex::new(r"\[([^#]*)#([0-9]+)\]").unwrap();
}
Loading

0 comments on commit daa642d

Please sign in to comment.