Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/archive_source.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use std::path::PathBuf;

#[derive(Debug, Clone)]
pub(crate) enum ArchiveSource {
Generated(GeneratedSourceData),
File(FileSourceData),
}

impl ArchiveSource {
pub(crate) fn executable(&self) -> bool {
match self {
Self::Generated(source) => source.executable,
Self::File(source) => source.executable,
}
}
}

#[derive(Debug, Clone)]
pub(crate) struct GeneratedSourceData {
pub(crate) data: Vec<u8>,
pub(crate) executable: bool,
}

#[derive(Debug, Clone)]
pub(crate) struct FileSourceData {
pub(crate) path: PathBuf,
pub(crate) executable: bool,
}
36 changes: 24 additions & 12 deletions src/binding_generator/cffi_binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use tracing::debug;
use crate::BuildArtifact;
use crate::BuildContext;
use crate::PythonInterpreter;
use crate::archive_source::ArchiveSource;
use crate::archive_source::GeneratedSourceData;
use crate::target::Os;

use super::BindingGenerator;
Expand Down Expand Up @@ -55,22 +57,32 @@ impl BindingGenerator for CffiBindingGenerator {
let artifact_target = base_path.join(&cffi_module_file_name);

let mut additional_files = HashMap::new();
let source = GeneratedSourceData {
data: cffi_init_file(&cffi_module_file_name).into(),
executable: false,
};
additional_files.insert(
base_path.join("__init__.py"),
cffi_init_file(&cffi_module_file_name).into(),
);
additional_files.insert(
base_path.join("ffi.py"),
generate_cffi_declarations(
context.manifest_path.parent().unwrap(),
&context.target_dir,
&interpreter
.ok_or_else(|| anyhow!("A python interpreter is required for cffi builds but one was not provided"))?
.executable,
)?
.into(),
ArchiveSource::Generated(source),
);

let declarations = generate_cffi_declarations(
context.manifest_path.parent().unwrap(),
&context.target_dir,
&interpreter
.ok_or_else(|| {
anyhow!(
"A python interpreter is required for cffi builds but one was not provided"
)
})?
.executable,
)?;
let source = GeneratedSourceData {
data: declarations.into(),
executable: false,
};
additional_files.insert(base_path.join("ffi.py"), ArchiveSource::Generated(source));

Ok(GeneratorOutput {
artifact_target,
artifact_source_override: None,
Expand Down
48 changes: 37 additions & 11 deletions src/binding_generator/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::io;
use std::io::Write as _;
use std::path::Path;
use std::path::PathBuf;
Expand All @@ -7,6 +8,8 @@ use anyhow::Context as _;
use anyhow::Result;
use fs_err as fs;
use fs_err::File;
#[cfg(unix)]
use fs_err::os::unix::fs::OpenOptionsExt as _;
use tempfile::TempDir;
use tempfile::tempdir;
use tracing::debug;
Expand All @@ -16,7 +19,9 @@ use crate::BuildContext;
use crate::Metadata24;
use crate::ModuleWriter;
use crate::PythonInterpreter;
use crate::archive_source::ArchiveSource;
use crate::module_writer::ModuleWriterExt;
use crate::module_writer::default_permission;
use crate::module_writer::write_python_part;

mod cffi_binding;
Expand All @@ -26,7 +31,7 @@ mod wasm_binding;

pub use cffi_binding::CffiBindingGenerator;
pub use pyo3_binding::Pyo3BindingGenerator;
pub use uniffi_binding::write_uniffi_module;
pub use uniffi_binding::UniFfiBindingGenerator;
pub use wasm_binding::write_wasm_launcher;

///A trait to generate the binding files to be included in the built module
Expand Down Expand Up @@ -56,7 +61,7 @@ pub(crate) struct GeneratorOutput {

/// Additional files to be installed (e.g. __init__.py)
/// The provided PathBuf should be relative to the archive root
additional_files: Option<HashMap<PathBuf, Vec<u8>>>,
additional_files: Option<HashMap<PathBuf, ArchiveSource>>,
}

/// Every binding generator ultimately has to install the following:
Expand Down Expand Up @@ -139,16 +144,25 @@ pub fn generate_binding(

// 3. Install additional files
if let Some(additional_files) = additional_files {
for (target, data) in additional_files {
for (target, source) in additional_files {
let target = base_path.join(target);
fs::create_dir_all(target.parent().unwrap())?;
debug!("Generating file {}", target.display());
let mut file = File::options()
.write(true)
.create(true)
.truncate(true)
.open(&target)?;
file.write_all(data.as_slice())?;
let mut options = File::options();
options.write(true).create(true).truncate(true);
#[cfg(unix)]
{
options.mode(default_permission(source.executable()));
}

let mut file = options.open(&target)?;
match source {
ArchiveSource::Generated(source) => file.write_all(&source.data)?,
ArchiveSource::File(source) => {
let mut source = File::options().read(true).open(source.path)?;
io::copy(&mut source, &mut file)?;
}
}
}
}
}
Expand All @@ -164,9 +178,21 @@ pub fn generate_binding(

// 3. Install additional files
if let Some(additional_files) = additional_files {
for (target, data) in additional_files {
for (target, source) in additional_files {
debug!("Generating archive entry {}", target.display());
writer.add_bytes(target, None, data.as_slice(), false)?;
match source {
ArchiveSource::Generated(source) => {
writer.add_bytes(
target,
None,
source.data.as_slice(),
source.executable,
)?;
}
ArchiveSource::File(source) => {
writer.add_file(target, source.path, source.executable)?;
}
}
}
}
}
Expand Down
11 changes: 7 additions & 4 deletions src/binding_generator/pyo3_binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use crate::BuildArtifact;
use crate::BuildContext;
use crate::PythonInterpreter;
use crate::Target;
use crate::archive_source::ArchiveSource;
use crate::archive_source::GeneratedSourceData;

use super::BindingGenerator;
use super::GeneratorOutput;
Expand Down Expand Up @@ -80,17 +82,18 @@ impl BindingGenerator for Pyo3BindingGenerator {
Some(_) => None,
None => {
let mut files = HashMap::new();
files.insert(
module.join("__init__.py"),
format!(
let source = GeneratedSourceData {
data: format!(
r#"from .{ext_name} import *

__doc__ = {ext_name}.__doc__
if hasattr({ext_name}, "__all__"):
__all__ = {ext_name}.__all__"#
)
.into(),
);
executable: false,
};
files.insert(module.join("__init__.py"), ArchiveSource::Generated(source));
Some(files)
}
};
Expand Down
Loading
Loading