advent_of_code_2024/bootstrap_day/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use error_chain::error_chain;
use itertools::Itertools;
use regex::Regex;
use reqwest::cookie::Jar;
use reqwest::Url;
use scraper::{Html, Selector};
use std::fs;
use std::fs::File;
use std::io::copy;
use std::sync::Arc;

error_chain! {
     foreign_links {
         Io(std::io::Error);
         HttpRequest(reqwest::Error);
     }
}

pub fn bootstrap_day(day: u8) -> Result<()> {
    let session_cookie =
        fs::read_to_string("res/session_cookie.txt").expect("Failed to read session cookie");

    let cookie = format!("session={}; Domain=adventofcode.com", session_cookie);
    let url = "https://www.adventofcode.com".parse::<Url>().unwrap();

    let jar = Jar::default();
    jar.add_cookie_str(cookie.as_str(), &url);

    let client = reqwest::blocking::Client::builder()
        .cookie_store(true)
        .cookie_provider(Arc::new(jar))
        .build()?;

    let input_target = format!("https://www.adventofcode.com/2024/day/{}/input", day);
    let input_file_contents = client.get(input_target).send()?.text()?;

    let output_filename = format!("res/day-{}-input.txt", day);
    let mut output_file = File::create(output_filename.clone())?;
    copy(&mut input_file_contents.as_bytes(), &mut output_file)?;

    println!("Puzzle input saved to {}", output_filename);

    let puzzle_target = format!("https://www.adventofcode.com/2024/day/{}", day);
    let input_file_contents = client.get(puzzle_target).send()?.text()?;

    let html = Html::parse_document(input_file_contents.as_str());
    let selector = Selector::parse("article.day-desc > h2").unwrap();
    let pattern = Regex::new(r"^--- Day \d+: (?<title>.*) ---$").unwrap();
    let title = html
        .select(&selector)
        .next()
        .map(|h2| h2.text().join(""))
        .and_then(|text| {
            pattern
                .captures_iter(text.as_str())
                .exactly_one()
                .ok()
                .and_then(|caps| caps.name("title").map(|m| m.as_str().to_string()))
        })
        .unwrap_or("???".to_string())
        .to_string();

    println!("Title: {title}");

    let rust_filename = format!("src/day_{}.rs", day);
    let rust_contents = format!("\
//! This is my solution for [Advent of Code - Day {day}: _{title}_](https://adventofcode.com/2024/day/{day})
//!
//!

use std::fs;

/// The entry point for running the solutions with the 'real' puzzle input.
///
/// - The puzzle input is expected to be at `<project_root>/res/day-{day}-input`
/// - It is expected this will be called by [`super::main()`] when the user elects to run day {day}.
pub fn run() {{
    let _contents = fs::read_to_string(\"res/day-{day}-input.txt\").expect(\"Failed to read file\");
}}

#[cfg(test)]
mod tests {{

}}",
        day=day
    );

    let mut rust_file = File::create(rust_filename.clone())?;
    copy(&mut rust_contents.as_bytes(), &mut rust_file)?;

    println!("Rust file written {}", rust_filename);

    let markdown_filename = format!("pubs/blog/day_{}.md", day);
    let markdown_contents = format!(
        "\
---
day: {day}
tags: [post]
header: 'Day {day}: {title}'
---
",
        day = day
    );

    let mut markdown_file = File::create(markdown_filename.clone())?;
    copy(&mut markdown_contents.as_bytes(), &mut markdown_file)?;

    println!("Blog file written {}", markdown_filename);

    // TODO - modify main.rs

    Ok(())
}