Fork of daniellemaywood.uk/gleam — Wasm codegen work
5.7 kB
184 lines
1use std::time::{Instant, SystemTime};
2
3use camino::{Utf8Path, Utf8PathBuf};
4use ecow::EcoString;
5
6use crate::{cli, fs::ProjectIO, http::HttpClient};
7use gleam_core::{
8 Result,
9 analyse::TargetSupport,
10 build::{Codegen, Compile, Mode, Options, Package, Target},
11 config::{DocsPage, PackageConfig},
12 docs::DocContext,
13 error::Error,
14 hex,
15 io::HttpClient as _,
16 paths::ProjectPaths,
17 type_,
18};
19
20pub fn remove(package: String, version: String) -> Result<()> {
21 let runtime = tokio::runtime::Runtime::new().expect("Unable to start Tokio async runtime");
22 let hex_config = hexpm::Config::new();
23 let api_key =
24 crate::hex::HexAuthentication::new(&runtime, hex_config.clone()).get_or_create_api_key()?;
25 let http = HttpClient::new();
26
27 // Remove docs from API
28 let request = hexpm::remove_docs_request(&package, &version, &api_key, &hex_config)
29 .map_err(Error::hex)?;
30 let response = runtime.block_on(http.send(request))?;
31 hexpm::remove_docs_response(response).map_err(Error::hex)?;
32
33 // Done!
34 println!("The docs for {package} {version} have been removed from HexDocs");
35 Ok(())
36}
37
38#[derive(Debug)]
39pub struct BuildOptions {
40 /// Whether to open the docs after building.
41 pub open: bool,
42 pub target: Option<Target>,
43}
44
45pub fn build(paths: &ProjectPaths, options: BuildOptions) -> Result<()> {
46 let config = crate::config::root_config(paths)?;
47
48 // Reset the build directory so we know the state of the project
49 crate::fs::delete_directory(&paths.build_directory_for_target(Mode::Prod, config.target))?;
50
51 let out = paths.build_documentation_directory(&config.name);
52 let mut built = crate::build::main(
53 paths,
54 Options {
55 mode: Mode::Prod,
56 target: options.target,
57 codegen: Codegen::All,
58 compile: Compile::All,
59 warnings_as_errors: false,
60 root_target_support: TargetSupport::Enforced,
61 no_print_progress: false,
62 },
63 crate::build::download_dependencies(paths, cli::Reporter::new())?,
64 )?;
65 let outputs = build_documentation(
66 paths,
67 &config,
68 &mut built.root_package,
69 DocContext::Build,
70 &built.module_interfaces,
71 )?;
72
73 // Write
74 crate::fs::delete_directory(&out)?;
75 crate::fs::write_outputs_under(&outputs, &out)?;
76
77 let index_html = out.join("index.html");
78
79 println!(
80 "\nThe documentation for {package} has been rendered to \n{index_html}",
81 package = config.name,
82 index_html = index_html
83 );
84
85 if options.open {
86 open_docs(&index_html)?;
87 }
88
89 // We're done!
90 Ok(())
91}
92
93/// Opens the indicated path in the default program configured by the system.
94///
95/// For the docs this will generally be a browser (unless some other program is
96/// configured as the default for `.html` files).
97fn open_docs(path: &Utf8Path) -> Result<()> {
98 opener::open(path).map_err(|error| Error::FailedToOpenDocs {
99 path: path.to_path_buf(),
100 error: error.to_string(),
101 })?;
102
103 Ok(())
104}
105
106pub(crate) fn build_documentation(
107 paths: &ProjectPaths,
108 config: &PackageConfig,
109 compiled: &mut Package,
110 is_hex_publish: DocContext,
111 cached_modules: &im::HashMap<EcoString, type_::ModuleInterface>,
112) -> Result<Vec<gleam_core::io::OutputFile>, Error> {
113 compiled.attach_doc_and_module_comments();
114 cli::print_generating_documentation();
115 let mut pages = vec![DocsPage {
116 title: "README".into(),
117 path: "index.html".into(),
118 source: paths.readme(), // TODO: support non markdown READMEs. Or a default if there is none.
119 }];
120 pages.extend(config.documentation.pages.iter().cloned());
121 let mut outputs = gleam_core::docs::generate_html(
122 paths,
123 config,
124 compiled.modules.as_slice(),
125 &pages,
126 ProjectIO::new(),
127 SystemTime::now(),
128 is_hex_publish,
129 );
130
131 outputs.push(gleam_core::docs::generate_json_package_interface(
132 Utf8PathBuf::from("package-interface.json"),
133 compiled,
134 cached_modules,
135 ));
136 Ok(outputs)
137}
138
139pub fn publish(paths: &ProjectPaths) -> Result<()> {
140 let config = crate::config::root_config(paths)?;
141
142 let runtime = tokio::runtime::Runtime::new().expect("Unable to start Tokio async runtime");
143 let hex_config = hexpm::Config::new();
144 let api_key =
145 crate::hex::HexAuthentication::new(&runtime, hex_config.clone()).get_or_create_api_key()?;
146
147 // Reset the build directory so we know the state of the project
148 crate::fs::delete_directory(&paths.build_directory_for_target(Mode::Prod, config.target))?;
149
150 let mut built = crate::build::main(
151 paths,
152 Options {
153 root_target_support: TargetSupport::Enforced,
154 warnings_as_errors: false,
155 codegen: Codegen::All,
156 compile: Compile::All,
157 mode: Mode::Prod,
158 target: None,
159 no_print_progress: false,
160 },
161 crate::build::download_dependencies(paths, cli::Reporter::new())?,
162 )?;
163 let outputs = build_documentation(
164 paths,
165 &config,
166 &mut built.root_package,
167 DocContext::HexPublish,
168 &built.module_interfaces,
169 )?;
170 let archive = crate::fs::create_tar_archive(outputs)?;
171
172 let start = Instant::now();
173 cli::print_publishing_documentation();
174 runtime.block_on(hex::publish_documentation(
175 &config.name,
176 &config.version,
177 archive,
178 &api_key,
179 &hex_config,
180 &HttpClient::new(),
181 ))?;
182 cli::print_published(start.elapsed());
183 Ok(())
184}