From a73e912e0f2c4fbb9c44bc200ebce2d71d6b3a99 Mon Sep 17 00:00:00 2001 From: Josh Thomas Date: Mon, 23 Dec 2024 10:12:10 -0600 Subject: [PATCH] swap from IPC architecture to PyO3 library (#45) --- Cargo.toml | 7 +- crates/djls-django/Cargo.toml | 12 -- crates/djls-django/src/apps.rs | 46 ---- crates/djls-django/src/django.rs | 97 --------- crates/djls-django/src/lib.rs | 5 - crates/djls-django/src/templates.rs | 63 ------ crates/djls-ipc/Cargo.toml | 19 -- crates/djls-ipc/build.rs | 38 ---- crates/djls-ipc/src/commands.rs | 78 ------- crates/djls-ipc/src/lib.rs | 11 - crates/djls-ipc/src/process.rs | 138 ------------ crates/djls-ipc/src/proto.rs | 17 -- crates/djls-ipc/src/transport.rs | 81 ------- crates/djls-ipc/tests/fixtures/echo_server.py | 47 ---- crates/djls-python/Cargo.toml | 13 -- crates/djls-python/src/lib.rs | 6 - crates/djls-python/src/packaging.rs | 87 -------- crates/djls-python/src/python.rs | 169 --------------- crates/djls-server/Cargo.toml | 3 - crates/djls-server/src/lib.rs | 8 +- crates/djls-server/src/server.rs | 9 +- crates/djls/Cargo.toml | 8 +- crates/djls/src/lib.rs | 113 ++++++++++ crates/djls/src/main.rs | 54 ----- packages/djls-agent/README.md | 1 - packages/djls-agent/pyproject.toml | 47 ---- .../djls-agent/src/djls_agent/__init__.py | 8 - .../djls-agent/src/djls_agent/__main__.py | 127 ----------- packages/djls-agent/src/djls_agent/_typing.py | 12 -- .../djls-agent/src/djls_agent/handlers.py | 204 ------------------ packages/djls-agent/src/djls_agent/logging.py | 44 ---- .../src/djls_agent/proto/v1/__init__.py | 4 - .../src/djls_agent/proto/v1/commands_pb2.py | 62 ------ .../src/djls_agent/proto/v1/commands_pb2.pyi | 59 ----- .../src/djls_agent/proto/v1/django_pb2.py | 40 ---- .../src/djls_agent/proto/v1/django_pb2.pyi | 15 -- .../src/djls_agent/proto/v1/messages_pb2.py | 47 ---- .../src/djls_agent/proto/v1/messages_pb2.pyi | 57 ----- .../src/djls_agent/proto/v1/python_pb2.py | 62 ------ .../src/djls_agent/proto/v1/python_pb2.pyi | 146 ------------- packages/djls-agent/src/djls_agent/py.typed | 0 packages/djls-server/LICENSE | 1 - packages/djls-server/README.md | 1 - packages/djls-server/crates | 1 - packages/djls-server/proto | 1 - packages/djls-server/pyproject.toml | 38 ---- packages/djls-server/rust-toolchain.toml | 1 - proto/v1/commands.proto | 35 --- proto/v1/django.proto | 7 - proto/v1/messages.proto | 36 ---- proto/v1/python.proto | 73 ------- pyproject.toml | 35 ++- uv.lock | 67 ------ 53 files changed, 136 insertions(+), 2224 deletions(-) delete mode 100644 crates/djls-django/Cargo.toml delete mode 100644 crates/djls-django/src/apps.rs delete mode 100644 crates/djls-django/src/django.rs delete mode 100644 crates/djls-django/src/lib.rs delete mode 100644 crates/djls-django/src/templates.rs delete mode 100644 crates/djls-ipc/Cargo.toml delete mode 100644 crates/djls-ipc/build.rs delete mode 100644 crates/djls-ipc/src/commands.rs delete mode 100644 crates/djls-ipc/src/lib.rs delete mode 100644 crates/djls-ipc/src/process.rs delete mode 100644 crates/djls-ipc/src/proto.rs delete mode 100644 crates/djls-ipc/src/transport.rs delete mode 100644 crates/djls-ipc/tests/fixtures/echo_server.py delete mode 100644 crates/djls-python/Cargo.toml delete mode 100644 crates/djls-python/src/lib.rs delete mode 100644 crates/djls-python/src/packaging.rs delete mode 100644 crates/djls-python/src/python.rs create mode 100644 crates/djls/src/lib.rs delete mode 100644 crates/djls/src/main.rs delete mode 100644 packages/djls-agent/README.md delete mode 100644 packages/djls-agent/pyproject.toml delete mode 100644 packages/djls-agent/src/djls_agent/__init__.py delete mode 100644 packages/djls-agent/src/djls_agent/__main__.py delete mode 100644 packages/djls-agent/src/djls_agent/_typing.py delete mode 100644 packages/djls-agent/src/djls_agent/handlers.py delete mode 100644 packages/djls-agent/src/djls_agent/logging.py delete mode 100644 packages/djls-agent/src/djls_agent/proto/v1/__init__.py delete mode 100644 packages/djls-agent/src/djls_agent/proto/v1/commands_pb2.py delete mode 100644 packages/djls-agent/src/djls_agent/proto/v1/commands_pb2.pyi delete mode 100644 packages/djls-agent/src/djls_agent/proto/v1/django_pb2.py delete mode 100644 packages/djls-agent/src/djls_agent/proto/v1/django_pb2.pyi delete mode 100644 packages/djls-agent/src/djls_agent/proto/v1/messages_pb2.py delete mode 100644 packages/djls-agent/src/djls_agent/proto/v1/messages_pb2.pyi delete mode 100644 packages/djls-agent/src/djls_agent/proto/v1/python_pb2.py delete mode 100644 packages/djls-agent/src/djls_agent/proto/v1/python_pb2.pyi delete mode 100644 packages/djls-agent/src/djls_agent/py.typed delete mode 120000 packages/djls-server/LICENSE delete mode 100644 packages/djls-server/README.md delete mode 120000 packages/djls-server/crates delete mode 120000 packages/djls-server/proto delete mode 100644 packages/djls-server/pyproject.toml delete mode 120000 packages/djls-server/rust-toolchain.toml delete mode 100644 proto/v1/commands.proto delete mode 100644 proto/v1/django.proto delete mode 100644 proto/v1/messages.proto delete mode 100644 proto/v1/python.proto diff --git a/Cargo.toml b/Cargo.toml index d3825c3..0a72ea4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,17 +4,14 @@ resolver = "2" [workspace.dependencies] djls = { path = "crates/djls" } -djls-django = { path = "crates/djls-django" } -djls-ipc = { path = "crates/djls-ipc" } -djls-python = { path = "crates/djls-python" } djls-server = { path = "crates/djls-server" } djls-template-ast = { path = "crates/djls-template-ast" } djls-worker = { path = "crates/djls-worker" } anyhow = "1.0" async-trait = "0.1" -prost = "0.13" -bytes = "1.9" +pyo3 = "0.23" +pyo3-async-runtimes = "0.23" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "2.0" diff --git a/crates/djls-django/Cargo.toml b/crates/djls-django/Cargo.toml deleted file mode 100644 index beb0360..0000000 --- a/crates/djls-django/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "djls-django" -version = "0.0.0" -edition = "2021" - -[dependencies] -djls-ipc = { workspace = true } -djls-python = { workspace = true } - -serde = { workspace = true } -serde_json = { workspace = true } -thiserror = { workspace = true } diff --git a/crates/djls-django/src/apps.rs b/crates/djls-django/src/apps.rs deleted file mode 100644 index bed027b..0000000 --- a/crates/djls-django/src/apps.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::fmt; - -#[derive(Debug)] -pub struct App(String); - -impl App { - pub fn name(&self) -> &str { - &self.0 - } -} - -impl fmt::Display for App { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -#[derive(Debug, Default)] -pub struct Apps(Vec); - -impl Apps { - pub fn from_strings(apps: Vec) -> Self { - Self(apps.into_iter().map(App).collect()) - } - - pub fn apps(&self) -> &[App] { - &self.0 - } - - pub fn has_app(&self, name: &str) -> bool { - self.apps().iter().any(|app| app.0 == name) - } - - pub fn iter(&self) -> impl Iterator { - self.apps().iter() - } -} - -impl fmt::Display for Apps { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for app in &self.0 { - writeln!(f, " {}", app)?; - } - Ok(()) - } -} diff --git a/crates/djls-django/src/django.rs b/crates/djls-django/src/django.rs deleted file mode 100644 index 8475637..0000000 --- a/crates/djls-django/src/django.rs +++ /dev/null @@ -1,97 +0,0 @@ -use djls_ipc::v1::*; -use djls_ipc::IpcCommand; -use djls_ipc::{ProcessError, PythonProcess, TransportError}; -use djls_python::Python; -use std::fmt; - -#[derive(Debug)] -pub struct DjangoProject { - py: Python, - python: PythonProcess, - version: String, -} - -impl DjangoProject { - fn new(py: Python, python: PythonProcess, version: String) -> Self { - Self { - py, - python, - version, - } - } - - pub fn setup(mut python: PythonProcess) -> Result { - let py = Python::setup(&mut python)?; - - match commands::check::GeoDjangoPrereqsRequest::execute(&mut python)?.result { - Some(messages::response::Result::CheckGeodjangoPrereqs(response)) => { - if !response.passed { - eprintln!("Warning: GeoDjango detected but GDAL is not available."); - eprintln!( - "Django initialization will be skipped. Some features may be limited." - ); - eprintln!("To enable full functionality, please install GDAL and other GeoDjango prerequisites."); - - return Ok(Self { - py, - python, - version: String::new(), - }); - } - } - Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message))?, - _ => Err(ProcessError::Response)?, - } - - let response = commands::django::GetProjectInfoRequest::execute(&mut python)?; - - let version = match response.result { - Some(messages::response::Result::DjangoGetProjectInfo(response)) => { - response.project.unwrap().version - } - _ => { - return Err(ProjectError::Process(ProcessError::Response)); - } - }; - - Ok(Self { - py, - python, - version, - }) - } - - pub fn py(&self) -> &Python { - &self.py - } - - fn version(&self) -> &String { - &self.version - } -} - -impl fmt::Display for DjangoProject { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "Django Project")?; - writeln!(f, "Version: {}", self.version)?; - Ok(()) - } -} - -#[derive(Debug, thiserror::Error)] -pub enum ProjectError { - #[error("Django is not installed or cannot be imported")] - DjangoNotFound, - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - #[error("JSON parsing error: {0}")] - Json(#[from] serde_json::Error), - #[error(transparent)] - Packaging(#[from] djls_python::PackagingError), - #[error("Process error: {0}")] - Process(#[from] ProcessError), - #[error(transparent)] - Python(#[from] djls_python::PythonError), - #[error("Transport error: {0}")] - Transport(#[from] TransportError), -} diff --git a/crates/djls-django/src/lib.rs b/crates/djls-django/src/lib.rs deleted file mode 100644 index 918eee3..0000000 --- a/crates/djls-django/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod apps; -mod django; -mod templates; - -pub use django::DjangoProject; diff --git a/crates/djls-django/src/templates.rs b/crates/djls-django/src/templates.rs deleted file mode 100644 index e3878b9..0000000 --- a/crates/djls-django/src/templates.rs +++ /dev/null @@ -1,63 +0,0 @@ -use serde::Deserialize; -use std::fmt; - -#[derive(Clone, Debug, Deserialize)] -pub struct TemplateTag { - name: String, - library: String, - doc: Option, -} - -impl fmt::Display for TemplateTag { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let library = if self.library.is_empty() { - "builtins" - } else { - &self.library - }; - - write!(f, "{} ({})", self.name, library)?; - writeln!(f)?; - - if let Some(doc) = &self.doc { - for line in doc.trim_end().split("\n") { - writeln!(f, "{}", line)?; - } - } - - Ok(()) - } -} - -#[derive(Debug, Default, Deserialize)] -pub struct TemplateTags(Vec); - -impl TemplateTags { - pub fn tags(&self) -> &Vec { - &self.0 - } - - fn iter(&self) -> impl Iterator { - self.tags().iter() - } - - pub fn filter_by_prefix<'a>( - &'a self, - prefix: &'a str, - ) -> impl Iterator { - self.iter().filter(move |tag| tag.name.starts_with(prefix)) - } - - pub fn get_by_name(&self, name: &str) -> Option<&TemplateTag> { - self.iter().find(|tag| tag.name == name) - } -} - -impl fmt::Display for TemplateTags { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for tag in &self.0 { - writeln!(f, " {}", tag)?; - } - Ok(()) - } -} diff --git a/crates/djls-ipc/Cargo.toml b/crates/djls-ipc/Cargo.toml deleted file mode 100644 index 9816c2a..0000000 --- a/crates/djls-ipc/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "djls-ipc" -version = "0.0.0" -edition = "2021" - -[dependencies] -anyhow = { workspace = true } -async-trait = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } -thiserror = { workspace = true } -tokio = { workspace = true } - -bytes = "1.9" -prost = "0.13" -tempfile = "3.14" - -[build-dependencies] -prost-build = "0.13" diff --git a/crates/djls-ipc/build.rs b/crates/djls-ipc/build.rs deleted file mode 100644 index ce9dd36..0000000 --- a/crates/djls-ipc/build.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::fs; -use std::path::{Path, PathBuf}; - -struct Version(&'static str); - -impl Version { - fn collect_protos(&self, proto_root: &Path) -> Vec { - fs::read_dir(proto_root.join(self.0)) - .unwrap() - .filter_map(Result::ok) - .filter(|entry| entry.path().extension().and_then(|s| s.to_str()) == Some("proto")) - .map(|entry| entry.path()) - .collect() - } -} - -const VERSIONS: &[Version] = &[Version("v1")]; - -fn main() { - let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let workspace_root = manifest_dir.parent().unwrap().parent().unwrap(); - let proto_dir = workspace_root.join("proto"); - - let mut protos = Vec::new(); - for version in VERSIONS { - protos.extend(version.collect_protos(&proto_dir)); - } - - prost_build::Config::new() - .compile_protos( - &protos - .iter() - .map(|p| p.to_str().unwrap()) - .collect::>(), - &[proto_dir], - ) - .unwrap(); -} diff --git a/crates/djls-ipc/src/commands.rs b/crates/djls-ipc/src/commands.rs deleted file mode 100644 index 4fb6f91..0000000 --- a/crates/djls-ipc/src/commands.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::proto::v1::{self, messages}; -use crate::{ProcessError, PythonProcess}; - -pub trait IpcCommand: Default { - fn into_request(&self) -> messages::Request; - fn from_response(response: messages::Response) -> Result; - - fn execute(process: &mut PythonProcess) -> Result { - let cmd = Self::default(); - let request = cmd.into_request(); - let response = process.send(request).map_err(ProcessError::Transport)?; - Self::from_response(response) - } -} - -impl IpcCommand for v1::commands::check::HealthRequest { - fn into_request(&self) -> messages::Request { - messages::Request { - command: Some(messages::request::Command::CheckHealth(*self)), - } - } - - fn from_response(response: messages::Response) -> Result { - match response.result { - Some(messages::response::Result::CheckHealth(_)) => Ok(response), - Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message)), - _ => Err(ProcessError::Response), - } - } -} - -impl IpcCommand for v1::commands::check::GeoDjangoPrereqsRequest { - fn into_request(&self) -> messages::Request { - messages::Request { - command: Some(messages::request::Command::CheckGeodjangoPrereqs(*self)), - } - } - - fn from_response(response: messages::Response) -> Result { - match response.result { - Some(messages::response::Result::CheckGeodjangoPrereqs(_)) => Ok(response), - Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message)), - _ => Err(ProcessError::Response), - } - } -} - -impl IpcCommand for v1::commands::python::GetEnvironmentRequest { - fn into_request(&self) -> messages::Request { - messages::Request { - command: Some(messages::request::Command::PythonGetEnvironment(*self)), - } - } - - fn from_response(response: messages::Response) -> Result { - match response.result { - Some(messages::response::Result::PythonGetEnvironment(_)) => Ok(response), - Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message)), - _ => Err(ProcessError::Response), - } - } -} - -impl IpcCommand for v1::commands::django::GetProjectInfoRequest { - fn into_request(&self) -> messages::Request { - messages::Request { - command: Some(messages::request::Command::DjangoGetProjectInfo(*self)), - } - } - - fn from_response(response: messages::Response) -> Result { - match response.result { - Some(messages::response::Result::DjangoGetProjectInfo(_)) => Ok(response), - Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message)), - _ => Err(ProcessError::Response), - } - } -} diff --git a/crates/djls-ipc/src/lib.rs b/crates/djls-ipc/src/lib.rs deleted file mode 100644 index de596a3..0000000 --- a/crates/djls-ipc/src/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod commands; -mod process; -mod proto; -mod transport; - -pub use commands::IpcCommand; -pub use process::ProcessError; -pub use process::PythonProcess; -pub use proto::v1; -pub use transport::Transport; -pub use transport::TransportError; diff --git a/crates/djls-ipc/src/process.rs b/crates/djls-ipc/src/process.rs deleted file mode 100644 index 08b0833..0000000 --- a/crates/djls-ipc/src/process.rs +++ /dev/null @@ -1,138 +0,0 @@ -use crate::proto::v1::*; -use crate::transport::{Transport, TransportError}; -use std::ffi::OsStr; -use std::process::{Child, Command, Stdio}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex}; -use std::time::Duration; -use tokio::time; - -#[derive(Debug)] -pub struct PythonProcess { - transport: Arc>, - _child: Child, - healthy: Arc, -} - -impl PythonProcess { - pub fn new( - module: &str, - args: Option, - health_check_interval: Option, - ) -> Result - where - I: IntoIterator, - S: AsRef, - { - let mut command = Command::new("python"); - command.arg("-m").arg(module); - - if let Some(args) = args { - command.args(args); - } - - command.stdin(Stdio::piped()).stdout(Stdio::piped()); - - let mut child = command.spawn().map_err(TransportError::Io)?; - - let stdin = child.stdin.take().unwrap(); - let stdout = child.stdout.take().unwrap(); - - let transport = Transport::new(stdin, stdout)?; - - let process = Self { - transport: Arc::new(Mutex::new(transport)), - _child: child, - healthy: Arc::new(AtomicBool::new(true)), - }; - - if let Some(interval) = health_check_interval { - let transport = process.transport.clone(); - let healthy = process.healthy.clone(); - tokio::spawn(async move { - let mut interval = time::interval(interval); - loop { - interval.tick().await; - let _ = PythonProcess::check_health(transport.clone(), healthy.clone()).await; - } - }); - } - - Ok(process) - } - - pub fn is_healthy(&self) -> bool { - self.healthy.load(Ordering::SeqCst) - } - - pub fn send( - &mut self, - request: messages::Request, - ) -> Result { - let mut transport = self.transport.lock().unwrap(); - transport.send(request) - } - - async fn check_health( - transport: Arc>, - healthy: Arc, - ) -> Result<(), ProcessError> { - let request = messages::Request { - command: Some(messages::request::Command::CheckHealth( - commands::check::HealthRequest {}, - )), - }; - - let response = tokio::time::timeout( - Duration::from_secs(5), - tokio::task::spawn_blocking(move || { - let mut transport = transport.lock().unwrap(); - transport.send(request) - }), - ) - .await - .map_err(|_| ProcessError::Timeout(5))? - .map_err(TransportError::Task)? - .map_err(ProcessError::Transport)?; - - let result = match response.result { - Some(messages::response::Result::CheckHealth(health)) => { - if !health.passed { - let error_msg = health.error.unwrap_or_else(|| "Unknown error".to_string()); - Err(ProcessError::Health(error_msg)) - } else { - Ok(()) - } - } - Some(messages::response::Result::Error(e)) => Err(ProcessError::Health(e.message)), - _ => Err(ProcessError::Response), - }; - - healthy.store(result.is_ok(), Ordering::SeqCst); - result - } -} - -impl Drop for PythonProcess { - fn drop(&mut self) { - if let Ok(()) = self._child.kill() { - let _ = self._child.wait(); - } - } -} - -#[derive(thiserror::Error, Debug)] -pub enum ProcessError { - #[error("Health check failed: {0}")] - Health(String), - #[error("Operation timed out after {0} seconds")] - Timeout(u64), - #[error("Unexpected response type")] - Response, - #[error("Failed to acquire lock: {0}")] - Lock(String), - #[error("Process not ready: {0}")] - Ready(String), - #[error("Transport error: {0}")] - Transport(#[from] TransportError), -} diff --git a/crates/djls-ipc/src/proto.rs b/crates/djls-ipc/src/proto.rs deleted file mode 100644 index 96112a9..0000000 --- a/crates/djls-ipc/src/proto.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub mod v1 { - pub mod commands { - include!(concat!(env!("OUT_DIR"), "/djls.v1.commands.rs")); - } - - pub mod django { - include!(concat!(env!("OUT_DIR"), "/djls.v1.django.rs")); - } - - pub mod messages { - include!(concat!(env!("OUT_DIR"), "/djls.v1.messages.rs")); - } - - pub mod python { - include!(concat!(env!("OUT_DIR"), "/djls.v1.python.rs")); - } -} diff --git a/crates/djls-ipc/src/transport.rs b/crates/djls-ipc/src/transport.rs deleted file mode 100644 index 9284421..0000000 --- a/crates/djls-ipc/src/transport.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::process::ProcessError; -use crate::proto::v1::*; -use prost::Message; -use std::io::{BufRead, BufReader, BufWriter, Read, Write}; -use std::process::{ChildStdin, ChildStdout}; -use std::sync::{Arc, Mutex}; - -#[derive(Debug, Clone)] -pub struct Transport { - reader: Arc>>, - writer: Arc>>, -} - -impl Transport { - pub fn new(mut stdin: ChildStdin, mut stdout: ChildStdout) -> Result { - stdin.flush().map_err(TransportError::Io)?; - - let mut ready_line = String::new(); - BufReader::new(&mut stdout) - .read_line(&mut ready_line) - .map_err(TransportError::Io)?; - - if ready_line.trim() != "ready" { - return Err(ProcessError::Ready("Python process not ready".to_string())); - } - - Ok(Self { - reader: Arc::new(Mutex::new(BufReader::new(stdout))), - writer: Arc::new(Mutex::new(BufWriter::new(stdin))), - }) - } - - pub fn send( - &mut self, - message: messages::Request, - ) -> Result { - let buf = message.encode_to_vec(); - - let mut writer = self.writer.lock().map_err(|_| { - TransportError::Io(std::io::Error::new( - std::io::ErrorKind::Other, - "Failed to acquire writer lock", - )) - })?; - writer - .write_all(&(buf.len() as u32).to_be_bytes()) - .map_err(TransportError::Io)?; - writer.write_all(&buf).map_err(TransportError::Io)?; - writer.flush().map_err(TransportError::Io)?; - - let mut reader = self.reader.lock().map_err(|_| { - TransportError::Io(std::io::Error::new( - std::io::ErrorKind::Other, - "Failed to acquire reader lock", - )) - })?; - let mut length_bytes = [0u8; 4]; - reader - .read_exact(&mut length_bytes) - .map_err(TransportError::Io)?; - let length = u32::from_be_bytes(length_bytes); - - let mut message_bytes = vec![0u8; length as usize]; - reader - .read_exact(&mut message_bytes) - .map_err(TransportError::Io)?; - - messages::Response::decode(message_bytes.as_slice()) - .map_err(|e| TransportError::Decode(e.to_string())) - } -} - -#[derive(thiserror::Error, Debug)] -pub enum TransportError { - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - #[error("Task error: {0}")] - Task(#[from] tokio::task::JoinError), - #[error("Failed to decode message: {0}")] - Decode(String), -} diff --git a/crates/djls-ipc/tests/fixtures/echo_server.py b/crates/djls-ipc/tests/fixtures/echo_server.py deleted file mode 100644 index 8f4eb78..0000000 --- a/crates/djls-ipc/tests/fixtures/echo_server.py +++ /dev/null @@ -1,47 +0,0 @@ -from __future__ import annotations - -import argparse -import asyncio -import json -from pathlib import Path - - -async def handle_client(reader, writer): - while True: - try: - data = await reader.readline() - if not data: - break - - # Parse the incoming message - message = json.loads(data) - # Echo back with same ID but just echo the content - response = {"id": message["id"], "content": message["content"]} - writer.write(json.dumps(response).encode() + b"\n") - await writer.drain() - except Exception: - break - writer.close() - await writer.wait_closed() - - -async def main(ipc_path): - try: - Path(ipc_path).unlink() - except FileNotFoundError: - pass - - server = await asyncio.start_unix_server( - handle_client, - path=ipc_path, - ) - - async with server: - await server.serve_forever() - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("--ipc-path", required=True) - args = parser.parse_args() - asyncio.run(main(args.ipc_path)) diff --git a/crates/djls-python/Cargo.toml b/crates/djls-python/Cargo.toml deleted file mode 100644 index 3a5fb6e..0000000 --- a/crates/djls-python/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "djls-python" -version = "0.0.0" -edition = "2021" - -[dependencies] -djls-ipc = { workspace = true } - -serde = { workspace = true } -serde_json = { workspace = true } -thiserror = { workspace = true } - -which = "7.0" diff --git a/crates/djls-python/src/lib.rs b/crates/djls-python/src/lib.rs deleted file mode 100644 index 35d7bf8..0000000 --- a/crates/djls-python/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod packaging; -mod python; - -pub use crate::packaging::PackagingError; -pub use crate::python::Python; -pub use crate::python::PythonError; diff --git a/crates/djls-python/src/packaging.rs b/crates/djls-python/src/packaging.rs deleted file mode 100644 index f775707..0000000 --- a/crates/djls-python/src/packaging.rs +++ /dev/null @@ -1,87 +0,0 @@ -use djls_ipc::v1::*; -use djls_ipc::{ProcessError, TransportError}; -use serde::Deserialize; -use std::collections::HashMap; -use std::fmt; -use std::path::PathBuf; - -#[derive(Clone, Debug, Deserialize)] -pub struct Package { - dist_name: String, - dist_version: String, - dist_location: Option, -} - -impl From for Package { - fn from(p: python::Package) -> Self { - Package { - dist_name: p.dist_name, - dist_version: p.dist_version, - dist_location: p.dist_location.map(PathBuf::from), - } - } -} - -impl fmt::Display for Package { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} {}", self.dist_name, self.dist_version)?; - if let Some(location) = &self.dist_location { - write!(f, " ({})", location.display())?; - } - Ok(()) - } -} - -#[derive(Clone, Debug, Deserialize)] -pub struct Packages(HashMap); - -impl Packages { - pub fn packages(&self) -> Vec<&Package> { - self.0.values().collect() - } -} - -impl From> for Packages { - fn from(packages: HashMap) -> Self { - Packages(packages.into_iter().map(|(k, v)| (k, v.into())).collect()) - } -} - -impl FromIterator<(String, Package)> for Packages { - fn from_iter>(iter: T) -> Self { - Self(HashMap::from_iter(iter)) - } -} - -impl fmt::Display for Packages { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut packages: Vec<_> = self.packages(); - packages.sort_by(|a, b| a.dist_name.cmp(&b.dist_name)); - - if packages.is_empty() { - writeln!(f, " (no packages installed)")?; - } else { - for package in packages { - writeln!(f, "{}", package)?; - } - } - Ok(()) - } -} - -#[derive(Debug, thiserror::Error)] -pub enum PackagingError { - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - - #[error("JSON parsing error: {0}")] - Json(#[from] serde_json::Error), - - #[error("Transport error: {0}")] - Transport(#[from] TransportError), - #[error("Process error: {0}")] - Process(#[from] ProcessError), - - #[error("UTF-8 conversion error: {0}")] - Utf8(#[from] std::string::FromUtf8Error), -} diff --git a/crates/djls-python/src/python.rs b/crates/djls-python/src/python.rs deleted file mode 100644 index c7563a7..0000000 --- a/crates/djls-python/src/python.rs +++ /dev/null @@ -1,169 +0,0 @@ -use crate::packaging::{Packages, PackagingError}; -use djls_ipc::v1::*; -use djls_ipc::IpcCommand; -use djls_ipc::{ProcessError, PythonProcess, TransportError}; -use serde::Deserialize; -use std::fmt; -use std::path::PathBuf; - -#[derive(Clone, Debug, Deserialize)] -pub struct VersionInfo { - major: u8, - minor: u8, - micro: u8, - releaselevel: ReleaseLevel, - serial: Option, -} - -impl From for VersionInfo { - fn from(v: python::VersionInfo) -> Self { - Self { - major: v.major as u8, - minor: v.minor as u8, - micro: v.micro as u8, - releaselevel: v.releaselevel().into(), - serial: Some(v.serial.to_string()), - } - } -} - -#[derive(Clone, Debug, Deserialize)] -pub enum ReleaseLevel { - Alpha, - Beta, - Candidate, - Final, -} - -impl From for ReleaseLevel { - fn from(level: python::ReleaseLevel) -> Self { - match level { - python::ReleaseLevel::Alpha => ReleaseLevel::Alpha, - python::ReleaseLevel::Beta => ReleaseLevel::Beta, - python::ReleaseLevel::Candidate => ReleaseLevel::Candidate, - python::ReleaseLevel::Final => ReleaseLevel::Final, - } - } -} - -impl fmt::Display for VersionInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}.{}.{}", self.major, self.minor, self.micro)?; - Ok(()) - } -} - -#[derive(Clone, Debug, Deserialize)] -pub struct SysconfigPaths { - data: PathBuf, - include: PathBuf, - platinclude: PathBuf, - platlib: PathBuf, - platstdlib: PathBuf, - purelib: PathBuf, - scripts: PathBuf, - stdlib: PathBuf, -} - -impl fmt::Display for SysconfigPaths { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "data: {}", self.data.display())?; - writeln!(f, "include: {}", self.include.display())?; - writeln!(f, "platinclude: {}", self.platinclude.display())?; - writeln!(f, "platlib: {}", self.platlib.display())?; - writeln!(f, "platstdlib: {}", self.platstdlib.display())?; - writeln!(f, "purelib: {}", self.purelib.display())?; - writeln!(f, "scripts: {}", self.scripts.display())?; - write!(f, "stdlib: {}", self.stdlib.display()) - } -} - -#[derive(Clone, Debug, Deserialize)] -pub struct Python { - version_info: VersionInfo, - sysconfig_paths: SysconfigPaths, - sys_prefix: PathBuf, - sys_base_prefix: PathBuf, - sys_executable: PathBuf, - sys_path: Vec, - packages: Packages, -} - -impl Python { - pub fn setup(python: &mut PythonProcess) -> Result { - let response = commands::python::GetEnvironmentRequest::execute(python)?; - match response.result { - Some(messages::response::Result::PythonGetEnvironment(response)) => response - .python - .ok_or_else(|| PythonError::Process(ProcessError::Response)) - .map(Into::into), - _ => Err(PythonError::Process(ProcessError::Response)), - } - } -} - -impl From for Python { - fn from(p: python::Python) -> Self { - let sys = p.sys.unwrap(); - let sysconfig = p.sysconfig.unwrap(); - let site = p.site.unwrap(); - - Self { - version_info: sys.version_info.unwrap_or_default().into(), - sysconfig_paths: SysconfigPaths { - data: PathBuf::from(sysconfig.data), - include: PathBuf::from(sysconfig.include), - platinclude: PathBuf::from(sysconfig.platinclude), - platlib: PathBuf::from(sysconfig.platlib), - platstdlib: PathBuf::from(sysconfig.platstdlib), - purelib: PathBuf::from(sysconfig.purelib), - scripts: PathBuf::from(sysconfig.scripts), - stdlib: PathBuf::from(sysconfig.stdlib), - }, - sys_prefix: PathBuf::from(sys.prefix), - sys_base_prefix: PathBuf::from(sys.base_prefix), - sys_executable: PathBuf::from(sys.executable), - sys_path: sys.path.into_iter().map(PathBuf::from).collect(), - packages: site.packages.into(), - } - } -} - -impl fmt::Display for Python { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "Version: {}", self.version_info)?; - writeln!(f, "Executable: {}", self.sys_executable.display())?; - writeln!(f, "Prefix: {}", self.sys_prefix.display())?; - writeln!(f, "Base Prefix: {}", self.sys_base_prefix.display())?; - writeln!(f, "Paths:")?; - for path in &self.sys_path { - writeln!(f, "{}", path.display())?; - } - writeln!(f, "Sysconfig Paths:")?; - write!(f, "{}", self.sysconfig_paths)?; - writeln!(f, "\nInstalled Packages:")?; - write!(f, "{}", self.packages) - } -} - -#[derive(Debug, thiserror::Error)] -pub enum PythonError { - #[error("Python execution failed: {0}")] - Execution(String), - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - #[error("JSON parsing error: {0}")] - Json(#[from] serde_json::Error), - #[error("Packaging error: {0}")] - Packaging(#[from] PackagingError), - #[error("Integer parsing error: {0}")] - Parse(#[from] std::num::ParseIntError), - #[error("Process error: {0}")] - Process(#[from] ProcessError), - #[error("Failed to locate Python executable: {0}")] - PythonNotFound(#[from] which::Error), - #[error("Transport error: {0}")] - Transport(#[from] TransportError), - #[error("UTF-8 conversion error: {0}")] - Utf8(#[from] std::string::FromUtf8Error), -} diff --git a/crates/djls-server/Cargo.toml b/crates/djls-server/Cargo.toml index 33c2b6e..c053952 100644 --- a/crates/djls-server/Cargo.toml +++ b/crates/djls-server/Cargo.toml @@ -4,9 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -djls-django = { workspace = true } -djls-ipc = { workspace = true } -djls-python = { workspace = true } djls-template-ast = { workspace = true } djls-worker = { workspace = true } diff --git a/crates/djls-server/src/lib.rs b/crates/djls-server/src/lib.rs index dbaeee9..4ce0c93 100644 --- a/crates/djls-server/src/lib.rs +++ b/crates/djls-server/src/lib.rs @@ -6,8 +6,6 @@ mod tasks; use crate::notifier::TowerLspNotifier; use crate::server::{DjangoLanguageServer, LspNotification, LspRequest}; use anyhow::Result; -use djls_django::DjangoProject; -use djls_ipc::PythonProcess; use std::sync::Arc; use tokio::sync::RwLock; use tower_lsp::jsonrpc::Result as LspResult; @@ -81,15 +79,13 @@ impl LanguageServer for TowerLspBackend { } } -pub async fn serve(python: PythonProcess) -> Result<()> { - let django = DjangoProject::setup(python)?; - +pub async fn serve() -> Result<()> { let stdin = tokio::io::stdin(); let stdout = tokio::io::stdout(); let (service, socket) = LspService::build(|client| { let notifier = Box::new(TowerLspNotifier::new(client.clone())); - let server = DjangoLanguageServer::new(django, notifier); + let server = DjangoLanguageServer::new(notifier); TowerLspBackend { server: Arc::new(RwLock::new(server)), } diff --git a/crates/djls-server/src/server.rs b/crates/djls-server/src/server.rs index f39cf96..3ba8b33 100644 --- a/crates/djls-server/src/server.rs +++ b/crates/djls-server/src/server.rs @@ -2,7 +2,6 @@ use crate::documents::Store; use crate::notifier::Notifier; use crate::tasks::DebugTask; use anyhow::Result; -use djls_django::DjangoProject; use djls_worker::Worker; use std::sync::Arc; use std::time::Duration; @@ -24,18 +23,16 @@ pub enum LspNotification { } pub struct DjangoLanguageServer { - django: DjangoProject, notifier: Arc>, documents: Store, worker: Worker, } impl DjangoLanguageServer { - pub fn new(django: DjangoProject, notifier: Box) -> Self { + pub fn new(notifier: Box) -> Self { let notifier = Arc::new(notifier); Self { - django, notifier, documents: Store::new(), worker: Worker::new(), @@ -125,10 +122,6 @@ impl DjangoLanguageServer { LspNotification::Initialized(_) => { self.notifier .log_message(MessageType::INFO, "server initialized!")?; - self.notifier - .log_message(MessageType::INFO, &format!("\n{}", self.django.py()))?; - self.notifier - .log_message(MessageType::INFO, &format!("\n{}", self.django))?; Ok(()) } LspNotification::Shutdown => Ok(()), diff --git a/crates/djls/Cargo.toml b/crates/djls/Cargo.toml index dd95714..34661e4 100644 --- a/crates/djls/Cargo.toml +++ b/crates/djls/Cargo.toml @@ -3,12 +3,16 @@ name = "djls" version = "5.1.0-alpha.0" edition = "2021" +[lib] +name = "djls" +crate-type = ["cdylib"] + [dependencies] -djls-django = { workspace = true } -djls-ipc = { workspace = true } djls-server = { workspace = true } anyhow = { workspace = true } +pyo3 = { workspace = true, features = ["extension-module"] } +pyo3-async-runtimes = { workspace = true, features = ["tokio-runtime"] } serde_json = { workspace = true } tokio = { workspace = true } diff --git a/crates/djls/src/lib.rs b/crates/djls/src/lib.rs new file mode 100644 index 0000000..1ed59b2 --- /dev/null +++ b/crates/djls/src/lib.rs @@ -0,0 +1,113 @@ +mod commands; + +use crate::commands::Serve; +use anyhow::Result; +use clap::{Parser, Subcommand}; +use pyo3::prelude::*; +use std::env; +use std::process::ExitCode; + +#[derive(Parser)] +#[command(name = "djls")] +#[command(version, about, long_about = None)] +pub struct Cli { + #[command(subcommand)] + command: Command, + + #[command(flatten)] + args: Args, +} + +#[derive(Debug, Subcommand)] +enum Command { + /// Start the LSP server + Serve(Serve), +} + +#[derive(Parser)] +pub struct Args { + #[command(flatten)] + global: GlobalArgs, +} + +#[derive(Parser, Debug, Clone)] +struct GlobalArgs { + /// Do not print any output. + #[arg(global = true, long, short, conflicts_with = "verbose")] + pub quiet: bool, + + /// Use verbose output. + #[arg(global = true, action = clap::ArgAction::Count, long, short, conflicts_with = "quiet")] + pub verbose: u8, +} + +#[pyfunction] +fn cli_entrypoint(_py: Python) -> PyResult<()> { + // Skip python interpreter and script path, add command name + let args: Vec = std::iter::once("djls".to_string()) + .chain(env::args().skip(2)) + .collect(); + + let runtime = tokio::runtime::Runtime::new().unwrap(); + let local = tokio::task::LocalSet::new(); + local.block_on(&runtime, async move { + tokio::select! { + // The main CLI program + result = cli_main(args) => { + match result { + Ok(code) => { + if code != ExitCode::SUCCESS { + std::process::exit(1); + } + Ok::<(), PyErr>(()) + } + Err(e) => { + eprintln!("Error: {}", e); + if let Some(source) = e.source() { + eprintln!("Caused by: {}", source); + } + std::process::exit(1); + } + } + } + // Ctrl+C handling + _ = tokio::signal::ctrl_c() => { + println!("\nReceived Ctrl+C, shutting down..."); + // Cleanup code here if needed + std::process::exit(130); // Standard Ctrl+C exit code + } + // SIGTERM handling (Unix only) + _ = async { + #[cfg(unix)] + { + use tokio::signal::unix::{signal, SignalKind}; + let mut term = signal(SignalKind::terminate()).unwrap(); + term.recv().await; + } + } => { + println!("\nReceived termination signal, shutting down..."); + std::process::exit(143); // Standard SIGTERM exit code + } + } + })?; + + Ok(()) +} + +async fn cli_main(args: Vec) -> Result { + let cli = Cli::try_parse_from(args).unwrap_or_else(|e| { + e.exit(); + }); + + match cli.command { + Command::Serve(_serve) => djls_server::serve().await?, + } + + Ok(ExitCode::SUCCESS) +} + +#[pymodule] +fn djls(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(wrap_pyfunction!(cli_entrypoint, m)?)?; + Ok(()) +} diff --git a/crates/djls/src/main.rs b/crates/djls/src/main.rs deleted file mode 100644 index f6b4ba8..0000000 --- a/crates/djls/src/main.rs +++ /dev/null @@ -1,54 +0,0 @@ -mod commands; - -use crate::commands::Serve; -use anyhow::Result; -use clap::{Parser, Subcommand}; -use djls_ipc::PythonProcess; -use std::ffi::OsStr; -use std::process::ExitCode; - -#[derive(Parser)] -#[command(name = "djls")] -#[command(version, about, long_about = None)] -pub struct Cli { - #[command(subcommand)] - command: Command, - - #[command(flatten)] - args: Args, -} - -#[derive(Debug, Subcommand)] -enum Command { - /// Start the LSP server - Serve(Serve), -} - -#[derive(Parser)] -pub struct Args { - #[command(flatten)] - global: GlobalArgs, -} - -#[derive(Parser, Debug, Clone)] -struct GlobalArgs { - /// Do not print any output. - #[arg(global = true, long, short, conflicts_with = "verbose")] - pub quiet: bool, - - /// Use verbose output. - #[arg(global = true, action = clap::ArgAction::Count, long, short, conflicts_with = "quiet")] - pub verbose: u8, -} - -#[tokio::main] -async fn main() -> Result { - let cli = Cli::parse(); - match cli.command { - Command::Serve(_serve) => { - let python = PythonProcess::new::, &OsStr>("djls_agent", None, None)?; - djls_server::serve(python).await? - } - } - Ok(ExitCode::SUCCESS) -} diff --git a/packages/djls-agent/README.md b/packages/djls-agent/README.md deleted file mode 100644 index 686fa89..0000000 --- a/packages/djls-agent/README.md +++ /dev/null @@ -1 +0,0 @@ -# djls-agent diff --git a/packages/djls-agent/pyproject.toml b/packages/djls-agent/pyproject.toml deleted file mode 100644 index 4959fcf..0000000 --- a/packages/djls-agent/pyproject.toml +++ /dev/null @@ -1,47 +0,0 @@ -[build-system] -build-backend = "hatchling.build" -requires = ["hatchling"] - -[dependency-groups] -dev = [ - "django-stubs>=5.1.1", - "ruff>=0.8.2", -] - -[project] -name = "djls-agent" -version = "5.1.0a0" -description = "Python agent for django-language-server" -readme = "README.md" -authors = [ - { name = "Josh Thomas", email = "josh@joshthomas.dev" } -] -requires-python = ">=3.9" -dependencies = [ - "django>=4.2", - "protobuf>=5.29.1", -] -classifiers = [ - "Development Status :: 3 - Alpha", - "Framework :: Django", - "Framework :: Django :: 4.2", - "Framework :: Django :: 5.0", - "Framework :: Django :: 5.1", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: Implementation :: CPython", - "Topic :: Software Development", - "Topic :: Text Editors :: Integrated Development Environments (IDE)" -] - -[tool.hatch.build] -packages = ["src/djls_agent"] diff --git a/packages/djls-agent/src/djls_agent/__init__.py b/packages/djls-agent/src/djls_agent/__init__.py deleted file mode 100644 index c186a7f..0000000 --- a/packages/djls-agent/src/djls_agent/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import annotations - -import importlib.metadata - -try: - __version__ = importlib.metadata.version(__name__) -except importlib.metadata.PackageNotFoundError: - __version__ = "0.0.0" diff --git a/packages/djls-agent/src/djls_agent/__main__.py b/packages/djls-agent/src/djls_agent/__main__.py deleted file mode 100644 index 0ff449d..0000000 --- a/packages/djls-agent/src/djls_agent/__main__.py +++ /dev/null @@ -1,127 +0,0 @@ -from __future__ import annotations - -import struct -import sys -from typing import Any -from typing import cast - -from google.protobuf.message import Message - -from .logging import configure_logging -from .proto.v1 import messages_pb2 - -logger = configure_logging() - - -class LSPAgent: - def __init__(self): - from .handlers import handlers - - self.handlers = handlers - logger.debug( - "LSPAgent initialized with handlers: %s", list(self.handlers.keys()) - ) - - async def serve(self): - print("ready", flush=True) - - try: - import django - - django.setup() - except Exception as e: - error_response = self.create_error(messages_pb2.Error.DJANGO_ERROR, str(e)) - self.write_message(error_response) - - while True: - try: - data = self.read_message() - if not data: - break - - response = await self.handle_request(data) - self.write_message(response) - - except Exception as e: - error_response = self.create_error(messages_pb2.Error.UNKNOWN, str(e)) - self.write_message(error_response) - - def read_message(self) -> bytes | None: - length_bytes = sys.stdin.buffer.read(4) - logger.debug("Read length bytes: %r", length_bytes) - if not length_bytes: - return None - - length = struct.unpack(">I", length_bytes)[0] - logger.debug("Unpacked length: %d", length) - data = sys.stdin.buffer.read(length) - logger.debug("Read data bytes: %r", data) - return data - - async def handle_request(self, request_data: bytes) -> Message: - request = messages_pb2.Request() - request.ParseFromString(request_data) - - command_name = request.WhichOneof("command") - logger.debug("Command name: %s", command_name) - - if not command_name: - logger.error("No command specified") - return self.create_error( - messages_pb2.Error.INVALID_REQUEST, "No command specified" - ) - - handler = self.handlers.get(command_name) - if not handler: - logger.error("Unknown command: %s", command_name) - return self.create_error( - messages_pb2.Error.INVALID_REQUEST, f"Unknown command: {command_name}" - ) - - try: - command_message = getattr(request, command_name) - result = await handler(command_message) - return messages_pb2.Response(**{command_name: cast(Any, result)}) - except Exception as e: - logger.exception("Error executing command") - return self.create_error(messages_pb2.Error.UNKNOWN, str(e)) - - def write_message(self, message: Message) -> None: - data = message.SerializeToString() - logger.debug(f"Sending response, length: {len(data)}, data: {data!r}") - length = struct.pack(">I", len(data)) - logger.debug(f"Length bytes: {length!r}") - sys.stdout.buffer.write(length) - sys.stdout.buffer.write(data) - sys.stdout.buffer.flush() - - def create_error( - self, code: messages_pb2.Error.Code, message: str - ) -> messages_pb2.Response: - response = messages_pb2.Response() - response.error.code = code - response.error.message = message - return response - - -async def main() -> None: - logger.debug("Starting djls-agent...") - - try: - logger.debug("Initializing LSPAgent...") - agent = LSPAgent() - logger.debug("Starting LSPAgent serve...") - await agent.serve() - except KeyboardInterrupt: - logger.debug("Received KeyboardInterrupt") - sys.exit(0) - except Exception as e: - logger.exception("Fatal error") - print(f"error: {e}", file=sys.stderr) - sys.exit(1) - - -if __name__ == "__main__": - import asyncio - - asyncio.run(main()) diff --git a/packages/djls-agent/src/djls_agent/_typing.py b/packages/djls-agent/src/djls_agent/_typing.py deleted file mode 100644 index 8e8b0eb..0000000 --- a/packages/djls-agent/src/djls_agent/_typing.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import annotations - -import sys - -if sys.version_info >= (3, 12): - from typing import override as typing_override -else: - from typing_extensions import ( - override as typing_override, # pyright: ignore[reportUnreachable] - ) - -override = typing_override diff --git a/packages/djls-agent/src/djls_agent/handlers.py b/packages/djls-agent/src/djls_agent/handlers.py deleted file mode 100644 index 12e2d60..0000000 --- a/packages/djls-agent/src/djls_agent/handlers.py +++ /dev/null @@ -1,204 +0,0 @@ -from __future__ import annotations - -import importlib.metadata -import inspect -import os -import subprocess -import sys -import sysconfig -import traceback -from collections.abc import Awaitable -from collections.abc import Coroutine -from functools import wraps -from typing import Any -from typing import Callable -from typing import TypeVar -from typing import cast - -import django -from django.apps import apps -from google.protobuf.message import Message - -from .proto.v1 import commands_pb2 -from .proto.v1 import django_pb2 -from .proto.v1 import messages_pb2 -from .proto.v1 import python_pb2 - -T = TypeVar("T", bound=Message) -R = TypeVar("R", bound=Message) - -handlers: dict[str, Callable[[Message], Coroutine[Any, Any, Message]]] = {} - - -def proto_handler( - request_type: type[T], - error: messages_pb2.Error | None = None, -) -> Callable[ - [Callable[[T], R] | Callable[[T], Awaitable[R]]], - Callable[[T], Coroutine[Any, Any, R]], -]: - for req_field in messages_pb2.Request.DESCRIPTOR.fields: - if req_field.message_type == request_type.DESCRIPTOR: - command_name = req_field.name - # Find corresponding response type - for resp_field in messages_pb2.Response.DESCRIPTOR.fields: - if resp_field.name == command_name: - response_type = resp_field.message_type._concrete_class - break - else: - raise ValueError(f"No response type found for {request_type}") - break - else: - raise ValueError(f"Message type {request_type} not found in Request message") - - def decorator( - func: Callable[[T], R] | Callable[[T], Awaitable[R]], - ) -> Callable[[T], Coroutine[Any, Any, R]]: - is_async = inspect.iscoroutinefunction(func) - - @wraps(func) - async def wrapper(request: T) -> R: - try: - if is_async: - result = await cast(Callable[[T], Awaitable[R]], func)(request) - else: - result = cast(Callable[[T], R], func)(request) - # Runtime type checking - if not isinstance(result, response_type): - raise TypeError( - f"Handler returned {type(result)}, expected {response_type}" - ) - return result - except Exception as e: - if error: - err = error - else: - err = messages_pb2.Error( - code=messages_pb2.Error.PYTHON_ERROR, - message=str(e), - traceback=traceback.format_exc(), - ) - return cast(R, messages_pb2.Response(error=err)) - - handlers[command_name] = wrapper # pyright: ignore[reportArgumentType] - - return wrapper - - return decorator - - -@proto_handler(commands_pb2.Check.HealthRequest) -async def check__health( - _request: commands_pb2.Check.HealthRequest, -) -> commands_pb2.Check.HealthResponse: - return commands_pb2.Check.HealthResponse(passed=True) - - -@proto_handler(commands_pb2.Check.GeoDjangoPrereqsRequest) -async def check__geodjango_prereqs( - request: commands_pb2.Check.GeoDjangoPrereqsRequest, -) -> commands_pb2.Check.GeoDjangoPrereqsResponse: - has_geodjango = apps.is_installed("django.contrib.gis") - - try: - gdal_process = subprocess.run( - ["gdalinfo", "--version"], capture_output=True, check=False - ) - gdal_is_installed = gdal_process.returncode == 0 - except FileNotFoundError: - gdal_is_installed = False - - return commands_pb2.Check.GeoDjangoPrereqsResponse( - passed=(not has_geodjango) or gdal_is_installed - ) - - -@proto_handler(commands_pb2.Python.GetEnvironmentRequest) -async def python__get_environment( - _request: commands_pb2.Python.GetEnvironmentRequest, -) -> commands_pb2.Python.GetEnvironmentResponse: - packages = {} - for dist in importlib.metadata.distributions(): - try: - requires = [] - try: - requires = list(dist.requires) if hasattr(dist, "requires") else [] - except Exception: - pass - - location = None - try: - location = str(dist._path) if hasattr(dist, "_path") else None - except Exception: - pass - - packages[dist.metadata["Name"]] = python_pb2.Package( - dist_name=dist.metadata["Name"], - dist_version=dist.metadata["Version"], - dist_location=location, - dist_requires=requires, - dist_requires_python=dist.metadata.get("Requires-Python"), - dist_entry_points=str(dist.entry_points) - if hasattr(dist, "entry_points") - else None, - ) - except Exception: - continue - - sysconfig_paths = sysconfig.get_paths() - - version_info = python_pb2.VersionInfo( - major=sys.version_info.major, - minor=sys.version_info.minor, - micro=sys.version_info.micro, - releaselevel={ - "alpha": python_pb2.ReleaseLevel.ALPHA, - "beta": python_pb2.ReleaseLevel.BETA, - "candidate": python_pb2.ReleaseLevel.CANDIDATE, - "final": python_pb2.ReleaseLevel.FINAL, - }[sys.version_info.releaselevel], - serial=sys.version_info.serial, - ) - - return commands_pb2.Python.GetEnvironmentResponse( - python=python_pb2.Python( - os=python_pb2.Os(environ={k: v for k, v in os.environ.items()}), - site=python_pb2.Site(packages=packages), - sys=python_pb2.Sys( - debug_build=hasattr(sys, "gettotalrefcount"), - dev_mode=sys.flags.dev_mode, - is_venv=sys.prefix != sys.base_prefix, - abiflags=sys.abiflags, - base_prefix=sys.base_prefix, - default_encoding=sys.getdefaultencoding(), - executable=sys.executable, - filesystem_encoding=sys.getfilesystemencoding(), - implementation_name=sys.implementation.name, - platform=sys.platform, - prefix=sys.prefix, - builtin_module_names=list(sys.builtin_module_names), - dll_paths=sys.path if sys.platform == "win32" else [], - path=sys.path, - version_info=version_info, - ), - sysconfig=python_pb2.Sysconfig( - data=sysconfig_paths.get("data", ""), - include=sysconfig_paths.get("include", ""), - platinclude=sysconfig_paths.get("platinclude", ""), - platlib=sysconfig_paths.get("platlib", ""), - platstdlib=sysconfig_paths.get("platstdlib", ""), - purelib=sysconfig_paths.get("purelib", ""), - scripts=sysconfig_paths.get("scripts", ""), - stdlib=sysconfig_paths.get("stdlib", ""), - ), - ) - ) - - -@proto_handler(commands_pb2.Django.GetProjectInfoRequest) -async def django__get_project_info( - _request: commands_pb2.Django.GetProjectInfoRequest, -) -> commands_pb2.Django.GetProjectInfoResponse: - return commands_pb2.Django.GetProjectInfoResponse( - project=django_pb2.Project(version=django.__version__) - ) diff --git a/packages/djls-agent/src/djls_agent/logging.py b/packages/djls-agent/src/djls_agent/logging.py deleted file mode 100644 index 3eb3338..0000000 --- a/packages/djls-agent/src/djls_agent/logging.py +++ /dev/null @@ -1,44 +0,0 @@ -from __future__ import annotations - -import logging -import sys -from dataclasses import dataclass -from pathlib import Path - - -@dataclass -class LogConfig: - log_file: Path | str = "/tmp/djls_debug.log" - log_level: int = logging.DEBUG - console_level: int = logging.DEBUG - file_level: int = logging.DEBUG - format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" - - -def configure_logging(config: LogConfig | None = None) -> logging.Logger: - if config is None: - config = LogConfig() - - logger = logging.getLogger("djls") - logger.setLevel(config.log_level) - - # Clear any existing handlers - logger.handlers.clear() - - # File handler - fh = logging.FileHandler(config.log_file) - fh.setLevel(config.file_level) - - # Console handler - ch = logging.StreamHandler(sys.stderr) - ch.setLevel(config.console_level) - - # Formatter - formatter = logging.Formatter(config.format) - fh.setFormatter(formatter) - ch.setFormatter(formatter) - - logger.addHandler(fh) - logger.addHandler(ch) - - return logger diff --git a/packages/djls-agent/src/djls_agent/proto/v1/__init__.py b/packages/djls-agent/src/djls_agent/proto/v1/__init__.py deleted file mode 100644 index 27ddd73..0000000 --- a/packages/djls-agent/src/djls_agent/proto/v1/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# WARNING: This file is generated by protobuf. DO NOT EDIT! -# Any changes made to this file will be overwritten when the protobuf files are regenerated. -# Source: generated by py-init - diff --git a/packages/djls-agent/src/djls_agent/proto/v1/commands_pb2.py b/packages/djls-agent/src/djls_agent/proto/v1/commands_pb2.py deleted file mode 100644 index 4814d83..0000000 --- a/packages/djls-agent/src/djls_agent/proto/v1/commands_pb2.py +++ /dev/null @@ -1,62 +0,0 @@ -# WARNING: This file is generated by protobuf. DO NOT EDIT! -# Any changes made to this file will be overwritten when the protobuf files are regenerated. -# Source: v1/commands.proto - -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# NO CHECKED-IN PROTOBUF GENCODE -# source: v1/commands.proto -# Protobuf Python Version: 5.29.1 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import runtime_version as _runtime_version -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder -_runtime_version.ValidateProtobufRuntimeVersion( - _runtime_version.Domain.PUBLIC, - 5, - 29, - 1, - '', - 'v1/commands.proto' -) -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -from . import django_pb2 as v1_dot_django__pb2 -from . import python_pb2 as v1_dot_python__pb2 - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11v1/commands.proto\x12\x10\x64jls.v1.commands\x1a\x0fv1/django.proto\x1a\x0fv1/python.proto\"\xbd\x01\n\x05\x43heck\x1a\x0f\n\rHealthRequest\x1a>\n\x0eHealthResponse\x12\x0e\n\x06passed\x18\x01 \x01(\x08\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\x1a\x19\n\x17GeoDjangoPrereqsRequest\x1aH\n\x18GeoDjangoPrereqsResponse\x12\x0e\n\x06passed\x18\x01 \x01(\x08\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"c\n\x06Python\x1a\x17\n\x15GetEnvironmentRequest\x1a@\n\x16GetEnvironmentResponse\x12&\n\x06python\x18\x01 \x01(\x0b\x32\x16.djls.v1.python.Python\"e\n\x06\x44jango\x1a\x17\n\x15GetProjectInfoRequest\x1a\x42\n\x16GetProjectInfoResponse\x12(\n\x07project\x18\x01 \x01(\x0b\x32\x17.djls.v1.django.Projectb\x06proto3') - -_globals = globals() -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'v1.commands_pb2', _globals) -if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None - _globals['_CHECK']._serialized_start=74 - _globals['_CHECK']._serialized_end=263 - _globals['_CHECK_HEALTHREQUEST']._serialized_start=83 - _globals['_CHECK_HEALTHREQUEST']._serialized_end=98 - _globals['_CHECK_HEALTHRESPONSE']._serialized_start=100 - _globals['_CHECK_HEALTHRESPONSE']._serialized_end=162 - _globals['_CHECK_GEODJANGOPREREQSREQUEST']._serialized_start=164 - _globals['_CHECK_GEODJANGOPREREQSREQUEST']._serialized_end=189 - _globals['_CHECK_GEODJANGOPREREQSRESPONSE']._serialized_start=191 - _globals['_CHECK_GEODJANGOPREREQSRESPONSE']._serialized_end=263 - _globals['_PYTHON']._serialized_start=265 - _globals['_PYTHON']._serialized_end=364 - _globals['_PYTHON_GETENVIRONMENTREQUEST']._serialized_start=275 - _globals['_PYTHON_GETENVIRONMENTREQUEST']._serialized_end=298 - _globals['_PYTHON_GETENVIRONMENTRESPONSE']._serialized_start=300 - _globals['_PYTHON_GETENVIRONMENTRESPONSE']._serialized_end=364 - _globals['_DJANGO']._serialized_start=366 - _globals['_DJANGO']._serialized_end=467 - _globals['_DJANGO_GETPROJECTINFOREQUEST']._serialized_start=376 - _globals['_DJANGO_GETPROJECTINFOREQUEST']._serialized_end=399 - _globals['_DJANGO_GETPROJECTINFORESPONSE']._serialized_start=401 - _globals['_DJANGO_GETPROJECTINFORESPONSE']._serialized_end=467 -# @@protoc_insertion_point(module_scope) diff --git a/packages/djls-agent/src/djls_agent/proto/v1/commands_pb2.pyi b/packages/djls-agent/src/djls_agent/proto/v1/commands_pb2.pyi deleted file mode 100644 index 3b8935e..0000000 --- a/packages/djls-agent/src/djls_agent/proto/v1/commands_pb2.pyi +++ /dev/null @@ -1,59 +0,0 @@ -# WARNING: This file is generated by protobuf. DO NOT EDIT! -# Any changes made to this file will be overwritten when the protobuf files are regenerated. -# Source: v1/commands.proto - -from . import django_pb2 as _django_pb2 -from . import python_pb2 as _python_pb2 -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union - -DESCRIPTOR: _descriptor.FileDescriptor - -class Check(_message.Message): - __slots__ = () - class HealthRequest(_message.Message): - __slots__ = () - def __init__(self) -> None: ... - class HealthResponse(_message.Message): - __slots__ = ("passed", "error") - PASSED_FIELD_NUMBER: _ClassVar[int] - ERROR_FIELD_NUMBER: _ClassVar[int] - passed: bool - error: str - def __init__(self, passed: bool = ..., error: _Optional[str] = ...) -> None: ... - class GeoDjangoPrereqsRequest(_message.Message): - __slots__ = () - def __init__(self) -> None: ... - class GeoDjangoPrereqsResponse(_message.Message): - __slots__ = ("passed", "error") - PASSED_FIELD_NUMBER: _ClassVar[int] - ERROR_FIELD_NUMBER: _ClassVar[int] - passed: bool - error: str - def __init__(self, passed: bool = ..., error: _Optional[str] = ...) -> None: ... - def __init__(self) -> None: ... - -class Python(_message.Message): - __slots__ = () - class GetEnvironmentRequest(_message.Message): - __slots__ = () - def __init__(self) -> None: ... - class GetEnvironmentResponse(_message.Message): - __slots__ = ("python",) - PYTHON_FIELD_NUMBER: _ClassVar[int] - python: _python_pb2.Python - def __init__(self, python: _Optional[_Union[_python_pb2.Python, _Mapping]] = ...) -> None: ... - def __init__(self) -> None: ... - -class Django(_message.Message): - __slots__ = () - class GetProjectInfoRequest(_message.Message): - __slots__ = () - def __init__(self) -> None: ... - class GetProjectInfoResponse(_message.Message): - __slots__ = ("project",) - PROJECT_FIELD_NUMBER: _ClassVar[int] - project: _django_pb2.Project - def __init__(self, project: _Optional[_Union[_django_pb2.Project, _Mapping]] = ...) -> None: ... - def __init__(self) -> None: ... diff --git a/packages/djls-agent/src/djls_agent/proto/v1/django_pb2.py b/packages/djls-agent/src/djls_agent/proto/v1/django_pb2.py deleted file mode 100644 index 8d60c04..0000000 --- a/packages/djls-agent/src/djls_agent/proto/v1/django_pb2.py +++ /dev/null @@ -1,40 +0,0 @@ -# WARNING: This file is generated by protobuf. DO NOT EDIT! -# Any changes made to this file will be overwritten when the protobuf files are regenerated. -# Source: v1/django.proto - -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# NO CHECKED-IN PROTOBUF GENCODE -# source: v1/django.proto -# Protobuf Python Version: 5.29.1 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import runtime_version as _runtime_version -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder -_runtime_version.ValidateProtobufRuntimeVersion( - _runtime_version.Domain.PUBLIC, - 5, - 29, - 1, - '', - 'v1/django.proto' -) -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0fv1/django.proto\x12\x0e\x64jls.v1.django\"\x1a\n\x07Project\x12\x0f\n\x07version\x18\x03 \x01(\tb\x06proto3') - -_globals = globals() -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'v1.django_pb2', _globals) -if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None - _globals['_PROJECT']._serialized_start=35 - _globals['_PROJECT']._serialized_end=61 -# @@protoc_insertion_point(module_scope) diff --git a/packages/djls-agent/src/djls_agent/proto/v1/django_pb2.pyi b/packages/djls-agent/src/djls_agent/proto/v1/django_pb2.pyi deleted file mode 100644 index 433a580..0000000 --- a/packages/djls-agent/src/djls_agent/proto/v1/django_pb2.pyi +++ /dev/null @@ -1,15 +0,0 @@ -# WARNING: This file is generated by protobuf. DO NOT EDIT! -# Any changes made to this file will be overwritten when the protobuf files are regenerated. -# Source: v1/django.proto - -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from typing import ClassVar as _ClassVar, Optional as _Optional - -DESCRIPTOR: _descriptor.FileDescriptor - -class Project(_message.Message): - __slots__ = ("version",) - VERSION_FIELD_NUMBER: _ClassVar[int] - version: str - def __init__(self, version: _Optional[str] = ...) -> None: ... diff --git a/packages/djls-agent/src/djls_agent/proto/v1/messages_pb2.py b/packages/djls-agent/src/djls_agent/proto/v1/messages_pb2.py deleted file mode 100644 index 428d13d..0000000 --- a/packages/djls-agent/src/djls_agent/proto/v1/messages_pb2.py +++ /dev/null @@ -1,47 +0,0 @@ -# WARNING: This file is generated by protobuf. DO NOT EDIT! -# Any changes made to this file will be overwritten when the protobuf files are regenerated. -# Source: v1/messages.proto - -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# NO CHECKED-IN PROTOBUF GENCODE -# source: v1/messages.proto -# Protobuf Python Version: 5.29.1 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import runtime_version as _runtime_version -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder -_runtime_version.ValidateProtobufRuntimeVersion( - _runtime_version.Domain.PUBLIC, - 5, - 29, - 1, - '', - 'v1/messages.proto' -) -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -from . import commands_pb2 as v1_dot_commands__pb2 - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11v1/messages.proto\x12\x10\x64jls.v1.messages\x1a\x11v1/commands.proto\"\xd2\x02\n\x07Request\x12>\n\rcheck__health\x18\x01 \x01(\x0b\x32%.djls.v1.commands.Check.HealthRequestH\x00\x12S\n\x18\x63heck__geodjango_prereqs\x18\x02 \x01(\x0b\x32/.djls.v1.commands.Check.GeoDjangoPrereqsRequestH\x00\x12R\n\x17python__get_environment\x18\xe8\x07 \x01(\x0b\x32..djls.v1.commands.Python.GetEnvironmentRequestH\x00\x12S\n\x18\x64jango__get_project_info\x18\xd0\x0f \x01(\x0b\x32..djls.v1.commands.Django.GetProjectInfoRequestH\x00\x42\t\n\x07\x63ommand\"\x81\x03\n\x08Response\x12?\n\rcheck__health\x18\x01 \x01(\x0b\x32&.djls.v1.commands.Check.HealthResponseH\x00\x12T\n\x18\x63heck__geodjango_prereqs\x18\x02 \x01(\x0b\x32\x30.djls.v1.commands.Check.GeoDjangoPrereqsResponseH\x00\x12S\n\x17python__get_environment\x18\xe8\x07 \x01(\x0b\x32/.djls.v1.commands.Python.GetEnvironmentResponseH\x00\x12T\n\x18\x64jango__get_project_info\x18\xd0\x0f \x01(\x0b\x32/.djls.v1.commands.Django.GetProjectInfoResponseH\x00\x12)\n\x05\x65rror\x18\xa8\x46 \x01(\x0b\x32\x17.djls.v1.messages.ErrorH\x00\x42\x08\n\x06result\"\xa5\x01\n\x05\x45rror\x12*\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1c.djls.v1.messages.Error.Code\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x11\n\ttraceback\x18\x03 \x01(\t\"L\n\x04\x43ode\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x13\n\x0fINVALID_REQUEST\x10\x01\x12\x10\n\x0cPYTHON_ERROR\x10\x02\x12\x10\n\x0c\x44JANGO_ERROR\x10\x03\x62\x06proto3') - -_globals = globals() -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'v1.messages_pb2', _globals) -if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None - _globals['_REQUEST']._serialized_start=59 - _globals['_REQUEST']._serialized_end=397 - _globals['_RESPONSE']._serialized_start=400 - _globals['_RESPONSE']._serialized_end=785 - _globals['_ERROR']._serialized_start=788 - _globals['_ERROR']._serialized_end=953 - _globals['_ERROR_CODE']._serialized_start=877 - _globals['_ERROR_CODE']._serialized_end=953 -# @@protoc_insertion_point(module_scope) diff --git a/packages/djls-agent/src/djls_agent/proto/v1/messages_pb2.pyi b/packages/djls-agent/src/djls_agent/proto/v1/messages_pb2.pyi deleted file mode 100644 index 46311a7..0000000 --- a/packages/djls-agent/src/djls_agent/proto/v1/messages_pb2.pyi +++ /dev/null @@ -1,57 +0,0 @@ -# WARNING: This file is generated by protobuf. DO NOT EDIT! -# Any changes made to this file will be overwritten when the protobuf files are regenerated. -# Source: v1/messages.proto - -from . import commands_pb2 as _commands_pb2 -from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union - -DESCRIPTOR: _descriptor.FileDescriptor - -class Request(_message.Message): - __slots__ = ("check__health", "check__geodjango_prereqs", "python__get_environment", "django__get_project_info") - CHECK__HEALTH_FIELD_NUMBER: _ClassVar[int] - CHECK__GEODJANGO_PREREQS_FIELD_NUMBER: _ClassVar[int] - PYTHON__GET_ENVIRONMENT_FIELD_NUMBER: _ClassVar[int] - DJANGO__GET_PROJECT_INFO_FIELD_NUMBER: _ClassVar[int] - check__health: _commands_pb2.Check.HealthRequest - check__geodjango_prereqs: _commands_pb2.Check.GeoDjangoPrereqsRequest - python__get_environment: _commands_pb2.Python.GetEnvironmentRequest - django__get_project_info: _commands_pb2.Django.GetProjectInfoRequest - def __init__(self, check__health: _Optional[_Union[_commands_pb2.Check.HealthRequest, _Mapping]] = ..., check__geodjango_prereqs: _Optional[_Union[_commands_pb2.Check.GeoDjangoPrereqsRequest, _Mapping]] = ..., python__get_environment: _Optional[_Union[_commands_pb2.Python.GetEnvironmentRequest, _Mapping]] = ..., django__get_project_info: _Optional[_Union[_commands_pb2.Django.GetProjectInfoRequest, _Mapping]] = ...) -> None: ... - -class Response(_message.Message): - __slots__ = ("check__health", "check__geodjango_prereqs", "python__get_environment", "django__get_project_info", "error") - CHECK__HEALTH_FIELD_NUMBER: _ClassVar[int] - CHECK__GEODJANGO_PREREQS_FIELD_NUMBER: _ClassVar[int] - PYTHON__GET_ENVIRONMENT_FIELD_NUMBER: _ClassVar[int] - DJANGO__GET_PROJECT_INFO_FIELD_NUMBER: _ClassVar[int] - ERROR_FIELD_NUMBER: _ClassVar[int] - check__health: _commands_pb2.Check.HealthResponse - check__geodjango_prereqs: _commands_pb2.Check.GeoDjangoPrereqsResponse - python__get_environment: _commands_pb2.Python.GetEnvironmentResponse - django__get_project_info: _commands_pb2.Django.GetProjectInfoResponse - error: Error - def __init__(self, check__health: _Optional[_Union[_commands_pb2.Check.HealthResponse, _Mapping]] = ..., check__geodjango_prereqs: _Optional[_Union[_commands_pb2.Check.GeoDjangoPrereqsResponse, _Mapping]] = ..., python__get_environment: _Optional[_Union[_commands_pb2.Python.GetEnvironmentResponse, _Mapping]] = ..., django__get_project_info: _Optional[_Union[_commands_pb2.Django.GetProjectInfoResponse, _Mapping]] = ..., error: _Optional[_Union[Error, _Mapping]] = ...) -> None: ... - -class Error(_message.Message): - __slots__ = ("code", "message", "traceback") - class Code(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = () - UNKNOWN: _ClassVar[Error.Code] - INVALID_REQUEST: _ClassVar[Error.Code] - PYTHON_ERROR: _ClassVar[Error.Code] - DJANGO_ERROR: _ClassVar[Error.Code] - UNKNOWN: Error.Code - INVALID_REQUEST: Error.Code - PYTHON_ERROR: Error.Code - DJANGO_ERROR: Error.Code - CODE_FIELD_NUMBER: _ClassVar[int] - MESSAGE_FIELD_NUMBER: _ClassVar[int] - TRACEBACK_FIELD_NUMBER: _ClassVar[int] - code: Error.Code - message: str - traceback: str - def __init__(self, code: _Optional[_Union[Error.Code, str]] = ..., message: _Optional[str] = ..., traceback: _Optional[str] = ...) -> None: ... diff --git a/packages/djls-agent/src/djls_agent/proto/v1/python_pb2.py b/packages/djls-agent/src/djls_agent/proto/v1/python_pb2.py deleted file mode 100644 index a01398c..0000000 --- a/packages/djls-agent/src/djls_agent/proto/v1/python_pb2.py +++ /dev/null @@ -1,62 +0,0 @@ -# WARNING: This file is generated by protobuf. DO NOT EDIT! -# Any changes made to this file will be overwritten when the protobuf files are regenerated. -# Source: v1/python.proto - -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# NO CHECKED-IN PROTOBUF GENCODE -# source: v1/python.proto -# Protobuf Python Version: 5.29.1 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import runtime_version as _runtime_version -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder -_runtime_version.ValidateProtobufRuntimeVersion( - _runtime_version.Domain.PUBLIC, - 5, - 29, - 1, - '', - 'v1/python.proto' -) -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0fv1/python.proto\x12\x0e\x64jls.v1.python\"\x9c\x01\n\x06Python\x12\x1e\n\x02os\x18\x01 \x01(\x0b\x32\x12.djls.v1.python.Os\x12\"\n\x04site\x18\x02 \x01(\x0b\x32\x14.djls.v1.python.Site\x12 \n\x03sys\x18\x03 \x01(\x0b\x32\x13.djls.v1.python.Sys\x12,\n\tsysconfig\x18\x04 \x01(\x0b\x32\x19.djls.v1.python.Sysconfig\"f\n\x02Os\x12\x30\n\x07\x65nviron\x18\x01 \x03(\x0b\x32\x1f.djls.v1.python.Os.EnvironEntry\x1a.\n\x0c\x45nvironEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x86\x01\n\x04Site\x12\x34\n\x08packages\x18\x01 \x03(\x0b\x32\".djls.v1.python.Site.PackagesEntry\x1aH\n\rPackagesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.djls.v1.python.Package:\x02\x38\x01\"\xe0\x02\n\x03Sys\x12\x13\n\x0b\x64\x65\x62ug_build\x18\x01 \x01(\x08\x12\x10\n\x08\x64\x65v_mode\x18\x02 \x01(\x08\x12\x0f\n\x07is_venv\x18\x03 \x01(\x08\x12\x10\n\x08\x61\x62iflags\x18\x04 \x01(\t\x12\x13\n\x0b\x62\x61se_prefix\x18\x05 \x01(\t\x12\x18\n\x10\x64\x65\x66\x61ult_encoding\x18\x06 \x01(\t\x12\x12\n\nexecutable\x18\x07 \x01(\t\x12\x1b\n\x13\x66ilesystem_encoding\x18\x08 \x01(\t\x12\x1b\n\x13implementation_name\x18\t \x01(\t\x12\x10\n\x08platform\x18\n \x01(\t\x12\x0e\n\x06prefix\x18\x0b \x01(\t\x12\x1c\n\x14\x62uiltin_module_names\x18\x0c \x03(\t\x12\x11\n\tdll_paths\x18\r \x03(\t\x12\x0c\n\x04path\x18\x0e \x03(\t\x12\x31\n\x0cversion_info\x18\x0f \x01(\x0b\x32\x1b.djls.v1.python.VersionInfo\"~\n\x0bVersionInfo\x12\r\n\x05major\x18\x01 \x01(\r\x12\r\n\x05minor\x18\x02 \x01(\r\x12\r\n\x05micro\x18\x03 \x01(\r\x12\x32\n\x0creleaselevel\x18\x04 \x01(\x0e\x32\x1c.djls.v1.python.ReleaseLevel\x12\x0e\n\x06serial\x18\x05 \x01(\r\"\x96\x01\n\tSysconfig\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t\x12\x0f\n\x07include\x18\x02 \x01(\t\x12\x13\n\x0bplatinclude\x18\x03 \x01(\t\x12\x0f\n\x07platlib\x18\x04 \x01(\t\x12\x12\n\nplatstdlib\x18\x05 \x01(\t\x12\x0f\n\x07purelib\x18\x06 \x01(\t\x12\x0f\n\x07scripts\x18\x07 \x01(\t\x12\x0e\n\x06stdlib\x18\x08 \x01(\t\"\x97\x02\n\x07Package\x12\x11\n\tdist_name\x18\x01 \x01(\t\x12\x14\n\x0c\x64ist_version\x18\x02 \x01(\t\x12\x1a\n\rdist_editable\x18\x03 \x01(\x08H\x00\x88\x01\x01\x12\x1e\n\x11\x64ist_entry_points\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rdist_location\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x15\n\rdist_requires\x18\x06 \x03(\t\x12!\n\x14\x64ist_requires_python\x18\x07 \x01(\tH\x03\x88\x01\x01\x42\x10\n\x0e_dist_editableB\x14\n\x12_dist_entry_pointsB\x10\n\x0e_dist_locationB\x17\n\x15_dist_requires_python*=\n\x0cReleaseLevel\x12\t\n\x05\x41LPHA\x10\x00\x12\x08\n\x04\x42\x45TA\x10\x01\x12\r\n\tCANDIDATE\x10\x02\x12\t\n\x05\x46INAL\x10\x03\x62\x06proto3') - -_globals = globals() -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'v1.python_pb2', _globals) -if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None - _globals['_OS_ENVIRONENTRY']._loaded_options = None - _globals['_OS_ENVIRONENTRY']._serialized_options = b'8\001' - _globals['_SITE_PACKAGESENTRY']._loaded_options = None - _globals['_SITE_PACKAGESENTRY']._serialized_options = b'8\001' - _globals['_RELEASELEVEL']._serialized_start=1353 - _globals['_RELEASELEVEL']._serialized_end=1414 - _globals['_PYTHON']._serialized_start=36 - _globals['_PYTHON']._serialized_end=192 - _globals['_OS']._serialized_start=194 - _globals['_OS']._serialized_end=296 - _globals['_OS_ENVIRONENTRY']._serialized_start=250 - _globals['_OS_ENVIRONENTRY']._serialized_end=296 - _globals['_SITE']._serialized_start=299 - _globals['_SITE']._serialized_end=433 - _globals['_SITE_PACKAGESENTRY']._serialized_start=361 - _globals['_SITE_PACKAGESENTRY']._serialized_end=433 - _globals['_SYS']._serialized_start=436 - _globals['_SYS']._serialized_end=788 - _globals['_VERSIONINFO']._serialized_start=790 - _globals['_VERSIONINFO']._serialized_end=916 - _globals['_SYSCONFIG']._serialized_start=919 - _globals['_SYSCONFIG']._serialized_end=1069 - _globals['_PACKAGE']._serialized_start=1072 - _globals['_PACKAGE']._serialized_end=1351 -# @@protoc_insertion_point(module_scope) diff --git a/packages/djls-agent/src/djls_agent/proto/v1/python_pb2.pyi b/packages/djls-agent/src/djls_agent/proto/v1/python_pb2.pyi deleted file mode 100644 index d321a0d..0000000 --- a/packages/djls-agent/src/djls_agent/proto/v1/python_pb2.pyi +++ /dev/null @@ -1,146 +0,0 @@ -# WARNING: This file is generated by protobuf. DO NOT EDIT! -# Any changes made to this file will be overwritten when the protobuf files are regenerated. -# Source: v1/python.proto - -from google.protobuf.internal import containers as _containers -from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union - -DESCRIPTOR: _descriptor.FileDescriptor - -class ReleaseLevel(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = () - ALPHA: _ClassVar[ReleaseLevel] - BETA: _ClassVar[ReleaseLevel] - CANDIDATE: _ClassVar[ReleaseLevel] - FINAL: _ClassVar[ReleaseLevel] -ALPHA: ReleaseLevel -BETA: ReleaseLevel -CANDIDATE: ReleaseLevel -FINAL: ReleaseLevel - -class Python(_message.Message): - __slots__ = ("os", "site", "sys", "sysconfig") - OS_FIELD_NUMBER: _ClassVar[int] - SITE_FIELD_NUMBER: _ClassVar[int] - SYS_FIELD_NUMBER: _ClassVar[int] - SYSCONFIG_FIELD_NUMBER: _ClassVar[int] - os: Os - site: Site - sys: Sys - sysconfig: Sysconfig - def __init__(self, os: _Optional[_Union[Os, _Mapping]] = ..., site: _Optional[_Union[Site, _Mapping]] = ..., sys: _Optional[_Union[Sys, _Mapping]] = ..., sysconfig: _Optional[_Union[Sysconfig, _Mapping]] = ...) -> None: ... - -class Os(_message.Message): - __slots__ = ("environ",) - class EnvironEntry(_message.Message): - __slots__ = ("key", "value") - KEY_FIELD_NUMBER: _ClassVar[int] - VALUE_FIELD_NUMBER: _ClassVar[int] - key: str - value: str - def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... - ENVIRON_FIELD_NUMBER: _ClassVar[int] - environ: _containers.ScalarMap[str, str] - def __init__(self, environ: _Optional[_Mapping[str, str]] = ...) -> None: ... - -class Site(_message.Message): - __slots__ = ("packages",) - class PackagesEntry(_message.Message): - __slots__ = ("key", "value") - KEY_FIELD_NUMBER: _ClassVar[int] - VALUE_FIELD_NUMBER: _ClassVar[int] - key: str - value: Package - def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Package, _Mapping]] = ...) -> None: ... - PACKAGES_FIELD_NUMBER: _ClassVar[int] - packages: _containers.MessageMap[str, Package] - def __init__(self, packages: _Optional[_Mapping[str, Package]] = ...) -> None: ... - -class Sys(_message.Message): - __slots__ = ("debug_build", "dev_mode", "is_venv", "abiflags", "base_prefix", "default_encoding", "executable", "filesystem_encoding", "implementation_name", "platform", "prefix", "builtin_module_names", "dll_paths", "path", "version_info") - DEBUG_BUILD_FIELD_NUMBER: _ClassVar[int] - DEV_MODE_FIELD_NUMBER: _ClassVar[int] - IS_VENV_FIELD_NUMBER: _ClassVar[int] - ABIFLAGS_FIELD_NUMBER: _ClassVar[int] - BASE_PREFIX_FIELD_NUMBER: _ClassVar[int] - DEFAULT_ENCODING_FIELD_NUMBER: _ClassVar[int] - EXECUTABLE_FIELD_NUMBER: _ClassVar[int] - FILESYSTEM_ENCODING_FIELD_NUMBER: _ClassVar[int] - IMPLEMENTATION_NAME_FIELD_NUMBER: _ClassVar[int] - PLATFORM_FIELD_NUMBER: _ClassVar[int] - PREFIX_FIELD_NUMBER: _ClassVar[int] - BUILTIN_MODULE_NAMES_FIELD_NUMBER: _ClassVar[int] - DLL_PATHS_FIELD_NUMBER: _ClassVar[int] - PATH_FIELD_NUMBER: _ClassVar[int] - VERSION_INFO_FIELD_NUMBER: _ClassVar[int] - debug_build: bool - dev_mode: bool - is_venv: bool - abiflags: str - base_prefix: str - default_encoding: str - executable: str - filesystem_encoding: str - implementation_name: str - platform: str - prefix: str - builtin_module_names: _containers.RepeatedScalarFieldContainer[str] - dll_paths: _containers.RepeatedScalarFieldContainer[str] - path: _containers.RepeatedScalarFieldContainer[str] - version_info: VersionInfo - def __init__(self, debug_build: bool = ..., dev_mode: bool = ..., is_venv: bool = ..., abiflags: _Optional[str] = ..., base_prefix: _Optional[str] = ..., default_encoding: _Optional[str] = ..., executable: _Optional[str] = ..., filesystem_encoding: _Optional[str] = ..., implementation_name: _Optional[str] = ..., platform: _Optional[str] = ..., prefix: _Optional[str] = ..., builtin_module_names: _Optional[_Iterable[str]] = ..., dll_paths: _Optional[_Iterable[str]] = ..., path: _Optional[_Iterable[str]] = ..., version_info: _Optional[_Union[VersionInfo, _Mapping]] = ...) -> None: ... - -class VersionInfo(_message.Message): - __slots__ = ("major", "minor", "micro", "releaselevel", "serial") - MAJOR_FIELD_NUMBER: _ClassVar[int] - MINOR_FIELD_NUMBER: _ClassVar[int] - MICRO_FIELD_NUMBER: _ClassVar[int] - RELEASELEVEL_FIELD_NUMBER: _ClassVar[int] - SERIAL_FIELD_NUMBER: _ClassVar[int] - major: int - minor: int - micro: int - releaselevel: ReleaseLevel - serial: int - def __init__(self, major: _Optional[int] = ..., minor: _Optional[int] = ..., micro: _Optional[int] = ..., releaselevel: _Optional[_Union[ReleaseLevel, str]] = ..., serial: _Optional[int] = ...) -> None: ... - -class Sysconfig(_message.Message): - __slots__ = ("data", "include", "platinclude", "platlib", "platstdlib", "purelib", "scripts", "stdlib") - DATA_FIELD_NUMBER: _ClassVar[int] - INCLUDE_FIELD_NUMBER: _ClassVar[int] - PLATINCLUDE_FIELD_NUMBER: _ClassVar[int] - PLATLIB_FIELD_NUMBER: _ClassVar[int] - PLATSTDLIB_FIELD_NUMBER: _ClassVar[int] - PURELIB_FIELD_NUMBER: _ClassVar[int] - SCRIPTS_FIELD_NUMBER: _ClassVar[int] - STDLIB_FIELD_NUMBER: _ClassVar[int] - data: str - include: str - platinclude: str - platlib: str - platstdlib: str - purelib: str - scripts: str - stdlib: str - def __init__(self, data: _Optional[str] = ..., include: _Optional[str] = ..., platinclude: _Optional[str] = ..., platlib: _Optional[str] = ..., platstdlib: _Optional[str] = ..., purelib: _Optional[str] = ..., scripts: _Optional[str] = ..., stdlib: _Optional[str] = ...) -> None: ... - -class Package(_message.Message): - __slots__ = ("dist_name", "dist_version", "dist_editable", "dist_entry_points", "dist_location", "dist_requires", "dist_requires_python") - DIST_NAME_FIELD_NUMBER: _ClassVar[int] - DIST_VERSION_FIELD_NUMBER: _ClassVar[int] - DIST_EDITABLE_FIELD_NUMBER: _ClassVar[int] - DIST_ENTRY_POINTS_FIELD_NUMBER: _ClassVar[int] - DIST_LOCATION_FIELD_NUMBER: _ClassVar[int] - DIST_REQUIRES_FIELD_NUMBER: _ClassVar[int] - DIST_REQUIRES_PYTHON_FIELD_NUMBER: _ClassVar[int] - dist_name: str - dist_version: str - dist_editable: bool - dist_entry_points: str - dist_location: str - dist_requires: _containers.RepeatedScalarFieldContainer[str] - dist_requires_python: str - def __init__(self, dist_name: _Optional[str] = ..., dist_version: _Optional[str] = ..., dist_editable: bool = ..., dist_entry_points: _Optional[str] = ..., dist_location: _Optional[str] = ..., dist_requires: _Optional[_Iterable[str]] = ..., dist_requires_python: _Optional[str] = ...) -> None: ... diff --git a/packages/djls-agent/src/djls_agent/py.typed b/packages/djls-agent/src/djls_agent/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/packages/djls-server/LICENSE b/packages/djls-server/LICENSE deleted file mode 120000 index 30cff74..0000000 --- a/packages/djls-server/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/djls-server/README.md b/packages/djls-server/README.md deleted file mode 100644 index 0a988e7..0000000 --- a/packages/djls-server/README.md +++ /dev/null @@ -1 +0,0 @@ -# djls-server diff --git a/packages/djls-server/crates b/packages/djls-server/crates deleted file mode 120000 index ba93643..0000000 --- a/packages/djls-server/crates +++ /dev/null @@ -1 +0,0 @@ -../../crates \ No newline at end of file diff --git a/packages/djls-server/proto b/packages/djls-server/proto deleted file mode 120000 index b943f93..0000000 --- a/packages/djls-server/proto +++ /dev/null @@ -1 +0,0 @@ -../../proto \ No newline at end of file diff --git a/packages/djls-server/pyproject.toml b/packages/djls-server/pyproject.toml deleted file mode 100644 index ab799b6..0000000 --- a/packages/djls-server/pyproject.toml +++ /dev/null @@ -1,38 +0,0 @@ -[build-system] -requires = ["maturin>=1.0,<2.0"] -build-backend = "maturin" - -[project] -name = "djls-server" -version = "5.1.0a0" -description = "Binary distribution package for the Django Language Server" -readme = "README.md" -authors = [ - { name = "Josh Thomas", email = "josh@joshthomas.dev" } -] -requires-python = ">=3.9" -dependencies = [] -classifiers = [ - "Development Status :: 3 - Alpha", - "Framework :: Django", - "Framework :: Django :: 4.2", - "Framework :: Django :: 5.0", - "Framework :: Django :: 5.1", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Rust", - "Topic :: Software Development", - "Topic :: Text Editors :: Integrated Development Environments (IDE)" -] - -[tool.maturin] -bindings = "bin" -manifest-path = "crates/djls/Cargo.toml" -module-name = "djls" -strip = true -include = [ - { path = "proto/**/*", format = ["sdist", "wheel"] }, - { path = "LICENSE", format = "sdist" }, - { path = "rust-toolchain.toml", format = ["sdist", "wheel"] }, -] diff --git a/packages/djls-server/rust-toolchain.toml b/packages/djls-server/rust-toolchain.toml deleted file mode 120000 index e01fe10..0000000 --- a/packages/djls-server/rust-toolchain.toml +++ /dev/null @@ -1 +0,0 @@ -../../rust-toolchain.toml \ No newline at end of file diff --git a/proto/v1/commands.proto b/proto/v1/commands.proto deleted file mode 100644 index 3a5c0ee..0000000 --- a/proto/v1/commands.proto +++ /dev/null @@ -1,35 +0,0 @@ -syntax = "proto3"; - -package djls.v1.commands; - -import "v1/django.proto"; -import "v1/python.proto"; - -message Check { - message HealthRequest {} - message HealthResponse { - bool passed = 1; - optional string error = 2; - } - - message GeoDjangoPrereqsRequest {} - message GeoDjangoPrereqsResponse { - bool passed = 1; - optional string error = 2; - } -} - -message Python { - message GetEnvironmentRequest {} - message GetEnvironmentResponse { - python.Python python = 1; - } -} - -message Django { - message GetProjectInfoRequest {} - message GetProjectInfoResponse { - django.Project project = 1; - } -} - diff --git a/proto/v1/django.proto b/proto/v1/django.proto deleted file mode 100644 index 1e01599..0000000 --- a/proto/v1/django.proto +++ /dev/null @@ -1,7 +0,0 @@ -syntax = "proto3"; - -package djls.v1.django; - -message Project { - string version = 3; -} diff --git a/proto/v1/messages.proto b/proto/v1/messages.proto deleted file mode 100644 index 692470b..0000000 --- a/proto/v1/messages.proto +++ /dev/null @@ -1,36 +0,0 @@ -syntax = "proto3"; - -package djls.v1.messages; - -import "v1/commands.proto"; - -message Request { - oneof command { - commands.Check.HealthRequest check__health = 1; - commands.Check.GeoDjangoPrereqsRequest check__geodjango_prereqs = 2; - commands.Python.GetEnvironmentRequest python__get_environment = 1000; - commands.Django.GetProjectInfoRequest django__get_project_info = 2000; - } -} - -message Response { - oneof result { - commands.Check.HealthResponse check__health = 1; - commands.Check.GeoDjangoPrereqsResponse check__geodjango_prereqs = 2; - commands.Python.GetEnvironmentResponse python__get_environment = 1000; - commands.Django.GetProjectInfoResponse django__get_project_info = 2000; - Error error = 9000; - } -} - -message Error { - Code code = 1; - string message = 2; - string traceback = 3; - enum Code { - UNKNOWN = 0; - INVALID_REQUEST = 1; - PYTHON_ERROR = 2; - DJANGO_ERROR = 3; - } -} diff --git a/proto/v1/python.proto b/proto/v1/python.proto deleted file mode 100644 index 88dd76e..0000000 --- a/proto/v1/python.proto +++ /dev/null @@ -1,73 +0,0 @@ -syntax = "proto3"; - -package djls.v1.python; - -// models -message Python { - Os os = 1; - Site site = 2; - Sys sys = 3; - Sysconfig sysconfig = 4; -} - -message Os { - map environ = 1; -} - -message Site { - map packages = 1; -} - -message Sys { - bool debug_build = 1; - bool dev_mode = 2; - bool is_venv = 3; - string abiflags = 4; - string base_prefix = 5; - string default_encoding = 6; - string executable = 7; - string filesystem_encoding = 8; - string implementation_name = 9; - string platform = 10; - string prefix = 11; - repeated string builtin_module_names = 12; - repeated string dll_paths = 13; - repeated string path = 14; - VersionInfo version_info = 15; -} - -message VersionInfo { - uint32 major = 1; - uint32 minor = 2; - uint32 micro = 3; - ReleaseLevel releaselevel = 4; - uint32 serial = 5; -} - -enum ReleaseLevel { - ALPHA = 0; - BETA = 1; - CANDIDATE = 2; - FINAL = 3; -} - -message Sysconfig { - string data = 1; - string include = 2; - string platinclude = 3; - string platlib = 4; - string platstdlib = 5; - string purelib = 6; - string scripts = 7; - string stdlib = 8; -} - -message Package { - string dist_name = 1; - string dist_version = 2; - optional bool dist_editable = 3; - optional string dist_entry_points = 4; - optional string dist_location = 5; - repeated string dist_requires = 6; - optional string dist_requires_python = 7; -} diff --git a/pyproject.toml b/pyproject.toml index 74eb4f6..5acdb0d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] -build-backend = "hatchling.build" -requires = ["hatchling"] +requires = ["maturin>=1.0,<2.0"] +build-backend = "maturin" [dependency-groups] dev = [ @@ -20,9 +20,6 @@ authors = [ { name = "Josh Thomas", email = "josh@joshthomas.dev" } ] requires-python = ">=3.9" -dependencies = [ - "djls-agent" -] classifiers = [ "Development Status :: 3 - Alpha", "Framework :: Django", @@ -46,8 +43,8 @@ classifiers = [ "Topic :: Text Editors :: Integrated Development Environments (IDE)" ] -[project.optional-dependencies] -server = ["djls-server"] +[project.scripts] +djls = "djls:cli_entrypoint" [tool.bumpver] commit = true @@ -61,19 +58,18 @@ version_pattern = "MAJOR.MINOR.PATCH[-TAG[.NUM]]" "crates/djls/Cargo.toml" = [ 'version = "{version}"', ] -"packages/djls-agent/pyproject.toml" = [ - 'version = "{pep440_version}"', -] -"packages/djls-server/pyproject.toml" = [ - 'version = "{pep440_version}"', -] "pyproject.toml" = [ 'version = "{pep440_version}"', 'current_version = "{version}"', ] -[tool.hatch.build] -packages = [".uv-workspace/"] +[tool.maturin] +manifest-path = "crates/djls/Cargo.toml" +strip = true +include = [ + { path = "LICENSE", format = "sdist" }, + { path = "rust-toolchain.toml", format = ["sdist", "wheel"] }, +] [tool.ruff] # Exclude a variety of commonly ignored directories. @@ -129,7 +125,7 @@ unfixable = [] [tool.ruff.lint.isort] force-single-line = true -known-first-party = ["djls_agent"] +known-first-party = ["djls"] required-imports = ["from __future__ import annotations"] [tool.ruff.lint.per-file-ignores] @@ -139,10 +135,3 @@ required-imports = ["from __future__ import annotations"] [tool.ruff.lint.pyupgrade] # Preserve types, even if a file imports `from __future__ import annotations`. keep-runtime-typing = true - -[tool.uv.sources] -djls-agent = { workspace = true } -djls-server = { workspace = true } - -[tool.uv.workspace] -members = ["packages/*"] diff --git a/uv.lock b/uv.lock index 45ee1fd..611f27c 100644 --- a/uv.lock +++ b/uv.lock @@ -1,13 +1,6 @@ version = 1 requires-python = ">=3.9" -[manifest] -members = [ - "djls", - "djls-agent", - "djls-server", -] - [[package]] name = "asgiref" version = "3.8.1" @@ -191,14 +184,6 @@ wheels = [ name = "djls" version = "5.1.0a0" source = { editable = "." } -dependencies = [ - { name = "djls-agent" }, -] - -[package.optional-dependencies] -server = [ - { name = "djls-server" }, -] [package.dev-dependencies] dev = [ @@ -210,10 +195,6 @@ docs = [ ] [package.metadata] -requires-dist = [ - { name = "djls-agent", editable = "packages/djls-agent" }, - { name = "djls-server", marker = "extra == 'server'", editable = "packages/djls-server" }, -] [package.metadata.requires-dev] dev = [ @@ -222,38 +203,6 @@ dev = [ ] docs = [{ name = "mkdocs-material", specifier = ">=9.5.49" }] -[[package]] -name = "djls-agent" -version = "5.1.0a0" -source = { editable = "packages/djls-agent" } -dependencies = [ - { name = "django" }, - { name = "protobuf" }, -] - -[package.dev-dependencies] -dev = [ - { name = "django-stubs" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "django", specifier = ">=4.2" }, - { name = "protobuf", specifier = ">=5.29.1" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "django-stubs", specifier = ">=5.1.1" }, - { name = "ruff", specifier = ">=0.8.2" }, -] - -[[package]] -name = "djls-server" -version = "5.1.0a0" -source = { editable = "packages/djls-server" } - [[package]] name = "ghp-import" version = "2.1.0" @@ -495,22 +444,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, ] -[[package]] -name = "protobuf" -version = "5.29.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d2/4f/1639b7b1633d8fd55f216ba01e21bf2c43384ab25ef3ddb35d85a52033e8/protobuf-5.29.1.tar.gz", hash = "sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb", size = 424965 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/c7/28669b04691a376cf7d0617d612f126aa0fff763d57df0142f9bf474c5b8/protobuf-5.29.1-cp310-abi3-win32.whl", hash = "sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110", size = 422706 }, - { url = "https://files.pythonhosted.org/packages/e3/33/dc7a7712f457456b7e0b16420ab8ba1cc8686751d3f28392eb43d0029ab9/protobuf-5.29.1-cp310-abi3-win_amd64.whl", hash = "sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34", size = 434505 }, - { url = "https://files.pythonhosted.org/packages/e5/39/44239fb1c6ec557e1731d996a5de89a9eb1ada7a92491fcf9c5d714052ed/protobuf-5.29.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18", size = 417822 }, - { url = "https://files.pythonhosted.org/packages/fb/4a/ec56f101d38d4bef2959a9750209809242d86cf8b897db00f2f98bfa360e/protobuf-5.29.1-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155", size = 319572 }, - { url = "https://files.pythonhosted.org/packages/04/52/c97c58a33b3d6c89a8138788576d372a90a6556f354799971c6b4d16d871/protobuf-5.29.1-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d", size = 319671 }, - { url = "https://files.pythonhosted.org/packages/99/19/5a3957e08de18578131810563ccfeebc7d2aad31ee52e367a61f56cc3cab/protobuf-5.29.1-cp39-cp39-win32.whl", hash = "sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57", size = 422671 }, - { url = "https://files.pythonhosted.org/packages/24/67/8bc07bb755c8badf08db4a8bc2eb542a4e733135a6d584d1922b701d7751/protobuf-5.29.1-cp39-cp39-win_amd64.whl", hash = "sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c", size = 434591 }, - { url = "https://files.pythonhosted.org/packages/3b/24/c8c49df8f6587719e1d400109b16c10c6902d0c9adddc8fff82840146f99/protobuf-5.29.1-py3-none-any.whl", hash = "sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0", size = 172547 }, -] - [[package]] name = "pygments" version = "2.18.0"