diff --git a/crates/djls-project/src/inspector.rs b/crates/djls-project/src/inspector.rs index 805f742..2497453 100644 --- a/crates/djls-project/src/inspector.rs +++ b/crates/djls-project/src/inspector.rs @@ -1,6 +1,7 @@ pub mod ipc; pub mod pool; pub mod queries; +mod zipapp; pub use queries::Query; use serde::Deserialize; diff --git a/crates/djls-project/src/inspector/ipc.rs b/crates/djls-project/src/inspector/ipc.rs index 903af9c..820b852 100644 --- a/crates/djls-project/src/inspector/ipc.rs +++ b/crates/djls-project/src/inspector/ipc.rs @@ -9,43 +9,25 @@ use std::process::Stdio; use anyhow::Context; use anyhow::Result; use serde_json; -use tempfile::NamedTempFile; +use super::zipapp::InspectorFile; use super::DjlsRequest; use super::DjlsResponse; use crate::python::PythonEnvironment; -const INSPECTOR_PYZ: &[u8] = include_bytes!(concat!( - env!("CARGO_WORKSPACE_DIR"), - "/python/dist/djls_inspector.pyz" -)); - pub struct InspectorProcess { child: Child, stdin: std::process::ChildStdin, stdout: BufReader, - _zipapp_file: NamedTempFile, + _zipapp_file: InspectorFile, } impl InspectorProcess { pub fn new(python_env: &PythonEnvironment, project_path: &Path) -> Result { - let mut zipapp_file = tempfile::Builder::new() - .prefix("djls_inspector_") - .suffix(".pyz") - .tempfile() - .context("Failed to create temp file for inspector")?; - - zipapp_file - .write_all(INSPECTOR_PYZ) - .context("Failed to write inspector zipapp to temp file")?; - zipapp_file - .flush() - .context("Failed to flush inspector zipapp")?; - - let zipapp_path = zipapp_file.path(); + let zipapp_file = InspectorFile::create()?; let mut cmd = Command::new(&python_env.python_path); - cmd.arg(zipapp_path) + cmd.arg(zipapp_file.path()) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::inherit()) diff --git a/crates/djls-project/src/inspector/queries.rs b/crates/djls-project/src/inspector/queries.rs index a3460f2..12b68ae 100644 --- a/crates/djls-project/src/inspector/queries.rs +++ b/crates/djls-project/src/inspector/queries.rs @@ -12,15 +12,6 @@ pub enum Query { DjangoInit, } -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum VersionReleaseLevel { - Alpha, - Beta, - Candidate, - Final, -} - #[derive(Serialize, Deserialize)] pub struct PythonEnvironmentQueryData { pub sys_base_prefix: PathBuf, @@ -31,6 +22,15 @@ pub struct PythonEnvironmentQueryData { pub sys_version_info: (u32, u32, u32, VersionReleaseLevel, u32), } +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum VersionReleaseLevel { + Alpha, + Beta, + Candidate, + Final, +} + #[derive(Serialize, Deserialize)] pub struct TemplateTagQueryData { pub templatetags: Vec, @@ -42,9 +42,3 @@ pub struct TemplateTag { pub module: String, pub doc: Option, } - -#[derive(Serialize, Deserialize)] -pub struct DjangoInitQueryData { - pub success: bool, - pub message: Option, -} diff --git a/crates/djls-project/src/inspector/zipapp.rs b/crates/djls-project/src/inspector/zipapp.rs new file mode 100644 index 0000000..239571a --- /dev/null +++ b/crates/djls-project/src/inspector/zipapp.rs @@ -0,0 +1,36 @@ +use std::io::Write; +use std::path::Path; + +use anyhow::Context; +use anyhow::Result; +use tempfile::NamedTempFile; + +const INSPECTOR_PYZ: &[u8] = include_bytes!(concat!( + env!("CARGO_WORKSPACE_DIR"), + "/python/dist/djls_inspector.pyz" +)); + +pub struct InspectorFile(NamedTempFile); + +impl InspectorFile { + pub fn create() -> Result { + let mut zipapp_file = tempfile::Builder::new() + .prefix("djls_inspector_") + .suffix(".pyz") + .tempfile() + .context("Failed to create temp file for inspector")?; + + zipapp_file + .write_all(INSPECTOR_PYZ) + .context("Failed to write inspector zipapp to temp file")?; + zipapp_file + .flush() + .context("Failed to flush inspector zipapp")?; + + Ok(Self(zipapp_file)) + } + + pub fn path(&self) -> &Path { + self.0.path() + } +} diff --git a/crates/djls-project/src/lib.rs b/crates/djls-project/src/lib.rs index 0761bd7..6474d17 100644 --- a/crates/djls-project/src/lib.rs +++ b/crates/djls-project/src/lib.rs @@ -26,7 +26,7 @@ pub struct DjangoProject { path: PathBuf, env: Option, template_tags: Option, - inspector_pool: Arc, + inspector: Arc, } impl DjangoProject { @@ -36,7 +36,7 @@ impl DjangoProject { path, env: None, template_tags: None, - inspector_pool: Arc::new(InspectorPool::new()), + inspector: Arc::new(InspectorPool::new()), } } @@ -52,7 +52,7 @@ impl DjangoProject { let request = DjlsRequest { query: Query::DjangoInit, }; - let response = self.inspector_pool.query(env, &self.path, &request)?; + let response = self.inspector.query(env, &self.path, &request)?; if !response.ok { anyhow::bail!("Failed to initialize Django: {:?}", response.error); @@ -62,7 +62,7 @@ impl DjangoProject { let request = DjlsRequest { query: Query::Templatetags, }; - let response = self.inspector_pool.query(env, &self.path, &request)?; + let response = self.inspector.query(env, &self.path, &request)?; if let Some(data) = response.data { self.template_tags = Some(TemplateTags::from_json(&data)?); diff --git a/python/src/djls_inspector/inspector.py b/python/src/djls_inspector/inspector.py index 43dd2d7..91c1ba4 100644 --- a/python/src/djls_inspector/inspector.py +++ b/python/src/djls_inspector/inspector.py @@ -69,7 +69,8 @@ def handle_request(request: dict[str, Any]) -> DjlsResponse: return DjlsResponse(ok=True, data=get_installed_templatetags()) elif query == Query.DJANGO_INIT: - return DjlsResponse(ok=True, data=initialize_django()) + success, error = initialize_django() + return DjlsResponse(ok=success, data=None, error=error) return DjlsResponse(ok=False, error=f"Unhandled query type: {query}") diff --git a/python/src/djls_inspector/queries.py b/python/src/djls_inspector/queries.py index 3204614..cb81209 100644 --- a/python/src/djls_inspector/queries.py +++ b/python/src/djls_inspector/queries.py @@ -90,13 +90,8 @@ def get_installed_templatetags() -> TemplateTagQueryData: return TemplateTagQueryData(templatetags=templatetags) -@dataclass -class DjangoInitQueryData: - success: bool - message: str | None = None - - -def initialize_django() -> DjangoInitQueryData: +def initialize_django() -> tuple[bool, str | None]: + """Initialize Django and return (success, error_message).""" import os import django from django.apps import apps @@ -122,9 +117,9 @@ def initialize_django() -> DjangoInitQueryData: current_path = current_path.parent if not manage_py: - return DjangoInitQueryData( - success=False, - message="Could not find manage.py or DJANGO_SETTINGS_MODULE not set", + return ( + False, + "Could not find manage.py or DJANGO_SETTINGS_MODULE not set", ) # Add project directory to sys.path @@ -163,12 +158,10 @@ def initialize_django() -> DjangoInitQueryData: if not apps.ready: django.setup() - return DjangoInitQueryData( - success=True, message="Django initialized successfully" - ) + return True, None except Exception as e: - return DjangoInitQueryData(success=False, message=str(e)) + return False, str(e) -QueryData = PythonEnvironmentQueryData | TemplateTagQueryData | DjangoInitQueryData +QueryData = PythonEnvironmentQueryData | TemplateTagQueryData