Skip to content

Commit 30b9b48

Browse files
authored
Scala Native (#381)
1 parent 7ff54a3 commit 30b9b48

38 files changed

+228
-78
lines changed

.envrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use flake

.github/workflows/ci.yml

+18-18
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,21 @@ jobs:
2727
strategy:
2828
matrix:
2929
os: [ubuntu-latest]
30-
scala: [3.1.2]
31-
java: [graal_21.3.0@11]
30+
scala: [3.2.0]
31+
java: [temurin@11]
3232
runs-on: ${{ matrix.os }}
3333
steps:
3434
- name: Checkout current branch (full)
3535
uses: actions/checkout@v2
3636
with:
3737
fetch-depth: 0
3838

39-
- name: Setup GraalVM (graal_21.3.0@11)
40-
if: matrix.java == 'graal_21.3.0@11'
41-
uses: DeLaGuardo/setup-[email protected]
39+
- name: Setup Java (temurin@11)
40+
if: matrix.java == 'temurin@11'
41+
uses: actions/setup-java@v2
4242
with:
43-
graalvm: 21.3.0
44-
java: java11
43+
distribution: temurin
44+
java-version: 11
4545

4646
- name: Cache sbt
4747
uses: actions/cache@v2
@@ -62,7 +62,7 @@ jobs:
6262
run: sbt ++${{ matrix.scala }} test
6363

6464
- name: Compress target directories
65-
run: tar cf targets.tar target project/target
65+
run: tar cf targets.tar target app/.jvm/target app/.native/target project/target
6666

6767
- name: Upload target directories
6868
uses: actions/upload-artifact@v2
@@ -77,21 +77,21 @@ jobs:
7777
strategy:
7878
matrix:
7979
os: [ubuntu-latest]
80-
scala: [3.1.2]
81-
java: [graal_21.3.0@11]
80+
scala: [3.2.0]
81+
java: [temurin@11]
8282
runs-on: ${{ matrix.os }}
8383
steps:
8484
- name: Checkout current branch (full)
8585
uses: actions/checkout@v2
8686
with:
8787
fetch-depth: 0
8888

89-
- name: Setup GraalVM (graal_21.3.0@11)
90-
if: matrix.java == 'graal_21.3.0@11'
91-
uses: DeLaGuardo/setup-[email protected]
89+
- name: Setup Java (temurin@11)
90+
if: matrix.java == 'temurin@11'
91+
uses: actions/setup-java@v2
9292
with:
93-
graalvm: 21.3.0
94-
java: java11
93+
distribution: temurin
94+
java-version: 11
9595

9696
- name: Cache sbt
9797
uses: actions/cache@v2
@@ -105,12 +105,12 @@ jobs:
105105
~/Library/Caches/Coursier/v1
106106
key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}
107107

108-
- name: Download target directories (3.1.2)
108+
- name: Download target directories (3.2.0)
109109
uses: actions/download-artifact@v2
110110
with:
111-
name: target-${{ matrix.os }}-3.1.2-${{ matrix.java }}
111+
name: target-${{ matrix.os }}-3.2.0-${{ matrix.java }}
112112

113-
- name: Inflate target directories (3.1.2)
113+
- name: Inflate target directories (3.2.0)
114114
run: |
115115
tar xf targets.tar
116116
rm targets.tar

