use crate::build_context::BridgeModel;
use crate::compile::compile;
use crate::module_writer::{write_bindings_module, write_cffi_module, PathWriter};
use crate::PythonInterpreter;
use crate::Target;
use crate::{write_dist_info, BuildOptions};
use crate::{ModuleWriter, PlatformTag};
use anyhow::{anyhow, bail, format_err, Context, Result};
use fs_err as fs;
use std::path::Path;
use std::process::Command;
pub fn develop(
bindings: Option<String>,
manifest_file: &Path,
cargo_extra_args: Vec<String>,
rustc_extra_args: Vec<String>,
venv_dir: &Path,
release: bool,
strip: bool,
) -> Result<()> {
let target = Target::from_target_triple(None)?;
let python = target.get_venv_python(&venv_dir);
let build_options = BuildOptions {
platform_tag: Some(PlatformTag::Linux),
interpreter: Some(vec![target.get_python()]),
bindings,
manifest_path: manifest_file.to_path_buf(),
out: None,
skip_auditwheel: false,
target: None,
cargo_extra_args,
rustc_extra_args,
universal2: false,
};
let build_context = build_options.into_build_context(release, strip)?;
let interpreter = PythonInterpreter::check_executable(python, &target, &build_context.bridge)?
.ok_or_else(|| {
anyhow!("Expected `python` to be a python interpreter inside a virtualenv ಠ_ಠ")
})?;
if !build_context.metadata21.requires_dist.is_empty() {
let mut args = vec!["-m", "pip", "install"];
args.extend(
build_context
.metadata21
.requires_dist
.iter()
.map(|x| x.as_str()),
);
let status = Command::new(&interpreter.executable)
.args(&args)
.status()
.context("Failed to run pip install")?;
if !status.success() {
bail!(r#"pip install finished with "{}""#, status)
}
}
let base_path = target.get_venv_site_package(venv_dir, &interpreter);
let dist_info_dir = base_path.join(build_context.metadata21.get_dist_info_dir());
if dist_info_dir.is_dir() {
fs::remove_dir_all(&dist_info_dir).context(format!(
"Failed to uninstall existing installation by removing {}",
dist_info_dir.display()
))?;
}
let mut writer = PathWriter::venv(&target, &venv_dir, &build_context.bridge)?;
let context = "Failed to build a native library through cargo";
match build_context.bridge {
BridgeModel::Bin => {
let artifacts = compile(&build_context, None, &BridgeModel::Bin).context(context)?;
let artifact = artifacts
.get("bin")
.ok_or_else(|| format_err!("Cargo didn't build a binary"))?;
let bin_name = artifact.file_name().unwrap();
let bin_path = target.get_venv_bin_dir(&venv_dir).join(bin_name);
fs::copy(&artifact, &bin_path).context(format!(
"Failed to copy {} to {}",
artifact.display(),
bin_path.display()
))?;
}
BridgeModel::Cffi => {
let artifact = build_context.compile_cdylib(None, None).context(context)?;
writer.delete_dir(&build_context.module_name)?;
write_cffi_module(
&mut writer,
&build_context.project_layout,
&build_context.manifest_path.parent().unwrap(),
&build_context.module_name,
&artifact,
&interpreter.executable,
true,
)?;
}
BridgeModel::Bindings(_) => {
let artifact = build_context
.compile_cdylib(Some(&interpreter), Some(&build_context.module_name))
.context(context)?;
writer.delete_dir(&build_context.module_name)?;
write_bindings_module(
&mut writer,
&build_context.project_layout,
&build_context.module_name,
&artifact,
Some(&interpreter),
&target,
true,
)?;
}
BridgeModel::BindingsAbi3(_, _) => {
let artifact = build_context
.compile_cdylib(Some(&interpreter), Some(&build_context.module_name))
.context(context)?;
writer.delete_dir(&build_context.module_name)?;
write_bindings_module(
&mut writer,
&build_context.project_layout,
&build_context.module_name,
&artifact,
None,
&target,
true,
)?;
}
}
let tags = match build_context.bridge {
BridgeModel::Bindings(_) => {
vec![build_context.interpreter[0].get_tag(PlatformTag::Linux, build_context.universal2)]
}
BridgeModel::BindingsAbi3(major, minor) => {
let platform = target.get_platform_tag(PlatformTag::Linux, build_context.universal2);
vec![format!("cp{}{}-abi3-{}", major, minor, platform)]
}
BridgeModel::Bin | BridgeModel::Cffi => {
build_context
.target
.get_universal_tags(PlatformTag::Linux, build_context.universal2)
.1
}
};
write_dist_info(&mut writer, &build_context.metadata21, &tags)?;
writer.add_bytes(
build_context
.metadata21
.get_dist_info_dir()
.join("INSTALLER"),
env!("CARGO_PKG_NAME").as_bytes(),
)?;
writer.write_record(&build_context.metadata21)?;
Ok(())
}