mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-02 22:41:31 +01:00
cli: implement better self-updating
- Start separating a "standalone" CLI. This is a little awkward with clap- derive, but I got it working. Detection of whether the CLI _is_ standalone is still todo. - Remove the old ad-hoc update code for code-server, and use the update service instead. - Fix some of the "permission denied" errors people got while updating before. We need to rename the old running binary, not just overwrite it.
This commit is contained in:
@@ -24,7 +24,14 @@ const TEMPLATE: &str = "
|
||||
name = "Visual Studio Code CLI",
|
||||
version = match constants::VSCODE_CLI_VERSION { Some(v) => v, None => "dev" },
|
||||
)]
|
||||
pub struct Cli {
|
||||
pub struct IntegratedCli {
|
||||
#[clap(flatten)]
|
||||
pub core: CliCore,
|
||||
}
|
||||
|
||||
/// Common CLI shared between intergated and standalone interfaces.
|
||||
#[derive(Args, Debug, Default, Clone)]
|
||||
pub struct CliCore {
|
||||
/// One or more files, folders, or URIs to open.
|
||||
#[clap(name = "paths")]
|
||||
pub open_paths: Vec<String>,
|
||||
@@ -42,7 +49,36 @@ pub struct Cli {
|
||||
pub subcommand: Option<Commands>,
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
#[derive(Parser, Debug, Default)]
|
||||
#[clap(
|
||||
help_template = TEMPLATE,
|
||||
long_about = None,
|
||||
name = "Visual Studio Code CLI",
|
||||
version = match constants::VSCODE_CLI_VERSION { Some(v) => v, None => "dev" },
|
||||
)]
|
||||
pub struct StandaloneCli {
|
||||
#[clap(flatten)]
|
||||
pub core: CliCore,
|
||||
|
||||
#[clap(subcommand)]
|
||||
pub subcommand: Option<StandaloneCommands>,
|
||||
}
|
||||
|
||||
pub enum AnyCli {
|
||||
Integrated(IntegratedCli),
|
||||
Standalone(StandaloneCli),
|
||||
}
|
||||
|
||||
impl AnyCli {
|
||||
pub fn core(&self) -> &CliCore {
|
||||
match self {
|
||||
AnyCli::Integrated(cli) => &cli.core,
|
||||
AnyCli::Standalone(cli) => &cli.core,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CliCore {
|
||||
pub fn get_base_code_args(&self) -> Vec<String> {
|
||||
let mut args = self.open_paths.clone();
|
||||
self.editor_options.add_code_args(&mut args);
|
||||
@@ -52,8 +88,8 @@ impl Cli {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Cli> for CodeServerArgs {
|
||||
fn from(cli: &'a Cli) -> Self {
|
||||
impl<'a> From<&'a CliCore> for CodeServerArgs {
|
||||
fn from(cli: &'a CliCore) -> Self {
|
||||
let mut args = CodeServerArgs {
|
||||
log: cli.global_options.log,
|
||||
accept_server_license_terms: true,
|
||||
@@ -77,6 +113,19 @@ impl<'a> From<&'a Cli> for CodeServerArgs {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum StandaloneCommands {
|
||||
/// Updates the VS Code CLI.
|
||||
Update(StandaloneUpdateArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug, Clone)]
|
||||
pub struct StandaloneUpdateArgs {
|
||||
/// Only check for updates, without actually updating the CLI.
|
||||
#[clap(long)]
|
||||
pub check: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
|
||||
pub enum Commands {
|
||||
@@ -234,7 +283,7 @@ pub struct UninstallVersionArgs {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug, Default)]
|
||||
#[derive(Args, Debug, Default, Clone)]
|
||||
pub struct EditorOptions {
|
||||
/// Compare two files with each other.
|
||||
#[clap(short, long, value_names = &["file", "file"])]
|
||||
@@ -348,7 +397,7 @@ impl DesktopCodeOptions {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Debug, Default)]
|
||||
#[derive(Args, Debug, Default, Clone)]
|
||||
pub struct GlobalOptions {
|
||||
/// Directory where CLI metadata, such as VS Code installations, should be stored.
|
||||
#[clap(long, env = "VSCODE_CLI_DATA_DIR", global = true)]
|
||||
@@ -389,7 +438,7 @@ impl GlobalOptions {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Debug, Default)]
|
||||
#[derive(Args, Debug, Default, Clone)]
|
||||
pub struct EditorTroubleshooting {
|
||||
/// Run CPU profiler during startup.
|
||||
#[clap(long)]
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
use crate::{log, state::LauncherPaths};
|
||||
|
||||
use super::args::Cli;
|
||||
use super::args::CliCore;
|
||||
|
||||
pub struct CommandContext {
|
||||
pub log: log::Logger,
|
||||
pub paths: LauncherPaths,
|
||||
pub args: Cli,
|
||||
pub args: CliCore,
|
||||
pub http: reqwest::Client,
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use tokio::sync::oneshot;
|
||||
|
||||
use super::{
|
||||
args::{
|
||||
AuthProvider, Cli, ExistingTunnelArgs, TunnelRenameArgs, TunnelServeArgs,
|
||||
AuthProvider, CliCore, ExistingTunnelArgs, TunnelRenameArgs, TunnelServeArgs,
|
||||
TunnelServiceSubCommands, TunnelUserSubCommands,
|
||||
},
|
||||
CommandContext,
|
||||
@@ -57,11 +57,11 @@ impl From<ExistingTunnelArgs> for Option<dev_tunnels::ExistingTunnel> {
|
||||
}
|
||||
|
||||
struct TunnelServiceContainer {
|
||||
args: Cli,
|
||||
args: CliCore,
|
||||
}
|
||||
|
||||
impl TunnelServiceContainer {
|
||||
fn new(args: Cli) -> Self {
|
||||
fn new(args: CliCore) -> Self {
|
||||
Self { args }
|
||||
}
|
||||
}
|
||||
|
||||
44
cli/src/commands/update.rs
Normal file
44
cli/src/commands/update.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
use indicatif::ProgressBar;
|
||||
|
||||
use crate::{
|
||||
self_update::SelfUpdate,
|
||||
update_service::UpdateService,
|
||||
util::{errors::AnyError, input::ProgressBarReporter},
|
||||
};
|
||||
|
||||
use super::{args::StandaloneUpdateArgs, CommandContext};
|
||||
|
||||
pub async fn update(ctx: CommandContext, args: StandaloneUpdateArgs) -> Result<i32, AnyError> {
|
||||
let update_service = UpdateService::new(ctx.log.clone(), ctx.http.clone());
|
||||
let update_service = SelfUpdate::new(&update_service)?;
|
||||
|
||||
let current_version = update_service.get_current_release().await?;
|
||||
if update_service.is_up_to_date_with(¤t_version) {
|
||||
ctx.log.result(format!(
|
||||
"VS Code is already to to date ({})",
|
||||
current_version.commit
|
||||
));
|
||||
return Ok(1);
|
||||
}
|
||||
|
||||
if args.check {
|
||||
ctx.log
|
||||
.result(format!("Update to {} is available", current_version));
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let pb = ProgressBar::new(1);
|
||||
pb.set_message("Downloading...");
|
||||
update_service
|
||||
.do_update(¤t_version, ProgressBarReporter::from(pb))
|
||||
.await?;
|
||||
ctx.log
|
||||
.result(format!("Successfully updated to {}", current_version));
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
Reference in New Issue
Block a user