Skip to content

Commit c21dbf6

Browse files
committed
add pq files
1 parent 09b6a60 commit c21dbf6

6 files changed

Lines changed: 145 additions & 122 deletions

File tree

cli/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM ubuntu:24.04
22

33
RUN apt-get update && apt-get install -y \
44
git curl unzip build-essential pkg-config \
5-
libssl-dev ca-certificates python3 \
5+
libssl-dev ca-certificates python3 mcpp \
66
&& rm -rf /var/lib/apt/lists/*
77

88
# Install Rust

cli/entrypoint.sh

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ case "$MODE" in
7171
fi
7272
fi
7373

74+
# Preprocess with mcpp if the file contains #include directives
75+
COMPILE_FILE="$FILE_PATH"
76+
TMP_PREPROCESSED=""
77+
if grep -q '^[[:space:]]*#include' "$FILE_PATH" 2>/dev/null; then
78+
TMP_PREPROCESSED=$(mktemp --suffix=.simf)
79+
mcpp "$FILE_PATH" -o "$TMP_PREPROCESSED"
80+
COMPILE_FILE="$TMP_PREPROCESSED"
81+
fi
82+
7483
# Build simc flags based on kind
7584
SIMC_EXTRA_ARGS=()
7685
if [[ "$KIND" == "wit" && -n "$ITEM_VALUE" ]]; then
@@ -87,18 +96,19 @@ case "$MODE" in
8796
TMP_FILE=""
8897
fi
8998

90-
simc_out=$(simc "$FILE_PATH" "${SIMC_EXTRA_ARGS[@]}" --json 2>/tmp/simc_stderr) || {
91-
err=$(head -1 /tmp/simc_stderr | tr '"\\' "''")
99+
simc_out=$(simc "$COMPILE_FILE" "${SIMC_EXTRA_ARGS[@]}" --json 2>/tmp/simc_stderr) || {
100+
err=$(grep -m1 'error' /tmp/simc_stderr | tr '"\\' "''" || head -1 /tmp/simc_stderr | tr '"\\' "''")
92101
[[ -n "$TMP_FILE" ]] && rm -f "$TMP_FILE"
93102

94103
# On simc failure: still run parse.py so jets/types/etc are captured,
95104
# then emit merged output with _error set.
96105
if [[ -n "${PARSE_CACHE[$FILE_PATH]+x}" ]]; then
97106
parse_out="${PARSE_CACHE[$FILE_PATH]}"
98107
else
99-
parse_out=$(python3 /parse.py "$FILE_PATH")
108+
parse_out=$(python3 /parse.py "$COMPILE_FILE")
100109
PARSE_CACHE[$FILE_PATH]="$parse_out"
101110
fi
111+
[[ -n "$TMP_PREPROCESSED" ]] && rm -f "$TMP_PREPROCESSED"
102112
TMP_PARSE=$(mktemp)
103113
echo "$parse_out" > "$TMP_PARSE"
104114
python3 - "$TMP_PARSE" "$FILE_PATH" "$KIND" "$ITEM_NAME" "$err" <<'PYEOF'
@@ -119,9 +129,10 @@ PYEOF
119129
if [[ -n "${PARSE_CACHE[$FILE_PATH]+x}" ]]; then
120130
parse_out="${PARSE_CACHE[$FILE_PATH]}"
121131
else
122-
parse_out=$(python3 /parse.py "$FILE_PATH")
132+
parse_out=$(python3 /parse.py "$COMPILE_FILE")
123133
PARSE_CACHE[$FILE_PATH]="$parse_out"
124134
fi
135+
[[ -n "$TMP_PREPROCESSED" ]] && rm -f "$TMP_PREPROCESSED"
125136

126137
# Extract program from simc output
127138
program=$(python3 -c "import json,sys; d=json.loads(sys.argv[1]); print(d.get('program',''))" "$simc_out")

cli/src/main.rs

Lines changed: 58 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,6 @@ enum Commands {
101101
#[arg(conflicts_with_all = ["all", "tag"])]
102102
slugs: Vec<String>,
103103

104-
/// Re-clone repos even if a local cache already exists
105-
#[arg(long)]
106-
refresh: bool,
107104
},
108105
}
109106

@@ -186,27 +183,6 @@ fn entry_path_parts(gh: &GithubFile) -> (String, String, String) {
186183
(gh.owner.clone(), gh.repo.clone(), script_name(gh))
187184
}
188185

189-
// ---------------------------------------------------------------------------
190-
// Docker output shapes
191-
// ---------------------------------------------------------------------------
192-
193-
/// Output from parse mode (parse.py via Docker).
194-
#[derive(Debug, Deserialize)]
195-
struct ParseOutput {
196-
_file_path: String,
197-
#[serde(default)]
198-
reserved_words: BTreeMap<String, u64>,
199-
#[serde(default)]
200-
jets: BTreeMap<String, u64>,
201-
#[serde(default)]
202-
builtins: BTreeMap<String, u64>,
203-
#[serde(default)]
204-
types: BTreeMap<String, u64>,
205-
#[serde(default)]
206-
macros: BTreeMap<String, u64>,
207-
}
208-
209-
210186
/// Output from compile mode — merged simc + hal-simplicity + parse.py output.
211187
#[derive(Debug, Deserialize)]
212188
struct SimcOutput {
@@ -286,61 +262,6 @@ struct EntryMeta {
286262
// Docker
287263
// ---------------------------------------------------------------------------
288264

289-
// ---------------------------------------------------------------------------
290-
// Repo cache
291-
// ---------------------------------------------------------------------------
292-
293-
/// Returns the local cache path for a given repo URL + branch.
294-
fn repo_cache_path(clone_url: &str, branch: &str) -> PathBuf {
295-
const FNV_OFFSET: u64 = 0xcbf29ce484222325;
296-
const FNV_PRIME: u64 = 0x100000001b3;
297-
let mut hash = FNV_OFFSET;
298-
for b in clone_url.bytes().chain(std::iter::once(b'|')).chain(branch.bytes()) {
299-
hash ^= b as u64;
300-
hash = hash.wrapping_mul(FNV_PRIME);
301-
}
302-
std::env::temp_dir()
303-
.join("simplicity-catalog-repos")
304-
.join(format!("{:016x}", hash))
305-
}
306-
307-
/// Clone or reuse a cached local clone of the repo.
308-
/// Pass `refresh = true` to delete the cache and re-clone.
309-
fn ensure_repo_cached(clone_url: &str, branch: &str, refresh: bool) -> Result<PathBuf> {
310-
let path = repo_cache_path(clone_url, branch);
311-
if refresh && path.exists() {
312-
fs::remove_dir_all(&path)?;
313-
}
314-
if path.join(".git").exists() {
315-
return Ok(path);
316-
}
317-
println!("Cloning {clone_url} ({branch}) …");
318-
fs::create_dir_all(&path)?;
319-
let status = Command::new("git")
320-
.args(["clone", "--depth", "1", "--branch", branch, clone_url])
321-
.arg(&path)
322-
.status()
323-
.context("failed to run git — is it installed and on PATH?")?;
324-
if !status.success() {
325-
bail!("git clone failed for {clone_url}");
326-
}
327-
Ok(path)
328-
}
329-
330-
/// Convert a host path to the format Docker expects for `-v` mounts.
331-
/// On Windows, converts `C:\foo\bar` → `/c/foo/bar`.
332-
fn to_docker_volume_path(path: &Path) -> String {
333-
let s = path.to_string_lossy();
334-
#[cfg(windows)]
335-
{
336-
if s.len() >= 3 && s.as_bytes()[1] == b':' {
337-
let drive = s.chars().next().unwrap().to_ascii_lowercase();
338-
return format!("/{}/{}", drive, s[3..].replace('\\', "/"));
339-
}
340-
}
341-
s.replace('\\', "/")
342-
}
343-
344265
fn ensure_docker_image(tag: &str) -> Result<()> {
345266
let check = Command::new("docker")
346267
.args(["image", "inspect", tag])
@@ -372,19 +293,21 @@ fn ensure_docker_image(tag: &str) -> Result<()> {
372293
Ok(())
373294
}
374295

375-
fn run_docker<T>(mode: &str, clone_url: &str, branch: &str, local_repo: &Path, file_paths: &[&str]) -> Result<Vec<T>>
296+
fn run_docker<T>(
297+
mode: &str,
298+
clone_url: &str,
299+
branch: &str,
300+
file_paths: &[&str],
301+
) -> Result<Vec<T>>
376302
where
377303
T: serde::de::DeserializeOwned,
378304
{
379305
let tag = image_tag();
380306
ensure_docker_image(&tag)?;
381307

382-
let vol = format!("{}:/workspace/repo:ro", to_docker_volume_path(local_repo));
383-
384308
let output = Command::new("docker")
385309
.arg("run")
386310
.arg("--rm")
387-
.arg("-v").arg(&vol)
388311
.arg(&tag)
389312
.arg(mode)
390313
.arg(clone_url)
@@ -674,7 +597,16 @@ fn select_tomls(
674597
}
675598

676599
/// `(toml_path, file_path, witnesses, args, arg_values)` — name→value maps
677-
type RepoGroup = BTreeMap<(String, String), Vec<(PathBuf, String, BTreeMap<String, String>, BTreeMap<String, String>, BTreeMap<String, String>)>>;
600+
type RepoGroup = BTreeMap<
601+
(String, String),
602+
Vec<(
603+
PathBuf,
604+
String,
605+
BTreeMap<String, String>,
606+
BTreeMap<String, String>,
607+
BTreeMap<String, String>,
608+
)>,
609+
>;
678610

679611
fn group_by_repo(paths: &[PathBuf]) -> Result<RepoGroup> {
680612
let mut groups: RepoGroup = BTreeMap::new();
@@ -684,10 +616,13 @@ fn group_by_repo(paths: &[PathBuf]) -> Result<RepoGroup> {
684616
let meta: EntryMeta = toml_edit::de::from_str(&raw)
685617
.with_context(|| format!("cannot parse {}", path.display()))?;
686618
let clone_url = meta.clone_url.or(meta.repo).unwrap_or_default();
687-
groups
688-
.entry((clone_url, meta.branch))
689-
.or_default()
690-
.push((path.to_owned(), meta.file_path, meta.example_witnesses, meta.example_args, meta.example_arg_values));
619+
groups.entry((clone_url, meta.branch)).or_default().push((
620+
path.to_owned(),
621+
meta.file_path,
622+
meta.example_witnesses,
623+
meta.example_args,
624+
meta.example_arg_values,
625+
));
691626
}
692627
Ok(groups)
693628
}
@@ -722,7 +657,15 @@ fn cmd_add(
722657
let commit = fetch_file_commit(&gh)?;
723658
println!("{}", &commit[..12]);
724659

725-
write_skeleton_toml(&out_path, &gh, tags, &commit, example_witnesses, example_args, example_arg_values)?;
660+
write_skeleton_toml(
661+
&out_path,
662+
&gh,
663+
tags,
664+
&commit,
665+
example_witnesses,
666+
example_args,
667+
example_arg_values,
668+
)?;
726669

727670
println!("Added: data/programs/{org}/{repo}/{name}.toml");
728671
if !tags.is_empty() {
@@ -732,7 +675,7 @@ fn cmd_add(
732675
Ok(())
733676
}
734677

735-
fn cmd_compile(all: bool, tag: Option<&str>, slugs: &[String], refresh: bool) -> Result<()> {
678+
fn cmd_compile(all: bool, tag: Option<&str>, slugs: &[String]) -> Result<()> {
736679
if !all && tag.is_none() && slugs.is_empty() {
737680
bail!("specify --all, --tag <tag>, or one or more slugs");
738681
}
@@ -767,23 +710,15 @@ fn cmd_compile(all: bool, tag: Option<&str>, slugs: &[String], refresh: bool) ->
767710
}
768711
let file_args: Vec<&str> = encoded.iter().map(|s| s.as_str()).collect();
769712

770-
let local_repo = match ensure_repo_cached(clone_url, branch, refresh) {
771-
Ok(p) => p,
772-
Err(e) => {
773-
eprintln!("error cloning {clone_url}: {e:#}");
774-
failed += entries.len();
775-
continue;
776-
}
777-
};
778-
779-
let results: Vec<SimcOutput> = match run_docker("compile", clone_url, branch, &local_repo, &file_args) {
780-
Ok(r) => r,
781-
Err(e) => {
782-
eprintln!("error compiling {clone_url}: {e:#}");
783-
failed += entries.len();
784-
continue;
785-
}
786-
};
713+
let results: Vec<SimcOutput> =
714+
match run_docker("compile", clone_url, branch, &file_args) {
715+
Ok(r) => r,
716+
Err(e) => {
717+
eprintln!("error compiling {clone_url}: {e:#}");
718+
failed += entries.len();
719+
continue;
720+
}
721+
};
787722

788723
for (toml_path, file_path, witnesses, args, arg_values) in entries {
789724
let stem = toml_path
@@ -800,7 +735,9 @@ fn cmd_compile(all: bool, tag: Option<&str>, slugs: &[String], refresh: bool) ->
800735

801736
let meta_result = base_result.or_else(|| {
802737
if !args.is_empty() || !arg_values.is_empty() {
803-
results.iter().find(|r| &r._file_path == file_path && r._kind == "args")
738+
results
739+
.iter()
740+
.find(|r| &r._file_path == file_path && r._kind == "args")
804741
} else {
805742
None
806743
}
@@ -831,7 +768,10 @@ fn cmd_compile(all: bool, tag: Option<&str>, slugs: &[String], refresh: bool) ->
831768
if let Some(r) = results.iter().find(|r| {
832769
&r._file_path == file_path && r._kind == "wit" && &r._item_name == item_name
833770
}) {
834-
write_simb(&toml_path.with_file_name(format!("{stem}.{item_name}.simb")), r)?;
771+
write_simb(
772+
&toml_path.with_file_name(format!("{stem}.{item_name}.simb")),
773+
r,
774+
)?;
835775
println!(" compiled witness: {stem}.{item_name}");
836776
} else {
837777
eprintln!("warning: no witness result for {file_path} (wit: {item_name})");
@@ -843,7 +783,10 @@ fn cmd_compile(all: bool, tag: Option<&str>, slugs: &[String], refresh: bool) ->
843783
if let Some(r) = results.iter().find(|r| {
844784
&r._file_path == file_path && r._kind == "args" && &r._item_name == item_name
845785
}) {
846-
write_simb(&toml_path.with_file_name(format!("{stem}.args.{item_name}.simb")), r)?;
786+
write_simb(
787+
&toml_path.with_file_name(format!("{stem}.args.{item_name}.simb")),
788+
r,
789+
)?;
847790
println!(" compiled args: {stem}.args.{item_name}");
848791
} else {
849792
eprintln!("warning: no args result for {file_path} (args: {item_name})");
@@ -855,7 +798,10 @@ fn cmd_compile(all: bool, tag: Option<&str>, slugs: &[String], refresh: bool) ->
855798
if let Some(r) = results.iter().find(|r| {
856799
&r._file_path == file_path && r._kind == "args" && r._item_name == "default"
857800
}) {
858-
write_simb(&toml_path.with_file_name(format!("{stem}.args.default.simb")), r)?;
801+
write_simb(
802+
&toml_path.with_file_name(format!("{stem}.args.default.simb")),
803+
r,
804+
)?;
859805
println!(" compiled arg-values: {stem}.args.default");
860806
} else {
861807
eprintln!("warning: no arg-values result for {file_path}");
@@ -876,13 +822,9 @@ fn cmd_debug(url: &str) -> Result<()> {
876822
let gh = parse_github_url(url)?;
877823
let tag = image_tag();
878824
ensure_docker_image(&tag)?;
879-
let local_repo = ensure_repo_cached(&gh.clone_url, &gh.branch, false)?;
880-
let vol = format!("{}:/workspace/repo:ro", to_docker_volume_path(&local_repo));
881-
882825
let status = Command::new("docker")
883826
.arg("run")
884827
.arg("--rm")
885-
.arg("-v").arg(&vol)
886828
.arg(&tag)
887829
.arg("compile")
888830
.arg(&gh.clone_url)
@@ -935,7 +877,7 @@ fn main() {
935877
cmd_add(&url, &tags, &witnesses, &args, &arg_values, force)
936878
}
937879
Commands::Debug { url } => cmd_debug(&url),
938-
Commands::Compile { all, tag, slugs, refresh } => cmd_compile(all, tag.as_deref(), &slugs, refresh),
880+
Commands::Compile { all, tag, slugs } => cmd_compile(all, tag.as_deref(), &slugs),
939881
};
940882
if let Err(e) = result {
941883
eprintln!("error: {e:#}");

0 commit comments

Comments
 (0)