Skip to content

Commit

Permalink
working wip
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Aug 1, 2024
1 parent 9a6294f commit b71d1a8
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 34 deletions.
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ edition = "2021"
clap = "4.5.11"
pixi_manifest = { git = "https://github.com/prefix-dev/pixi", branch="main" }
pixi_consts = { git = "https://github.com/prefix-dev/pixi", branch="main" }
rattler-build = { git = "https://github.com/tdejager/rattler-build", branch = "feat/optional-recipe-generation", default-features = false }
rattler-build = { git = "https://github.com/prefix-dev/rattler-build", branch = "main", default-features = false }
rattler_conda_types = "0.26.3"
rattler_package_streaming = "0.21.7"
chrono = "0.4.38"
miette = "7.2.0"
reqwest = "0.12.5"
reqwest-middleware = "0.3.2"
tokio = "1.37.0"
tempfile = "3.10.1"
clap-verbosity-flag = "2.2.1"
tracing-subscriber = "0.3.18"
7 changes: 7 additions & 0 deletions crates/pixi-build-python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ clap = { workspace = true, features = ["derive", "env"] }
rattler_conda_types = { workspace = true }
rattler_package_streaming = { workspace = true }
chrono = { workspace = true }
miette = { workspace = true }
reqwest-middleware = { workspace = true }
reqwest = { workspace = true }
tokio = { workspace = true, features = ["macros"] }
tempfile = { workspace = true }
clap-verbosity-flag = { workspace = true}
tracing-subscriber = { workspace = true }
206 changes: 173 additions & 33 deletions crates/pixi-build-python/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
mod consts;

use std::{collections::BTreeMap, path::PathBuf, sync::Arc};
use std::{collections::BTreeMap, path::PathBuf, str::FromStr, sync::Arc};

use chrono::Utc;
use clap::Parser;
use pixi_manifest::TargetSelector::Platform;
use pixi_manifest::{FeatureName, Manifest, SpecType};
use rattler_build::recipe::parser::{Build, Requirements};
use clap_verbosity_flag::{InfoLevel, Verbosity};
use miette::{Context, IntoDiagnostic};
use pixi_manifest::{Manifest, SpecType};
use rattler_build::{
build::run_build,
console_utils::{get_default_env_filter, LoggingOutputHandler},
hash::HashInfo,
metadata::{BuildConfiguration, Directories, Output, PackagingSettings},
recipe::{
parser::{Package, PathSource, Source},
parser::{Build, Dependency, Package, PathSource, Requirements, ScriptContent, Source},
Recipe,
},
tool_configuration::{Configuration, SkipExisting},
};
use rattler_conda_types::{
package::ArchiveType, ChannelConfig, MatchSpec, NoArchType, PackageName, Platform,
};
use rattler_conda_types::{package::ArchiveType, MatchSpec, NoArchType};
use rattler_package_streaming::write::CompressionLevel;
use reqwest::{Client, Url};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

#[allow(missing_docs)]
#[derive(Parser)]
Expand All @@ -24,17 +32,16 @@ pub struct App {
/// The path to the manifest file
#[clap(env, long, env = "PIXI_PROJECT_MANIFEST", default_value = consts::PROJECT_MANIFEST)]
manifest_path: PathBuf,

/// Enable verbose logging.
#[command(flatten)]
verbose: Verbosity<InfoLevel>,
}

