openlang

버전 카탈로그, 컨벤션 플러그인에서만 안 보이는 libs

gradle/libs.versions.toml로 버전을 옮기는 중입니다. 공통 설정은 buildSrc 아래 컨벤션 플러그인에 둡니다. 버전은 한 곳에 두자는 생각이었습니다. 경우를 순서대로 놓겠습니다.

하위 프로젝트의 빌드 스크립트에서는 alias(libs.plugins.kotlin.jvm)도 libs도 잘 됩니다. 불만 없습니다.

buildSrc 자체의 빌드 스크립트는 메인 프로젝트의 카탈로그를 물려받지 않습니다. buildSrc/settings.gradle.kts에서 직접 가져와야 합니다.

dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

여기까지도 문서대로입니다. 자기 저장소의 파일이 어디 있는지 buildSrc에 일일이 알려 줘야 한다는 게 조금 이상하지만, 동작하고 접근자도 생깁니다.

세 번째부터 피곤해집니다. buildSrc 안의 미리 컴파일된 스크립트 플러그인에는 타입 안전한 libs가 없습니다. 문서는 extensions.getByType(VersionCatalogsExtension::class.java).named("libs")로 카탈로그를 이름으로 꺼낸 뒤 항목마다 별칭으로 물어보라고 합니다. 게다가 그 플러그인의 plugins 블록은 카탈로그에 아예 닿지 않습니다. 다른 플러그인을 적용하는 컨벤션 플러그인은 id로만 이름을 부르고, 버전은 buildSrc가 플러그인 아티팩트를 선언한 곳에서 옵니다.

그림이 고르지 않습니다. 제일 덜 중요한 빌드 스크립트가 제일 좋은 접근자를 받고, 공통 설정 대부분이 사는 컨벤션 플러그인은 문자열 조회를 받습니다.

결국 이름으로 꺼내야 하는 곳이 꼭 하나 남습니다. 이럴 거면 컨벤션 플러그인 안의 좌표는 그냥 문자열로 두는 편이 정직한 것 아닌가 싶습니다.

이어지는 대화 3

서로의 근거를 따라
  1. 고유 링크

    문자열로 두는 건 반대예요. 그럼 버전이 두 군데 생겨요. 카탈로그에 한 번, 컨벤션 플러그인에 한 번. 언젠가 한쪽만 올라가요.

    ko_jae 님 말대로 이름으로 꺼내는 건 못생겼어요. 그래도 못생긴 건 한 줄이고, 버전은 여전히 한 곳에 있어요. findLibrary 호출은 플러그인 하나에 모아 두세요. 그러면 별칭을 틀려도 적어도 어느 파일을 볼지는 알아요.

  2. 고유 링크

    otto 님 방식은 라이브러리에는 잘 맞습니다. 컨벤션 플러그인 하나에서 named("libs")로 카탈로그를 꺼내고 findLibrary("guava").get()으로 라이브러리 좌표를 받습니다.

    걸리는 건 오타 하나가 실패하는 방식이 서로 아주 다르다는 점입니다. 하위 프로젝트에서 libs.guava를 잘못 쓰면 스크립트 컴파일 단계에서 이름을 못 찾는다고 바로 멈춥니다. 컨벤션 플러그인에서 별칭을 틀리면 findLibrary가 빈 Optional을 돌려주고, get()이 NoSuchElementException을 던지는데 메시지에 별칭 이름이 없습니다. 이 메시지에 별칭을 넣을 방법이 있습니까, 아니면 다들 그럴 때마다 findLibrary를 grep합니까?

  3. 고유 링크

    ko_jae가 본 그 맨 예외는 get()에서 나온다. orElseThrow로 바꾸고 메시지를 준다. fun VersionCatalog.lib(alias: String) = findLibrary(alias).orElseThrow { IllegalStateException("catalog has no library '$alias'") }. 조회는 전부 이 함수 하나를 거친다.

    틀린 별칭은 설정 단계에서 자기 이름을 달고 실패한다.

같은 질문의 다른 갈래

  1. 일부러 망가뜨린 패키지가 tryEval을 통과했다

    오버레이의 패키지마다 builtins.tryEval을 씌우고 실패하는 것만 나열하는 작은 점검 스크립트를 짰어요. 그런데 전부 괜찮다고 나왔어요. 의존성 목록에 throw를 넣어 일부러 망가뜨린 패키지까지요. 항목을 끝까지…

    답글 4nix
  2. for_each 키는 이름표가 아니라 주소다

    for_each 키를 이름표로 보면 안 된다. 리소스 주소의 절반이다. terraform_data.queue["prod-orders"] 같은 주소로 state가 객체를 추적한다. 키를 바꾸면 plan은 이름이 바뀌었다고 보지…

    답글 6hcl
  3. 정지된 셸 작업은 끝난 작업이 아니다

    멈춘 프로세스를 끝난 것으로 치는 감독 규칙에 대해 질문을 받았는데, 작은 재현 하나면 문제가 바로 보여요. 셸 단계가 입력 파일을 쓰고, 그 뒤에 소비자가 예약돼 있어요. 쓰는 쪽이 중간에 일시 정지돼요. 감독자는 정지 이…