Merge remote-tracking branch 'origin/main' into dot
This commit is contained in:
@@ -5,31 +5,51 @@ end
|
||||
|
||||
set host $argv[1]
|
||||
set branch $argv[2]
|
||||
set branch_source explicit
|
||||
|
||||
if test -z "$branch"
|
||||
set branch_source current
|
||||
set branch (git branch --show-current)
|
||||
end
|
||||
|
||||
if test -z "$branch"
|
||||
echo "deploy-to: could not determine the current branch" >&2
|
||||
return 2
|
||||
end
|
||||
|
||||
git rev-parse --show-toplevel >/dev/null 2>&1
|
||||
or begin
|
||||
echo "deploy-to: run this from a git checkout" >&2
|
||||
return 2
|
||||
end
|
||||
|
||||
set dirty_lines (git status --porcelain)
|
||||
if test (count $dirty_lines) -gt 0
|
||||
echo "deploy-to: refusing to deploy with a dirty local worktree" >&2
|
||||
set untracked_lines (git status --porcelain --untracked-files=normal | string match -r '^\?\? ')
|
||||
if test (count $untracked_lines) -gt 0
|
||||
echo "deploy-to: refusing to deploy untracked files" >&2
|
||||
echo "deploy-to: git add new files that Nix must see, or remove them" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
git fetch origin
|
||||
or return $status
|
||||
|
||||
if test -z "$branch"; or not git rev-parse --verify --quiet refs/remotes/origin/$branch >/dev/null
|
||||
if test "$branch_source" = explicit
|
||||
echo "deploy-to: origin/$branch does not exist" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
set branch_source upstream
|
||||
set upstream_ref (git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null)
|
||||
set branch (string replace -r '^origin/' '' -- $upstream_ref)
|
||||
end
|
||||
|
||||
if test -z "$branch"; or not git rev-parse --verify --quiet refs/remotes/origin/$branch >/dev/null
|
||||
set branch_source default
|
||||
set origin_head (git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null)
|
||||
set branch (string replace -r '^origin/' '' -- $origin_head)
|
||||
end
|
||||
|
||||
if test -z "$branch"
|
||||
echo "deploy-to: could not determine a deploy branch" >&2
|
||||
return 2
|
||||
end
|
||||
|
||||
set remote_ref refs/remotes/origin/$branch
|
||||
git rev-parse --verify --quiet $remote_ref >/dev/null
|
||||
or begin
|
||||
@@ -37,17 +57,37 @@ or begin
|
||||
return 1
|
||||
end
|
||||
|
||||
set local_head (git rev-parse HEAD)
|
||||
set remote_head (git rev-parse $remote_ref)
|
||||
|
||||
if test "$local_head" != "$remote_head"
|
||||
echo "deploy-to: local HEAD differs from origin/$branch" >&2
|
||||
echo "deploy-to: push or reset the branch before deploying" >&2
|
||||
return 1
|
||||
set has_local_changes false
|
||||
if not git diff --quiet $remote_ref --
|
||||
set has_local_changes true
|
||||
end
|
||||
|
||||
set escaped_branch (string escape -- $branch)
|
||||
set escaped_host (string escape -- $host)
|
||||
set remote_command "cd ~/dev && git fetch origin && git switch -- $escaped_branch && git reset --hard origin/$escaped_branch && sudo nixos-rebuild switch --flake .#$escaped_host --print-build-logs"
|
||||
set remote_command "cd ~/dev && git fetch origin && git switch -- $escaped_branch && git reset --hard origin/$escaped_branch && git clean -fd"
|
||||
|
||||
set patch_file ""
|
||||
set remote_patch_file ""
|
||||
if test "$has_local_changes" = true
|
||||
set patch_file (mktemp)
|
||||
set remote_patch_file "/tmp/deploy-to-$host.patch"
|
||||
git diff --binary $remote_ref -- >$patch_file
|
||||
or begin
|
||||
rm -f $patch_file
|
||||
return $status
|
||||
end
|
||||
|
||||
scp $patch_file $host:$remote_patch_file
|
||||
set scp_status $status
|
||||
rm -f $patch_file
|
||||
if test $scp_status -ne 0
|
||||
return $scp_status
|
||||
end
|
||||
|
||||
set escaped_remote_patch_file (string escape -- $remote_patch_file)
|
||||
set remote_command "$remote_command && git apply --index $escaped_remote_patch_file && rm -f $escaped_remote_patch_file"
|
||||
end
|
||||
|
||||
set remote_command "$remote_command && sudo nixos-rebuild switch --flake .#$escaped_host --print-build-logs"
|
||||
|
||||
ssh -t $host $remote_command
|
||||
|
||||
@@ -3,13 +3,19 @@ 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",
|
||||
"pipeline.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"] }
|
||||
|
||||
@@ -1,18 +1,53 @@
|
||||
# Ariadne
|
||||
|
||||
Ariadne analyzes Clew output for a local Ren'Py game install.
|
||||
|
||||
Keep project-owned source under `src/ariadne/`.
|
||||
Keep game-derived files local and ignored under `src/ariadne/output/`.
|
||||
Ariadne analyzes Clew-produced data for local Ren'Py projects.
|
||||
|
||||
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.
|
||||
Ariadne consumes Clew output and builds analysis artifacts from it.
|
||||
Keep project-owned source under `src/ariadne/`; keep generated or game-derived files out of Git.
|
||||
|
||||
## Bazel shape
|
||||
## CLI
|
||||
|
||||
Run the current placeholder CLI with:
|
||||
Run the default target, `all`:
|
||||
|
||||
```sh
|
||||
bazel run //src/ariadne:ariadne
|
||||
```
|
||||
|
||||
By default, Ariadne writes output under `output/`.
|
||||
Use `--output-dir` to choose a different output directory:
|
||||
|
||||
```sh
|
||||
bazel run //src/ariadne:ariadne -- --output-dir scratch/ariadne-output
|
||||
```
|
||||
|
||||
Run through a specific target stage and its prerequisites:
|
||||
|
||||
```sh
|
||||
bazel run //src/ariadne:ariadne -- parse
|
||||
bazel run //src/ariadne:ariadne -- add-jump-edges
|
||||
```
|
||||
|
||||
Available target stages:
|
||||
|
||||
- `all`
|
||||
- `parse`
|
||||
- `add-implicit-edges`
|
||||
- `add-init-edges`
|
||||
- `add-jump-edges`
|
||||
|
||||
Relative `--output-dir` paths resolve from the workspace root when Ariadne runs through `bazel run`.
|
||||
|
||||
## Pipeline skeleton
|
||||
|
||||
Ariadne currently has pipeline scaffolding only.
|
||||
Each executable stage prepares an output directory at:
|
||||
|
||||
```text
|
||||
<output-dir>/graph/<stage>/
|
||||
```
|
||||
|
||||
If a stage output directory already exists and is not empty, Ariadne fails unless `--force` is set.
|
||||
With `--force`, Ariadne removes the existing stage output directory before recreating it.
|
||||
|
||||
Stage implementations are placeholders and do not write graph artifacts yet.
|
||||
|
||||
59
src/ariadne/lib.rs
Normal file
59
src/ariadne/lib.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::pipeline::Stage;
|
||||
|
||||
pub mod pipeline;
|
||||
|
||||
const OUTPUT_GRAPH_DIR: &str = "graph";
|
||||
|
||||
pub type Result<T> = io::Result<T>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub output_dir: PathBuf,
|
||||
pub force: bool,
|
||||
pub target_stage: pipeline::Stage,
|
||||
}
|
||||
|
||||
pub fn run(config: &Config) -> Result<()> {
|
||||
for stage in config.target_stage.with_prerequisites() {
|
||||
run_stage(config, stage)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_output_dir(config: &Config, stage: Stage) -> Result<PathBuf> {
|
||||
let output_dir = config.output_dir.join(OUTPUT_GRAPH_DIR).join(stage.name());
|
||||
|
||||
if output_dir.exists() && !output_dir.is_dir() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotADirectory,
|
||||
format!("output path is not a directory: {path}", path = output_dir.display()),
|
||||
));
|
||||
}
|
||||
|
||||
if output_dir.is_dir() && fs::read_dir(&output_dir)?.next().transpose()?.is_some() {
|
||||
if !config.force {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::AlreadyExists,
|
||||
format!(
|
||||
"output directory already exists and is not empty: {path}",
|
||||
path = output_dir.display()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
fs::remove_dir_all(&output_dir)?;
|
||||
}
|
||||
|
||||
fs::create_dir_all(&output_dir)?;
|
||||
Ok(output_dir)
|
||||
}
|
||||
|
||||
fn run_stage(config: &Config, stage: Stage) -> Result<()> {
|
||||
let output_dir = get_output_dir(config, stage)?;
|
||||
pipeline::run_stage(stage, &output_dir)
|
||||
}
|
||||
51
src/ariadne/main.rs
Normal file
51
src/ariadne/main.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Args {
|
||||
#[arg(long, default_value = "output")]
|
||||
output_dir: PathBuf,
|
||||
|
||||
#[arg(long)]
|
||||
force: bool,
|
||||
|
||||
#[arg(default_value = "all", value_parser = parse_stage)]
|
||||
target_stage: ariadne::pipeline::Stage,
|
||||
}
|
||||
|
||||
impl From<Args> for ariadne::Config {
|
||||
fn from(args: Args) -> Self {
|
||||
ariadne::Config {
|
||||
output_dir: resolve_workspace_path(args.output_dir),
|
||||
force: args.force,
|
||||
target_stage: args.target_stage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_stage(value: &str) -> Result<ariadne::pipeline::Stage, String> {
|
||||
ariadne::pipeline::Stage::ALL
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|stage| stage.name() == value)
|
||||
.ok_or_else(|| format!("unknown stage: {value}"))
|
||||
}
|
||||
|
||||
// TODO: Move this into a shared Rust utility crate.
|
||||
fn resolve_workspace_path(path: PathBuf) -> PathBuf {
|
||||
if path.is_absolute() {
|
||||
return path;
|
||||
}
|
||||
|
||||
if let Some(workspace) = std::env::var_os("BUILD_WORKSPACE_DIRECTORY") {
|
||||
return PathBuf::from(workspace).join(path);
|
||||
}
|
||||
|
||||
path
|
||||
}
|
||||
|
||||
fn main() -> ariadne::Result<()> {
|
||||
let config: ariadne::Config = Args::parse().into();
|
||||
ariadne::run(&config)
|
||||
}
|
||||
101
src/ariadne/pipeline.rs
Normal file
101
src/ariadne/pipeline.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, Hash, PartialEq, Ord, PartialOrd)]
|
||||
pub enum Stage {
|
||||
#[default]
|
||||
All,
|
||||
|
||||
Parse,
|
||||
AddImplicitEdges,
|
||||
AddInitEdges,
|
||||
AddJumpEdges,
|
||||
}
|
||||
|
||||
impl Stage {
|
||||
pub const ALL: &'static [Stage] = &[
|
||||
Stage::All,
|
||||
Stage::Parse,
|
||||
Stage::AddImplicitEdges,
|
||||
Stage::AddInitEdges,
|
||||
Stage::AddJumpEdges,
|
||||
];
|
||||
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Stage::All => "all",
|
||||
Stage::Parse => "parse",
|
||||
Stage::AddImplicitEdges => "add-implicit-edges",
|
||||
Stage::AddInitEdges => "add-init-edges",
|
||||
Stage::AddJumpEdges => "add-jump-edges",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prerequisites(self) -> &'static [Stage] {
|
||||
match self {
|
||||
Stage::All => &[
|
||||
Stage::AddImplicitEdges,
|
||||
Stage::AddInitEdges,
|
||||
Stage::AddJumpEdges,
|
||||
],
|
||||
Stage::Parse => &[],
|
||||
Stage::AddImplicitEdges => &[Stage::Parse],
|
||||
Stage::AddInitEdges => &[Stage::Parse],
|
||||
Stage::AddJumpEdges => &[Stage::Parse],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_prerequisites(self) -> Vec<Stage> {
|
||||
self.with_prerequisites_impl(BTreeSet::new())
|
||||
}
|
||||
|
||||
fn with_prerequisites_impl(self, seen: BTreeSet<Stage>) -> Vec<Stage> {
|
||||
if seen.contains(&self) {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let mut seen = seen;
|
||||
seen.insert(self);
|
||||
|
||||
let mut stages = Vec::new();
|
||||
for prerequisite in self.prerequisites() {
|
||||
let prerequisite_stages = prerequisite.with_prerequisites_impl(seen.clone());
|
||||
seen.extend(prerequisite_stages.iter().copied());
|
||||
stages.extend(prerequisite_stages);
|
||||
}
|
||||
|
||||
if self != Stage::All {
|
||||
stages.push(self);
|
||||
}
|
||||
|
||||
stages
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_stage(stage: Stage, output_dir: &Path) -> Result<()> {
|
||||
match stage {
|
||||
Stage::All => Ok(()),
|
||||
Stage::Parse => run_parse(output_dir),
|
||||
Stage::AddImplicitEdges => run_add_implicit_edges(output_dir),
|
||||
Stage::AddInitEdges => run_add_init_edges(output_dir),
|
||||
Stage::AddJumpEdges => run_add_jump_edges(output_dir),
|
||||
}
|
||||
}
|
||||
|
||||
fn run_parse(_output_dir: &Path) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_add_implicit_edges(_output_dir: &Path) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_add_init_edges(_output_dir: &Path) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_add_jump_edges(_output_dir: &Path) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
pub fn run() {
|
||||
println!("Ariadne");
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
ariadne::run();
|
||||
}
|
||||
Reference in New Issue
Block a user