/// Get the requirements for a default feature
fn requirements_from_manifest(manifest: &Manifest) -> Requirements {
let mut requirements = Requirements::default();
let default_features = manifest
.default_environment()
.features
.iter()
.filter_map(|e| manifest.feature(&FeatureName::Named(e.clone())))
.collect::<Vec<_>>();
let default_features = vec![manifest.default_feature()];

// Get all different feature types
let run_dependencies = default_features
Expand All @@ -43,47 +50,137 @@ fn requirements_from_manifest(manifest: &Manifest) -> Requirements {
.collect::<Vec<_>>();
let host_dependencies = default_features
.iter()
.filter_map(|f| f.dependencies(Some(SpecType::Run), None))
.filter_map(|f| f.dependencies(Some(SpecType::Host), None))
.collect::<Vec<_>>();
let build_dependencies = default_features
.iter()
.filter_map(|f| f.dependencies(Some(SpecType::Run), None))
.filter_map(|f| f.dependencies(Some(SpecType::Build), None))
.collect::<Vec<_>>();

requirements.build = build_dependencies
.into_iter()
.flat_map(|d| d.into_owned().into_iter())
.map(|(name, spec)| MatchSpec::from_nameless(spec, Some(name)))
.map(Dependency::Spec)
.collect();

requirements.host = host_dependencies
.into_iter()
.flat_map(|d| d.into_owned().into_iter())
.map(|(name, spec)| MatchSpec::from_nameless(spec, Some(name)))
.map(Dependency::Spec)
.collect();

requirements.run = run_dependencies
.into_iter()
.flat_map(|d| d.into_owned().into_iter())
.map(|(name, spec)| MatchSpec::from_nameless(spec, Some(name)))
.map(Dependency::Spec)
.collect();

// TODO: If the host requirements don't contain pip or python add those

requirements
}

fn main() {
fn channels_from_manifest(manifest: &Manifest, channel_config: &ChannelConfig) -> Vec<Url> {
// TODO: Improve
manifest
.parsed
.project
.channels
.iter()
.map(|c| c.channel.clone().into_base_url(channel_config))
.collect()
}

#[tokio::main]
pub async fn main() {
if let Err(err) = actual_main().await {
eprintln!("{err:?}");
std::process::exit(1);
}
}

async fn actual_main() -> miette::Result<()> {
let args = App::parse();

let manifest = Manifest::from_path(args.manifest_path).expect("could not load manifest");
requirements_from_manifest(&manifest);
// Setup logging
let log_handler = LoggingOutputHandler::default();
let registry = tracing_subscriber::registry()
.with(get_default_env_filter(args.verbose.log_level_filter()).into_diagnostic()?);
registry.with(log_handler.clone()).init();

// Load the manifest
eprintln!("Looking for manifest at {:?}", args.manifest_path);
let manifest = Manifest::from_path(&args.manifest_path).with_context(|| {
format!(
"failed to parse manifest from {}",
args.manifest_path.display()
)
})?;
let manifest_root = args
.manifest_path
.parent()
.expect("the project manifest must reside in a directory");

// Parse the package name from the manifest
let Some(name) = manifest.parsed.project.name.clone() else {
miette::bail!("a 'name' field is required in the project manifest");
};
let name = PackageName::from_str(&name).into_diagnostic()?;

// Parse the package version from the manifest
let Some(version) = manifest.parsed.project.version.clone() else {
miette::bail!("a 'version' field is required in the project manifest");
};

// TODO: Variants???
let variants = BTreeMap::default();

// TODO: NoArchType???
let noarch_type = NoArchType::None;
let noarch_type = NoArchType::python();

// TODO: Setup defaults
let directories = Directories::default();
let output_dir = std::env::current_dir()
.expect("failed to get current directory")
.join("pixi-build-python-output");
std::fs::create_dir_all(&output_dir)
.into_diagnostic()
.context("failed to create output directory")?;
let directories = Directories::setup(
name.as_normalized(),
args.manifest_path.as_path(),
&output_dir,
false,
&Utc::now(),
)
.into_diagnostic()
.context("failed to setup build directories")?;

// TODO: Read from config / project.
let channel_config = ChannelConfig::default_with_root_dir(manifest_root.to_path_buf());

let requirements = requirements_from_manifest(&manifest);
let channels = channels_from_manifest(&manifest, &channel_config);

let host_platform = Platform::current();
let build_platform = Platform::current();

let hash = HashInfo::from_variant(&variants, &noarch_type);
let build_number = 0;
let build_string = format!("{}_{}", &hash.hash, build_number);

let output = Output {
recipe: Recipe {
schema_version: 1,
package: Package {
// TODO:
version: version.to_string(),

Check failure on line 177 in crates/pixi-build-python/src/main.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

mismatched types
name,
},
cache: None,
source: vec![Source::Path(PathSource {
path: args
.manifest_path
.parent()
.expect("the project manifest must reside in a directory")
.to_path_buf(),
// TODO: How can we use a git source?
path: manifest_root.to_path_buf(),
sha256: None,
md5: None,
patches: vec![],
Expand All @@ -92,23 +189,48 @@ fn main() {
use_gitignore: true,
})],
build: Build {
// TODO:
number: build_number,
string: Some(build_string),

// skip: Default::default(),
script: ScriptContent::Commands(
if build_platform.is_windows() {
vec![
"%PYTHON% -m pip install --ignore-installed --no-deps --no-build-isolation . -vv".to_string(),
"if errorlevel 1 exit 1".to_string()]
} else {
vec!["$PYTHON -m pip install --ignore-installed --no-deps --no-build-isolation . -vv".to_string()]
})
.into(),
noarch: noarch_type,

// TODO: Python is not exposed properly
//python: Default::default(),
// dynamic_linking: Default::default(),
// always_copy_files: Default::default(),
// always_include_files: Default::default(),
// merge_build_and_host_envs: false,
// variant: Default::default(),
// prefix_detection: Default::default(),
// post_process: vec![],
// files: Default::default(),
..Build::default()
},
// TODO read from manifest
requirements: Requirements {},
requirements,
tests: vec![],
about: Default::default(),
extra: Default::default(),
},
build_configuration: BuildConfiguration {
// TODO: NoArch??
target_platform: Platform::NoArch,
host_platform: Platform::current(),
build_platform: Platform::current(),
hash: HashInfo::from_variant(&variants, &noarch_type),
variant,
host_platform,
build_platform,
hash,
variant: Default::default(),
directories,
channels: vec![], // TODO: read from manifest
channels,
channel_priority: Default::default(),
solve_strategy: Default::default(),
timestamp: chrono::Utc::now(),
Expand All @@ -126,4 +248,22 @@ fn main() {
build_summary: Arc::default(),
system_tools: Default::default(),
};

let tool_config = Configuration {
fancy_log_handler: log_handler,
client: reqwest_middleware::ClientWithMiddleware::from(Client::default()),
no_clean: false,
no_test: false,
use_zstd: true,
use_bz2: true,
render_only: false,
skip_existing: SkipExisting::None,
channel_config,
compression_threads: None,
};

let (_output, package) = run_build(output, &tool_config).await?;
eprintln!("Successfully build '{}'", package.display());

Ok(())
}

0 comments on commit b71d1a8

Please sign in to comment.