Skip to main content

codex_apply_patch/
standalone_executable.rs

1use std::io::Read;
2use std::io::Write;
3
4pub fn main() -> ! {
5    let exit_code = run_main();
6    std::process::exit(exit_code);
7}
8
9/// We would prefer to return `std::process::ExitCode`, but its `exit_process()`
10/// method is still a nightly API and we want main() to return !.
11pub fn run_main() -> i32 {
12    // Expect either one argument (the full apply_patch payload) or read it from stdin.
13    let mut args = std::env::args_os();
14    let _argv0 = args.next();
15
16    let patch_arg = match args.next() {
17        Some(arg) => match arg.into_string() {
18            Ok(s) => s,
19            Err(_) => {
20                eprintln!("Error: apply_patch requires a UTF-8 PATCH argument.");
21                return 1;
22            }
23        },
24        None => {
25            // No argument provided; attempt to read the patch from stdin.
26            let mut buf = String::new();
27            match std::io::stdin().read_to_string(&mut buf) {
28                Ok(_) => {
29                    if buf.is_empty() {
30                        eprintln!("Usage: apply_patch 'PATCH'\n       echo 'PATCH' | apply_patch");
31                        return 2;
32                    }
33                    buf
34                }
35                Err(err) => {
36                    eprintln!("Error: Failed to read PATCH from stdin.\n{err}");
37                    return 1;
38                }
39            }
40        }
41    };
42
43    // Refuse extra args to avoid ambiguity.
44    if args.next().is_some() {
45        eprintln!("Error: apply_patch accepts exactly one argument.");
46        return 2;
47    }
48
49    let mut stdout = std::io::stdout();
50    let mut stderr = std::io::stderr();
51    let cwd = match codex_utils_absolute_path::AbsolutePathBuf::current_dir() {
52        Ok(cwd) => cwd,
53        Err(err) => {
54            eprintln!("Error: Failed to determine current directory.\n{err}");
55            return 1;
56        }
57    };
58    let runtime = match tokio::runtime::Builder::new_current_thread()
59        .enable_all()
60        .build()
61    {
62        Ok(runtime) => runtime,
63        Err(err) => {
64            eprintln!("Error: Failed to initialize runtime.\n{err}");
65            return 1;
66        }
67    };
68    // TODO(anp): Discover the standalone executable cwd as PathUri directly.
69    let cwd = codex_utils_path_uri::PathUri::from_abs_path(&cwd);
70    match runtime.block_on(crate::apply_patch(
71        &patch_arg,
72        &cwd,
73        &mut stdout,
74        &mut stderr,
75        codex_exec_server::LOCAL_FS.as_ref(),
76        /*sandbox*/ None,
77    )) {
78        Ok(_) => {
79            // Flush to ensure output ordering when used in pipelines.
80            let _ = stdout.flush();
81            0
82        }
83        Err(_) => 1,
84    }
85}