Post

시작시 프로그램 실행시키기

백업이나 스케쥴 보여주는 프로그램들을 몇개 짜다보니 컴퓨터 부팅할 때마다 실행시키려고 몇개의 폴더를 왔다갔다 하면서 일일이 실행시키는 게 부담이 되었습니다.

간단히 쉘 스크립트를 짜서 실행시키면 되겠지만 os-libscala-cli 사용법을 배워볼까 싶어 간단히 프로그램을 짜 보았습니다.

os.proc

os.proc으로 실행시킬 프로그램, 인자, 실행 위치 등을 지정할 수 있습니다. 실행을 마치는 프로그램이면 call을 호출하고 아니면 spawn을 사용하면 되겠습니다. spawn 실행시 SubProcess가 반환되며 이를 이용해서 나중에 종료시킬 수 있습니다.

Resource

프로그램 종료시 spawn으로 실행시킨 프로세스들을 어떻게 종료시켜야 하나 고민하다 cats의 Resource를 사용하기로 했습니다. Resource.make에서 리소스를 생성하는 함수와 종료시 필요한 함수를 지정하면 프로그램 종료시 자동으로 리소스를 해제해 줍니다.

scala-cli

scala-cli를 사용하면 build.sbt를 사용하지 않고도 >// using dep 형식으로 사용할 라이브러리들을 지정할 수 있고 package 명령을 사용하면 직접 컴파일해서 실행 파일까지 만들어 줍니다. 현재로는 graal-native image는 잘 동작하나 더 작은 크기의 scala-native를 사용하는 native 명령은 컴파일 에러가 발생합니다. 예전에 scala-native 사용해서 실행파일을 만든 적이 있는데 지금 버전은 왜 그런지 모르겠네요.

Tip

>// using dep 명령 사용시 native 형식을 사용하기 위해서는 //> using dep com.lihaoyi::os-lib::0.9.3와 같이 두번째 버전 앞에 콜론을 2개 사용해야 합니다. os-lib:0.9.3과 같이 colon을 하나만 사용하면 JVM에서는 잘 동작하지만 native 형식에서는 컴파일이 되지 않습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//> using scala 3.3.1
//> using dep org.typelevel::cats-effect::3.5.3
//> using dep com.lihaoyi::os-lib::0.9.3

import cats.effect.*
import cats.syntax.all.*

object ResourceTest extends IOApp:
    def r(label: String, cmd: String, wd: Option[String] = None)(args: String*) =
        Resource.make(
            IO.pure(os.proc(cmd, args)
                .spawn(cwd = wd.map(os.Path(_)).getOrElse(os.pwd),
                    stdout = os.Inherit, stderr = os.Inherit
                ))
        )((p: os.SubProcess) =>
            if p.isAlive() then
                IO.println(s"Destroying $label") *>
                IO(p.destroy())
            else
                IO.println(s"$label already finished.")
        )

    case class Command(label: String, cmd: String, wd: String, args: List[String])
    val commands = Seq(
            Command("mcal", "mix", "mcal", List("phx.server")),
            Command("cpraddb", "java", "cpraddb", List("-Dconfig.file=application.conf", "-jar", "target/scala-3.3.1/craddb.jar")),
            Command("radreport", "java", "radreportserver2", List("-Dconfig.file=rrs.conf", "-jar", "rrs-server.jar"))
        ).map(c => c.copy(wd = "/Users/nineclue/lab/" ++ c.wd))

    def run(as: List[String]): IO[ExitCode] =
        commands.map(c => r(c.label, c.cmd, Some(c.wd))(c.args:_*))
            .sequence
            .use(_ => IO.never)
        *> IO(ExitCode.Success)
This post is licensed under CC BY 4.0 by the author.