diff --git a/build/azure-pipelines/cli/compile-linux.yml b/build/azure-pipelines/cli/compile-linux.yml index b84e76ea60a..18f0700a582 100644 --- a/build/azure-pipelines/cli/compile-linux.yml +++ b/build/azure-pipelines/cli/compile-linux.yml @@ -43,7 +43,7 @@ steps: VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) VSCODE_CLI_COMMIT: $(VSCODE_CLI_COMMIT) - VSCODE_QUALITY: $(VSCODE_QUALITY) + VSCODE_CLI_QUALITY: $(VSCODE_QUALITY) CXX_aarch64-unknown-linux-musl: musl-g++ CC_aarch64-unknown-linux-musl: musl-gcc diff --git a/build/azure-pipelines/cli/compile-macos.yml b/build/azure-pipelines/cli/compile-macos.yml index bb0353d514f..4981a53e1db 100644 --- a/build/azure-pipelines/cli/compile-macos.yml +++ b/build/azure-pipelines/cli/compile-macos.yml @@ -36,7 +36,7 @@ steps: VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) VSCODE_CLI_COMMIT: $(VSCODE_CLI_COMMIT) - VSCODE_QUALITY: $(VSCODE_QUALITY) + VSCODE_CLI_QUALITY: $(VSCODE_QUALITY) - publish: ${{ parameters.VSCODE_CLI_DIR }}/target/${{ target.target }}/release/${{ parameters.VSCODE_CLI_BINARY_NAME }} artifact: ${{ target.artifact }} diff --git a/build/azure-pipelines/cli/compile-windows.yml b/build/azure-pipelines/cli/compile-windows.yml index f02a6c9d937..03c30726f11 100644 --- a/build/azure-pipelines/cli/compile-windows.yml +++ b/build/azure-pipelines/cli/compile-windows.yml @@ -36,7 +36,7 @@ steps: VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) VSCODE_CLI_COMMIT: $(VSCODE_CLI_COMMIT) - VSCODE_QUALITY: $(VSCODE_QUALITY) + VSCODE_CLI_QUALITY: $(VSCODE_QUALITY) ${{ if eq(target, 'x86_64-pc-windows-msvc') }}: OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/lib OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/x64-windows-static-md/include diff --git a/cli/src/bin/code/main.rs b/cli/src/bin/code/main.rs index ca64b7478e9..3096665be45 100644 --- a/cli/src/bin/code/main.rs +++ b/cli/src/bin/code/main.rs @@ -14,6 +14,7 @@ use cli::{ update_service::UpdateService, util::{ errors::{wrap, AnyError}, + is_integrated_cli, prereqs::PreReqChecker, }, }; @@ -26,10 +27,15 @@ use log::{Level, Metadata, Record}; #[tokio::main] async fn main() -> Result<(), std::convert::Infallible> { let raw_args = std::env::args_os().collect::>(); - // todo: only parse to the standalone CLI if not integrated let parsed = try_parse_legacy(&raw_args) .map(|core| args::AnyCli::Integrated(args::IntegratedCli { core })) - .unwrap_or_else(|| args::AnyCli::Standalone(args::StandaloneCli::parse_from(&raw_args))); + .unwrap_or_else(|| { + if let Ok(true) = is_integrated_cli() { + args::AnyCli::Integrated(args::IntegratedCli::parse_from(&raw_args)) + } else { + args::AnyCli::Standalone(args::StandaloneCli::parse_from(&raw_args)) + } + }); let core = parsed.core(); let context = CommandContext { diff --git a/cli/src/options.rs b/cli/src/options.rs index 81009f72029..80e6c03d7c7 100644 --- a/cli/src/options.rs +++ b/cli/src/options.rs @@ -74,7 +74,7 @@ impl TryFrom<&str> for Quality { fn try_from(s: &str) -> Result { match s { "stable" => Ok(Quality::Stable), - "insiders" => Ok(Quality::Insiders), + "insiders" | "insider" => Ok(Quality::Insiders), "exploration" => Ok(Quality::Exploration), _ => Err(format!( "Unknown quality: {}. Must be one of stable, insiders, or exploration.", diff --git a/cli/src/self_update.rs b/cli/src/self_update.rs index 275ebb12716..103b505bfe1 100644 --- a/cli/src/self_update.rs +++ b/cli/src/self_update.rs @@ -3,7 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use std::{fs::rename, path::Path}; +use std::{ + fs::{rename, set_permissions}, + path::Path, +}; use tempfile::tempdir; use crate::{ @@ -91,8 +94,6 @@ impl<'a> SelfUpdate<'a> { #[cfg(target_os = "windows")] fn copy_file_metadata(from: &Path, to: &Path) -> Result<(), std::io::Error> { - use std::fs::set_permissions; - let permissions = from.metadata()?.permissions(); set_permissions(&to, permissions)?; Ok(()) diff --git a/cli/src/update.rs b/cli/src/update.rs deleted file mode 100644 index 2863b632490..00000000000 --- a/cli/src/update.rs +++ /dev/null @@ -1,120 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -use crate::constants::{VSCODE_CLI_ASSET_NAME, VSCODE_CLI_VERSION}; -use crate::util::{errors, http, io::SilentCopyProgress}; -use serde::Deserialize; -use std::{ - fs::{rename, set_permissions}, - path::Path, -}; - -pub struct Update { - client: reqwest::Client, -} -const LATEST_URL: &str = "https://aka.ms/vscode-server-launcher/update"; - -impl Default for Update { - fn default() -> Self { - Self::new() - } -} - -impl Update { - // Creates a new Update instance without authentication - pub fn new() -> Update { - Update { - client: reqwest::Client::new(), - } - } - - // Gets the asset to update to, or None if the current launcher is up to date. - pub async fn get_latest_release(&self) -> Result { - let res = self - .client - .get(LATEST_URL) - .header( - "User-Agent", - format!( - "vscode-server-launcher/{}", - VSCODE_CLI_VERSION.unwrap_or("dev") - ), - ) - .send() - .await?; - - if !res.status().is_success() { - return Err(errors::StatusError::from_res(res).await?.into()); - } - - Ok(res.json::().await?) - } - - pub async fn switch_to_release( - &self, - update: &LauncherRelease, - target_path: &Path, - ) -> Result<(), errors::AnyError> { - let mut staging_path = target_path.to_owned(); - staging_path.set_file_name(format!( - "{}.next", - target_path.file_name().unwrap().to_string_lossy() - )); - - let an = VSCODE_CLI_ASSET_NAME.unwrap(); - let mut url = format!("{}/{}/{}", update.url, an, an); - if cfg!(target_os = "windows") { - url += ".exe"; - } - - let res = self.client.get(url).send().await?; - - if !res.status().is_success() { - return Err(errors::StatusError::from_res(res).await?.into()); - } - - http::download_into_file(&staging_path, SilentCopyProgress(), res).await?; - - copy_file_metadata(target_path, &staging_path) - .map_err(|e| errors::wrap(e, "failed to set file permissions"))?; - - rename(&staging_path, &target_path) - .map_err(|e| errors::wrap(e, "failed to copy new launcher version"))?; - - Ok(()) - } -} - -#[derive(Deserialize, Clone)] -pub struct LauncherRelease { - pub version: String, - pub url: String, - pub released_at: u64, -} - -#[cfg(target_os = "windows")] -fn copy_file_metadata(from: &Path, to: &Path) -> Result<(), std::io::Error> { - let permissions = from.metadata()?.permissions(); - set_permissions(&to, permissions)?; - Ok(()) -} - -#[cfg(not(target_os = "windows"))] -fn copy_file_metadata(from: &Path, to: &Path) -> Result<(), std::io::Error> { - use std::os::unix::ffi::OsStrExt; - use std::os::unix::fs::MetadataExt; - - let metadata = from.metadata()?; - set_permissions(&to, metadata.permissions())?; - - // based on coreutils' chown https://github.com/uutils/coreutils/blob/72b4629916abe0852ad27286f4e307fbca546b6e/src/chown/chown.rs#L266-L281 - let s = std::ffi::CString::new(to.as_os_str().as_bytes()).unwrap(); - let ret = unsafe { libc::chown(s.as_ptr(), metadata.uid(), metadata.gid()) }; - if ret != 0 { - return Err(std::io::Error::last_os_error()); - } - - Ok(()) -} diff --git a/cli/src/util.rs b/cli/src/util.rs index 43abe7c08e5..2ed47f2f263 100644 --- a/cli/src/util.rs +++ b/cli/src/util.rs @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +mod is_integrated; + pub mod command; pub mod errors; pub mod http; @@ -11,6 +13,7 @@ pub mod io; pub mod machine; pub mod prereqs; pub mod sync; +pub use is_integrated::*; #[cfg(target_os = "linux")] pub mod tar; diff --git a/cli/src/util/is_integrated.rs b/cli/src/util/is_integrated.rs new file mode 100644 index 00000000000..48701fff173 --- /dev/null +++ b/cli/src/util/is_integrated.rs @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +use std::{env, io}; + +use crate::constants::VSCODE_CLI_QUALITY; + +pub fn is_integrated_cli() -> io::Result { + let exe = env::current_exe()?; + let parent = match exe.parent().and_then(|p| p.parent()) { + Some(p) => p, + None => return Ok(false), + }; + + let expected_file = if cfg!(windows) { + match VSCODE_CLI_QUALITY { + Some("insider") => "Code - Insiders.exe", + Some("exploration") => "Code - Exploration.exe", + _ => "Code.exe", + } + } else { + match VSCODE_CLI_QUALITY { + Some("insider") => "code-insiders", + Some("exploration") => "code-exploration", + _ => "code", + } + }; + + Ok(parent.join(expected_file).exists()) +} diff --git a/cli/src/util/machine.rs b/cli/src/util/machine.rs index c35a73f222e..cac5407893a 100644 --- a/cli/src/util/machine.rs +++ b/cli/src/util/machine.rs @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use crate::util::errors; + use std::path::Path; use sysinfo::{Pid, PidExt, ProcessExt, System, SystemExt}; @@ -49,30 +49,3 @@ pub fn find_running_process(name: &Path) -> Option { } None } - -#[cfg(not(target_family = "unix"))] -pub async fn set_executable_permission>( - _file: P, -) -> Result<(), errors::WrappedError> { - Ok(()) -} - -#[cfg(target_family = "unix")] -pub async fn set_executable_permission>( - file: P, -) -> Result<(), errors::WrappedError> { - use std::os::unix::prelude::PermissionsExt; - - let mut permissions = tokio::fs::metadata(&file) - .await - .map_err(|e| errors::wrap(e, "failed to read executable file metadata"))? - .permissions(); - - permissions.set_mode(0o750); - - tokio::fs::set_permissions(&file, permissions) - .await - .map_err(|e| errors::wrap(e, "failed to set executable permissions"))?; - - Ok(()) -}