Compare commits
4 Commits
main
...
0718ca1d53
| Author | SHA1 | Date | |
|---|---|---|---|
| 0718ca1d53 | |||
| 2d1900e061 | |||
| bf3a116797 | |||
| 45ff66947a |
@@ -3,13 +3,16 @@ load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library")
|
||||
rust_library(
|
||||
name = "ariadne_lib",
|
||||
crate_name = "ariadne",
|
||||
srcs = ["src/lib.rs"],
|
||||
srcs = ["lib.rs"],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "ariadne",
|
||||
crate_name = "ariadne_cli",
|
||||
srcs = ["src/main.rs"],
|
||||
deps = [":ariadne_lib"],
|
||||
srcs = ["main.rs"],
|
||||
deps = [
|
||||
":ariadne_lib",
|
||||
"//third_party/crates:clap",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,13 @@ name = "ariadne"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "ariadne"
|
||||
path = "main.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@@ -9,10 +9,15 @@ Clew owns extraction, preparation, and Ren'Py AST export.
|
||||
Ariadne consumes Clew's `clew-renpy-ast-v1` JSON from `output/ast/`.
|
||||
Ariadne maps that data into internal analysis state.
|
||||
|
||||
## Bazel shape
|
||||
## CLI skeleton
|
||||
|
||||
Run the current placeholder CLI with:
|
||||
Run all declared stages with:
|
||||
|
||||
```sh
|
||||
bazel run //src/ariadne:ariadne
|
||||
bazel run //src/ariadne:ariadne -- --output-dir output/
|
||||
```
|
||||
|
||||
The skeleton currently declares one `parse` stage.
|
||||
It writes a placeholder artifact under `output/graph/parse/`.
|
||||
|
||||
Use `--force` to remove stage output before rerunning the stage.
|
||||
|
||||
107
src/ariadne/lib.rs
Normal file
107
src/ariadne/lib.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub type Result<T> = io::Result<T>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub output_dir: PathBuf,
|
||||
pub force: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(output_dir: PathBuf, force: bool) -> Self {
|
||||
Self { output_dir, force }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub enum Stage {
|
||||
Parse,
|
||||
}
|
||||
|
||||
impl Stage {
|
||||
pub const ALL: &'static [Stage] = &[Stage::Parse];
|
||||
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Stage::Parse => "parse",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prerequisites(self) -> &'static [Stage] {
|
||||
match self {
|
||||
Stage::Parse => &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(config: &Config) -> Result<()> {
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
run_with_writer(config, &mut handle)
|
||||
}
|
||||
|
||||
pub fn run_with_writer(config: &Config, writer: &mut dyn Write) -> Result<()> {
|
||||
for stage in plan_stages(Stage::ALL) {
|
||||
run_stage(stage, config, writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn plan_stages(stages: &[Stage]) -> Vec<Stage> {
|
||||
fn visit(stage: Stage, seen: &mut HashSet<Stage>, planned: &mut Vec<Stage>) {
|
||||
if !seen.insert(stage) {
|
||||
return;
|
||||
}
|
||||
for prerequisite in stage.prerequisites() {
|
||||
visit(*prerequisite, seen, planned);
|
||||
}
|
||||
planned.push(stage);
|
||||
}
|
||||
|
||||
let mut seen = HashSet::new();
|
||||
let mut planned = Vec::new();
|
||||
for stage in stages {
|
||||
visit(*stage, &mut seen, &mut planned);
|
||||
}
|
||||
planned
|
||||
}
|
||||
|
||||
fn run_stage(stage: Stage, config: &Config, writer: &mut dyn Write) -> Result<()> {
|
||||
let stage_dir = stage_dir(&config.output_dir, stage);
|
||||
|
||||
if stage_dir.exists() {
|
||||
if config.force {
|
||||
fs::remove_dir_all(&stage_dir)?;
|
||||
} else {
|
||||
writeln!(
|
||||
writer,
|
||||
"SKIP {}: output exists at {}",
|
||||
stage.name(),
|
||||
stage_dir.display()
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(writer, "RUN {}", stage.name())?;
|
||||
match stage {
|
||||
Stage::Parse => run_parse(&stage_dir, writer)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stage_dir(output_dir: &Path, stage: Stage) -> PathBuf {
|
||||
output_dir.join("graph").join(stage.name())
|
||||
}
|
||||
|
||||
fn run_parse(stage_dir: &Path, writer: &mut dyn Write) -> Result<()> {
|
||||
fs::create_dir_all(stage_dir)?;
|
||||
let summary_path = stage_dir.join("summary.txt");
|
||||
fs::write(&summary_path, "parse stage placeholder\n")?;
|
||||
writeln!(writer, "WRITE {}", summary_path.display())?;
|
||||
Ok(())
|
||||
}
|
||||
27
src/ariadne/main.rs
Normal file
27
src/ariadne/main.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use std::path::PathBuf;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "ariadne", about = "Analyze Clew output for a Ren'Py game.")]
|
||||
struct Cli {
|
||||
#[arg(long, default_value = "output")]
|
||||
output_dir: PathBuf,
|
||||
|
||||
#[arg(long)]
|
||||
force: bool,
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let cli = Cli::parse();
|
||||
let config = ariadne::Config::new(cli.output_dir, cli.force);
|
||||
|
||||
match ariadne::run(&config) {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
Err(error) => {
|
||||
eprintln!("ERROR: {error}");
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
pub fn run() {
|
||||
println!("Ariadne");
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
ariadne::run();
|
||||
}
|
||||
Reference in New Issue
Block a user