.sbtopts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-J-Xmx8G
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.kubukoz.next
2+
3+
import cats.effect.unsafe.IORuntime
4+
5+
object RuntimePlatform {
6+
val default: IORuntime = IORuntime.global
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.kubukoz.next
2+
3+
import epollcat.unsafe.EpollRuntime
4+
import cats.effect.unsafe.IORuntime
5+
6+
object RuntimePlatform {
7+
val default: IORuntime = EpollRuntime.global
8+
}
File renamed without changes.

src/main/scala/com/kubukoz/next/Main.scala app/src/main/scala/com/kubukoz/next/Main.scala

+7-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ import cats.effect.implicits.*
1515
import java.io.EOFException
1616
import LoginProcess.given
1717
import org.typelevel.log4cats.Logger
18-
import org.typelevel.log4cats.slf4j.Slf4jLogger
18+
// import org.typelevel.log4cats.slf4j.Slf4jLogger
19+
import org.typelevel.log4cats.noop.NoOpLogger
20+
import cats.effect.unsafe.IORuntime
1921

2022
enum Choice {
2123
case Login
@@ -57,19 +59,19 @@ object Choice {
5759

5860
object Main extends CommandIOApp(name = "spotify-next", header = "spotify-next: Gather great music.", version = BuildInfo.version) {
5961

62+
override protected def runtime: IORuntime = RuntimePlatform.default
63+
6064
import Program.*
61-
given Logger[IO] = Slf4jLogger.getLogger[IO]
65+
given Logger[IO] = NoOpLogger[IO]
66+
// given Logger[IO] = Slf4jLogger.getLogger[IO]
6267

6368
def makeProgram[F[_]: Async: Console: Logger]: Resource[F, Runner[F]] = {
6469
given UserOutput[F] = UserOutput.toConsole(sonos.baseUri)
6570

66-
val dummy = Async[F].unit.toResource
67-
6871
for {
6972
given ConfigLoader[F] <- makeLoader[F].toResource
7073
rawClient <- makeBasicClient[F]
7174
given Config.Ask[F] = ConfigLoader[F].configAsk
72-
_ <- dummy
7375
// obviously quite a lot of duplication here...
7476
spotifyLogin = Login.ember[F](OAuth.fromKernel[F](rawClient, OAuth.spotify))
7577
spotifyLoginProcess = LoginProcess

src/main/scala/com/kubukoz/next/OAuth.scala app/src/main/scala/com/kubukoz/next/OAuth.scala

+9-4
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,19 @@ object OAuth {
3939
private val baseUri = uri"https://accounts.spotify.com"
4040

4141
def refreshToken(token: RefreshToken): F[Token] =
42-
client
43-
.fetchAs[RefreshedTokenResponse](kernel.refreshToken(token))
42+
kernel
43+
.refreshToken(token)
44+
.flatMap(
45+
client
46+
.fetchAs[RefreshedTokenResponse](_)
47+
)
4448
.map(_.access_token)
4549
.map(Token(_))
4650

4751
def getTokens(code: Code): F[Tokens] =
48-
client
49-
.expect[TokenResponse](kernel.getTokens(code))
52+
kernel
53+
.getTokens(code)
54+
.flatMap(client.expect[TokenResponse](_))
5055
.map { response =>
5156
Tokens(Token(response.access_token), RefreshToken(response.refresh_token))
5257
}

src/main/scala/com/kubukoz/next/Program.scala app/src/main/scala/com/kubukoz/next/Program.scala

+6-3
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,15 @@ object Program {
9595
def sonosMiddlewares[F[_]: MonadCancelThrow]: Client[F] => Client[F] =
9696
middlewares.defaultContentType(`Content-Type`(MediaType.application.json, Charset.`UTF-8`))
9797

98-
def makeSpotify[F[_]: UserOutput: ConfigLoader: Concurrent](spotifyClient: Client[F], sonosClient: Client[F]): F[Spotify[F]] =
98+
def makeSpotify[F[_]: UserOutput: ConfigLoader: Concurrent](spotifyClient: Client[F], sonosClient: Client[F]): F[Spotify[F]] = {
99+
val spotifyBaseUri = com.kubukoz.next.api.spotify.baseUri
100+
99101
for {
100-
given SpotifyApi[F] <- SimpleRestJsonBuilder(SpotifyApiGen).client[F](spotifyClient, com.kubukoz.next.api.spotify.baseUri).liftTo[F]
101-
given SonosApi[F] <- SimpleRestJsonBuilder(SonosApiGen).client[F](sonosClient, sonos.baseUri).liftTo[F]
102+
given SpotifyApi[F] <- SimpleRestJsonBuilder(SpotifyApiGen).client[F](spotifyClient).uri(spotifyBaseUri).use.liftTo[F]
103+
given SonosApi[F] <- SimpleRestJsonBuilder(SonosApiGen).client[F](sonosClient).uri(sonos.baseUri).use.liftTo[F]
102104
result <- makeSpotifyInternal[F]
103105
} yield result
106+
}
104107

105108
def makeSpotifyInternal[F[_]: UserOutput: SpotifyApi: SonosApi: ConfigLoader: Concurrent]: F[Spotify[F]] = {
106109
given Spotify.DeviceInfo[F] = Spotify.DeviceInfo.instance

app/src/main/scala/monocle/Lens.scala

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package monocle
2+
3+
import cats.Functor
4+
5+
type Lens[S, A] = PLens[S, S, A, A]
6+
7+
object Lens {
8+
9+
def apply[S, A](_get: S => A)(_set: A => S => S): Lens[S, A] = new Lens[S, A] {
10+
11+
def get(s: S): A = _get(s)
12+
13+
def set(s: S, a: A): S = _set(a)(s)
14+
}
15+
16+
}
17+
18+
trait PLens[S, T, A, B] {
19+
def get(s: S): A
20+
def set(s: S, b: B): T
21+
def replace(b: B): S => T = set(_, b)
22+
23+
def asGetter: Getter[S, A] = get(_)
24+
25+
def modifyF[F[_]: Functor](f: A => F[B])(s: S): F[T] = Functor[F].map(f(get(s)))(set(s, _))
26+
}
27+
28+
object PLens {
29+
30+
def apply[S, T, A, B](_get: S => A)(_set: B => S => T): PLens[S, T, A, B] = new PLens[S, T, A, B] {
31+
32+
def get(s: S): A = _get(s)
33+
34+
def set(s: S, b: B): T = _set(b)(s)
35+
36+
}
37+
38+
}
39+
40+
trait Getter[S, A] {
41+
def get(s: S): A
42+
def map[B](f: A => B): Getter[S, B] = s => f(get(s))
43+
}
44+
45+
object syntax {
46+
object all {}
47+
}
File renamed without changes.
File renamed without changes.

build.sbt

+46-27
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ inThisBuild(
1515
)
1616
Global / onChangedBuildSource := ReloadOnSourceChanges
1717

18-
(ThisBuild / scalaVersion) := "3.1.2"
18+
ThisBuild / scalaVersion := "3.2.0"
1919

20-
ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.graalvm("21.3.0", "11"))
2120
ThisBuild / githubWorkflowTargetTags := Seq("v*")
2221
ThisBuild / githubWorkflowPublishTargetBranches := List(RefPredicate.StartsWith(Ref.Tag("v")), RefPredicate.Equals(Ref.Branch("main")))
2322

@@ -65,8 +64,8 @@ val commonSettings = Seq(
6564
),
6665
libraryDependencies ++= Seq(
6766
"org.typelevel" %%% "cats-effect" % "3.3.14",
68-
"org.scalameta" %%% "munit" % "0.7.29" % Test,
69-
"org.typelevel" %% "munit-cats-effect-3" % "1.0.7" % Test
67+
"org.scalameta" %%% "munit" % "1.0.0-M6" % Test,
68+
"org.typelevel" %%% "munit-cats-effect" % "2.0.0-M3" % Test
7069
),
7170
addCompilerPlugins,
7271
Compile / doc / sources := Nil
@@ -118,29 +117,49 @@ val front = project
118117
.dependsOn(core)
119118
*/
120119

120+
val app = crossProject(JVMPlatform, NativePlatform)
121+
.crossType(CrossType.Pure)
122+
.settings(commonSettings)
123+
.settings(
124+
libraryDependencies ++= Seq(
125+
"com.disneystreaming.smithy4s" %%% "smithy4s-http4s" % smithy4sVersion.value,
126+
"org.typelevel" %%% "cats-mtl" % "1.3.0",
127+
"com.monovore" %%% "decline-effect" % "2.3.1",
128+
"org.http4s" %%% "http4s-dsl" % "0.23.16",
129+
"org.http4s" %%% "http4s-ember-server" % "0.23.16",
130+
"org.http4s" %%% "http4s-ember-client" % "0.23.16",
131+
"org.http4s" %%% "http4s-circe" % "0.23.16",
132+
"io.circe" %%% "circe-parser" % "0.14.3",
133+
"org.typelevel" %%% "log4cats-noop" % "2.5.0"
134+
// waiting
135+
// "dev.optics" %%% "monocle-core" % "3.1.0"
136+
),
137+
buildInfoKeys := Seq[BuildInfoKey](version),
138+
buildInfoPackage := "com.kubukoz.next"
139+
)
140+
.settings(name := "spotify-next")
141+
.enablePlugins(BuildInfoPlugin)
142+
.settings(
143+
Compile / smithy4sInputDir := (ThisBuild / baseDirectory).value / "app" / "src" / "main" / "smithy"
144+
)
145+
.enablePlugins(Smithy4sCodegenPlugin)
146+
.jvmConfigure(
147+
_.settings(
148+
libraryDependencies ++= Seq(
149+
"ch.qos.logback" % "logback-classic" % "1.2.11"
150+
)
151+
).enablePlugins(JavaAppPackaging)
152+
)
153+
.nativeConfigure(
154+
_.settings(
155+
libraryDependencies ++= Seq(
156+
"com.armanbilge" %%% "epollcat" % "0.1.1"
157+
)
158+
)
159+
)
160+
121161
val root =
122162
project
123163
.in(file("."))
124-
.settings(commonSettings)
125-
.settings(
126-
libraryDependencies ++= Seq(
127-
"com.disneystreaming.smithy4s" %% "smithy4s-http4s" % smithy4sVersion.value,
128-
"org.typelevel" %% "cats-mtl" % "1.3.0",
129-
"com.monovore" %% "decline-effect" % "2.3.0",
130-
"org.http4s" %% "http4s-dsl" % "0.23.13",
131-
"org.http4s" %% "http4s-ember-server" % "0.23.12",
132-
"org.http4s" %% "http4s-ember-client" % "0.23.12",
133-
"org.http4s" %% "http4s-circe" % "0.23.13",
134-
"ch.qos.logback" % "logback-classic" % "1.2.11",
135-
"io.circe" %% "circe-parser" % "0.14.2",
136-
"dev.optics" %% "monocle-core" % "3.1.0"
137-
),
138-
buildInfoKeys := Seq[BuildInfoKey](version),
139-
buildInfoPackage := "com.kubukoz.next"
140-
)
141-
.settings(name := "spotify-next")
142-
.enablePlugins(BuildInfoPlugin)
143-
.enablePlugins(JavaAppPackaging)
144-
.enablePlugins(Smithy4sCodegenPlugin)
145-
// .dependsOn(core)
146-
// .aggregate(core /* , front */ )
164+
.enablePlugins(NoPublishPlugin)
165+
.aggregate(app.componentProjects.map(p => p: ProjectReference): _*)

core/src/main/scala/com/kubukoz/next/Model.scala

-5
This file was deleted.

flake.lock

+42
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
inputs.nixpkgs.url = "github:nixos/nixpkgs";
3+
inputs.flake-utils.url = "github:numtide/flake-utils";
4+
5+
outputs = { self, nixpkgs, flake-utils, ... }@inputs:
6+
flake-utils.lib.eachDefaultSystem (
7+
system:
8+
let
9+
pkgs = import nixpkgs { inherit system; };
10+
in
11+
{
12+
devShells.default = pkgs.mkShell {
13+
nativeBuildInputs = [ pkgs.s2n-tls ];
14+
};
15+
}
16+
);
17+
}

pkgs.nix

-4
This file was deleted.

0 commit comments

Comments
 (0)