Skip to content

Commit

Permalink
Get php debug adapter to auto download when needed
Browse files Browse the repository at this point in the history
  • Loading branch information
Anthony-Eid committed Oct 7, 2024
1 parent 20d4704 commit 2ccc879
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 12 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/dap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ fs.workspace = true
futures.workspace = true
gpui.workspace = true
http_client.workspace = true
log.workspace = true
node_runtime.workspace = true
parking_lot.workspace = true
paths.workspace = true
node_runtime.workspace = true
schemars.workspace = true
serde.workspace = true
serde_json.workspace = true
Expand Down
31 changes: 25 additions & 6 deletions crates/dap/src/adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use futures::AsyncReadExt;
use gpui::AsyncAppContext;
use http_client::HttpClient;
use node_runtime::NodeRuntime;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use smol::{
self,
Expand All @@ -19,7 +18,7 @@ use std::{
ffi::OsString,
fmt::Debug,
net::{Ipv4Addr, SocketAddrV4},
path::PathBuf,
path::{Path, PathBuf},
process::Stdio,
sync::Arc,
time::Duration,
Expand Down Expand Up @@ -61,8 +60,14 @@ pub async fn create_tcp_client(
if port.is_none() {
port = get_port(host_address).await;
}
let mut command = if let Some(start_command) = &adapter_binary.start_command {
let mut command = process::Command::new(start_command);
command.arg(adapter_binary.path);
command
} else {
process::Command::new(adapter_binary.path)
};

let mut command = process::Command::new(adapter_binary.path);
command
.args(adapter_binary.arguments)
.envs(adapter_binary.env.clone().unwrap_or_default())
Expand All @@ -89,6 +94,7 @@ pub async fn create_tcp_client(
);

let (rx, tx) = TcpStream::connect(address).await?.split();
log::info!("Debug adapter has connected to tcp server");

Ok(TransportParams::new(
Box::new(BufReader::new(rx)),
Expand All @@ -108,12 +114,12 @@ pub fn create_stdio_client(adapter_binary: DebugAdapterBinary) -> Result<Transpo
command.arg(adapter_binary.path);
command
} else {
let mut command = process::Command::new(adapter_binary.path);
command.args(adapter_binary.arguments);
let command = process::Command::new(adapter_binary.path);
command
};

command
.args(adapter_binary.arguments)
.envs(adapter_binary.env.clone().unwrap_or_default())
.stdin(Stdio::piped())
.stdout(Stdio::piped())
Expand All @@ -137,6 +143,8 @@ pub fn create_stdio_client(adapter_binary: DebugAdapterBinary) -> Result<Transpo
.take()
.ok_or_else(|| anyhow!("Failed to open stderr"))?;

log::info!("Debug adapter has connected to stdio adapter");

Ok(TransportParams::new(
Box::new(BufReader::new(stdout)),
Box::new(stdin),
Expand All @@ -145,9 +153,20 @@ pub fn create_stdio_client(adapter_binary: DebugAdapterBinary) -> Result<Transpo
))
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct DebugAdapterName(pub Arc<str>);

impl AsRef<Path> for DebugAdapterName {
fn as_ref(&self) -> &Path {
Path::new(&*self.0)
}
}

impl std::fmt::Display for DebugAdapterName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}

#[derive(Debug, Clone)]
pub struct DebugAdapterBinary {
pub start_command: Option<String>,
Expand Down
98 changes: 95 additions & 3 deletions crates/dap_adapters/src/php.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub(crate) struct PhpDebugAdapter {
}

impl PhpDebugAdapter {
const _ADAPTER_NAME: &'static str = "vscode-php-debug";
const ADAPTER_NAME: &'static str = "vscode-php-debug";

pub(crate) fn new(adapter_config: &DebugAdapterConfig) -> Self {
PhpDebugAdapter {
Expand All @@ -20,7 +20,7 @@ impl PhpDebugAdapter {
#[async_trait(?Send)]
impl DebugAdapter for PhpDebugAdapter {
fn name(&self) -> DebugAdapterName {
DebugAdapterName(Self::_ADAPTER_NAME.into())
DebugAdapterName(Self::ADAPTER_NAME.into())
}

async fn connect(
Expand All @@ -39,8 +39,100 @@ impl DebugAdapter for PhpDebugAdapter {

async fn install_or_fetch_binary(
&self,
_delegate: Box<dyn DapDelegate>,
delegate: Box<dyn DapDelegate>,
) -> Result<DebugAdapterBinary> {
let adapter_path = paths::debug_adapters_dir().join(self.name());
let fs = delegate.fs();

if fs.is_dir(adapter_path.as_path()).await {
return Ok(DebugAdapterBinary {
start_command: Some("bun".into()),
path: adapter_path.join("out/phpDebug.js"),
arguments: vec!["--server=8132".into()],
env: None,
});
} else if let Some(http_client) = delegate.http_client() {
if !adapter_path.exists() {
fs.create_dir(&adapter_path.as_path()).await?;
}

let release =
latest_github_release("xdebug/vscode-php-debug", false, false, http_client.clone())
.await?;

let asset_name = format!("{}-{}", self.name(), release.tag_name);
let zip_path = adapter_path.join(asset_name);

if fs::metadata(&zip_path).await.is_err() {
let mut response = http_client
.get(&release.zipball_url, Default::default(), true)
.await
.context("Error downloading release")?;

let mut file = File::create(&zip_path).await?;
futures::io::copy(response.body_mut(), &mut file).await?;

let _unzip_status = process::Command::new("unzip")
.current_dir(&adapter_path)
.arg(&zip_path)
.output()
.await?
.status;

let mut ls = process::Command::new("ls")
.current_dir(&adapter_path)
.stdout(Stdio::piped())
.spawn()?;

let std = ls
.stdout
.take()
.ok_or(anyhow!("Failed to list directories"))?
.into_stdio()
.await?;

let file_name = String::from_utf8(
process::Command::new("grep")
.arg("xdebug-vscode-php-debug")
.stdin(std)
.output()
.await?
.stdout,
)?;

let file_name = file_name.trim_end();

process::Command::new("sh")
.current_dir(&adapter_path)
.arg("-c")
.arg(format!("mv {file_name}/* ."))
.output()
.await?;

process::Command::new("rm")
.current_dir(&adapter_path)
.arg("-rf")
.arg(file_name)
.arg(zip_path)
.output()
.await?;

let _npm = delegate
.node_runtime()
.ok_or(anyhow!("Couldn't get npm runtime"))?
.run_npm_subcommand(&adapter_path, "run", &["build"])
.await
.is_ok();

return Ok(DebugAdapterBinary {
start_command: Some("bun".into()),
path: adapter_path.join("out/phpDebug.js"),
arguments: vec!["--server=8132".into()],
env: None,
});
}
}

bail!("Install or fetch not implemented for Php debug adapter (yet)");
}

Expand Down
5 changes: 3 additions & 2 deletions crates/project/src/dap_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,10 @@ impl DapStore {
.unwrap_or_default();

if support_configuration_done_request {
client
let res = client
.request::<ConfigurationDone>(ConfigurationDoneArguments)
.await
.await;
res
} else {
Ok(())
}
Expand Down

0 comments on commit 2ccc879

Please sign in to comment.