{"id":23112624,"url":"https://github.com/cvogt/cbt","last_synced_at":"2025-04-05T06:05:33.177Z","repository":{"id":51364863,"uuid":"43394868","full_name":"cvogt/cbt","owner":"cvogt","description":"CBT - fun, fast, intuitive, compositional, statically checked builds written in Scala","archived":false,"fork":false,"pushed_at":"2018-05-28T13:07:38.000Z","size":1371,"stargazers_count":489,"open_issues_count":224,"forks_count":59,"subscribers_count":28,"default_branch":"master","last_synced_at":"2025-03-29T05:04:38.169Z","etag":null,"topics":["build-automation","build-system","build-tool","cbt","cli","command-line","command-line-tool","dotty","frege","reproducible-builds","sbt","scala","scala-support"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cvogt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-09-29T21:14:08.000Z","updated_at":"2025-01-27T17:54:59.000Z","dependencies_parsed_at":"2022-09-04T07:23:10.380Z","dependency_job_id":null,"html_url":"https://github.com/cvogt/cbt","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cvogt%2Fcbt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cvogt%2Fcbt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cvogt%2Fcbt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cvogt%2Fcbt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cvogt","download_url":"https://codeload.github.com/cvogt/cbt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247294538,"owners_count":20915340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["build-automation","build-system","build-tool","cbt","cli","command-line","command-line-tool","dotty","frege","reproducible-builds","sbt","scala","scala-support"],"created_at":"2024-12-17T02:19:44.923Z","updated_at":"2025-04-05T06:05:33.158Z","avatar_url":"https://github.com/cvogt.png","language":"Scala","readme":"[![Join us on gitter](http://badges.gitter.im/cvogt/cbt.png)](https://gitter.im/cvogt/cbt)\n\n(For a tutorial scroll down.)\n\nChris' Build Tool (CBT) for Scala\n============================================\n\nEasy to learn and master, lightning fast and backed by a thriving community of enthusiasts and contributors. For talks, development roadmap, projects using cbt, etc see the wiki.\n\nWhat is CBT?\n----------------------------------------------\nCBT is a build tool meaning it helps orchestrating compilation, code and\ndocumentation generation, packaging, deployment and custom tooling for\nyour project. It mainly targets Scala projects but is not exclusive to them.\n\nCBT builds are full programs written using vanilla Scala code.\nFamiliar concepts make you feel right at home - build files are classes,\ntasks are defs, you customize using method overrides. You already know these\nthings and everything behaves as expected. That way implementing any\nbuild related requirement becomes as easy as writing any other Scala code.\n\nCBT is simple in the sense that it uses very few concepts.\nA single build uses classes, defs and inheritance.\nBuilds and binary dependencies can be composed to model \nmodules depending on each other.\n\nCBT believes good integration with existing tools to be very\nhelpful. In that spirit CBT aims for excellent integration with\nthe command line and your shell.\n\nCBT considers source files to be an excellent way to distribute code\nand has first class support for source and git dependencies.\n\nHow is CBT different from other build tools?\n----------------------------------------------\nNot all build tools allow you to write builds in a full programming language.\nCBT is based on the assumption that builds are complex enough problems to\nwarrant this and abstraction and re-use is better handled through libraries\nrather than some restricted, declarative DSL. CBT shares this philosophy with sbt.\n(This also means that integration with external tools such as an IDE better happens\nprogrammatically through an api rather than a static data representation such as xml.)\n\nLike sbt, CBT chooses Scala as its language of choice, trying to appeal to\nScala programmers allowing them to re-use their knowledge and the safety of the language.\n\nUnlike sbt 0.11 and later, CBT maps task execution to JVM method invocations.\nsbt implements its own self-contained task graph model and interpreter.\nThis allows sbt to have its model exactly fit the requirements.\nCBT instead uses existing JVM concepts for the solution and adds\ncustom concepts only when necessary. CBT assumes this to lead to better\nease of use due to familarity and better integration with existing tools\nsuch as interactive debuggers or stack traces because CBT's task call stack\nIS the JVM call stack.\n\nsbt 0.7 shared this design decision as many may have forgotten.\nHowever, CBT is still quite a bit simpler than even sbt 0.7 as\nCBT gets away with fewer concepts. sbt 0.7 had notions of\nmain vs test sources, multi-project builds, task-dependencies\nwhich weren't invocations and other concepts. CBT maps all of\nthese to def invocations and build composition instead.\n\nSystem requirements\n-------------------\n\nCBT is best tested under OSX. People are also using it also under\nUbuntu and Windows via cygwin. It should be easy to port CBT to\nother systems or drop the cygwin requirement. You will only\nhave to touch the launcher bash or .bat scripts.\nPlease contribute back if you fixed something :).\n\nYou currently need javac and realpath or gcc installed.\nnailgun is optional for speedup. gpg is required only for publishing maven artifacts.\n\nFeatures\n--------\n\nCBT supports the basic needs for Scala builds right now:\nCompiling, running, testing, packaging, publishing local and to sonatype,\nscaladoc, maven dependencies, source dependencies (e.g. for modularized projects),\ntriggering tasks on file changes, cross-compilation, reproducible builds.\n\nThere is also a growing number of plugins in `plugins/` and `stage2/plugins/`,\nbut some things you'd like may still be missing. Consider writing\na plugin in that case. It's super easy, just a trait. Share it :).\n\n\nTutorial\n--------\n\nThis section explains how to get started with cbt step-by-step.\nThere are also example projects with build files in examples/ and test/.\n\n### Installation\n\nIf you haven't cloned cbt yet, clone it now. Cloning is how you install cbt.\nWe know that's a bit unusual, but roll with it, there are good reasons :).\nOpen a shell, cd to the directory where you want to install cbt and execute:\n\n```\n$ git clone https://github.com/cvogt/cbt.git\n```\n\nThere are a bash script `cbt` and a `cbt.bat` in the checkout directory.\nAdd one to your `$PATH`, e.g. symlink it from `~/bin/cbt`.\n\nCheck that it works by calling `cbt`. You should see CBT compiling itself\nand showing a list of built-in tasks.\n\nGreat, you're all set up. Now, let's use cbt for a new example project.\nFollow the below steps. (There is also an experimental GUI described\nlater to create a project, but going through the steps this time will help\nyou understand what exactly is going on.)\n\n### Creating your first project\n\nCreate a new directory and cd into it. E.g. `my-project`.\n\n```\n$ mkdir my-project\n$ cd my-project\n```\n\nLet's create a tiny sample app. CBT can generate it for you. Just run:\n\n```\n$ cbt tools createMain\n```\n\n### Running your code\n\nNow there should be a file `Main.scala`, which prints `Hello World` when run.\nSo let's run it:\n\n```\n$ cbt run\n```\n\nYou should see how CBT first compiles your project, then runs it and prints\n`Hello World`. CBT created the file `Main.scala` top-level in your directory.\nYou can alternatively place `.scala` or `.java` files in `src/`\nor any of its subdirectories.\n\n### Creating a build file\n\nWithout a build file, CBT just uses some default build settings.\nLet's make the build more concrete by creating a build file.\n\nCBT can help you with that. Execute:\n\n```\n$ cbt tools createBuild\n```\n\nNow there should be a file `build/build.scala` with a sample `Build` class.\n\nBtw., a build file can have its own build and so on recursively like in sbt.\nWhen you create a file `build/build/build.scala` and change `Build` class in there\nto extend `BuildBuild`, it will be used to build your `build/build.scala`. You can\nadd built-time dependencies like plugins this way.\n\n### Adding dependencies\n\nIn the generated `build/build.scala` there are\nseveral examples for dependencies. We recommend using the constructor syntax\n`ScalaDependency` (for automatically adding the scala version to the artifact id)\nor `MavenDependency` (for leaving the artifact id as is). The sbt-style `%`-DSL\nsyntax is also supported for copy-and-paste convenience, but discouraged.\n\nAlright, let's enable the `override def dependencies`. Make sure to include\n`super.dependencies`, which currently only includes the Scala standard library.\nAdd a dependency of your choice, start using it from `Main.scala` and `cbt run` again.\n\nAs you can see CBT makes choice of the maven repository explicit. It does so for clarity.\n\n### Calling other tasks\n\nTasks are just defs. You can call any public zero-arguments method of your\n`Build class or its parents straight from the command line. To see how it works\nlet's call the compile task.\n\n```\n$ cbt compile\n```\n\n### Creating custom tasks\n\nIn order to create a custom task, simply add a new def to your Build class, e.g.\n\n```\nclass Build...{\n  ...\n  def foo = \"asdf\"\n}\n```\n\nNow call the def from the command line:\n\n```\n$ cbt foo\n```\n\nAs you can see it prints `asdf`. Adding tasks is that easy.\n\n### Triggering tasks on file-changes\n\nWhen you call a task, you can prefix it with `loop`. You need to\nhave fswatch install (e.g. via `brew install fswatch`).\nCBT then watches the source files, the build files and even CBT's own\nsource code and re-runs the task when anything changes. If necessary,\nthis forces CBT to re-build itself, the project's dependencies and the project itself.\n\nLet's try it. Let's loop the run task. Call this from the shell:\n\n```\n$ cbt loop run\n```\n\nNow change `Main.scala and see how cbt picks it up and re-runs it.\nCBT is fast. It may already be done re-compiling and re-running before\nyou managed to change windows back from your editor to the shell.\n\nTry changing the build file and see how CBT reacts to it as well.\n\nTo also clear the screen on each run use:\n```\n$ cbt loop clear run\n```\n\nTo call and restart the main method on file change (like sbt-revolver)\n```\n$ cbt direct loop restart\n```\n\n### Adding tests\n\nThe simplest way to add tests is putting a few assertions into the previously\ncreated Main.scala and be done with it. Alternatively you can add a test\nframework plugin to your build file to use something more sophisticated.\n\nThis however means that the class files of your tests will be included in the\njar should you create one. If that's fine, you are done :). If it is not you\nneed to create another project, which depends on your previous project. This\nproject will be packaged separately or you can disable packaging there. Let's create\nsuch a project now.\n\nYour project containing tests can be anywhere but a recommended location is a\nsub-folder called `test/` in your main project. Let's create it and create a\nMain class and build file:\n\n```\n$ mkdir test\n$ cd test\n$ rm ../Main.scala\n$ cbt tools createMain\n$ cbt tools createBuild\n```\n\nWe also deleted the main projects Main.scala, because now that we created a new one\nwe would have two classes with the same name on the classpath which can be very confusing.\n\nNow that we have a Main file in our test project, we can add some assertions to it.\nIn order for them to see the main projects code, we still need to do one more thing - \nadd a `DirectoryDependency` to your test project's build file. There is a similar example\nin the generated build.scala. What you need is this:\n\n```\noverride def dependencies = super.dependencies ++ Seq(\n  DirectoryDependency( projectDirectory ++ \"/..\" )\n)\n```\n\nThis successfully makes your test project's code see the main projects code.\nAdd some class to your main project, e.g. `case class Foo(i: Int = 5)`. Now\nput an assertion into the Main class of your test project, e.g.\n`assert(Foo().i == 5)` and hit `cbt run` inside your test project.\n\nMake sure you deleted your main projects class Main when running your tests.\n\nCongratulations, you successfully created a dependent project and ran your tests.\n\n### Dynamic overrides and eval\n\nBy making your Build extend trait `CommandLineOverrides` you get access to the `eval` and `with` commands.\n\n`eval` allows you to evaluate scala expressions in the scope of your build and show the result.\nYou can use this to inspect your build.\n\n```\n$ cbt eval '1 + 1'\n2\n\n$ cbt eval scalaVersion\n2.11.8\n\n$ cbt eval 'sources.map(_.string).mkString(\":\")'\n/a/b/c:/d/e/f\n```\n\n`with` allows you to inject code into your build (or rather a dynamically generated subclass).\nFollow the code with another task name and arguments if needed to run tasks of your modified build.\nYou can use this to override build settings dynamically.\n\n```\n$ cbt with 'def hello = \"Hello\"' hello\nHello\n\n$ cbt with 'def hello = \"Hello\"; def world = \"World\"; def helloWorld = hello ++ \" \" ++ world' helloWorld\nHello World\n\n$ cbt with 'def version = super.version ++ \"-SNAPSHOT\"' package\n/a/b/c/e-SNAPSHOT.jar\n```\n\n### Multi-projects Builds\n\nA single build only handles a single project in CBT. So there isn't exactly\nsuch a things as a Multi-project Build. Instead you can simply write multiple\nprojects that depend on each other. We have already done that with tests above,\nbut you can do the exact same thing to modularize your project into multiple ones.\n\n### Reproducible builds\n\nTo achieve reproducible builds, you'll need to tie your build files to a particular\nCBT-version. It doesn't matter what version of CBT you are actually running,\nas long as the `BuildInterface` is compatible (which should be true for a large number\nof versions and we may find a better solution long term. If you see a compile error \nduring compilation of CBT itself that some method in BuildInterface was not\nimplemented or incorrectly implemented, you may be running an incompatible CBT\nversion. We'll try to fix that later, but for now you might have to checkout\nthe required hash of CBT by hand.).\n\nWhen you specify a particular version, CBT will use that one instead of the installed one.\n\nYou can specify one by adding one line right before `class Build`. It looks like this:\n\n```\n// cbt:https://github.com/cvogt/cbt.git#f11b8318b85f16843d8cfa0743f64c1576614ad6\nclass Build...\n```\n\nThe URL points to any git repository containing one of CBT's forks. You currently\nhave to use a stable reference - i.e. a hash or tag. (Checkouts are currently not\nupdated. If you refer to a branch or tag which is moved on the remote, CBT\nwill not realize that and keep using the old version).\n\n### Using CBT like a boss\n\nDo you own your Build Tool or does your Build Tool own you? CBT makes it easy for YOU\nto be in control. We try to work on solid documentation, but even good\ndocumentation never tells the whole truth. Documentation can tell how to use\nsomething and why things are happening, but only the code can tell all the\ndetails of what exactly is happening. Reading the code can be intimidating for\nmany Scala libraries, but not so with CBT. The source code is easy to read\nto the point that even Scala beginners will be able to understand it. So\ndon't be afraid to actually look under the hood and check out what's happening.\n\nAnd guess what, you already have the source code on your disk, because\nyou installed CBT by cloning its git repository. You can even debug CBT and\nyour build files in an interactive debugger like IntelliJ after some minor setup.\n\nFinally, you can easily change CBT's code. Then CBT re-builds itself when you try\nto use it the next time. This means any changes you make are instantly reflected.\nThis and the simple code make it super easy to fix bugs or add features yourself\nand feed them back into main line CBT.\n\nWhen debugging things, it can help to enable CBT's debug logging by passing\n`-Dlog=all` to CBT (or a logger name instead of `all`).\n\nOther design decisions\n--------------------\n\nCBT tries to couple its code very loosely. OO is used for configuration in build files.\nInteresting logic is in simple supporting library classes/objects, which can be used\nindependently. You could even build a different configuration api than OO on top of them.\n\n\nKnown limitations\n--------------------------\n- currently CBT supports no generic task scoping. A solution is known, but not implemented.\n  For now manually create intermediate tasks which serve as scoping for\n  known situations and encode the scope in the name, e.g. fastOptScalaJsOptions\n- currently CBT supports no dynamic overrides of tasks. A solution is known, but not implemented.\n  scalaVersion and version are passed through the context instead for dynamic overrides.\n- there is currently no built-in support for resources being added to a jar.\n  Should be simple to add, consider a PR\n- test framework support is currently a bit spotty but actively being worked on\n- concurrent task and build execution is currently disabled\n- CBT uses its own custom built maven resolver, which is really fast,\n  but likely does not work in some edge cases. Those may or may not be easy to fix.\n  We should add optional coursier integration back for a more complete solution.\n\nKnown bugs\n-------------\n- currently there is a bug in CBT where dependent builds may miss changes in the things\n  they depend on. Deleting all target directories and starting from scratch helps.\n- There are some yet unknown bugs which can be solved by killing the nailgun background process\n  and/or re-running the desired cbt task multiple times until it succeeds.\n- if you ever see no output from a command but expect some, make sure you are in the right directory\n  and try to see if any of the above recommendations help\n\n\nIDE Support\n-------------------\n\n### IntelliJ\n\nIntelliJ IDEA has CBT support. Plugin for CBT support can be installed as any other IntelliJ plugin via JetBrains plugin repository. More information about IntellJ support and documentation can be found [here](https://github.com/darthorimar/intellij-cbt)\n\nPlugin page on JetBrains plugin repository: http://plugins.jetbrains.com/plugin/10482-cbt\n\nShell completions\n-------------------\n\n### Bash completions\nTo auto-complete cbt task names in bash do this:\n\n```\nmkdir ~/.bash_completion.d/\ncp shell-integration/cbt-completions.bash ~/.bash_completion.d/\n```\n\nAdd this to your .bashrc\n```\nfor f in ~/.bash_completion.d/*; do\n    source $f\ndone\n```\n\n### Fish shell completions\n\ncopy this line into your fish configuration, on OSX: `/.config/fish/config.fish`\n\n```\ncomplete -c cbt -a '(cbt taskNames)'\n```\n\n### Zsh completions\n\n##### Manual installation\nAdd the following to your `.zshrc`\n```\nsource /path/to/cbt/shell-integration/cbt-completions.zsh\n```\n##### oh-my-zsh\nIf using oh-my-zsh, you can install it as a plugin:\n```\nmkdir ~/.oh-my-zsh/custom/plugins/cbt\ncp shell-integration/cbt-completions.zsh ~/.oh-my-zsh/custom/plugins/cbt/cbt.plugin.zsh\n```\nThen enable it in your `.zshrc`:\n```\nplugins=( ... cbt)\n```\nExperimental GUI\n--------------------\n\n### Creating a project via the GUI\n\n`cd` into the directory inside of which you want to create a new project directory and run `cbt tools gui`.\n\nE.g.\n\n```\n$ cd ~/my-projects\n$ cbt tools gui\n```\n\nThis should start UI server at http://localhost:9080. There you can create Main class, CBT build,\nadd libraries, plugins, readme and other things. Let's say you choose `my-project` as the project name.\nThe GUI will create `~/my-projects/my-project` for you.\n\n\nPlugin-author guide\n--------------------\n\nA CBT plugin is a trait that is mixed into a Build class.\nOnly use this trait only for wiring things together.\nDon't put logic in there. Instead simply call methods\non a separate class or object which serves as a library\nfor your actual logic. It should be callable and testable\noutside of a Build class. This way the code of your plugin\nwill be easier to test and easier to re-use. Feel free\nto make your logic rely on CBT's logger.\n\n See `plugins/` for examples.\n\nScala.js support\n----------------\n\nCBT supports cross-project Scala.js builds.\nIt preserves same structure as in sbt (https://www.scala-js.org/doc/project/cross-build.html)\n\n 1. Example for user scalajs project is in: `$CBT_HOME/cbt/examples/scalajs-*`\n 2. `$CBT_HOME/cbt compile`\n    Will compile JVM and JS sources\n    `$CBT_HOME/cbt jsCompile`\n    Will compile JS sources\n    `$CBT_HOME/cbt jvmCompile`\n    Will compile JVM sources\n 3. `$CBT_HOME/cbt fastOptJS` and `$CBT_HOME/cbt fullOptJS`\n    Same as in Scala.js sbt project\n\n Note: Scala.js support is under ongoing development.\n\n Currently missing features:\n * No support for jsDependencies:\n   It means that all 3rd party dependencies should added manually, see scalajs build example\n * No support for test\n\n\nCBT productivity hacks\n----------------------\n\nonly show first 20 lines of type errors to catch the root ones\n```\ncbt c 2\u003e\u00261 | head -n 20\n```\n\nInheritance Pittfalls\n---------------------\n```\ntrait Shared extends BaseBuild{\n  // this lowers the type from Seq[Dependency] to Seq[DirectoryDependency]\n  override def dependencies = Seq( DirectoryDependency(...) )\n}\nclass Build(...) extends Shared{\n  // this now fails because GitDependency is not a DirectoryDependency\n  override def dependencies = Seq( GitDependency(...) )\n}\n// Solution: raise the type explicitly\ntrait Shared extends BaseBuild{\n  // this lowers the type from Seq[Dependency] to Seq[DirectoryDependency]\n  override def dependencies: Seq[Dependency] = Seq( DirectoryDependency(...) )\n}\n```\n\n```\ntrait Shared extends BaseBuild{\n  override def dependencies: Seq[Dependency] = Seq() // removes all dependencies, does not inclide super.dependencies\n}\ntrait SomePlugin extends BaseBuild{\n  // adds a dependency\n  override def dependencies: Seq[Dependency] = super.dependencies ++ Seq( baz )\n}\nclass Build(...) extends Shared with SomePlugin{\n  // dependencies does now contain baz here, which can be surprising\n}\n// Solution can be being careful about the order and using traits instead of classes for mixins\nclass Build(...) extends SomePlugin with Shared\n```\n","funding_links":[],"categories":["构建工具"],"sub_categories":["Spring Cloud框架"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcvogt%2Fcbt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcvogt%2Fcbt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcvogt%2Fcbt/lists"}