mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-28 04:23:32 +01:00
add detection for integrated cli, verify
This commit is contained in:
@@ -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::<Vec<_>>();
|
||||
// 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 {
|
||||
|
||||
@@ -74,7 +74,7 @@ impl TryFrom<&str> for Quality {
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
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.",
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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<LauncherRelease, errors::AnyError> {
|
||||
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::<LauncherRelease>().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(())
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
32
cli/src/util/is_integrated.rs
Normal file
32
cli/src/util/is_integrated.rs
Normal file
@@ -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<bool> {
|
||||
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())
|
||||
}
|
||||
@@ -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<u32> {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(not(target_family = "unix"))]
|
||||
pub async fn set_executable_permission<P: AsRef<std::path::Path>>(
|
||||
_file: P,
|
||||
) -> Result<(), errors::WrappedError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
pub async fn set_executable_permission<P: AsRef<std::path::Path>>(
|
||||
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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user