diff --git a/pyoxidizer/src/py_packaging/binary.rs b/pyoxidizer/src/py_packaging/binary.rs index fdf2a8513..448409248 100644 --- a/pyoxidizer/src/py_packaging/binary.rs +++ b/pyoxidizer/src/py_packaging/binary.rs @@ -168,6 +168,9 @@ pub trait PythonBinaryBuilder { /// The name of the binary. fn name(&self) -> String; + /// Set the name of the binary. + fn set_name(&mut self, value: &str) -> Result<()>; + /// How the binary will link against libpython. fn libpython_link_mode(&self) -> LibpythonLinkMode; diff --git a/pyoxidizer/src/py_packaging/standalone_builder.rs b/pyoxidizer/src/py_packaging/standalone_builder.rs index 4b937494c..7c4baed05 100644 --- a/pyoxidizer/src/py_packaging/standalone_builder.rs +++ b/pyoxidizer/src/py_packaging/standalone_builder.rs @@ -422,6 +422,12 @@ impl PythonBinaryBuilder for StandalonePythonExecutableBuilder { self.exe_name.clone() } + fn set_name(&mut self, value: &str) -> Result<()> { + self.exe_name = value.to_string(); + + Ok(()) + } + fn libpython_link_mode(&self) -> LibpythonLinkMode { self.link_mode } diff --git a/pyoxidizer/src/starlark/python_executable.rs b/pyoxidizer/src/starlark/python_executable.rs index b68bbdf35..c3f77d136 100644 --- a/pyoxidizer/src/starlark/python_executable.rs +++ b/pyoxidizer/src/starlark/python_executable.rs @@ -188,6 +188,7 @@ impl TypedValue for PythonExecutableValue { Ok(Value::from(exe.windows_runtime_dlls_mode().to_string())) } "windows_subsystem" => Ok(Value::from(exe.windows_subsystem())), + "name" => Ok(Value::from(exe.name())), _ => Err(ValueError::OperationNotSupported { op: UnsupportedOperation::GetAttr(attribute.to_string()), left: Self::TYPE.to_string(), @@ -204,6 +205,7 @@ impl TypedValue for PythonExecutableValue { | "tcl_files_path" | "windows_runtime_dlls_mode" | "windows_subsystem" + | "name" )) } @@ -260,6 +262,11 @@ impl TypedValue for PythonExecutableValue { Ok(()) } + "name" => { + let _ = exe.set_name(value.to_string().as_str()); + + Ok(()) + } _ => Err(ValueError::OperationNotSupported { op: UnsupportedOperation::SetAttr(attribute.to_string()), left: Self::TYPE.to_string(), @@ -962,6 +969,8 @@ impl PythonExecutableValue { builder.add_program_files_manifest(type_values, call_stack, manifest.deref().clone())?; + let _ = builder.set_exe_name(self.get_attr("name").unwrap().to_str())?; + Ok(builder_value.clone()) } @@ -1385,6 +1394,27 @@ mod tests { Ok(()) } + #[test] + fn name() -> Result<()> { + let mut env = test_evaluation_context_builder()?.into_context()?; + add_exe(&mut env)?; + + let v = env.eval("exe.name")?; + assert_eq!(v.get_type(), "string"); + assert_eq!(v.to_string(), "COPYING.txt"); + + env.eval("exe.name = 'myapp'")?; + let v = env.eval("exe.name")?; + assert_eq!(v.get_type(), "string"); + assert_eq!(v.to_string(), "myapp"); + + env.eval("exe.name = None")?; + let v = env.eval("exe.name")?; + assert_eq!(v.get_type(), "NoneType"); + + Ok(()) + } + #[test] fn test_windows_runtime_dlls_mode() -> Result<()> { let mut env = test_evaluation_context_builder()?.into_context()?; diff --git a/tugger-wix/src/simple_msi_builder.rs b/tugger-wix/src/simple_msi_builder.rs index 124246515..96d1b9d3f 100644 --- a/tugger-wix/src/simple_msi_builder.rs +++ b/tugger-wix/src/simple_msi_builder.rs @@ -45,6 +45,8 @@ pub struct WiXSimpleMsiBuilder { /// Files to materialize in `Program Files`. program_files_manifest: FileManifest, + add_to_start_menu: Option, + exe_name: Option, upgrade_code: Option, package_keywords: Option, package_description: Option, @@ -91,6 +93,15 @@ impl WiXSimpleMsiBuilder { Ok(()) } + /// Set the `exe_name` attribute value. + /// + /// This should be set to the name of the exe file to add to the start menu shortcut. + pub fn set_exe_name(&mut self, value: String) -> Result<()> { + self.exe_name = Some(value); + + Ok(()) + } + /// Attempt to add the Visual C++ Redistributable DLLs to the program files manifest. /// /// This will use `vswhere.exe` to attempt to locate a Visual Studio installation @@ -117,6 +128,13 @@ impl WiXSimpleMsiBuilder { Ok(()) } + /// Set the ` Self { + self.add_to_start_menu = Some(value); + self + } + /// Set the ` String { + Uuid::new_v5( + &Uuid::NAMESPACE_DNS, + format!("tugger.application_shortcut.{}", self.product_name).as_bytes(), + ) + .as_hyphenated() + .encode_upper(&mut Uuid::encode_buffer()) + .to_string() + } } #[cfg(test)] diff --git a/tugger/docs/tugger_starlark_type_wix_msi_builder.rst b/tugger/docs/tugger_starlark_type_wix_msi_builder.rst index 4ecc7cee2..16fb63e44 100644 --- a/tugger/docs/tugger_starlark_type_wix_msi_builder.rst +++ b/tugger/docs/tugger_starlark_type_wix_msi_builder.rst @@ -94,6 +94,22 @@ If not set, the default is ``-.msi``. + .. py:attribute:: add_to_start_menu + + (``bool``) + + If enabled a shortcut wil be created in the Start Menu pointing to ``exe_name`` + eg. ``msi.add_to_start_menu = True`` + + If not set no shortcut will be installed. + + .. py:attribute:: exe_name + + (``str``) + + The filename of the installed application, used by add_to_start_menu. + This is automatically set when using ``exe.to_wix_msi_builder()``. + .. py:attribute:: package_description (``str``) diff --git a/tugger/src/starlark/wix_msi_builder.rs b/tugger/src/starlark/wix_msi_builder.rs index c5f90f7b1..f23a9b7f0 100644 --- a/tugger/src/starlark/wix_msi_builder.rs +++ b/tugger/src/starlark/wix_msi_builder.rs @@ -109,6 +109,12 @@ impl TypedValue for WiXMsiBuilderValue { "upgrade_code" => { inner.builder = inner.builder.clone().upgrade_code(value.to_string()); } + "add_to_start_menu" => { + inner.builder = inner.builder.clone().add_to_start_menu(value.to_bool()); + } + "set_exe_name" => { + let _ = inner.builder.set_exe_name(value.to_string()); + } attr => { return Err(ValueError::OperationNotSupported { op: UnsupportedOperation::SetAttr(attr.to_string()), @@ -325,6 +331,16 @@ impl WiXMsiBuilderValue { }) } + pub fn set_exe_name(&mut self, exe_name: String) -> ValueResult { + const LABEL: &str = "WiXMSIBuilder.set_exe_name()"; + + let mut inner = self.inner(LABEL)?; + + let _ = inner.builder.set_exe_name(exe_name); + + Ok(Value::new(NoneType::None)) + } + pub fn to_file_content( &self, type_values: &TypeValues,