Scala CLI Documentation

repository·main·Indexed 20 days ago

https://github.com/virtuslab/scala-cli

A lightweight command-line tool for compiling, running, testing, and packaging Scala code. It serves as the official scala runner for Scala 3.5.0+ and provides a fast alternative to complex build tools for single-module workflows.

Tokens
124.4K
Snippets
550
Records
693
Agent score
69%

What's inside Scala CLI

  1. Overview of Scala CLI

    main

    Scala CLI is a command-line tool designed for interacting with the Scala language. It provides a streamlined way to compile, run, test, and package Scala code.

    While it shares similarities with traditional build tools, it is specifically designed for simplicity and does not aim to support multi-module projects or a task-based extension system.

    As of Scala 3.5.0, Scala CLI serves as the official scala runner for the language.

  2. What is Scala CLI?

    main

    Scala CLI is a tool designed to simplify the process of compiling, running, testing, and packaging Scala code. It provides a streamlined workflow for Scala developers by handling common tasks through a single interface.

    Key capabilities include:

    • Compiling Scala code.
    • Running Scala applications.
    • Packaging code into JAR files or system-specific formats like deb, rpm, and MSI.
    • REPL: Launching an interactive Read-Eval-Print Loop for rapid experimentation.
    • Testing: Compiling and executing test suites.

    Scala CLI supports recent Scala versions (3.x, 2.13.x, and 2.12.x) and allows switching between them easily using the --scala parameter. While it defaults to the JVM, it also supports Scala.js and Scala Native.

  3. What is Sclicheck and how does it work?

    main

    Sclicheck is a command-line tool used to verify documentation (cookbooks) by executing the commands and code snippets contained within .md files.

    Unlike tools that run commands in isolation, Sclicheck maintains a single workspace state throughout the entire document. This allows a sequence of commands to build upon each other (e.g., creating a file in one step, then compiling it in the next).

  4. How to compute project versions from Git

    main

    You can automate versioning by using the publish.computeVersion directive. This is particularly useful in CI environments.

    Supported values:

    • git:tag or git: Uses the latest stable git tag. If the tag is older than HEAD, it appends -SNAPSHOT. If no tag exists, it defaults to 0.1.0-SNAPSHOT.
    • git:dynver: Uses the latest tag (stable or unstable). If the tag is older than HEAD, it generates a dynamic version string following the format -{distance}-g{short_hash}-SNAPSHOT.

    You can also specify a path to a specific repository: git:tag:../my-repo or git:dynver:../my-repo.

    //> using publish.computeVersion git:tag
  5. How Scala CLI manages `.scalafmt.conf` files

    main

    Scala CLI searches for configuration in this order:

    1. The file specified by --scalafmt-conf.
    2. The current workspace directory.
    3. The git root directory.

    Depending on what is found, Scala CLI behaves as follows:

    • If a complete config is found: It uses it.
    • If a partial config is found: It creates a new .scalafmt.conf inside the .scala-build directory, copies the existing content, infers missing parameters, and uses that for execution.
    • If no config is found: It creates a .scalafmt.conf in .scala-build with inferred version and dialect.

    Saving configuration: If you use the --save-scalafmt-conf flag, Scala CLI will write the inferred parameters directly into your existing .scalafmt.conf file (if found) or create a new one in your current workspace directory.

  6. Refer to piped code using the `stdin` identifier

    main

    When mixing piped sources with on-disk files, you can refer to the code coming from standard input by using the identifier stdin. This allows on-disk files to depend on definitions provided via the pipe.

    Example: An on-disk file PrintMessage.scala that uses a definition from a piped Scala script:

    echo '@main def main() = println(stdin.message)' > PrintMessage.scala
    echo 'def message: String = "Hello"' | scala-cli PrintMessage.scala _.sc
  7. Include source files via using directives

    main

    You can include additional source files in your compilation by using the //> using file or //> using files directive. This is useful for splitting code across multiple files without a formal project structure.

    Supported file types: .java, .scala, .sc, or directories.

    //> using file Utils.scala
    
    object Main extends App {
      println(Utils.message)
    }
  8. Handle script file extensions with `shebang`

    main

    When using the shebang sub-command, the requirements for file extensions change:

    • No extension required: Files without extensions (e.g., my-script) can be run using scala-cli shebang my-script. However, these files must start with a valid shebang line.
    • Extension requirement: If a file does not have a .scala or .sc extension and does not contain a shebang line, scala-cli shebang will fail with an unrecognized source type error.
    • Automatic script mode: Files with no extensions are always treated as scripts by Scala CLI, even if they contain valid .scala code.

    Note: If you use scala-cli shebang on a file without an extension, ensure the file starts with a shebang line like #!/usr/bin/env -S scala-cli shebang ... to avoid source type errors.

  9. Understand the integration test structure

    main

    The integration test suite follows a hierarchical structure based on Scala versions:

    • Abstract Layer: *TestDefinitions.scala files contain the core test logic.
    • Concrete Layer: Traits like *TestsDefault, *Tests213, etc., implement the logic for specific Scala versions.
    • Supported Scala Version Traits:
      • TestDefault
      • Test212
      • Test213
      • Test3Lts
      • Test3NextRc

    This structure allows the same test logic to be applied across different Scala runtime environments.

  10. How to manage project scope (Directories vs Single Files) in an IDE

    main

    When working with an IDE, the IDE imports the exact build configuration you provide via Scala CLI.

    To ensure all files within a folder are automatically included in your IDE project and builds, run setup-ide on the directory:

    scala-cli setup-ide some-directory
    # or
    cd some-directory && scala-cli setup-ide .

    Using Single Files

    If you run setup-ide on a specific file, only that file is included in the build. Other files in the same directory will be visible in your IDE's file explorer but will not be part of the compilation/build. To include multiple specific files, you must list them all:

    scala-cli setup-ide some-directory/A.scala some-directory/B.scala
    scala-cli setup-ide some-directory/A.scala some-directory/B.scala
  11. Compile and use multiple scripts together

    main

    When you pass multiple .sc files to Scala CLI, they are compiled together into a single context, allowing them to reference each other.

    • Naming: Script names are inferred from the filename (e.g., hello.sc becomes hello).
    • Packages: If a script is in a subdirectory, its package name is inferred from the relative path from the project root. For example, my-app/constants/message.sc is in the constants.message package.
    • Piped Scripts: When using a script from stdin, reference it using the stdin keyword.

    To disambiguate which script to run when multiple scripts are present, use the --main-class flag. For Scala 2 scripts, use the filename without the _sc suffix.

    # Running multiple scripts together
    scala-cli hello.sc message.sc
    
    # Specifying a main class to disambiguate
    scala-cli my-app --main-class main_sc
    
    # Referencing a piped script via stdin
    echo 'def message: String = "Hello"' | scala-cli PrintMessage.scala _.sc