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
#![feature(try_trait_v2)]
#![allow(dead_code)]
#![feature(trait_alias)]

use std::fmt::Debug;
use std::io;
use std::process::Output as CmdOutput;

use backtrace::Backtrace;

pub use config::{Config, GoObjectPath, UnitLikeStructPath};

use crate::generator::Generator;

mod config;
mod generator;
mod go_os_arch_gen;
mod os_arch;
mod rust_os_arch_gen;
#[cfg(not(feature = "no-codec"))]
mod with_codec;
#[cfg(feature = "no-codec")]
mod without_codec;

#[allow(dead_code)]
enum GenMode {
    Codec,
    NoCodec,
}

#[cfg(feature = "no-codec")]
const GEN_MODE: GenMode = GenMode::NoCodec;
#[cfg(not(feature = "no-codec"))]
const GEN_MODE: GenMode = GenMode::Codec;

#[cfg(not(debug_assertions))]
const BUILD_MODE: &'static str = "release";
#[cfg(debug_assertions)]
const BUILD_MODE: &'static str = "debug";

pub fn generate_code(config: Config) {
    Generator::generate(config)
}

const CODE_UNKNOWN: i32 = -1;
const CODE_CMD_UNKNOWN: i32 = -2;
const CODE_IO: i32 = -3;
const CODE_GIT: i32 = -4;

fn exit_with_warning(code: i32, message: impl AsRef<str>) {
    let mut frames = vec![];
    for bf in Backtrace::new().frames()[4..].as_ref() {
        if bf
            .symbols()
            .get(0)
            .unwrap()
            .name()
            .unwrap()
            .to_string()
            .starts_with("build_script_build::main::")
        {
            break;
        }
        frames.push(bf.clone());
    }
    println!(
        "cargo:warning={}\nbacktrace:\n{:?}",
        message.as_ref(),
        Backtrace::from(frames)
    );
    std::process::exit(code);
}

fn deal_result<T, E: Debug>(code: i32, result: Result<T, E>) -> T {
    match result {
        Ok(t) => t,
        Err(e) => {
            exit_with_warning(code, format!("{e:?}"));
            unreachable!()
        }
    }
}

fn deal_output(output: io::Result<CmdOutput>) {
    match output {
        Ok(output) => {
            if !output.status.success() {
                exit_with_warning(
                    output.status.code().unwrap_or(CODE_CMD_UNKNOWN),
                    format!("{output:?}"),
                );
            } else {
                if output.stderr.is_empty() {
                    println!("{output:?}");
                } else {
                    println!(
                        "cargo:warning={:?}",
                        String::from_utf8(output.stderr.clone()).unwrap_or(format!("{output:?}"))
                    );
                }
            }
        }
        Err(e) => {
            exit_with_warning(CODE_UNKNOWN, format!("{e:?}"));
        }
    }
}