Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/cli/build.rs
3285 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
const FILE_HEADER: &str = "/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/";
7
8
use std::{
9
collections::HashMap,
10
env, fs, io,
11
path::{Path, PathBuf},
12
process::{self},
13
str::FromStr,
14
};
15
16
use serde::{de::DeserializeOwned, Deserialize};
17
use serde_json::Value;
18
19
fn main() {
20
let files = enumerate_source_files().expect("expected to enumerate files");
21
ensure_file_headers(&files).expect("expected to ensure file headers");
22
apply_build_environment_variables();
23
}
24
25
fn camel_case_to_constant_case(key: &str) -> String {
26
let mut output = String::new();
27
let mut prev_upper = false;
28
for c in key.chars() {
29
if c.is_uppercase() {
30
if prev_upper {
31
output.push(c.to_ascii_lowercase());
32
} else {
33
output.push('_');
34
output.push(c.to_ascii_uppercase());
35
}
36
prev_upper = true;
37
} else if c.is_lowercase() {
38
output.push(c.to_ascii_uppercase());
39
prev_upper = false;
40
} else {
41
output.push(c);
42
prev_upper = false;
43
}
44
}
45
46
output
47
}
48
49
fn set_env_vars_from_map_keys(prefix: &str, map: impl IntoIterator<Item = (String, Value)>) {
50
let mut win32_app_ids = vec![];
51
52
for (key, value) in map {
53
//#region special handling
54
let value = match key.as_str() {
55
"tunnelServerQualities" | "serverLicense" => {
56
Value::String(serde_json::to_string(&value).unwrap())
57
}
58
"nameLong" => {
59
if let Value::String(s) = &value {
60
let idx = s.find(" - ");
61
println!(
62
"cargo:rustc-env=VSCODE_CLI_QUALITYLESS_PRODUCT_NAME={}",
63
idx.map(|i| &s[..i]).unwrap_or(s)
64
);
65
}
66
67
value
68
}
69
"tunnelApplicationConfig" => {
70
if let Value::Object(v) = value {
71
set_env_vars_from_map_keys(&format!("{}_{}", prefix, "TUNNEL"), v);
72
}
73
continue;
74
}
75
_ => value,
76
};
77
if key.contains("win32") && key.contains("AppId") {
78
if let Value::String(s) = value {
79
win32_app_ids.push(s);
80
continue;
81
}
82
}
83
//#endregion
84
85
if let Value::String(s) = value {
86
println!(
87
"cargo:rustc-env={}_{}={}",
88
prefix,
89
camel_case_to_constant_case(&key),
90
s
91
);
92
}
93
}
94
95
if !win32_app_ids.is_empty() {
96
println!(
97
"cargo:rustc-env=VSCODE_CLI_WIN32_APP_IDS={}",
98
win32_app_ids.join(",")
99
);
100
}
101
}
102
103
fn read_json_from_path<T>(path: &Path) -> T
104
where
105
T: DeserializeOwned,
106
{
107
let mut file = fs::File::open(path).expect("failed to open file");
108
serde_json::from_reader(&mut file).expect("failed to deserialize JSON")
109
}
110
111
fn apply_build_from_product_json(path: &Path) {
112
let json: HashMap<String, Value> = read_json_from_path(path);
113
set_env_vars_from_map_keys("VSCODE_CLI", json);
114
}
115
116
#[derive(Deserialize)]
117
struct PackageJson {
118
pub version: String,
119
}
120
121
fn apply_build_environment_variables() {
122
let repo_dir = env::current_dir().unwrap().join("..");
123
let package_json = read_json_from_path::<PackageJson>(&repo_dir.join("package.json"));
124
println!(
125
"cargo:rustc-env=VSCODE_CLI_VERSION={}",
126
package_json.version
127
);
128
129
match env::var("VSCODE_CLI_PRODUCT_JSON") {
130
Ok(v) => {
131
let path = if cfg!(windows) {
132
PathBuf::from_str(&v.replace('/', "\\")).unwrap()
133
} else {
134
PathBuf::from_str(&v).unwrap()
135
};
136
println!("cargo:warning=loading product.json from <{path:?}>");
137
apply_build_from_product_json(&path);
138
}
139
140
Err(_) => {
141
apply_build_from_product_json(&repo_dir.join("product.json"));
142
143
let overrides = repo_dir.join("product.overrides.json");
144
if overrides.exists() {
145
apply_build_from_product_json(&overrides);
146
}
147
}
148
};
149
}
150
151
fn ensure_file_headers(files: &[PathBuf]) -> Result<(), io::Error> {
152
let mut ok = true;
153
154
let crlf_header_str = str::replace(FILE_HEADER, "\n", "\r\n");
155
let crlf_header = crlf_header_str.as_bytes();
156
let lf_header = FILE_HEADER.as_bytes();
157
for file in files {
158
let contents = fs::read(file)?;
159
160
if !(contents.starts_with(lf_header) || contents.starts_with(crlf_header)) {
161
eprintln!("File missing copyright header: {}", file.display());
162
ok = false;
163
}
164
}
165
166
if !ok {
167
process::exit(1);
168
}
169
170
Ok(())
171
}
172
173
/// Gets all "rs" files in the source directory
174
fn enumerate_source_files() -> Result<Vec<PathBuf>, io::Error> {
175
let mut files = vec![];
176
let mut queue = vec![];
177
178
let current_dir = env::current_dir()?.join("src");
179
queue.push(current_dir);
180
181
while !queue.is_empty() {
182
for entry in fs::read_dir(queue.pop().unwrap())? {
183
let entry = entry?;
184
let ftype = entry.file_type()?;
185
if ftype.is_dir() {
186
queue.push(entry.path());
187
} else if ftype.is_file() && entry.file_name().to_string_lossy().ends_with(".rs") {
188
files.push(entry.path());
189
}
190
}
191
}
192
193
Ok(files)
194
}
195
196