├── project ├── build.properties └── plugins.sbt ├── src ├── sbt-test │ ├── sbt-frege │ │ ├── mixed │ │ │ ├── project │ │ │ │ └── plugins.sbt │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ ├── frege │ │ │ │ │ └── com │ │ │ │ │ │ └── earldouglas │ │ │ │ │ │ └── helloworld │ │ │ │ │ │ └── HelloWorld.fr │ │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── earldouglas │ │ │ │ │ └── helloworld │ │ │ │ │ └── HelloFrege.java │ │ │ └── test │ │ ├── simple │ │ │ ├── project │ │ │ │ └── plugins.sbt │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── frege │ │ │ │ │ └── com │ │ │ │ │ └── earldouglas │ │ │ │ │ └── helloworld │ │ │ │ │ └── HelloWorld.fr │ │ │ └── test │ │ ├── imports │ │ │ ├── project │ │ │ │ └── plugins.sbt │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── frege │ │ │ │ │ ├── Main.fr │ │ │ │ │ └── example │ │ │ │ │ ├── Other.fr │ │ │ │ │ └── Hello.fr │ │ │ └── test │ │ ├── with-test │ │ │ ├── project │ │ │ │ └── plugins.sbt │ │ │ ├── src │ │ │ │ ├── main │ │ │ │ │ └── frege │ │ │ │ │ │ └── com │ │ │ │ │ │ └── earldouglas │ │ │ │ │ │ └── helloworld │ │ │ │ │ │ └── HelloWorld.fr │ │ │ │ └── test │ │ │ │ │ └── frege │ │ │ │ │ └── com │ │ │ │ │ └── earldouglas │ │ │ │ │ └── helloworld │ │ │ │ │ └── HelloWorldTest.fr │ │ │ └── test │ │ ├── frege-from-java │ │ │ ├── project │ │ │ │ └── plugins.sbt │ │ │ ├── build.sbt │ │ │ ├── plainFrege │ │ │ │ └── src │ │ │ │ │ └── main │ │ │ │ │ └── frege │ │ │ │ │ └── com │ │ │ │ │ └── earldouglas │ │ │ │ │ └── helloworld │ │ │ │ │ └── HelloWorld.fr │ │ │ ├── javaCallsFrege │ │ │ │ └── src │ │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── earldouglas │ │ │ │ │ └── helloworld │ │ │ │ │ └── HelloFrege.java │ │ │ └── test │ │ └── java-from-frege │ │ │ ├── project │ │ │ └── plugins.sbt │ │ │ ├── build.sbt │ │ │ ├── plainJava │ │ │ └── src │ │ │ │ └── main │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── earldouglas │ │ │ │ └── helloworld │ │ │ │ └── HelloWorld.java │ │ │ ├── fregeCallsJava │ │ │ └── src │ │ │ │ └── main │ │ │ │ └── frege │ │ │ │ └── com │ │ │ │ └── earldouglas │ │ │ │ └── helloworld │ │ │ │ └── HelloJava.fr │ │ │ └── test │ └── examples │ │ └── servlet │ │ ├── build.sbt │ │ ├── test │ │ ├── project │ │ └── plugins.sbt │ │ ├── src │ │ └── main │ │ │ ├── webapp │ │ │ └── WEB-INF │ │ │ │ └── web.xml │ │ │ ├── frege │ │ │ └── FregeWeb.fr │ │ │ └── scala │ │ │ └── FregeServlet.scala │ │ ├── README.md │ │ ├── test-get.sbt │ │ └── test-await.sbt └── main │ ├── scala-2.12 │ └── Compat.scala │ ├── scala-3 │ └── Compat.scala │ └── scala │ └── SbtFrege.scala ├── shell.nix ├── .github └── workflows │ └── build.yml ├── CONTRIBUTING.md ├── LICENSE └── README.md /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.11.7 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/mixed/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.earldouglas" % "sbt-frege" % "0.1.0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/simple/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.earldouglas" % "sbt-frege" % "0.1.0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/imports/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.earldouglas" % "sbt-frege" % "0.1.0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/with-test/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.earldouglas" % "sbt-frege" % "0.1.0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/frege-from-java/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.earldouglas" % "sbt-frege" % "0.1.0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/java-from-frege/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.earldouglas" % "sbt-frege" % "0.1.0-SNAPSHOT") 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/frege-from-java/build.sbt: -------------------------------------------------------------------------------- 1 | lazy val plainFrege = project 2 | lazy val javaCallsFrege = project dependsOn plainFrege 3 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/java-from-frege/build.sbt: -------------------------------------------------------------------------------- 1 | lazy val plainJava = project 2 | lazy val fregeCallsJava = project dependsOn plainJava 3 | -------------------------------------------------------------------------------- /src/sbt-test/examples/servlet/build.sbt: -------------------------------------------------------------------------------- 1 | libraryDependencies += "javax.servlet" % "javax.servlet-api" % "3.0.1" % "provided" 2 | enablePlugins(JettyPlugin) 3 | -------------------------------------------------------------------------------- /src/sbt-test/examples/servlet/test: -------------------------------------------------------------------------------- 1 | > jetty:quickstart 2 | > await 8080 3 | > get http://localhost:8080/hello 200 4 | > jetty:stop 5 | -> get http://localhost:8080/hello 200 6 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/imports/src/main/frege/Main.fr: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import example.Hello 4 | import example.Other 5 | 6 | main = putStrLn "this is the main" 7 | -------------------------------------------------------------------------------- /src/sbt-test/examples/servlet/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "4.0.1") 2 | addSbtPlugin("com.earldouglas" % "sbt-frege" % "0.1.0-SNAPSHOT") 3 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/imports/src/main/frege/example/Other.fr: -------------------------------------------------------------------------------- 1 | module example.Other where 2 | 3 | data Other = Any | Old 4 | 5 | main :: [String] -> IO () 6 | main _ = do 7 | putStrLn "This is the other" 8 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/mixed/src/main/frege/com/earldouglas/helloworld/HelloWorld.fr: -------------------------------------------------------------------------------- 1 | package com.earldouglas.helloworld.HelloWorld where 2 | 3 | main :: [String] -> IO () 4 | main _ = print "Hello, world!" 5 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/simple/src/main/frege/com/earldouglas/helloworld/HelloWorld.fr: -------------------------------------------------------------------------------- 1 | package com.earldouglas.helloworld.HelloWorld where 2 | 3 | main :: [String] -> IO () 4 | main _ = print "Hello, world!" 5 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/with-test/src/main/frege/com/earldouglas/helloworld/HelloWorld.fr: -------------------------------------------------------------------------------- 1 | package com.earldouglas.helloworld.HelloWorld where 2 | 3 | main :: [String] -> IO () 4 | main _ = print "Hello, world!" 5 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value 2 | 3 | addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") 4 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.12.2") 5 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/frege-from-java/plainFrege/src/main/frege/com/earldouglas/helloworld/HelloWorld.fr: -------------------------------------------------------------------------------- 1 | package com.earldouglas.helloworld.HelloWorld where 2 | 3 | main :: [String] -> IO () 4 | main _ = print "Hello, world!" 5 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/with-test/src/test/frege/com/earldouglas/helloworld/HelloWorldTest.fr: -------------------------------------------------------------------------------- 1 | package com.earldouglas.helloworld.HelloWorldTest where 2 | 3 | import com.earldouglas.helloworld.HelloWorld () 4 | 5 | someTest :: IO () 6 | someTest = HelloWorld.main [] 7 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/java-from-frege/plainJava/src/main/java/com/earldouglas/helloworld/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package com.earldouglas.helloworld; 2 | 3 | public class HelloWorld { 4 | public static void main(String[] args) { 5 | System.out.println("Hello, world!"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/imports/src/main/frege/example/Hello.fr: -------------------------------------------------------------------------------- 1 | module example.Hello where 2 | 3 | data Other = Any | Old 4 | 5 | showOther :: Other -> String 6 | showOther Any = "any" 7 | showOther Old = "old" 8 | 9 | main :: [String] -> IO () 10 | main _ = println "Hello, world!" 11 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/mixed/src/main/java/com/earldouglas/helloworld/HelloFrege.java: -------------------------------------------------------------------------------- 1 | package com.earldouglas.helloworld; 2 | 3 | public class HelloFrege { 4 | public static void main(String[] args) { 5 | HelloWorld.main(args); // Will not compile unless Frege code is compiled 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import {} }: 2 | let 3 | jdk = pkgs.jdk8; 4 | in 5 | pkgs.mkShell { 6 | nativeBuildInputs = [ 7 | (pkgs.sbt.override { jre = jdk; }) 8 | ]; 9 | shellHook = '' 10 | export JAVA_HOME=${jdk} 11 | PATH="${jdk}/bin:$PATH" 12 | ''; 13 | } 14 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/frege-from-java/javaCallsFrege/src/main/java/com/earldouglas/helloworld/HelloFrege.java: -------------------------------------------------------------------------------- 1 | package com.earldouglas.helloworld; 2 | 3 | public class HelloFrege { 4 | public static void main(String[] args) { 5 | HelloWorld.main(args); // Will not compile unless Frege code is compiled 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/simple/test: -------------------------------------------------------------------------------- 1 | # check if the file gets created 2 | $ absent target/frege/com/earldouglas/helloworld/HelloWorld.java 3 | $ absent target/scala-2.12/classes/com/earldouglas/helloworld/HelloWorld.class 4 | > compile 5 | $ exists target/frege/com/earldouglas/helloworld/HelloWorld.java 6 | $ exists target/scala-2.12/classes/com/earldouglas/helloworld/HelloWorld.class 7 | -------------------------------------------------------------------------------- /src/sbt-test/examples/servlet/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | frege-web 5 | fregeweb.FregeServlet 6 | 7 | 8 | 9 | frege-web 10 | /* 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/java-from-frege/fregeCallsJava/src/main/frege/com/earldouglas/helloworld/HelloJava.fr: -------------------------------------------------------------------------------- 1 | package com.earldouglas.helloworld.HelloJava where 2 | 3 | data HelloWorld = native com.earldouglas.helloworld.HelloWorld where 4 | native main HelloWorld.main :: MutableIO (JArray String) -> IO () 5 | 6 | main :: [String] -> IO () 7 | main = HelloWorld.main . mutable . arrayFromList 8 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/frege-from-java/test: -------------------------------------------------------------------------------- 1 | $ absent plainFrege/target/frege/com/earldouglas/helloworld/HelloWorld.java 2 | $ absent javaCallsFrege/target/scala-2.12/classes/com/earldouglas/helloworld/HelloFrege.class 3 | > compile 4 | $ exists plainFrege/target/frege/com/earldouglas/helloworld/HelloWorld.java 5 | $ exists javaCallsFrege/target/scala-2.12/classes/com/earldouglas/helloworld/HelloFrege.class 6 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/java-from-frege/test: -------------------------------------------------------------------------------- 1 | $ absent fregeCallsJava/target/frege/com/earldouglas/helloworld/HelloJava.java 2 | $ absent plainJava/target/scala-2.12/classes/com/earldouglas/helloworld/HelloWorld.class 3 | > compile 4 | $ exists fregeCallsJava/target/frege/com/earldouglas/helloworld/HelloJava.java 5 | $ exists plainJava/target/scala-2.12/classes/com/earldouglas/helloworld/HelloWorld.class 6 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-24.04 9 | 10 | steps: 11 | 12 | - uses: actions/checkout@v4 13 | 14 | - uses: actions/setup-java@v4 15 | with: 16 | java-version: 8 17 | distribution: temurin 18 | cache: sbt 19 | 20 | - uses: sbt/setup-sbt@v1 21 | 22 | - run: sbt scripted +test +publishLocal 23 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/mixed/test: -------------------------------------------------------------------------------- 1 | # check if the file gets created 2 | $ absent target/frege/com/earldouglas/helloworld/HelloWorld.java 3 | $ absent target/scala-2.12/classes/com/earldouglas/helloworld/HelloWorld.class 4 | $ absent target/scala-2.12/classes/com/earldouglas/helloworld/HelloFrege.class 5 | > compile 6 | $ exists target/frege/com/earldouglas/helloworld/HelloWorld.java 7 | $ exists target/scala-2.12/classes/com/earldouglas/helloworld/HelloWorld.class 8 | $ exists target/scala-2.12/classes/com/earldouglas/helloworld/HelloFrege.class 9 | -------------------------------------------------------------------------------- /src/sbt-test/examples/servlet/src/main/frege/FregeWeb.fr: -------------------------------------------------------------------------------- 1 | module fregeweb.FregeWeb where 2 | 3 | data Request = Request { method :: String, uri :: String } 4 | data Response = Response { status :: Int, body :: String } 5 | 6 | service :: Request -> Response 7 | service (Request "GET" "/") = response 200 "hello" 8 | service (Request "GET" "/hello") = response 200 "Hello, world!" 9 | service _ = response 404 "404'd!" 10 | 11 | response :: Int -> String -> Response 12 | response status body = Response status body 13 | -------------------------------------------------------------------------------- /src/sbt-test/examples/servlet/README.md: -------------------------------------------------------------------------------- 1 | This is a simple Frege-based J2EE Web application to demonstrate using 2 | [sbt-frege] with [xsbt-web-plugin]. 3 | 4 | ## Usage 5 | 6 | Start the service: 7 | 8 | ``` 9 | $ sbt 10 | > jetty:quickstart 11 | ``` 12 | 13 | Try it out: 14 | 15 | ``` 16 | $ curl localhost:8080 17 | hello 18 | ``` 19 | 20 | ``` 21 | $ curl localhost:8080/hello 22 | Hello, world! 23 | ``` 24 | 25 | ``` 26 | $ curl localhost:8080/foo 27 | 404'd! 28 | ``` 29 | 30 | [sbt-frege]: https://github.com/earldouglas/sbt-frege 31 | [xsbt-web-plugin]: https://github.com/earldouglas/xsbt-web-plugin 32 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/imports/test: -------------------------------------------------------------------------------- 1 | # check if the file gets created 2 | $ absent target/frege/Main.java 3 | $ absent target/frege/example/Hello.java 4 | $ absent target/frege/example/Other.java 5 | $ absent target/scala-2.12/classes/Main.class 6 | $ absent target/scala-2.12/classes/example/Hello.class 7 | $ absent target/scala-2.12/classes/example/Other.class 8 | > compile 9 | $ exists target/frege/Main.java 10 | $ exists target/frege/example/Hello.java 11 | $ exists target/frege/example/Other.java 12 | $ exists target/scala-2.12/classes/Main.class 13 | $ exists target/scala-2.12/classes/example/Hello.class 14 | $ exists target/scala-2.12/classes/example/Other.class 15 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-frege/with-test/test: -------------------------------------------------------------------------------- 1 | # check if the file gets created 2 | $ absent target/frege/com/earldouglas/helloworld/HelloWorld.java 3 | $ absent target/scala-2.12/classes/com/earldouglas/helloworld/HelloWorld.class 4 | $ absent target/test-frege/com/earldouglas/helloworld/HelloWorldTest.java 5 | $ absent target/scala-2.12/test-classes/com/earldouglas/helloworld/HelloWorldTest.class 6 | > test 7 | $ exists target/frege/com/earldouglas/helloworld/HelloWorld.java 8 | $ exists target/scala-2.12/classes/com/earldouglas/helloworld/HelloWorld.class 9 | $ exists target/test-frege/com/earldouglas/helloworld/HelloWorldTest.java 10 | $ exists target/scala-2.12/test-classes/com/earldouglas/helloworld/HelloWorldTest.class 11 | -------------------------------------------------------------------------------- /src/sbt-test/examples/servlet/test-get.sbt: -------------------------------------------------------------------------------- 1 | val get = inputKey[Unit]("get") 2 | 3 | get := { 4 | javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier( 5 | new javax.net.ssl.HostnameVerifier() { 6 | override def verify(hostname: String, sslSession: javax.net.ssl.SSLSession): Boolean = { 7 | hostname == "localhost" 8 | } 9 | } 10 | ) 11 | complete.DefaultParsers.spaceDelimited("").parsed.toList match { 12 | case List(url, status) => 13 | import java.net.URL 14 | import java.net.HttpURLConnection 15 | val conn = (new URL(url)).openConnection.asInstanceOf[HttpURLConnection] 16 | conn.setInstanceFollowRedirects(false) 17 | conn.setRequestMethod("GET") 18 | conn.setDoOutput(false) 19 | Right(conn.getResponseCode) 20 | if (conn.getResponseCode != status.toInt) 21 | sys.error(s"Expected status $status but received ${conn.getResponseCode}") 22 | case _ => sys.error("Usage: get ") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://github.com/earldouglas/sbt-frege/workflows/build/badge.svg)](https://github.com/earldouglas/sbt-frege/actions) 2 | [![Latest version](https://img.shields.io/github/tag/earldouglas/sbt-frege.svg)](https://index.scala-lang.org/earldouglas/sbt-frege) 3 | 4 | # Contributing 5 | 6 | ## Publishing 7 | 8 | This project uses [sbt-sonatype](https://github.com/xerial/sbt-sonatype) 9 | to automate most of the publishing process. 10 | 11 | ``` 12 | $ export OLD_VERSION=3.0.2 13 | $ export NEW_VERSION=3.0.3 14 | ``` 15 | 16 | Update the documentation: 17 | 18 | ``` 19 | $ git checkout -b v$NEW_VERSION 20 | $ sed -i "s/$OLD_VERSION/$NEW_VERSION/g" README.md 21 | $ git add README.md 22 | $ git commit -m "sbt-frege: $OLD_VERSION -> $NEW_VERSION" 23 | $ git push origin v$NEW_VERSION 24 | ``` 25 | 26 | Publish: 27 | 28 | ``` 29 | $ nix-shell 30 | $ sbt 31 | > set ThisBuild / version := sys.env("NEW_VERSION") 32 | > +publishSigned 33 | > sonatypeBundleRelease 34 | ``` 35 | 36 | Tag: 37 | 38 | ``` 39 | $ git tag -m "sbt-frege: $NEW_VERSION" $NEW_VERSION 40 | $ git push --tags origin 41 | ``` 42 | -------------------------------------------------------------------------------- /src/main/scala-2.12/Compat.scala: -------------------------------------------------------------------------------- 1 | package com.earldouglas.sbt.frege 2 | 3 | import sbt.Def.Initialize 4 | import sbt.Keys._ 5 | import sbt._ 6 | 7 | object Compat { 8 | 9 | val Compile_fullClasspath: Initialize[Task[Seq[File]]] = 10 | Def.task { 11 | (Compile / fullClasspath).value 12 | .map(_.data) 13 | } 14 | 15 | def dependencyClasspath(scope: Configuration): Initialize[Task[Seq[File]]] = 16 | Def.task { 17 | (scope / sbt.Keys.dependencyClasspath).value 18 | .map(_.data) 19 | } 20 | 21 | def managedClasspath(scope: Configuration): Initialize[Task[Seq[File]]] = 22 | Def.task { 23 | (scope / sbt.Keys.managedClasspath).value 24 | .map(_.data) 25 | } 26 | 27 | def fregeCompiler(scope: Configuration) = scope / SbtFregec.autoImport.fregeCompiler 28 | def fregeOptions(scope: Configuration) = scope / SbtFregec.autoImport.fregeOptions 29 | def fregeSource(scope: Configuration) = scope / SbtFregec.autoImport.fregeSource 30 | def fregeTarget(scope: Configuration) = scope / SbtFregec.autoImport.fregeTarget 31 | def sourceDirectory(scope: Configuration) = scope / sbt.Keys.sourceDirectory 32 | def sourceGenerators(scope: Configuration) = scope / sbt.Keys.sourceGenerators 33 | 34 | def managedJars(config: Configuration): Initialize[Task[Seq[File]]] = 35 | Def.task { 36 | Classpaths.managedJars(config, classpathTypes.value, update.value) 37 | .map(_.data) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/sbt-test/examples/servlet/test-await.sbt: -------------------------------------------------------------------------------- 1 | def isOpen(port: Int): Boolean = 2 | try { 3 | import java.net.Socket 4 | import java.net.InetSocketAddress 5 | val socket = new Socket() 6 | socket.connect(new InetSocketAddress("localhost", port)) 7 | socket.close() 8 | true 9 | } catch { 10 | case e: Exception => false 11 | } 12 | 13 | def awaitOpen(port: Int, retries: Int = 40): Unit = 14 | if (!isOpen(port)) { 15 | if (retries > 0) { 16 | Thread.sleep(250) 17 | awaitOpen(port, retries - 1) 18 | } else { 19 | throw new Exception(s"expected port $port to be open") 20 | } 21 | } else { Thread.sleep(5000) } 22 | 23 | def awaitClosed(port: Int, retries: Int = 40): Unit = 24 | if (isOpen(port)) { 25 | if (retries > 0) { 26 | Thread.sleep(250) 27 | awaitClosed(port, retries - 1) 28 | } else { 29 | throw new Exception(s"expected port $port to be closed") 30 | } 31 | } 32 | 33 | val await = inputKey[Unit]("await") 34 | 35 | await := { 36 | complete.DefaultParsers.spaceDelimited("").parsed.toList match { 37 | case List(port) => awaitOpen(port.toInt) 38 | case _ => throw new Exception("Usage: await ") 39 | } 40 | } 41 | 42 | val awaitClosed = inputKey[Unit]("awaitClosed") 43 | 44 | awaitClosed := { 45 | complete.DefaultParsers.spaceDelimited("").parsed.toList match { 46 | case List(port) => awaitClosed(port.toInt) 47 | case _ => throw new Exception("Usage: awaitClosed ") 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 James Earl Douglas 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /src/sbt-test/examples/servlet/src/main/scala/FregeServlet.scala: -------------------------------------------------------------------------------- 1 | package fregeweb 2 | 3 | import scala.language.implicitConversions 4 | 5 | import javax.servlet.http.HttpServlet 6 | import javax.servlet.http.{ HttpServletRequest => HSReq } 7 | import javax.servlet.http.{ HttpServletResponse => HSRes } 8 | 9 | import FregeWeb.TRequest 10 | import FregeWeb.TResponse 11 | 12 | import frege.run8.Box 13 | 14 | class FregeServlet extends HttpServlet { 15 | 16 | override def service(hsReq: HSReq, hsRes: HSRes): Unit = 17 | hsRes service hsReq 18 | 19 | } 20 | 21 | object `package` { 22 | 23 | implicit class HSResService(val hsRes: HSRes) extends AnyVal { 24 | 25 | def service(hsReq: HSReq): Unit = { 26 | val tReq: TRequest = TRequest.mk( new Box(hsReq.method) 27 | , new Box(hsReq.uri) 28 | ) 29 | val tRes: TResponse = FregeWeb.service(tReq).asInstanceOf[TResponse] 30 | write(tRes) 31 | } 32 | 33 | private def write(tRes: TResponse): Unit = { 34 | val status: Int = TResponse.status(tRes).asInstanceOf[Int] 35 | val body: String = TResponse.body(tRes).asInstanceOf[String] 36 | hsRes.setStatus(status) 37 | hsRes.getWriter().write(body) 38 | } 39 | 40 | } 41 | 42 | implicit class RichHSReq(val hsReq: HSReq) extends AnyVal { 43 | def method: String = hsReq.getMethod() 44 | def uri: String = 45 | if (hsReq.getRequestURI().startsWith(hsReq.getServletPath())) 46 | hsReq.getRequestURI().substring(hsReq.getServletPath().length()) 47 | else 48 | hsReq.getRequestURI() 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/scala-3/Compat.scala: -------------------------------------------------------------------------------- 1 | package com.earldouglas.sbt.frege 2 | 3 | import sbt.Def.Initialize 4 | import sbt.Keys._ 5 | import sbt._ 6 | import sbt.given 7 | 8 | object Compat: 9 | 10 | val Compile_fullClasspath: Initialize[Task[Seq[File]]] = 11 | Def.task: 12 | (Compile / fullClasspath).value 13 | .map(_.data) 14 | .map(fileConverter.value.toPath(_)) 15 | .map(_.toFile()) 16 | 17 | def dependencyClasspath(scope: Configuration): Initialize[Task[Seq[File]]] = 18 | Def.task: 19 | (scope / sbt.Keys.dependencyClasspath).value 20 | .map(_.data) 21 | .map(fileConverter.value.toPath(_)) 22 | .map(_.toFile()) 23 | 24 | def managedClasspath(scope: Configuration): Initialize[Task[Seq[File]]] = 25 | Def.task: 26 | (scope / sbt.Keys.managedClasspath).value 27 | .map(_.data) 28 | .map(fileConverter.value.toPath(_)) 29 | .map(_.toFile()) 30 | 31 | def fregeCompiler(scope: Configuration) = scope / SbtFregec.autoImport.fregeCompiler 32 | def fregeOptions(scope: Configuration) = scope / SbtFregec.autoImport.fregeOptions 33 | def fregeSource(scope: Configuration) = scope / SbtFregec.autoImport.fregeSource 34 | def fregeTarget(scope: Configuration) = scope / SbtFregec.autoImport.fregeTarget 35 | def sourceDirectory(scope: Configuration) = scope / sbt.Keys.sourceDirectory 36 | def sourceGenerators(scope: Configuration) = scope / sbt.Keys.sourceGenerators 37 | 38 | def managedJars(config: Configuration): Initialize[Task[Seq[File]]] = 39 | Def.task: 40 | Classpaths.managedJars(config, classpathTypes.value, update.value, fileConverter.value) 41 | .map(_.data) 42 | .map(fileConverter.value.toPath(_)) 43 | .map(_.toFile()) 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://github.com/earldouglas/sbt-frege/workflows/build/badge.svg)](https://github.com/earldouglas/sbt-frege/actions) 2 | [![Latest version](https://img.shields.io/github/tag/earldouglas/sbt-frege.svg)](https://index.scala-lang.org/earldouglas/sbt-frege) 3 | 4 | ## Features 5 | 6 | * Compile Frege code from your project's *src/main/frege/* directory 7 | * Call Frege code from your project's Java/Scala/etc. code 8 | * Launch the [Frege REPL][1] with your project's classes and libraries 9 | 10 | ## Requirements 11 | 12 | * sbt 1.0.1+ 13 | * Scala 2.4.0+ 14 | 15 | *For sbt 0.13.6+ projects, use sbt-frege version 1.1.3* 16 | 17 | ## Getting started from a template 18 | 19 | ``` 20 | $ sbt new earldouglas/sbt-frege.g8 21 | A project built with sbt-frege 22 | 23 | name [My Frege Project]: hello frege 24 | 25 | Template applied in ./hello-frege 26 | 27 | $ cd hello-frege/ 28 | $ sbt 29 | > test 30 | example.HelloWorldSuite: 31 | + multiply 0.008s 32 | + showWork 0.016s 33 | [info] Passed: Total 2, Failed 0, Errors 0, Passed 2 34 | > run 35 | [info] 6 * 7 = 42 36 | ``` 37 | 38 | ## Getting started from scratch 39 | 40 | Add the Frege sbt plugin to your project: 41 | 42 | *project/plugins.sbt:* 43 | 44 | ```scala 45 | addSbtPlugin("com.earldouglas" % "sbt-frege" % "3.0.3") 46 | ``` 47 | 48 | Write some Frege code: 49 | 50 | *src/main/frege/example/HelloWorld.fr:* 51 | 52 | ```frege 53 | package example.HelloWorld where 54 | 55 | main :: [String] -> IO () 56 | main _ = println "Hello, world!" 57 | ``` 58 | 59 | Build and run it: 60 | 61 | ``` 62 | $ sbt 63 | > compile 64 | > run 65 | Hello, world! 66 | ``` 67 | 68 | Try it from the Frege REPL: 69 | 70 | ``` 71 | $ sbt 72 | > fregeRepl 73 | 74 | frege> import example.HelloWorld (main) 75 | 76 | frege> main [] 77 | Hello, world! 78 | () 79 | ``` 80 | 81 | ## Configuration 82 | 83 | ### Frege compiler 84 | 85 | * `fregeOptions: Seq[String]` - Extra options for fregec 86 | * `fregeSource: File` - Frege source directory (default 87 | *src/main/frege/*) 88 | * `fregeTarget: File` - Frege target directory (default *target/frege/*) 89 | * `fregeCompiler: String` - Full name of the Frege compiler (default 90 | *frege.compiler.Main*) 91 | * `fregeLibrary: ModuleID` - Frege library (fregec.jar) to use (default 92 | *Frege 3.23.288*) 93 | 94 | ### Frege REPL 95 | 96 | * `fregeReplVersion: String` - The version of [frege-repl][1] to use 97 | (default 1.3) 98 | * `fregeReplMainClass: String` - The Frege REPL main class (default 99 | `frege.repl.FregeRepl`) 100 | 101 | Though sbt-frege uses 3.24.100.1 by default, Frege REPL 1.3 depends on 102 | Frege 3.23.288, so it takes priority when launching `fregeRepl`. 103 | 104 | [1]: https://github.com/Frege/frege-repl 105 | -------------------------------------------------------------------------------- /src/main/scala/SbtFrege.scala: -------------------------------------------------------------------------------- 1 | package com.earldouglas.sbt.frege 2 | 3 | import sbt._ 4 | import sbt.Keys._ 5 | 6 | object SbtFregec extends AutoPlugin { 7 | 8 | object autoImport { 9 | lazy val fregeOptions = settingKey[Seq[String]]("Extra options for fregec") 10 | lazy val fregeSource = settingKey[File]("Frege source directory") 11 | lazy val fregeTarget = settingKey[File]("Frege target directory") 12 | lazy val fregeCompiler = settingKey[String]("Full name of the Frege compiler") 13 | lazy val fregeLibrary = settingKey[ModuleID]("Frege library (fregec.jar)") 14 | } 15 | 16 | import autoImport._ 17 | import java.io.File 18 | 19 | override def trigger = allRequirements 20 | override def requires = plugins.JvmPlugin 21 | 22 | def fregec(cp: Seq[File], fregeSource: File, fregeTarget: File, 23 | fregeCompiler: String, fregeOptions: Seq[String]) 24 | (fregeSrcs: Set[File]): Set[File] = { 25 | 26 | val cps = cp.mkString(String.valueOf(File.pathSeparatorChar)) 27 | 28 | fregeTarget.mkdirs() 29 | 30 | val fregeArgs = Seq( 31 | fregeCompiler, 32 | "-fp", cps, 33 | "-d", fregeTarget.getPath, 34 | "-sp", fregeSource.getPath, 35 | "-make" 36 | ) ++ fregeOptions ++ fregeSrcs.map(_.getPath) 37 | 38 | val forkOptions: ForkOptions = ForkOptions() 39 | val fork = new Fork("java", None) 40 | val result = fork(forkOptions, Seq("-cp", cps) ++ fregeArgs) 41 | if (result != 0) { 42 | throw new RuntimeException("Frege compilation error") 43 | } else { 44 | (PathFinder(fregeTarget) ** "*.java").get().toSet 45 | } 46 | } 47 | 48 | def scopedSettings(scope: Configuration, dirName: String) = Seq( 49 | Compat.fregeSource(scope) := (Compat.sourceDirectory(scope)).value / "frege", 50 | Compat.fregeTarget(scope) := baseDirectory.value / "target" / dirName, 51 | Compat.sourceGenerators(scope) += Def.task { 52 | val cacheDir = streams.value.cacheDirectory / dirName 53 | val cached = FileFunction.cached( 54 | cacheDir, FilesInfo.lastModified, FilesInfo.exists) { 55 | fregec((Compat.managedClasspath(scope)).value ++ (Compat.dependencyClasspath(scope)).value, 56 | (Compat.fregeSource(scope)).value, 57 | (Compat.fregeTarget(scope)).value, 58 | (Compat.fregeCompiler(scope)).value, 59 | (Compat.fregeOptions(scope)).value) 60 | } 61 | cached(((Compat.fregeSource(scope)).value ** "*.fr").get().toSet).toSeq 62 | }.taskValue, 63 | watchSources ++= ((Compat.fregeSource(scope)).value ** "*").get().map(x=>WatchSource(x)) 64 | ) 65 | 66 | override def projectSettings = 67 | scopedSettings(Compile, "frege") ++ 68 | scopedSettings(Test, "test-frege") ++ 69 | Seq( 70 | fregeOptions := Seq("-j"), 71 | fregeCompiler := "frege.compiler.Main", 72 | fregeLibrary := "org.frege-lang" % "frege" % "3.24.100.1" classifier "jdk8", 73 | libraryDependencies += fregeLibrary.value 74 | ) 75 | 76 | } 77 | 78 | /* Adds integration with frege-repl: 79 | * * Launch the Frege REPL from sbt with the fregeRepl command 80 | * * Access your project's classes and libraries from the Frege REPL 81 | * See: https://github.com/Frege/frege-repl 82 | */ 83 | object SbtFregeRepl extends AutoPlugin { 84 | 85 | object autoImport { 86 | // Use a special configuration so as not to pollute the Compile 87 | // configuration with frege-repl's jar and transitive dependencies. 88 | lazy val FregeReplConfig = config("FregeReplConfig").hide 89 | lazy val fregeReplVersion = settingKey[String]("Frege REPL version") 90 | lazy val fregeRepl = inputKey[Unit]("Run the Frege REPL") 91 | lazy val fregeReplMainClass = settingKey[String]("Frege REPL main class") 92 | } 93 | 94 | import autoImport._ 95 | 96 | override def trigger = allRequirements 97 | override def requires = plugins.JvmPlugin 98 | override val projectConfigurations = Seq(FregeReplConfig) 99 | 100 | override def projectSettings = Seq( 101 | fregeReplVersion := "1.3", 102 | libraryDependencies += "org.frege-lang" % "frege-repl-core" % fregeReplVersion.value % FregeReplConfig, 103 | fregeReplMainClass := "frege.repl.FregeRepl", 104 | fregeRepl := { 105 | val cp: String = 106 | Path.makeString( 107 | Compat.managedJars(FregeReplConfig).value ++ 108 | (Compat.Compile_fullClasspath).value 109 | ) 110 | val forkOptions = ForkOptions().withConnectInput(true).withOutputStrategy(Some(sbt.StdoutOutput)) 111 | val mainClass: String = fregeReplMainClass.value 112 | new Fork("java", None).fork(forkOptions, Seq("-cp", cp, mainClass)).exitValue() 113 | } 114 | ) 115 | 116 | } 117 | --------------------------------------------------------------------------------