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