Bazel의 lockfile 기능을 사용하면 프로젝트에 필요한 소프트웨어 라이브러리 또는 패키지의 특정 버전이나 종속 항목을 기록할 수 있습니다. 모듈 확인 및 확장 프로그램 평가 결과를 저장하여 이를 달성합니다. 잠금 파일은 재현 가능한 빌드를 촉진하여 일관된 개발 환경을 보장합니다. 또한 Bazel이 프로젝트 종속 항목의 변경사항에 영향을 받지 않는 확인 프로세스의 부분을 건너뛸 수 있도록 하여 빌드 효율성을 향상합니다. 또한 lockfile은 외부 라이브러리의 예기치 않은 업데이트나 호환성이 깨지는 변경사항을 방지하여 안정성을 개선하므로 버그가 발생할 위험을 줄입니다.
잠금 파일 생성
잠금 파일은 작업공간 루트 아래에 MODULE.bazel.lock
라는 이름으로 생성됩니다. 빌드 프로세스 중에, 특히 모듈 해결 및 확장 프로그램 평가 후에 생성되거나 업데이트됩니다. 중요한 점은 빌드의 현재 호출에 포함된 종속 항목만 포함된다는 것입니다.
종속 항목에 영향을 미치는 변경사항이 프로젝트에 발생하면 새로운 상태를 반영하도록 잠금 파일이 자동으로 업데이트됩니다. 이렇게 하면 잠금 파일이 현재 빌드에 필요한 특정 종속 항목 집합에 계속 집중되어 프로젝트의 확인된 종속 항목을 정확하게 나타낼 수 있습니다.
Lockfile 사용
잠금 파일은 --lockfile_mode
플래그로 제어하여 프로젝트 상태가 잠금 파일과 다른 경우 Bazel의 동작을 맞춤설정할 수 있습니다. 사용 가능한 모드는 다음과 같습니다.
update
(기본값): 알려진 레지스트리 파일의 다운로드를 건너뛰고 결과가 아직 최신인 확장 프로그램을 다시 평가하지 않도록 잠금 파일에 있는 정보를 사용합니다. 정보가 누락된 경우 lockfile에 추가됩니다. 이 모드에서 Bazel은 변경되지 않은 종속 항목에 대해 yanked 버전과 같은 변경 가능한 정보의 새로고침도 방지합니다.refresh
:update
와 비슷하지만 이 모드로 전환할 때와 이 모드에 있는 동안 약 1시간마다 변경 가능한 정보가 항상 새로고침됩니다.error
:update
와 유사하지만 정보가 누락되거나 오래된 경우 Bazel이 오류와 함께 실패합니다. 이 모드는 잠금 파일을 변경하거나 해결 중에 네트워크 요청을 실행하지 않습니다.reproducible
로 표시된 모듈 확장 프로그램은 여전히 네트워크 요청을 실행할 수 있지만 항상 동일한 결과를 생성해야 합니다.off
: lockfile이 확인되거나 업데이트되지 않습니다.
잠금 파일의 이점
잠금 파일은 여러 이점을 제공하며 다양한 방식으로 활용할 수 있습니다.
재현 가능한 빌드. 소프트웨어 라이브러리의 특정 버전이나 종속 항목을 캡처하여 잠금 파일은 다양한 환경에서 시간이 지나도 빌드를 재현할 수 있도록 합니다. 개발자는 프로젝트를 빌드할 때 일관되고 예측 가능한 결과를 사용할 수 있습니다.
빠른 증분 해결. 잠금 파일을 사용하면 Bazel이 이전 빌드에서 이미 사용된 레지스트리 파일을 다운로드하지 않아도 됩니다. 이렇게 하면 특히 해결에 시간이 오래 걸릴 수 있는 시나리오에서 빌드 효율성이 크게 향상됩니다.
안정성 및 위험 감소. lockfile은 외부 라이브러리의 예기치 않은 업데이트나 호환성이 보장되지 않는 변경사항을 방지하여 안정성을 유지하는 데 도움이 됩니다. 종속 항목을 특정 버전으로 잠그면 버그가 발생할 위험이 줄어듭니다.
호환되지 않거나 테스트되지 않은 업데이트로 인한 다운타임이 줄어듭니다.
숨겨진 잠금 파일
Bazel은 "$(bazel info output_base)"/MODULE.bazel.lock
에서도 다른 lockfile을 유지합니다. 이 잠금 파일의 형식과 콘텐츠는 명시적으로 지정되지 않습니다. 성능 최적화로만 사용됩니다. bazel clean --expunge
를 통해 출력 베이스와 함께 삭제할 수 있지만 이렇게 해야 하는 것은 Bazel 자체 또는 모듈 확장 프로그램의 버그입니다.
Lockfile Contents
잠금 파일에는 프로젝트 상태가 변경되었는지 확인하는 데 필요한 모든 정보가 포함되어 있습니다. 또한 현재 상태에서 프로젝트를 빌드한 결과도 포함됩니다. 잠금 파일은 두 가지 주요 부분으로 구성됩니다.
- 모듈 확인의 입력인 모든 원격 파일의 해시입니다.
- 각 모듈 확장 프로그램의 경우
bzlTransitiveDigest
,usagesDigest
및 기타 필드로 표시되는 영향을 미치는 입력과 해당 확장 프로그램 실행의 출력(generatedRepoSpecs
라고 함)이 lockfile에 포함됩니다.
다음은 잠금 파일의 구조를 보여주는 예시와 각 섹션에 대한 설명입니다.
{
"lockFileVersion": 10,
"registryFileHashes": {
"https://bcr.bazel.build/bazel_registry.json": "8a28e4af...5d5b3497",
"https://bcr.bazel.build/modules/foo/1.0/MODULE.bazel": "7cd0312e...5c96ace2",
"https://bcr.bazel.build/modules/foo/2.0/MODULE.bazel": "70390338... 9fc57589",
"https://bcr.bazel.build/modules/foo/2.0/source.json": "7e3a9adf...170d94ad",
"https://registry.mycorp.com/modules/foo/1.0/MODULE.bazel": "not found",
...
},
"selectedYankedVersions": {
"foo@2.0": "Yanked for demo purposes"
},
"moduleExtensions": {
"//:extension.bzl%lockfile_ext": {
"general": {
"bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
"usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=",
...,
"generatedRepoSpecs": {
"hello": {
"bzlFile": "@@//:extension.bzl",
...
}
}
}
},
"//:extension.bzl%lockfile_ext2": {
"os:macos": {
"bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
"usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
...,
"generatedRepoSpecs": {
"hello": {
"bzlFile": "@@//:extension.bzl",
...
}
}
},
"os:linux": {
"bzlTransitiveDigest": "eWDzxG/aLsyY3Ubrto....+Jp4maQvEPxn0pLK=",
"usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
...,
"generatedRepoSpecs": {
"hello": {
"bzlFile": "@@//:extension.bzl",
...
}
}
}
}
}
}
레지스트리 파일 해시
registryFileHashes
섹션에는 모듈 확인 중에 액세스한 원격 레지스트리의 모든 파일 해시가 포함됩니다. 해결 알고리즘은 동일한 입력이 제공되고 모든 원격 입력이 해싱될 때 완전히 결정적이므로 이를 통해 잠금 파일에서 원격 정보의 과도한 중복을 방지하면서 완전히 재현 가능한 해결 결과를 보장합니다. 또한 특정 레지스트리에 특정 모듈이 포함되지 않았지만 우선순위가 낮은 레지스트리에는 포함된 경우도 기록해야 합니다 (예의 'not found' 항목 참고). 이 본질적으로 변경 가능한 정보는 bazel mod deps --lockfile_mode=refresh
를 통해 업데이트할 수 있습니다.
Bazel은 잠금 파일의 해시를 사용하여 다운로드하기 전에 저장소 캐시에서 레지스트리 파일을 조회하므로 후속 해결 속도가 빨라집니다.
선택한 철회된 버전
selectedYankedVersions
섹션에는 모듈 확인에서 선택한 모듈의 yanked 버전이 포함됩니다. 일반적으로 빌드하려고 할 때 오류가 발생하므로 이 섹션은 --allow_yanked_versions
또는 BZLMOD_ALLOW_YANKED_VERSIONS
를 통해 취소된 버전이 명시적으로 허용된 경우에만 비어 있지 않습니다.
이 필드는 모듈 파일과 달리 yanked 버전 정보는 본질적으로 변경 가능하므로 해시로 참조할 수 없기 때문에 필요합니다. 이 정보는 bazel mod deps --lockfile_mode=refresh
를 통해 업데이트할 수 있습니다.
모듈 확장 프로그램
moduleExtensions
섹션은 현재 호출에서 사용되거나 이전에 호출된 확장 프로그램만 포함하고 더 이상 사용되지 않는 확장 프로그램은 제외하는 맵입니다. 즉, 종속 항목 그래프에서 더 이상 사용되지 않는 확장 프로그램은 moduleExtensions
맵에서 삭제됩니다.
확장 프로그램이 운영체제 또는 아키텍처 유형과 무관한 경우 이 섹션에는 단일 '일반' 항목만 표시됩니다. 그렇지 않으면 OS, 아키텍처 또는 둘 다의 이름을 따서 명명된 여러 항목이 포함되며 각 항목은 이러한 세부정보에 대한 확장 프로그램 평가 결과에 해당합니다.
확장 프로그램 맵의 각 항목은 사용된 확장 프로그램에 해당하며 포함된 파일과 이름으로 식별됩니다. 각 항목의 해당 값에는 해당 확장 프로그램과 관련된 정보가 포함됩니다.
bzlTransitiveDigest
은 확장 프로그램 구현과 확장 프로그램에서 전이적으로 로드한 .bzl 파일의 다이제스트입니다.usagesDigest
은 모든 태그를 포함하는 종속 항목 그래프에 있는 확장 프로그램의 usages의 다이제스트입니다.- 확장이 읽는 파일 또는 디렉터리의 콘텐츠나 사용하는 환경 변수와 같은 확장 프로그램에 대한 기타 입력을 추적하는 추가 미지정 필드입니다.
generatedRepoSpecs
는 현재 입력으로 확장 프로그램에서 생성된 저장소를 인코딩합니다.- 선택사항인
moduleExtensionMetadata
필드에는 확장 프로그램에서 제공하는 메타데이터가 포함됩니다. 예를 들어 생성된 특정 저장소를 루트 모듈에서use_repo
을 통해 가져와야 하는지 여부가 포함됩니다. 이 정보는bazel mod tidy
명령어를 지원합니다.
모듈 확장 프로그램은 reproducible = True
로 반환되는 메타데이터를 설정하여 잠금 파일에 포함되지 않도록 선택할 수 있습니다. 이렇게 하면 동일한 입력이 주어졌을 때 항상 동일한 저장소를 생성하겠다고 약속하는 것입니다.
권장사항
잠금 파일 기능의 이점을 극대화하려면 다음 권장사항을 고려하세요.
프로젝트 종속 항목 또는 구성의 변경사항을 반영하도록 정기적으로 lockfile을 업데이트합니다. 이렇게 하면 후속 빌드가 최신이고 정확한 종속 항목 집합을 기반으로 합니다. 모든 확장 프로그램을 한 번에 잠그려면
bazel mod deps --lockfile_mode=update
를 실행합니다.버전 관리에 lockfile을 포함하여 공동작업을 용이하게 하고 모든 팀 구성원이 동일한 lockfile에 액세스할 수 있도록 하여 프로젝트 전반에서 일관된 개발 환경을 조성합니다.
bazelisk
을 사용하여 Bazel을 실행하고 버전 제어에.bazelversion
파일을 포함합니다. 이 파일은 잠금 파일에 해당하는 Bazel 버전을 지정합니다. Bazel 자체가 빌드의 종속 항목이므로 lockfile은 Bazel 버전에 따라 다르며 하위 호환 Bazel 출시 간에도 변경됩니다.bazelisk
를 사용하면 모든 개발자가 lockfile과 일치하는 Bazel 버전을 사용하게 됩니다.
이러한 권장사항을 따르면 Bazel에서 lockfile 기능을 효과적으로 활용하여 더 효율적이고 안정적이며 협업적인 소프트웨어 개발 워크플로를 만들 수 있습니다.
병합 충돌
잠금 파일 형식은 병합 충돌을 최소화하도록 설계되었지만 여전히 발생할 수 있습니다.
자동 해결
Bazel은 이러한 충돌을 자동으로 해결하는 데 도움이 되는 맞춤 git 병합 드라이버를 제공합니다.
Git 저장소의 루트에 있는 .gitattributes
파일에 다음 줄을 추가하여 드라이버를 설정합니다.
# A custom merge driver for the Bazel lockfile.
# https://bazel.build/external/lockfile#automatic-resolution
MODULE.bazel.lock merge=bazel-lockfile-merge
그런 다음 드라이버를 사용하려는 각 개발자는 다음 단계에 따라 한 번 등록해야 합니다.
- jq (1.5 이상)를 설치합니다.
- 다음 명령어를 실행합니다.
jq_script=$(curl https://raw.githubusercontent.com/bazelbuild/bazel/master/scripts/bazel-lockfile-merge.jq)
printf '%s\n' "${jq_script}" | less # to optionally inspect the jq script
git config --global merge.bazel-lockfile-merge.name "Merge driver for the Bazel lockfile (MODULE.bazel.lock)"
git config --global merge.bazel-lockfile-merge.driver "jq -s '${jq_script}' -- %O %A %B > %A.jq_tmp && mv %A.jq_tmp %A"
수동 해결
registryFileHashes
및 selectedYankedVersions
필드의 간단한 병합 충돌은 충돌의 양쪽 항목을 모두 유지하여 안전하게 해결할 수 있습니다.
다른 유형의 병합 충돌은 수동으로 해결하면 안 됩니다. 다음을 수행합니다.
git reset MODULE.bazel.lock && git checkout MODULE.bazel.lock
를 통해 lockfile의 이전 상태를 복원합니다.MODULE.bazel
파일의 충돌을 해결합니다.bazel mod deps
를 실행하여 lockfile을 업데이트합니다.