Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-cli / src / lib.rs
30 kB 1012 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2018 The Gleam contributors 3 4#![warn( 5 clippy::all, 6 clippy::redundant_clone, 7 clippy::dbg_macro, 8 clippy::todo, 9 clippy::mem_forget, 10 clippy::use_self, 11 clippy::filter_map_next, 12 clippy::needless_continue, 13 clippy::needless_borrow, 14 clippy::match_wildcard_for_single_variants, 15 clippy::imprecise_flops, 16 clippy::suboptimal_flops, 17 clippy::lossy_float_literal, 18 clippy::rest_pat_in_fully_bound_structs, 19 clippy::fn_params_excessive_bools, 20 clippy::inefficient_to_string, 21 clippy::linkedlist, 22 clippy::macro_use_imports, 23 clippy::option_option, 24 clippy::verbose_file_reads, 25 clippy::unnested_or_patterns, 26 rust_2018_idioms, 27 missing_debug_implementations, 28 missing_copy_implementations, 29 trivial_casts, 30 trivial_numeric_casts, 31 nonstandard_style, 32 unexpected_cfgs, 33 unused_import_braces, 34 unused_qualifications 35)] 36#![deny( 37 clippy::await_holding_lock, 38 clippy::if_let_mutex, 39 clippy::indexing_slicing, 40 clippy::mem_forget, 41 clippy::ok_expect, 42 clippy::unimplemented, 43 clippy::unwrap_used, 44 unsafe_code, 45 unstable_features, 46 unused_results 47)] 48#![allow( 49 clippy::match_single_binding, 50 clippy::inconsistent_struct_constructor, 51 clippy::assign_op_pattern, 52 clippy::len_without_is_empty 53)] 54 55#[cfg(test)] 56#[macro_use] 57extern crate pretty_assertions; 58 59mod add; 60mod beam_compiler; 61mod build; 62mod build_lock; 63mod cli; 64mod compile_package; 65mod config; 66mod dependencies; 67mod docs; 68mod export; 69mod fix; 70mod format; 71pub mod fs; 72mod hex; 73mod http; 74mod lsp; 75mod new; 76mod owner; 77mod panic; 78mod publish; 79mod remove; 80pub mod run; 81mod shell; 82mod text_layout; 83 84use config::root_config; 85use fs::{get_current_directory, get_project_root}; 86pub use gleam_core::error::{Error, Result}; 87 88use camino::Utf8PathBuf; 89use clap::{ 90 Args, Parser, Subcommand, 91 builder::{Styles, styling}, 92}; 93use gleam_core::{ 94 analyse::TargetSupport, 95 build::{Codegen, Compile, Mode, NullTelemetry, Options, Runtime, Target}, 96 hex::RetirementReason, 97 paths::ProjectPaths, 98 version::COMPILER_VERSION, 99}; 100 101#[derive(Args, Debug, Clone)] 102pub struct UpdateOptions { 103 /// (optional) Names of the packages to update 104 /// If omitted, all dependencies will be updated 105 #[arg(verbatim_doc_comment)] 106 packages: Vec<String>, 107} 108 109#[derive(Args, Debug, Clone)] 110pub struct TreeOptions { 111 /// Name of the package to get the dependency tree for 112 #[arg( 113 short, 114 long, 115 ignore_case = true, 116 conflicts_with = "invert", 117 help = "Package to be used as the root of the tree" 118 )] 119 package: Option<String>, 120 /// Name of the package to get the inverted dependency tree for 121 #[arg( 122 short, 123 long, 124 ignore_case = true, 125 conflicts_with = "package", 126 help = "Invert the tree direction and focus on the given package", 127 value_name = "PACKAGE" 128 )] 129 invert: Option<String>, 130} 131 132#[derive(Parser, Debug)] 133#[command( 134 version, 135 name = "gleam", 136 next_display_order = None, 137 help_template = "\ 138{before-help}{name} {version} 139 140{usage-heading} {usage} 141 142{all-args}{after-help}", 143 styles = Styles::styled() 144 .header(styling::AnsiColor::Yellow.on_default()) 145 .usage(styling::AnsiColor::Yellow.on_default()) 146 .literal(styling::AnsiColor::Green.on_default()) 147)] 148pub enum Command { 149 /// Build the project 150 Build { 151 /// Consider the build failed if the package contains any warnings 152 #[arg(long)] 153 warnings_as_errors: bool, 154 155 /// Which compilation target to use 156 #[arg(short, long, ignore_case = true, help = target_doc())] 157 target: Option<Target>, 158 159 #[arg(long, help = no_print_progress_doc())] 160 no_print_progress: bool, 161 }, 162 163 /// Type check the project 164 Check { 165 /// Which compilation target to use 166 #[arg(short, long, ignore_case = true, help = target_doc())] 167 target: Option<Target>, 168 }, 169 170 /// Publish the project to the Hex package repository 171 /// 172 /// Please ensure your package is suitable for production use before 173 /// publishing. If you have a prototype package that you wish to use 174 /// in another project then use git dependencies instead of publishing 175 /// to the package repository. 176 /// 177 /// This command optionally accepts the environment variable 178 /// `HEXPM_API_KEY`, which can hold a Hex API key to authenticate 179 /// with Hex. 180 /// 181 #[command(verbatim_doc_comment)] 182 Publish { 183 /// Replace the latest release with this one 184 #[arg(long)] 185 replace: bool, 186 /// Automatically accept confirmation prompts 187 #[arg(short, long)] 188 yes: bool, 189 }, 190 191 /// Render HTML documentation for the package 192 /// 193 /// There are several options in `gleam.toml` that can be used to 194 /// configure the output. 195 /// 196 /// repository = { type = "github", user = "lpil", repo = "wibble" } 197 /// 198 /// Specify the location of the source code repository for the package. 199 /// This will add a link to the side bar, and add "view code" links for 200 /// the documented types and values. 201 /// 202 /// links = [ 203 /// { title = "Home page", href = "https://example.com" }, 204 /// { title = "Other site", href = "https://another.example.com" }, 205 /// ] 206 /// 207 /// Specify some additional links to include in the sidebar. 208 /// 209 /// [documentation] 210 /// pages = [ 211 /// { title = "My Page", path = "my-page.html", source = "./path/to/my-page.md" }, 212 /// ] 213 /// 214 /// Specify additional markdown pages to include in the documentation, 215 /// with links for each added to the sidebar. 216 /// 217 #[command(subcommand, verbatim_doc_comment)] 218 Docs(Docs), 219 220 /// Work with dependency packages 221 /// 222 /// The packages and the acceptable version ranges are specified in 223 /// `gleam.toml`. You can edit this file manually, or use the `gleam add` 224 /// and `gleam remove` commands. 225 /// 226 /// Package versions follow semantic versioning: MAJOR.MINOR.PATCH. 227 /// - Major updates include breaking changes, either type changes or 228 /// semantic changes. 229 /// - Minor updates include new functionality, but no breaking changes. 230 /// - Patch updates include only bug fixes. 231 /// 232 /// Dependency resolution will be performed automatically by any command 233 /// that builds your project. Once versions have been selected they are 234 /// written to `manifest.toml`, which locks the package to those versions, 235 /// making your build deterministic. You should not edit this file manually. 236 /// 237 /// To upgrade the dependencies you can use the `gleam update` command, 238 /// which will select the newest versions compatible with the requirements 239 /// in `gleam.toml`. 240 /// 241 /// The `[dependencies]` section of `gleam.toml` holds the production 242 /// dependencies. These are included in your production application, or 243 /// are used as the dependencies when published as a library. The 244 /// `[dev_dependencies]` section holds dependencies that are only used 245 /// during development, e.g. code used for testing the package. 246 /// 247 /// ## Syntax examples: 248 /// 249 /// [dependencies] 250 /// wibble = ">= 1.2.0 and < 2.0.0" 251 /// 252 /// Require the package `wibble`, permitting versions greater than or 253 /// equal to 1.2.0, but lower than 2.0.0. 254 /// 255 /// [dependencies] 256 /// wibble = ">= 1.2.0 and < 2.0.0 and != 1.4.1" 257 /// 258 /// Permit a range, but deny a specific version within that range. This 259 /// could be useful if there is a version known to have a bug. 260 /// 261 /// [dependencies] 262 /// wibble = { git = "https://example.com/wibble.git", ref = "a8b3c5d82" } 263 /// 264 /// A dependency fetched from Git instead of from Hex. This is useful 265 /// for using packages of yours that are not-yet production-ready, or 266 /// for bug fixes that have not yet been published to Hex. 267 /// 268 /// [dependencies] 269 /// wibble = { path = "../wibble" } 270 /// 271 /// A local dependency, on your computer. This is useful for testing and 272 /// and for applications made of multiple packages in a single version 273 /// control repository. 274 /// 275 #[command(subcommand, verbatim_doc_comment)] 276 Deps(Dependencies), 277 278 /// Update dependency packages to their latest versions 279 Update(UpdateOptions), 280 281 /// Work with the Hex package manager 282 #[command(subcommand)] 283 Hex(Hex), 284 285 /// Create a new project 286 New(NewOptions), 287 288 /// Format source code 289 Format { 290 /// The files or directories to format 291 #[arg(default_value = ".")] 292 files: Vec<String>, 293 294 /// Read source from standard-input 295 #[arg(long)] 296 stdin: bool, 297 298 /// Only check if inputs are formatted correctly, erroring if they are not 299 #[arg(long)] 300 check: bool, 301 }, 302 303 /// Rewrite deprecated Gleam code 304 Fix, 305 306 /// Start an Erlang REPL with the Gleam code loaded 307 Shell, 308 309 /// Run the project 310 /// 311 /// This command runs the `main` function from the `<PROJECT_NAME>` module. 312 #[command(trailing_var_arg = true)] 313 Run { 314 /// Which compilation target to use 315 #[arg(short, long, ignore_case = true, help = target_doc())] 316 target: Option<Target>, 317 318 /// Which runtime to use 319 #[arg(long, ignore_case = true, help = runtime_doc())] 320 runtime: Option<Runtime>, 321 322 /// The module to run 323 #[arg(short, long)] 324 module: Option<String>, 325 326 #[arg(long, help = no_print_progress_doc())] 327 no_print_progress: bool, 328 329 arguments: Vec<String>, 330 }, 331 332 /// Run the project tests 333 /// 334 /// This command runs the `main` function from the `<PROJECT_NAME>_test` module. 335 #[command(trailing_var_arg = true)] 336 Test { 337 /// Which compilation target to use 338 #[arg(short, long, ignore_case = true, help = target_doc())] 339 target: Option<Target>, 340 341 /// Which runtime to use 342 #[arg(long, ignore_case = true, help = runtime_doc())] 343 runtime: Option<Runtime>, 344 345 arguments: Vec<String>, 346 }, 347 348 /// Run the project development entrypoint 349 /// 350 /// This command runs the `main` function from the `<PROJECT_NAME>_dev` module. 351 #[command(trailing_var_arg = true)] 352 Dev { 353 /// Which compilation target to use 354 #[arg(short, long, ignore_case = true, help = target_doc())] 355 target: Option<Target>, 356 357 /// Which runtime to use 358 #[arg(long, ignore_case = true, help = runtime_doc())] 359 runtime: Option<Runtime>, 360 361 #[arg(long, help = no_print_progress_doc())] 362 no_print_progress: bool, 363 364 arguments: Vec<String>, 365 }, 366 367 /// A low-level API for compiling a single Gleam package 368 /// 369 /// This is to be used by other build tools to implement support for Gleam 370 /// code. It is not used directly by humans. 371 /// 372 #[command(verbatim_doc_comment)] 373 CompilePackage(CompilePackage), 374 375 /// Read and print gleam.toml for debugging 376 #[command(hide = true)] 377 PrintConfig, 378 379 /// Add new dependencies 380 /// 381 /// The newest compatible version of the package is determined, and then 382 /// `gleam.toml` is updated to require at least that version, with a range 383 /// permitting future patch and minor updates. 384 /// 385 /// Add the package "wibble": 386 /// gleam add wibble 387 /// 388 /// Add the package "wibble", requiring version >= v2.0.0 and < v3.0.0: 389 /// gleam add wibble@2 390 /// 391 /// Add the package "wibble", requiring version >= v2.5.1 and < v3.0.0: 392 /// gleam add wibble@2.5.1 393 /// 394 /// Add multiple packages: 395 /// gleam add wibble@2 warble@1 396 /// 397 /// Add a package as a non-production dependency: 398 /// gleam add --dev wibble 399 /// 400 /// You can also edit `gleam.toml` directly, for further control over your 401 /// package dependencies. Run `gleam help deps` for documentation on the 402 /// format. 403 /// 404 #[command(verbatim_doc_comment)] 405 Add { 406 /// The names of Hex packages to add 407 #[arg(required = true)] 408 packages: Vec<String>, 409 410 /// Add the packages as dev-only dependencies 411 #[arg(long)] 412 dev: bool, 413 }, 414 415 /// Remove project dependencies 416 Remove { 417 /// The names of packages to remove 418 #[arg(required = true)] 419 packages: Vec<String>, 420 }, 421 422 /// Delete any build artifacts for this project 423 Clean, 424 425 /// Run the language server, to be used by editors 426 #[command(name = "lsp")] 427 LanguageServer, 428 429 /// Export something useful from the Gleam project 430 #[command(subcommand)] 431 Export(ExportTarget), 432} 433 434impl Command { 435 pub fn run(self, directory: Utf8PathBuf) -> Result<(), Error> { 436 match self { 437 Self::Build { 438 target, 439 warnings_as_errors, 440 no_print_progress, 441 } => { 442 let paths = find_project_paths(directory)?; 443 command_build(&paths, target, warnings_as_errors, no_print_progress) 444 } 445 446 Self::Check { target } => { 447 let paths = find_project_paths(directory)?; 448 command_check(&paths, target) 449 } 450 451 Self::Docs(Docs::Build { open, target }) => { 452 let paths = find_project_paths(directory)?; 453 docs::build(&paths, docs::BuildOptions { open, target }) 454 } 455 456 Self::Docs(Docs::Publish) => { 457 let paths = find_project_paths(directory)?; 458 docs::publish(&paths) 459 } 460 461 Self::Docs(Docs::Remove { package, version }) => docs::remove(package, version), 462 463 Self::Format { 464 stdin, 465 files, 466 check, 467 } => format::run(stdin, check, files), 468 469 Self::Fix => { 470 let paths = find_project_paths(directory)?; 471 fix::run(&paths) 472 } 473 474 Self::Deps(Dependencies::List) => { 475 let paths = find_project_paths(directory)?; 476 dependencies::list(&paths) 477 } 478 479 Self::Deps(Dependencies::Download) => { 480 let paths = find_project_paths(directory)?; 481 download_dependencies(&paths) 482 } 483 484 Self::Deps(Dependencies::Outdated) => { 485 let paths = find_project_paths(directory)?; 486 dependencies::outdated(&paths) 487 } 488 489 Self::Deps(Dependencies::Update(options)) => { 490 let paths = find_project_paths(directory)?; 491 dependencies::update(&paths, options.packages) 492 } 493 494 Self::Deps(Dependencies::Tree(options)) => { 495 let paths = find_project_paths(directory)?; 496 dependencies::tree(&paths, options) 497 } 498 499 Self::Hex(Hex::Authenticate) => hex::authenticate(), 500 501 Self::New(options) => new::create(options, COMPILER_VERSION), 502 503 Self::Shell => { 504 let paths = find_project_paths(directory)?; 505 shell::command(&paths) 506 } 507 508 Self::Run { 509 target, 510 arguments, 511 runtime, 512 module, 513 no_print_progress, 514 } => { 515 let paths = find_project_paths(directory)?; 516 run::command( 517 &paths, 518 arguments, 519 target, 520 runtime, 521 module, 522 run::Which::Src, 523 no_print_progress, 524 ) 525 } 526 527 Self::Test { 528 target, 529 arguments, 530 runtime, 531 } => { 532 let paths = find_project_paths(directory)?; 533 run::command( 534 &paths, 535 arguments, 536 target, 537 runtime, 538 None, 539 run::Which::Test, 540 false, 541 ) 542 } 543 544 Self::Dev { 545 target, 546 arguments, 547 runtime, 548 no_print_progress, 549 } => { 550 let paths = find_project_paths(directory)?; 551 run::command( 552 &paths, 553 arguments, 554 target, 555 runtime, 556 None, 557 run::Which::Dev, 558 no_print_progress, 559 ) 560 } 561 562 Self::CompilePackage(opts) => compile_package::command(opts), 563 564 Self::Publish { replace, yes } => { 565 let paths = find_project_paths(directory)?; 566 publish::command(&paths, replace, yes) 567 } 568 569 Self::PrintConfig => { 570 let paths = find_project_paths(directory)?; 571 print_config(&paths) 572 } 573 574 Self::Hex(Hex::Retire { 575 package, 576 version, 577 reason, 578 message, 579 }) => hex::retire(package, version, reason, message), 580 581 Self::Hex(Hex::Unretire { package, version }) => hex::unretire(package, version), 582 583 Self::Hex(Hex::Revert { package, version }) => { 584 let paths = find_project_paths(directory)?; 585 hex::revert(&paths, package, version) 586 } 587 588 Self::Hex(Hex::Owner(Owner::Add { 589 package, 590 username_or_email, 591 level, 592 })) => owner::add(package, username_or_email, level), 593 594 Self::Hex(Hex::Owner(Owner::Transfer { 595 package, 596 username_or_email, 597 })) => owner::transfer(package, username_or_email), 598 599 Self::Add { packages, dev } => { 600 let paths = find_project_paths(directory)?; 601 add::command(&paths, packages, dev) 602 } 603 604 Self::Remove { packages } => { 605 let paths = find_project_paths(directory)?; 606 remove::command(&paths, packages) 607 } 608 609 Self::Update(options) => { 610 let paths = find_project_paths(directory)?; 611 dependencies::update(&paths, options.packages) 612 } 613 614 Self::Clean => { 615 let paths = find_project_paths(directory)?; 616 clean(&paths) 617 } 618 619 Self::LanguageServer => lsp::main(), 620 621 Self::Export(ExportTarget::ErlangShipment) => { 622 let paths = find_project_paths(directory)?; 623 export::erlang_shipment(&paths) 624 } 625 Self::Export(ExportTarget::Escript) => { 626 let paths = find_project_paths(directory)?; 627 export::escript(&paths) 628 } 629 Self::Export(ExportTarget::HexTarball) => { 630 let paths = find_project_paths(directory)?; 631 export::hex_tarball(&paths) 632 } 633 Self::Export(ExportTarget::JavascriptPrelude) => export::javascript_prelude(), 634 Self::Export(ExportTarget::TypescriptPrelude) => export::typescript_prelude(), 635 Self::Export(ExportTarget::PackageInterface { output }) => { 636 let paths = find_project_paths(directory)?; 637 export::package_interface(&paths, output) 638 } 639 Self::Export(ExportTarget::PackageInformation { output }) => { 640 let paths = find_project_paths(directory)?; 641 export::package_information(&paths, output) 642 } 643 } 644 } 645} 646 647fn template_doc() -> &'static str { 648 "The template to use" 649} 650 651fn target_doc() -> &'static str { 652 "The platform to target" 653} 654 655fn no_print_progress_doc() -> &'static str { 656 "Don't print progress information" 657} 658 659fn runtime_doc() -> &'static str { 660 "The JavaScript runtime to target. This is only available on the \ 661 JavaScript target" 662} 663 664#[derive(Subcommand, Debug, Clone)] 665pub enum ExportTarget { 666 /// Precompiled Erlang in a single file, suitable for CLIs 667 Escript, 668 /// Precompiled Erlang, suitable for deployment 669 ErlangShipment, 670 /// The package bundled into a tarball, suitable for publishing to Hex 671 HexTarball, 672 /// The JavaScript prelude module 673 JavascriptPrelude, 674 /// The TypeScript prelude module 675 TypescriptPrelude, 676 /// Information on the modules, functions, and types in the project in JSON format 677 PackageInterface { 678 /// The path to write the JSON file to 679 #[arg(long = "out", required = true)] 680 output: Utf8PathBuf, 681 }, 682 /// Package information (gleam.toml) in JSON format 683 PackageInformation { 684 /// The path to write the JSON file to 685 #[arg(long = "out", required = true)] 686 output: Utf8PathBuf, 687 }, 688} 689 690#[derive(Args, Debug, Clone)] 691pub struct NewOptions { 692 /// Location of the project root 693 pub project_root: String, 694 695 /// Name of the project 696 #[arg(long)] 697 pub name: Option<String>, 698 699 #[arg(long, ignore_case = true, default_value = "erlang", help = template_doc())] 700 pub template: new::Template, 701 702 /// Skip git initialization and creation of .gitignore, .git/* and .github/* files 703 #[arg(long)] 704 pub skip_git: bool, 705 706 /// Skip creation of .github/* files 707 #[arg(long)] 708 pub skip_github: bool, 709} 710 711#[derive(Args, Debug)] 712pub struct CompilePackage { 713 /// The compilation target for the generated project 714 #[arg(long, ignore_case = true, help = target_doc())] 715 target: Target, 716 717 /// The directory of the Gleam package 718 #[arg(long = "package")] 719 package_directory: Utf8PathBuf, 720 721 /// A directory to write compiled package to 722 #[arg(long = "out")] 723 output_directory: Utf8PathBuf, 724 725 /// A directories of precompiled Gleam projects 726 #[arg(long = "lib")] 727 libraries_directory: Utf8PathBuf, 728 729 /// The location of the JavaScript prelude module, relative to the `out` 730 /// directory. 731 /// 732 /// Required when compiling to JavaScript. 733 /// 734 /// This likely wants to be a `.mjs` file as NodeJS does not permit 735 /// importing of other JavaScript file extensions. 736 /// 737 #[arg(verbatim_doc_comment, long = "javascript-prelude")] 738 javascript_prelude: Option<Utf8PathBuf>, 739 740 /// Skip Erlang to BEAM bytecode compilation 741 #[arg(long = "no-beam")] 742 skip_beam_compilation: bool, 743} 744 745#[derive(Subcommand, Debug)] 746pub enum Dependencies { 747 /// List all dependency packages 748 List, 749 750 /// Download all dependency packages 751 Download, 752 753 /// List all outdated dependencies 754 Outdated, 755 756 /// Update dependency packages to their latest versions 757 Update(UpdateOptions), 758 759 /// Tree of all the dependency packages 760 Tree(TreeOptions), 761} 762 763#[derive(Subcommand, Debug)] 764pub enum Hex { 765 /// Retire a release from Hex 766 /// 767 /// This command uses the environment variable: 768 /// 769 /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager. 770 /// 771 #[command(verbatim_doc_comment)] 772 Retire { 773 /// The name of the package to retire 774 #[arg(long)] 775 package: String, 776 /// The version to retire 777 #[arg(long)] 778 version: String, 779 /// The reason for the retirement 780 #[arg(long)] 781 reason: RetirementReason, 782 message: Option<String>, 783 }, 784 785 /// Un-retire a release from Hex 786 /// 787 /// This command uses this environment variable: 788 /// 789 /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager. 790 /// 791 #[command(verbatim_doc_comment)] 792 Unretire { 793 /// The name of the package to unretire 794 #[arg(long)] 795 package: String, 796 /// The version to unretire 797 #[arg(long)] 798 version: String, 799 }, 800 801 /// Revert a release from Hex 802 /// 803 /// This command uses this environment variable: 804 /// 805 /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager. 806 /// 807 #[command(verbatim_doc_comment)] 808 Revert { 809 /// The name of the package to revert 810 #[arg(long)] 811 package: Option<String>, 812 813 /// The version to revert 814 #[arg(long)] 815 version: Option<String>, 816 }, 817 818 /// Deal with package ownership 819 #[command(subcommand)] 820 Owner(Owner), 821 822 /// Log in to Hex. Replaces the credentials with new ones if already logged in. 823 Authenticate, 824} 825 826#[derive(Subcommand, Debug)] 827pub enum Owner { 828 /// Adds a new owner to the given package on Hex 829 /// 830 /// This command uses this environment variable: 831 /// 832 /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate against the Hex package manager. 833 /// 834 #[command(verbatim_doc_comment)] 835 Add { 836 package: String, 837 838 /// The username or email of the additional owner 839 #[arg(long = "user")] 840 username_or_email: String, 841 842 /// The ownership level 843 #[arg(long, default_value = "maintainer")] 844 level: hexpm::OwnerLevel, 845 }, 846 847 /// Transfers ownership of the given package to a new Hex user 848 /// 849 /// This command uses this environment variable: 850 /// 851 /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate against the Hex package manager. 852 /// 853 #[command(verbatim_doc_comment)] 854 Transfer { 855 /// The name of the package 856 #[arg(long)] 857 package: String, 858 859 /// The username or email of the new owner 860 #[arg(long = "to")] 861 username_or_email: String, 862 }, 863} 864 865#[derive(Subcommand, Debug)] 866pub enum Docs { 867 /// Render HTML docs locally 868 Build { 869 /// Opens the docs in a browser after rendering 870 #[arg(long)] 871 open: bool, 872 873 /// Which compilation target to use 874 #[arg(short, long, ignore_case = true, help = target_doc())] 875 target: Option<Target>, 876 }, 877 878 /// Publish HTML docs to HexDocs 879 /// 880 /// This command uses this environment variable: 881 /// 882 /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager. 883 /// 884 #[command(verbatim_doc_comment)] 885 Publish, 886 887 /// Remove HTML docs from HexDocs 888 /// 889 /// This command uses this environment variable: 890 /// 891 /// - HEXPM_API_KEY: (optional) A Hex API key to authenticate with the Hex package manager. 892 /// 893 #[command(verbatim_doc_comment)] 894 Remove { 895 /// The name of the package 896 #[arg(long)] 897 package: String, 898 899 /// The version of the docs to remove 900 #[arg(long)] 901 version: String, 902 }, 903} 904 905pub fn main() { 906 initialise_logger(); 907 panic::add_handler(); 908 let stderr = cli::stderr_buffer_writer(); 909 let result = get_current_directory() 910 .and_then(|working_directory| Command::parse().run(working_directory)); 911 match result { 912 Ok(_) => { 913 tracing::info!("Successfully completed"); 914 } 915 Err(error) => { 916 tracing::error!(error = ?error, "Failed"); 917 let mut buffer = stderr.buffer(); 918 error.pretty(&mut buffer); 919 stderr.print(&buffer).expect("Final result error writing"); 920 std::process::exit(1); 921 } 922 } 923} 924 925fn command_check(paths: &ProjectPaths, target: Option<Target>) -> Result<()> { 926 let _ = build::main( 927 paths, 928 Options { 929 root_target_support: TargetSupport::Enforced, 930 warnings_as_errors: false, 931 codegen: Codegen::DepsOnly, 932 compile: Compile::All, 933 mode: Mode::Dev, 934 target, 935 no_print_progress: false, 936 }, 937 build::download_dependencies(paths, cli::Reporter::new())?, 938 )?; 939 Ok(()) 940} 941 942fn command_build( 943 paths: &ProjectPaths, 944 target: Option<Target>, 945 warnings_as_errors: bool, 946 no_print_progress: bool, 947) -> Result<()> { 948 let manifest = if no_print_progress { 949 build::download_dependencies(paths, NullTelemetry)? 950 } else { 951 build::download_dependencies(paths, cli::Reporter::new())? 952 }; 953 let _ = build::main( 954 paths, 955 Options { 956 root_target_support: TargetSupport::Enforced, 957 warnings_as_errors, 958 codegen: Codegen::All, 959 compile: Compile::All, 960 mode: Mode::Dev, 961 target, 962 no_print_progress, 963 }, 964 manifest, 965 )?; 966 Ok(()) 967} 968 969fn print_config(paths: &ProjectPaths) -> Result<()> { 970 let config = root_config(paths)?; 971 println!("{config:#?}"); 972 Ok(()) 973} 974 975fn clean(paths: &ProjectPaths) -> Result<()> { 976 fs::delete_directory(&paths.build_directory()) 977} 978 979fn initialise_logger() { 980 let enable_colours = std::env::var("GLEAM_LOG_NOCOLOUR").is_err(); 981 tracing_subscriber::fmt() 982 .with_writer(std::io::stderr) 983 .with_env_filter(std::env::var("GLEAM_LOG").unwrap_or_else(|_| "off".into())) 984 .with_target(false) 985 .with_ansi(enable_colours) 986 .without_time() 987 .init(); 988} 989 990fn find_project_paths(current_dir: Utf8PathBuf) -> Result<ProjectPaths> { 991 get_project_root(current_dir).map(ProjectPaths::new) 992} 993 994#[cfg(test)] 995fn project_paths_at_current_directory_without_toml() -> ProjectPaths { 996 let current_dir = get_current_directory().expect("Failed to get current directory"); 997 ProjectPaths::new(current_dir) 998} 999 1000fn download_dependencies(paths: &ProjectPaths) -> Result<()> { 1001 _ = dependencies::resolve_and_download( 1002 paths, 1003 cli::Reporter::new(), 1004 None, 1005 Vec::new(), 1006 dependencies::DependencyManagerConfig { 1007 use_manifest: dependencies::UseManifest::Yes, 1008 check_major_versions: dependencies::CheckMajorVersions::No, 1009 }, 1010 )?; 1011 Ok(()) 1012}