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