배포판(distribution) 설정과 구조
배포판(distribution) 설정과 구조 (distributions_configuration-structure)
모듈을 배포하려면 META6.json 파일과 프로젝트 디렉터리 구조를 제대로 갖춰야 해요. 이 문서는 그 구조를 파일시스템과 META6.json 파일을 나란히 짚어가며 설명해요. fez로 skeleton을 빠르게 만드는 방법부터, 각 메타데이터 키가 실제로 하는 일까지 살펴볼게요.
본문
모듈 준비하기 (Preparing the module)
모듈이 어떤 ecosystem에서든 동작하려면 특정 구조를 따라야 해요. 사용 가능한 모듈 빌더·작성 도구 중 일부를 쓰는 걸 강력히 권장해요.
fez로 빠르게 훑어보기 (Quick Overview using fez)
skeleton을 만들려면 다음 명령을 실행하세요.
fez init MyNew::Module
# Will create the following:
# MyNew--Module/
# ├── lib
# │ └── MyNew
# │ └── Module.rakumod
# ├── META6.json
# └── t
# └── 00-use.rakutest
새 모듈·클래스·리소스·build-depends·depends를 추가해야 한다면 다음을 사용할 수 있어요 (각각의 리소스는 자동으로 META6.json에 추가돼요).
fez module My::New::Module
fez module --class My::New::Module
fez resource xyz
fez depends --build Build::Dependency
fez depends Runtime::Dependency
전체 설명 (Full Explanation)
fez나 그와 동등한 도구를 쓸 생각이라면(쓰는 게 좋아요), 그 전에 다음 내용을 한번 읽어 두면 유용해요. 모듈을 개발하면서 모듈이 어떻게 구조화되는지에 대한 요구사항과 관례를 미리 알 수 있으니까요.
META6.json 파일은 프로젝트의 각종 메타데이터와 그 용도를 지정해요. 파일에는 모듈의 파일시스템과 대응되는 여러 섹션이 있어서, 아래 섹션들은 파일시스템과 META6.json 파일을 나란히 따라가며 설명할게요. 어떤 섹션은 둘 중 하나에만 속하고, 많은 섹션은 둘 다에 걸쳐 있어요. 파일시스템 항목은 file이나 directory라고 부르고, META6.json 섹션은 key나 section이라고 부를게요.
모듈 루트 디렉터리와 META6.json 파일
이 파일의 속성들은 META6 클래스가 분석해요. 속성들은 optional(선택), mandatory(필수), customary(관례적)으로 나뉘어요. mandatory는 파일에 반드시 넣어야 하는 것이고, customary는 현재 Raku ecosystem이 사용하고 공개 시 모듈 페이지에 표시될 수 있지만 의무는 아닌 거예요.
모듈 이름을 딴 프로젝트 디렉터리를 만드세요. 예를 들어 모듈이 Vortex::TotalPerspective면 프로젝트 디렉터리 이름은 Vortex-TotalPerspective로요.
프로젝트 디렉터리를 이렇게 만드세요:
Vortex-TotalPerspective/
├── META6.json
├── LICENSE
├── README.md
├── lib
│ └── Vortex
│ └── TotalPerspective.rakumod
└── bin
│ └── vortex
└── t
└── basic.rakutest
[META6.json 파일을 이렇게 만들어 보세요:
{
"name" : "Vortex::TotalPerspective",
"description" : "Wonderful simulation to get some perspective.",
"source-url" : "git://github.com/you/Vortex-TotalPerspective.git"
"auth" : "github:SomeAuthor",
"authors" : [ "Your Name" ],
"tags": [
"Vortex", "Total", "Perspective"
],
"depends" : [ ],
"build-depends" : [ ],
"test-depends" : [ ],
"license" : "Artistic-2.0",
"version" : "0.0.1",
"api" : "1",
"raku" : "6.c",
"provides" : {
"Vortex::TotalPerspective" : "lib/Vortex/TotalPerspective.rakumod"
},
"resources" : [ ],
}
META 설계 문서에는 더 많은 필드가 설명되어 있지만, 그중 일부는 기존 패키지 매니저가 구현하지 않았어요. 그래서 zef 같은 기존 패키지 매니저와의 호환성을 보장하려면 위 예제 블록에 설명된 필드만 사용하는 게 좋아요. Moritz Lenz의 모든 모듈 저장소에서 예시를 찾아볼 수도 있어요. 다만 일부 모듈은 위의 source-type처럼 현재 무시되는 필드를 쓸 수도 있다는 점을 감안하세요.
name 키
name 키는 필수예요. 이걸 넣지 않으면 zef이 실패해요. 스크립트 묶음의 의존성을 표현하기 위해 META6.json 파일을 만들었다고 해도, 이 섹션은 반드시 포함해야 해요.
description 키
description 필드도 필수이며, 모듈에 대한 짧은 설명을 담아요.
source-url 키
source-url은 모듈이 개발되는 저장소의 URL을 나타내요. 모듈 ecosystem에 공개하려면 관례상 넣는 필드예요. 현재 모듈 ecosystem은 프로젝트 설명에서 이 URL을 링크해요.
auth 섹션도 함께 보세요.
auth와 authors 섹션
authors 섹션은 모든 모듈 작성자의 목록을 담아요. 작성자가 한 명뿐이라면 단일 요소 목록을 제공해야 해요. 이 필드는 선택이에요.
auth 섹션은 GitHub이나 Bitbucket·GitLab 같은 다른 저장소 호스팅 사이트에서 작성자를 식별해요. 이 필드는 customary인데, ecosystem에서 작성자를 식별하는 데 쓰이고, 같은 이름의 모듈이 서로 다른 작성자를 가질 수 있게 해 주기 때문이에요.
tags 섹션
tags 섹션도 선택이에요. Raku ecosystem에서 모듈을 설명하는 데 사용해요.
depends, build-depends, test-depends 섹션
depends, build-depends, test-depends 섹션은 설치 단계 중 해당 단계에서 사용되는 서로 다른 모듈들을 담아요. 모두 선택이지만, 있다면 해당 단계에 필요한 모듈을 반드시 포함해야 해요. 이 의존성들은 선택적으로 Version 지정 문자열을 사용할 수 있고, zef이 이 모듈들의 존재와 버전을 확인해 필요하면 설치하거나 업그레이드해요.
//...
"depends": [
"URI",
"File::Temp",
"JSON::Fast",
"Pod::To::BigPage:ver<0.5.0+>",
"Pod::To::HTML:ver<0.6.1+>",
"OO::Monitors",
"File::Find",
"Test::META"
],
//...
추가로, depends는 위처럼 배열이거나 runtime과 build 두 키를 쓰는 hash일 수도 있어요. 그 역할은 이름이 스스로 설명하죠. 예를 들어 Inline::Python에서 그렇게 써요.
//...
"depends" : {
"build": {
"requires": [
"Distribution::Builder::MakeFromJSON",
{
"from" : "bin",
"name" : {
"by-distro.name" : {
"macosx" : "python2.7-config",
"debian" : "python2.7-config",
"" : "python2-config"
}
}
}
]
},
"runtime": {
"requires": [
"python2.7:from<native>"
]
}
}, // ...
일반적으로 대부분의 경우 배열 형태가 충분해요.
README.md 파일
README.md 파일은 마크다운 형식의 텍스트 파일이에요. GitHub/GitLab에 보관된 모듈은 그쪽에서, zef로 접근 가능한 모듈은 raku.land 웹사이트가 나중에 자동으로 HTML로 렌더링해요.
LICENSE 파일과 키
LICENSE파일에 관해서, 다른 선호가 없다면 Rakudo Raku가 쓰는 것과 같은 걸 쓰면 돼요. 그 라이선스의 원본을 복사·붙여넣기해서 자신의LICENSE파일에 넣으세요.- META6.json의 license 필드는 여기 https://spdx.org/licenses/에 나열된 표준화된 이름 중 하나여야 해요. 많은 ecosystem 모듈이 쓰는 Artistic 2.0 라이선스의 식별자는
Artistic-2.0이에요. 표준화된 식별자를 쓰면 사람과 컴퓨터 모두 메타데이터만 보고 실제 어떤 라이선스가 쓰였는지 쉽게 알 수 있어요! spdx.org에서 자신의 라이선스를 찾을 수 없거나 자신만의 라이선스를 쓴다면, 라이선스 필드에 라이선스 이름을 넣으면 돼요. 자세한 내용은 https://github.com/Raku/old-design-docs/blob/master/S22-package-format.pod#license를 보세요.
버전 키 (The versioning keys)
version 키
버전 번호 체계를 고를 때는 "major.minor.patch"를 쓰는 걸 권장해요 (자세한 내용은 버저닝 사양 참고). 이 값은 META6.json의 version 키에 들어가요. 이 필드는 선택이지만, 설치 시 이미 설치된 버전이 있으면 그것과 비교하는 데 사용돼요.
api 키
선택적으로 api 필드를 설정할 수 있어요. 이 값을 올리면 모듈이 제공하는 인터페이스가 이전 버전과 하위 호환되지 않는다는 뜻이에요. 시맨틱 버저닝을 지키고 싶다면 쓸 수 있어요. 모범 사례는 api 필드를 major 버전 번호와 같은 값으로 유지하는 거예요. 그러면 의존 측에서 :api 부분을 포함해 모듈에 의존할 수 있고, 하위 호환되지 않는 릴리스가 당겨지지 않게 보장해요.
raku 키
raku 버전을 모듈이 동작하는 최소 Raku 버전으로 설정하세요. 이 필드는 필수예요. 모듈이 크리스마스 릴리스(6.c)와 그 이후에서 유효하면 6.c, 최소한 디왈리(6.d) 버전이 필요하면 6.d를 쓰세요.
provides 섹션과 lib 디렉터리
프로젝트에 메인 모듈의 일을 돕는 다른 모듈이 있다면, 그것들을 lib 디렉터리에 이렇게 둬야 해요.
lib
└── Vortex
├── TotalPerspective.rakumod
└── TotalPerspective
├── FairyCake.rakumod
└── Gargravarr.rakumod
provides 섹션에는 distribution이 제공하고 설치되길 원하는 모든 네임스페이스를 넣어요. 여기에 명시적으로 포함된 모듈 파일만 다른 프로그램에서 use·require로 설치·사용 가능해요. 이 필드는 필수예요.
provides 객체(JSON 의미의 객체)에서 키는 모듈 이름이고, 값은 모듈 루트에서 lib/ 디렉터리의 파일까지의 경로예요.
bin 디렉터리
$PATH에서 실행해야 하는 프로그램·스크립트는 bin 디렉터리에 넣어야 해요. 이들은 설치된 Rakudo distribution이 실행 파일용으로 할당한 디렉터리로 복사돼요. 보통 /path/to/installation/share/perl6/site/bin/이고, 이 폴더는 $PATH에 있어야 해요. 참고: perl6 경로 구성 요소는 언어 이름이 바뀌기 전의 것이라 그렇습니다.
resources 디렉터리와 섹션
resources 섹션은 선택이지만, 있다면 설치하길 원하는 resources 디렉터리의 파일 목록을 담아야 해요. 이 파일들은 라이브러리 파일 옆에 해시된 이름으로 설치돼요.
런타임에 접근할 수 있도록 설치하고 싶은 추가 파일(템플릿이나 동적 라이브러리 같은)이 있다면, 프로젝트의 resources 하위 디렉터리에 넣으세요. 예:
resources
└── templates
└── default-template.mustache
그 파일은 META6.json에서 참조되어 distribution 경로가 프로그램에 제공될 수 있어야 해요.
{
"name" : "Vortex::TotalPerspective",
"provides" : {
"Vortex::TotalPerspective" : "lib/Vortex/TotalPerspective.rakumod"
},
"resources": [ "templates/default-template.mustache"]
}
추가 파일은 모듈 코드 안에서 접근할 수 있어요. 아래의 %?RESOURCES 변수 섹션을 보세요.
$?DISTRIBUTION 변수
$?DISTRIBUTION 변수는 provides 섹션에 나열된 파일(보통 lib 디렉터리 안)에서만 값이 채워져요. 그 밖(예: 테스트)에서 쓰고 싶다면 그 값을 반환하는 Routine을 직접 제공해야 해요.
%?RESOURCES 변수
여기 예시는 Distribution::Resource 객체를 반환한다는 점을 주의하세요. 이걸 파일시스템의 객체에 대한 경로로 생각하면 안 돼요.
my $template-text = %?RESOURCES<templates/default-template.mustache>.slurp;
참고: %?RESOURCES로 이 파일들에 접근하는 것은 설치된 위치나 IO 클래스를 얻는 게 아니에요. 제공된 이름으로 인덱스된 Distribution::Resource 객체에 접근하는 거예요. 컴파일 타임에 파일명을 박아 두면 런타임 위치와 달라질 수 있으니, 사용할 때 주의해야 해요.
$?RESOURCES 변수는 provides 섹션에 나열된 파일(보통 lib 디렉터리 안)에서만 값이 채워져요. 그 밖(예: 테스트)에서 쓰고 싶다면 그 값을 반환하는 Routine을 직접 제공해야 해요.
사용 예시:
sub MyModule-resources(*@resources) is export(:tests) {
for @resources -> $resource-filename {
my $resource = %?RESOURCES{$resource-filename};
# Just some error-checking code
if $resource !~~ Distribution::Resource {
note "Could not find resource '$resource-filename' in distribution";
say qx{ls -laF ; ls -laF resources ; cat META6.json};
say "Resource is: " ~ $resource.raku;
say "Resource keys are: " ~ %?RESOURCES.keys.raku;
}
}
return %?RESOURCES;
}
...그리고 코드에서 이렇게 사용할 수 있어요.
use TOP :tests :DEFAULT; # Note that the :tests here matches the "is export" above
my $resource-name = 'templates/default-template.mustache';
my $resources = MyModule-resources($resource-name);
my $resource = $resources{$resource-name};
my $file_handle = $resource.open();
위 코드는 리소스를 찾지 못하면 꽤 많은 디버그 출력을 내지만, 그래도 계속 진행해요. GitHub 액션 같은 원격 환경에서 실행할 때 유용할 수 있어요.
t 디렉터리와 모듈 테스트
아직 테스트가 없으면 t 디렉터리와 basic.rakutest 파일은 일단 생략할 수 있어요. 테스트 작성 방법에 대한 자세한 내용은 (지금은) 다른 모듈이 Test을 어떻게 쓰는지 살펴보는 게 도움이 돼요.
Test::META 모듈은 META6.json 파일의 정확성을 검사하는 데 도움을 줘요. 필수 필드를 모두 있는지, 그리고 모든 필드에 사용된 타입이 올바른지 확인해요.
모듈을 테스트하고 싶다면 다음 명령으로 방금 만든 모듈 폴더에서 직접 모듈을 설치할 수 있어요.
zef install ./your-module-folder
이렇게 하면 모듈이 사전 컴파일·설치된다는 점에 주의하세요. 소스를 변경하면 모듈을 다시 설치해야 해요. (use lib 프라그마, -I 커맨드라인 스위치, 또는 RAKULIB 환경 변수를 사용해 개발 중 모듈 소스 경로를 포함시키면 설치를 전혀 하지 않아도 돼요.)
위의 test-depends 섹션도 참고하세요.
모듈 문서화하기 (Documenting your modules)
모듈을 문서화하려면 그 안에서 Raku Pod 마크업을 사용하세요. 모듈 문서는 아주 환영받고, Raku 모듈 디렉터리(또는 다른 사이트)가 Pod 문서를 HTML로 렌더링해 쉽게 탐색하게 되면 특히 더 중요해져요. 모듈 안의 Pod 문서 외에 추가 문서가 있다면 그것을 담을 doc 디렉터리를 만들고, lib 디렉터리와 같은 폴더 구조를 따르세요.
doc
└── Vortex
└── TotalPerspective.rakudoc
빌드 훅 (Build hooks)
모듈이 설치 중 추가 처리를 요구해서 비-Raku 운영체제 리소스와 완전히 통합·사용해야 한다면, 최상위 디렉터리에 [Build.rakumod 파일(빌드 훅)을 추가해야 할 수도 있어요. zef 설치 프로그램이 설치 과정의 첫 단계로 이 파일을 사용해요. 간단한 예는 zef의 README를 보세요. zef 자체처럼 기존 ecosystem 모듈들의 다양한 사용 시나리오도 참고하세요.
참고1: 일부 오래된 모듈은 소스 제어 시스템의 종류(보통
git)를 나타내는 데 쓰인source-type필드도 제공해요. 그러나 이 필드는 오늘날zef과 나머지 도구에서 무시돼요.
참고2: 위에서 설명한 것은 최소 프로젝트 디렉터리예요. 프로젝트에 모듈과 함께 배포하고 싶은 스크립트가 있다면
bin디렉터리에 넣으세요. 모듈 디렉터리에서 모듈 옆에 그래픽 로고가 표시되길 원한다면logotype디렉터리를 만들고 그 안에logo_32x32.png파일을 넣으세요. 나중에는CONTRIBUTORS,NEWS,TODO등의 파일을 추가하는 것도 고려해 볼 수 있어요.