Something went wrong. Try again.
⭐️ A friendly language for building type-safe, scalable systems!
Something went wrong. Try again.
8.1 kB · 248 lines
Rust
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249// SPDX-License-Identifier: Apache-2.0// SPDX-FileCopyrightText: 2020 The Gleam contributors
use std::{collections::HashMap, time::SystemTime};
use camino::{Utf8Path, Utf8PathBuf};use ecow::EcoString;
use crate::{cli, fs::ProjectIO, http::HttpClient};use gleam_core::{ Result, analyse::TargetSupport, build::{Codegen, Compile, Mode, Options, Package, Target}, config::{DocsPage, PackageConfig}, docs::{Dependency, DependencyKind, DocContext}, error::Error, hex, io::HttpClient as _, manifest::ManifestPackageSource, paths::ProjectPaths, type_,};
pub fn remove(package: String, version: String) -> Result<()> { let runtime = tokio::runtime::Runtime::new().expect("Unable to start Tokio async runtime"); let http = HttpClient::new(); let hex_config = hexpm::Config::new(); let credentials = crate::hex::HexAuthentication::new(&runtime, &http, hex_config.clone()) .get_or_create_api_credentials()?;
// Remove docs from API let request = hexpm::api_remove_docs_request( &package, &version, &crate::hex::write_credentials(&credentials)?, &hex_config, ) .map_err(Error::hex)?; let response = runtime.block_on(http.send(request))?; hexpm::api_remove_docs_response(response).map_err(Error::hex)?;
// Done! println!("The docs for {package} {version} have been removed from HexDocs"); Ok(())}
#[derive(Debug)]pub struct BuildOptions { /// Whether to open the docs after building. pub open: bool, pub target: Option<Target>,}
pub fn build(paths: &ProjectPaths, options: BuildOptions) -> Result<()> { let config = crate::config::root_config(paths)?;
// Reset the build directory for the root package so that's recompiled and // the docs can be up to date for all modules. // Note how this doesn't delete the entire build directory, this way we can // avoid recompiling all the dependencies every time we're building the // documentation for our package. crate::fs::delete_directory(&paths.build_directory_for_package( Mode::Prod, options.target.unwrap_or(config.target), &config.name, ))?;
let out = paths.build_documentation_directory(&config.name);
let manifest = crate::build::download_dependencies(paths, cli::Reporter::new())?; let dependencies = manifest .packages .iter() .map(|package| { ( package.name.clone(), Dependency { version: package.version.clone(), kind: match &package.source { ManifestPackageSource::Hex { .. } => DependencyKind::Hex, ManifestPackageSource::Git { .. } => DependencyKind::Git, ManifestPackageSource::Local { .. } => DependencyKind::Path, }, }, ) }) .collect();
let mut built = crate::build::main( paths, Options { mode: Mode::Prod, target: options.target, // Code generation is not needed when building docs, this can speed // up the docs building process quite drastically, especially on the // Erlang target where we can avoid calling erlc. codegen: Codegen::None, compile: Compile::All, warnings_as_errors: false, root_target_support: TargetSupport::Enforced, no_print_progress: false, }, manifest, )?; let outputs = build_documentation( paths, &config, dependencies, &mut built.root_package, DocContext::Build, &built.module_interfaces, )?;
// Write crate::fs::delete_directory(&out)?; crate::fs::write_outputs_under(&outputs, &out)?;
let index_html = out.join("index.html");
println!( "\nThe documentation for {package} has been rendered to \n{index_html}", package = config.name, index_html = index_html );
if options.open { open_docs(&index_html)?; }
// We're done! Ok(())}
/// Opens the indicated path in the default program configured by the system.////// For the docs this will generally be a browser (unless some other program is/// configured as the default for `.html` files).fn open_docs(path: &Utf8Path) -> Result<()> { opener::open(path).map_err(|error| Error::FailedToOpenDocs { path: path.to_path_buf(), error: error.to_string(), })?;
Ok(())}
pub(crate) fn build_documentation( paths: &ProjectPaths, config: &PackageConfig, dependencies: HashMap<EcoString, Dependency>, compiled: &mut Package, is_hex_publish: DocContext, cached_modules: &im::HashMap<EcoString, type_::ModuleInterface>,) -> Result<Vec<gleam_core::io::OutputFile>, Error> { compiled.attach_doc_and_module_comments(); cli::print_generating_documentation(); let mut pages = vec![DocsPage { title: "README".into(), path: "index.html".into(), source: paths.readme(), // TODO: support non markdown READMEs. Or a default if there is none. }]; pages.extend(config.documentation.pages.iter().cloned()); let mut outputs = gleam_core::docs::generate_html( paths, gleam_core::docs::DocumentationConfig { package_config: config, dependencies, analysed: compiled.modules.as_slice(), docs_pages: &pages, rendering_timestamp: SystemTime::now(), context: is_hex_publish, }, ProjectIO::new(), );
outputs.push(gleam_core::docs::generate_json_package_interface( Utf8PathBuf::from("package-interface.json"), compiled, cached_modules, )); Ok(outputs)}
pub fn publish(paths: &ProjectPaths) -> Result<()> { let config = crate::config::root_config(paths)?; let http = HttpClient::new(); let runtime = tokio::runtime::Runtime::new().expect("Unable to start Tokio async runtime"); let hex_config = hexpm::Config::new(); let credentials = crate::hex::HexAuthentication::new(&runtime, &http, hex_config.clone()) .get_or_create_api_credentials()?;
// Reset the build directory so we know the state of the project crate::fs::delete_directory(&paths.build_directory_for_target(Mode::Prod, config.target))?;
let manifest = crate::build::download_dependencies(paths, cli::Reporter::new())?; let dependencies = manifest .packages .iter() .map(|package| { ( package.name.clone(), Dependency { version: package.version.clone(), kind: match &package.source { ManifestPackageSource::Hex { .. } => DependencyKind::Hex, ManifestPackageSource::Git { .. } => DependencyKind::Git, ManifestPackageSource::Local { .. } => DependencyKind::Path, }, }, ) }) .collect();
let mut built = crate::build::main( paths, Options { root_target_support: TargetSupport::Enforced, warnings_as_errors: false, codegen: Codegen::All, compile: Compile::All, mode: Mode::Prod, target: None, no_print_progress: false, }, manifest, )?; let outputs = build_documentation( paths, &config, dependencies, &mut built.root_package, DocContext::HexPublish, &built.module_interfaces, )?; let archive = crate::fs::create_tar_archive(outputs)?;
cli::print_publishing_documentation(); runtime.block_on(hex::publish_documentation( &config.name, &config.version, archive, &crate::hex::write_credentials(&credentials)?, &hex_config, &http, ))?; cli::print_published("documentation"); Ok(())}