diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 9d876ba..2d965a7 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -45,6 +45,9 @@ pub enum PluginCommand { #[arg(short = 'd', long, default_value = "false")] build_with_dev: bool, + + #[arg(short = 'S', long, default_value = "true")] + follow_symlinks: bool, #[arg(short = 's', long, value_enum, default_value = "plugin-name")] output_filename_source: FilenameSource, @@ -68,6 +71,9 @@ pub enum PluginCommand { #[arg(short = 's', long, value_enum, default_value = "plugin-name")] output_filename_source: FilenameSource, + + #[arg(short = 'S', long, default_value = "true")] + follow_symlinks: bool, #[arg(short = 'i', long)] deck_ip: Option, diff --git a/src/cli/plugin/build.rs b/src/cli/plugin/build.rs index 17c9e63..587830c 100644 --- a/src/cli/plugin/build.rs +++ b/src/cli/plugin/build.rs @@ -5,9 +5,10 @@ use itertools::Itertools; use log::info; use rand::distributions::{Alphanumeric, DistString}; use std::{ + fs, fs::File, io::Write, - path::{Path, PathBuf}, + path::{Path, PathBuf}, os, }; use walkdir::WalkDir; use zip::{write::FileOptions, ZipWriter}; @@ -28,6 +29,7 @@ pub struct Builder { pub tmp_build_root: PathBuf, pub build_as_root: bool, pub build_with_dev: bool, + pub follow_symlinks: bool, pub output_filename_source: FilenameSource, } @@ -94,6 +96,53 @@ impl Builder { .await } + pub async fn build_py_modules(&self) -> Result<()> { + let source_py_modules_dir = self.plugin_root.join("py_modules"); + let tmp_py_modules_dir = self.tmp_build_root.join("py_modules"); + + if !&source_py_modules_dir.exists() { + info!("Plugin does not have a py_modules"); + return Ok(()); + } + + info!("Building py_modules"); + + self.copy_py_modules(source_py_modules_dir, tmp_py_modules_dir)?; + + Ok(()) + } + + fn copy_py_modules(&self, src: impl AsRef, dst: impl AsRef) -> Result<()> { + fs::create_dir_all(&dst)?; + + let src = src.as_ref(); + let dst = dst.as_ref(); + + for entry in fs::read_dir(src)? { + let entry = entry?; + let file_type = entry.file_type()?; + + let to = dst.join(entry.file_name()); + + if file_type.is_symlink() && self.follow_symlinks { + let original = src.join(fs::read_link(entry.path())?); + let original_fullpath = original.canonicalize()?; + + os::unix::fs::symlink(original_fullpath, to)?; + } else if file_type.is_dir() { + if entry.file_name() == "__pycache__" { + continue; + } + + self.copy_py_modules(entry.path(), to)?; + } else if file_type.is_file() { + fs::copy(entry.path(), to)?; + } + } + + Ok(()) + } + fn zip_path( &self, filename: &str, @@ -165,6 +214,11 @@ impl Builder { mandatory: false, permissions: FileOptions::default(), }, + DirDirective { + path: "py_modules", + mandatory: false, + permissions: FileOptions::default().unix_permissions(0o755), + }, ]; let expected_files = vec![ @@ -206,8 +260,7 @@ impl Builder { continue; } - let dir_entries = WalkDir::new(full_path); - + let dir_entries = WalkDir::new(full_path).follow_links(self.follow_symlinks); for entry in dir_entries { let file = entry?; self.zip_path( @@ -246,6 +299,9 @@ impl Builder { self.build_frontend().await.context( "Failed to build frontend. There might be more information in the output above.", )?; + self.build_py_modules().await.context( + "Failed to build py_modules. There might be more information in the output above.", + )?; self.zip_plugin().context("Failed to zip plugin.")?; Ok(()) @@ -257,6 +313,7 @@ impl Builder { tmp_build_root: PathBuf, build_as_root: bool, build_with_dev: bool, + follow_symlinks: bool, output_filename_source: FilenameSource, ) -> Result { if !output_root.exists() { @@ -281,6 +338,7 @@ impl Builder { docker_image: "ghcr.io/steamdeckhomebrew/builder:latest".to_owned(), build_as_root, build_with_dev, + follow_symlinks, output_filename_source, }) } diff --git a/src/cli/plugin/deploy.rs b/src/cli/plugin/deploy.rs index 7ef84e5..36c05f2 100644 --- a/src/cli/plugin/deploy.rs +++ b/src/cli/plugin/deploy.rs @@ -196,6 +196,7 @@ impl Deployer { tmp_build_root: PathBuf, build_as_root: bool, build_with_dev: bool, + follow_symlinks: bool, output_filename_source: FilenameSource, deck_ip: Option, deck_port: Option, @@ -211,6 +212,7 @@ impl Deployer { tmp_build_root.clone(), build_as_root, build_with_dev, + follow_symlinks, output_filename_source, ).expect("Could not create builder"); diff --git a/src/cli/plugin/mod.rs b/src/cli/plugin/mod.rs index 4caee07..bb22a96 100644 --- a/src/cli/plugin/mod.rs +++ b/src/cli/plugin/mod.rs @@ -12,6 +12,7 @@ pub async fn parse(args: &PluginCLI) -> Result<()> { tmp_output_path, build_as_root, build_with_dev, + follow_symlinks, output_filename_source, } => { build::Builder::new( @@ -20,6 +21,7 @@ pub async fn parse(args: &PluginCLI) -> Result<()> { tmp_output_path.into(), build_as_root.clone(), build_with_dev.clone(), + follow_symlinks.clone(), output_filename_source.clone(), )? .run() @@ -32,6 +34,7 @@ pub async fn parse(args: &PluginCLI) -> Result<()> { tmp_output_path, build_as_root, build_with_dev, + follow_symlinks, output_filename_source, deck_ip, deck_port, @@ -45,6 +48,7 @@ pub async fn parse(args: &PluginCLI) -> Result<()> { tmp_output_path.into(), build_as_root.clone(), build_with_dev.clone(), + follow_symlinks.clone(), output_filename_source.clone(), deck_ip.clone(), deck_port.clone(),