pray-cli 1.22.0

Package manager for the language placed before inference — Prayfile CLI (binary: pray)
use crate::materialize::build_package_archive_bytes;
use crate::publish_context::{PublishDestLabel, PublishIdentity};
use crate::publish_plan::{report_published, PublishStats};
use crate::publish_ssh::publish_to_ssh_server;
use crate::publish_version::published_registry_package_version;
use crate::registry_ops::{registry_artifact_path, torrent_manifest_bytes, torrent_manifest_path};
use crate::sync_peers::map_transport_error;
use crate::transport_metadata::transport_package_metadata;
use pray_core::distribution::fetch_registry_distribution_settings;
use pray_core::registry::{
    publish_authorization_header, upload_registry_artifact_with_authorization,
    RegistryPackageMetadata,
};
use pray_core::resolve::ResolvedPackage;
use pray_core::PrayResult;
use pray_transport::{PeerConfig, SyncDirection, TransportRegistry, TrustLevel};

pub(crate) fn publish_to_server(
    packages: &[&ResolvedPackage],
    identity: &PublishIdentity<'_>,
    server_url: &str,
    runtime: &tokio::runtime::Runtime,
    label: &PublishDestLabel<'_>,
) -> PrayResult<PublishStats> {
    if pray_core::ssh_client::is_pray_ssh_url(server_url) {
        publish_to_ssh_server(
            packages,
            identity.signer,
            identity.signer_fingerprint,
            identity.published_at,
            identity.signing_key,
            server_url,
        )?;
        return Ok(report_server_published(packages, label));
    }

    let authorization = publish_authorization_header();
    let mut headers = serde_json::Map::new();
    if let Some(authorization) = authorization.as_ref() {
        headers.insert(
            "Authorization".to_string(),
            serde_json::Value::String(authorization.clone()),
        );
    }
    let peer = PeerConfig {
        name: server_url.to_string(),
        transport: "http".to_string(),
        url: Some(server_url.to_string()),
        trust: TrustLevel::Full,
        direction: SyncDirection::Push,
        config: serde_json::json!({ "headers": headers }),
    };
    let registry = TransportRegistry::new();
    let transport = registry.create(&peer).map_err(map_transport_error)?;
    let distribution = fetch_registry_distribution_settings(server_url)?;

    let mut stats = PublishStats {
        published: 0,
        unchanged: 0,
    };
    for package in packages {
        let archive_bytes = build_package_archive_bytes(package)?;
        let artifact_path =
            registry_artifact_path(&package.declaration.name, &package.spec.version);
        upload_registry_artifact_with_authorization(
            server_url,
            &artifact_path,
            &archive_bytes,
            authorization.as_deref(),
        )?;
        if distribution.allows_torrent() {
            upload_registry_artifact_with_authorization(
                server_url,
                &torrent_manifest_path(&artifact_path),
                &torrent_manifest_bytes(
                    package,
                    &artifact_path,
                    &archive_bytes,
                    distribution.bootstrap_trackers.clone(),
                )?,
                authorization.as_deref(),
            )?;
        }

        let metadata = RegistryPackageMetadata {
            name: package.declaration.name.clone(),
            versions: vec![published_registry_package_version(
                package,
                identity.signer,
                identity.signer_fingerprint,
                identity.published_at,
                identity.signing_key,
                &artifact_path,
                &archive_bytes,
            )?],
        };
        let transport_metadata = transport_package_metadata(&metadata);
        runtime
            .block_on(transport.push_package(&peer, &transport_metadata))
            .map_err(map_transport_error)?;
        report_published(package, label.dest_name, label.target, &artifact_path);
        stats.published += 1;
    }

    Ok(stats)
}

fn report_server_published(
    packages: &[&ResolvedPackage],
    label: &PublishDestLabel<'_>,
) -> PublishStats {
    let mut stats = PublishStats {
        published: 0,
        unchanged: 0,
    };
    for package in packages {
        let artifact_path =
            registry_artifact_path(&package.declaration.name, &package.spec.version);
        report_published(package, label.dest_name, label.target, &artifact_path);
        stats.published += 1;
    }
    stats
}