2022-09-19 20:29:04 +00:00
/* ---------------------------------------------------------------------------------------------
* Copyright ( c ) Microsoft Corporation . All rights reserved .
* Licensed under the MIT License . See License . txt in the project root for license information .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
2022-09-19 23:40:39 +00:00
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 *--------------------------------------------------------------------------------------------*/ " ;
2022-09-19 20:29:04 +00:00
2022-11-22 14:13:16 +00:00
use std ::{
2023-08-11 03:14:30 +00:00
collections ::HashMap ,
2022-11-22 14:13:16 +00:00
env , fs , io ,
2023-08-11 03:14:30 +00:00
path ::{ Path , PathBuf } ,
process ::{ self } ,
2022-11-22 14:13:16 +00:00
str ::FromStr ,
} ;
2022-09-19 20:29:04 +00:00
2023-08-11 03:14:30 +00:00
use serde ::{ de ::DeserializeOwned , Deserialize } ;
use serde_json ::Value ;
2022-09-19 20:29:04 +00:00
fn main ( ) {
2022-09-23 21:17:01 +00:00
let files = enumerate_source_files ( ) . expect ( " expected to enumerate files " ) ;
ensure_file_headers ( & files ) . expect ( " expected to ensure file headers " ) ;
2022-11-22 14:13:16 +00:00
apply_build_environment_variables ( ) ;
}
2023-08-11 03:14:30 +00:00
fn camel_case_to_constant_case ( key : & str ) -> String {
let mut output = String ::new ( ) ;
let mut prev_upper = false ;
for c in key . chars ( ) {
if c . is_uppercase ( ) {
if prev_upper {
output . push ( c . to_ascii_lowercase ( ) ) ;
} else {
output . push ( '_' ) ;
output . push ( c . to_ascii_uppercase ( ) ) ;
}
prev_upper = true ;
} else if c . is_lowercase ( ) {
output . push ( c . to_ascii_uppercase ( ) ) ;
prev_upper = false ;
} else {
output . push ( c ) ;
prev_upper = false ;
}
2022-11-22 14:13:16 +00:00
}
2023-08-11 03:14:30 +00:00
output
}
fn set_env_vars_from_map_keys ( prefix : & str , map : impl IntoIterator < Item = ( String , Value ) > ) {
let mut win32_app_ids = vec! [ ] ;
for ( key , value ) in map {
//#region special handling
let value = match key . as_str ( ) {
" tunnelServerQualities " | " serverLicense " = > {
Value ::String ( serde_json ::to_string ( & value ) . unwrap ( ) )
}
" nameLong " = > {
if let Value ::String ( s ) = & value {
let idx = s . find ( " - " ) ;
println! (
" cargo:rustc-env=VSCODE_CLI_QUALITYLESS_PRODUCT_NAME={} " ,
idx . map ( | i | & s [ .. i ] ) . unwrap_or ( s )
) ;
}
value
}
" tunnelApplicationConfig " = > {
if let Value ::Object ( v ) = value {
set_env_vars_from_map_keys ( & format! ( " {} _ {} " , prefix , " TUNNEL " ) , v ) ;
}
continue ;
}
_ = > value ,
} ;
if key . contains ( " win32 " ) & & key . contains ( " AppId " ) {
if let Value ::String ( s ) = value {
win32_app_ids . push ( s ) ;
continue ;
}
}
//#endregion
if let Value ::String ( s ) = value {
println! (
" cargo:rustc-env={}_{}={} " ,
prefix ,
camel_case_to_constant_case ( & key ) ,
s
) ;
}
2022-11-22 14:13:16 +00:00
}
2023-08-11 03:14:30 +00:00
if ! win32_app_ids . is_empty ( ) {
println! (
" cargo:rustc-env=VSCODE_CLI_WIN32_APP_IDS={} " ,
win32_app_ids . join ( " , " )
2022-11-22 14:13:16 +00:00
) ;
}
2023-08-11 03:14:30 +00:00
}
2022-11-22 14:13:16 +00:00
2023-08-11 03:14:30 +00:00
fn read_json_from_path < T > ( path : & Path ) -> T
where
T : DeserializeOwned ,
{
let mut file = fs ::File ::open ( path ) . expect ( " failed to open file " ) ;
serde_json ::from_reader ( & mut file ) . expect ( " failed to deserialize JSON " )
}
fn apply_build_from_product_json ( path : & Path ) {
let json : HashMap < String , Value > = read_json_from_path ( path ) ;
set_env_vars_from_map_keys ( " VSCODE_CLI " , json ) ;
}
#[ derive(Deserialize) ]
struct PackageJson {
pub version : String ,
}
fn apply_build_environment_variables ( ) {
let repo_dir = env ::current_dir ( ) . unwrap ( ) . join ( " .. " ) ;
let package_json = read_json_from_path ::< PackageJson > ( & repo_dir . join ( " package.json " ) ) ;
println! (
" cargo:rustc-env=VSCODE_CLI_VERSION={} " ,
package_json . version
) ;
match env ::var ( " VSCODE_CLI_PRODUCT_JSON " ) {
Ok ( v ) = > {
let path = if cfg! ( windows ) {
PathBuf ::from_str ( & v . replace ( '/' , " \\ " ) ) . unwrap ( )
} else {
PathBuf ::from_str ( & v ) . unwrap ( )
} ;
println! ( " cargo:warning=loading product.json from < {:?} > " , path ) ;
apply_build_from_product_json ( & path ) ;
}
Err ( _ ) = > {
apply_build_from_product_json ( & repo_dir . join ( " product.json " ) ) ;
let overrides = repo_dir . join ( " product.overrides.json " ) ;
if overrides . exists ( ) {
apply_build_from_product_json ( & overrides ) ;
}
}
} ;
2022-09-19 20:29:04 +00:00
}
fn ensure_file_headers ( files : & [ PathBuf ] ) -> Result < ( ) , io ::Error > {
2022-09-23 21:17:01 +00:00
let mut ok = true ;
2022-09-19 23:40:39 +00:00
let crlf_header_str = str ::replace ( FILE_HEADER , " \n " , " \r \n " ) ;
let crlf_header = crlf_header_str . as_bytes ( ) ;
let lf_header = FILE_HEADER . as_bytes ( ) ;
2022-09-23 21:17:01 +00:00
for file in files {
let contents = fs ::read ( file ) ? ;
2022-09-19 20:29:04 +00:00
2022-09-23 21:17:01 +00:00
if ! ( contents . starts_with ( lf_header ) | | contents . starts_with ( crlf_header ) ) {
eprintln! ( " File missing copyright header: {} " , file . display ( ) ) ;
ok = false ;
}
}
2022-09-19 20:29:04 +00:00
2022-09-23 21:17:01 +00:00
if ! ok {
process ::exit ( 1 ) ;
}
2022-09-19 20:29:04 +00:00
2022-09-23 21:17:01 +00:00
Ok ( ( ) )
2022-09-19 20:29:04 +00:00
}
/// Gets all "rs" files in the source directory
fn enumerate_source_files ( ) -> Result < Vec < PathBuf > , io ::Error > {
2022-09-23 21:17:01 +00:00
let mut files = vec! [ ] ;
let mut queue = vec! [ ] ;
let current_dir = env ::current_dir ( ) ? . join ( " src " ) ;
queue . push ( current_dir ) ;
while ! queue . is_empty ( ) {
for entry in fs ::read_dir ( queue . pop ( ) . unwrap ( ) ) ? {
let entry = entry ? ;
let ftype = entry . file_type ( ) ? ;
if ftype . is_dir ( ) {
queue . push ( entry . path ( ) ) ;
} else if ftype . is_file ( ) & & entry . file_name ( ) . to_string_lossy ( ) . ends_with ( " .rs " ) {
files . push ( entry . path ( ) ) ;
}
}
}
Ok ( files )
2022-09-19 20:29:04 +00:00
}