하리Hari

패키지 쓰기와 만들기

hana add로 다른 사람이 만든 패키지를 가져다 쓰고, 내 패키지를 만들어 나누는 방법을 알아봐요.

패키지는 다른 사람이 (또는 내가) 만들어 둔 함수와 클래스 묶음이에요. Hana 런타임에는 패키지를 내려받고 관리하는 명령이 들어 있어요. 패키지는 git 저장소이고, 이름이 곧 저장소 주소예요. 중앙 서버는 없어요. 브라우저의 실행 버튼은 패키지를 쓸 수 없고, Hana 런타임으로 실행할 때만 써요.

패키지 쓰기

프로젝트 폴더에서 패키지를 추가해요. git이 설치되어 있어야 해요.

hana add github.com/주인/저장소

이 한 줄이 하는 일은 이래요.

  • 저장소의 v1.2.0이나 1.2.0 같은 버전 태그 중 가장 높은 것을 골라요.
  • 그 버전을 내 컴퓨터의 캐시 폴더(~/.hana/pkg)에 내려받아요. 폴더는 환경 변수 HANA_HOME으로 바꿀 수 있어요.
  • 그 패키지가 필요로 하는 다른 패키지도 함께 내려받아요.
  • 프로젝트 폴더에 hana.jsonhana-lock.json을 써요.

버전을 직접 정하려면 @를 붙여요: hana add github.com/주인/저장소@1.2.0.

이제 저장소 경로를 그대로 대괄호 안에 써서 가져와요. 다른 표준 모듈과 똑같이 생겼어요.

[github.com/주인/저장소]에서 <인사하기>를 가져오자
<인사하기>("하나")를 출력하자

패키지는 하자용과 카나데용 진입점을 따로 가질 수 있어요. 내 스크립트의 언어에 맞는 진입점이 없으면 “이 언어의 진입점이 없어요”라는 오류가 나요.

hana.json과 hana-lock.json

{
  "dependencies": {
    "github.com/주인/저장소": "1.2.0"
  }
}

hana.json내가 원하는 것이에요. 적힌 버전은 “이 버전 이상”이라는 뜻의 최소 버전이에요. ^~ 같은 범위 표기는 없어요.

{
  "github.com/주인/저장소": {
    "version": "1.3.4",
    "commit": "a1b2c3d4e5f6..."
  }
}

hana-lock.json실제로 고른 것이에요. 정확한 버전과, 그때 그 버전의 태그가 가리키던 커밋이 적혀요. 내가 추가한 패키지뿐 아니라 그 패키지가 필요로 하는 패키지까지 모두 들어 있어요. 두 파일 모두 git에 함께 올려 두면, 다른 컴퓨터에서 hana install 한 번으로 똑같은 버전을 받아요.

같은 패키지를 여러 곳에서 서로 다른 최소 버전으로 요구하면, 요구된 것 중 가장 높은 버전을 하나만 골라요. 최소 버전만 적으니 “조건이 서로 안 맞아서 설치가 실패하는” 일이 없어요.

다른 컴퓨터에서, 그리고 다른 명령들

명령 하는 일
hana install hana-lock.json에 적힌 패키지를 모두 내려받아요. lock이 hana.json보다 모자라면 버전을 다시 골라요
hana remove github.com/주인/저장소 패키지를 빼요. 그 패키지 때문에만 필요했던 것도 lock에서 빠져요
hana list 쓰고 있는 패키지와 버전을 보여줘요. *는 내가 직접 추가한 것이에요
hana why github.com/주인/저장소 그 패키지가 왜 들어와 있는지 보여줘요. 내가 직접 추가했는지, 어떤 패키지를 거쳐 들어왔는지(가 -> 나 -> 저장소)를 알려 줘요
hana outdated 더 높은 버전이 나온 패키지를 보여줘요. 올리려면 hana add 경로@버전을 다시 실행해요

hana run아무것도 내려받지 않아요. 패키지가 설치되어 있지 않으면 “설치되어 있지 않아요”라는 오류로 hana install을 알려 줘요. lock에 적힌 커밋과 실제로 내려받은 커밋이 다르면(누군가 태그를 옮겼다면) 설치를 거부해요.

내 컴퓨터에 있는 패키지를 고치면서 쓰기

패키지를 만들면서 그 패키지를 쓰는 프로젝트도 함께 고칠 때는, hana.jsonreplace를 적어 내려받기 대신 내 폴더를 가리키게 해요.

{
  "dependencies": { "github.com/주인/저장소": "1.2.0" },
  "replace": { "github.com/주인/저장소": "../저장소" }
}

replace는 이 프로젝트에서만 통하고, lock에는 적히지 않아요.

패키지 만들기

패키지는 git 저장소 하나예요. 폴더 구성은 이래요.

저장소/
├── hana.pkg.json
├── hari/
   └── index.hr 하자 진입점
└── kanade/
    └── index.knd 카나데 진입점

진입점은 둘 중 하나만 있어도 돼요. 진입점 안의 함수와 클래스를 다른 사람이 [github.com/주인/저장소]에서 …를 가져오자로 가져가요. hana.pkg.json은 패키지 자신의 정보예요.

{
  "name": "github.com/주인/저장소",
  "version": "1.2.0",
  "dependencies": {
    "github.com/주인/다른패키지": "2.0.0"
  }
}
  • name은 저장소 경로와 같아야 해요(다르면 설치가 거부돼요).
  • dependencies는 이 패키지가 필요로 하는 패키지와 최소 버전이에요. 패키지끼리 서로를 돌고 돌아 필요로 하면 설치가 거부돼요.
  • 진입점 경로를 바꾸려면 "entry": {"hari": "src/main.hr"}처럼 적어요.
  • 버전은 git 태그로 정해요. 새 버전을 낼 때 git tag v1.3.0을 만들고 푸시하면 돼요.

네이티브 라이브러리를 넣기

하자나 카나데로 하기 어려운 일은 Go나 C 같은 언어로 만든 라이브러리(.dll, .so, .dylib)에 맡길 수 있어요. 운영체제마다 미리 만들어 둔 파일을 hana.pkg.json에 적어요.

{
  "native": {
    "windows-amd64": {
      "file": "native/저장소.dll",
      "url": "https://주소/저장소-windows-amd64.dll",
      "sha256": "…64자리…"
    },
    "linux-amd64": {
      "file": "native/libjeojangso.so",
      "url": "https://주소/libjeojangso-linux-amd64.so",
      "sha256": "…64자리…"
    }
  }
}

hana add지금 컴퓨터의 플랫폼 것만 내려받고, sha256이 맞는지 확인해요. 다르면 파일을 버리고 설치를 멈춰요. 저장소 안에 파일이 이미 들어 있으면(file이 있으면) 내려받지 않아요. 라이브러리가 지켜야 하는 규칙은 hana 저장소의 native/native.go에 적혀 있어요.

설치 스크립트

미리 만든 파일을 못 주고 설치할 때 직접 빌드해야 한다면 설치 스크립트를 쓸 수 있어요. 셸을 거치지 않는 명령 배열로 적어요.

{
  "scripts": {
    "install": ["go", "build", "-buildmode=c-shared", "-o", "native/저장소.dll", "./native"]
  }
}

스크립트는 컴퓨터에서 마음대로 돌아가는 프로그램이라, 그냥은 실행하지 않아요.

  • 사용자가 hana add github.com/주인/저장소 --allow-scripts로 승인해야 해요. 승인하면 hana.jsontrustedScripts에 적혀요.
  • 승인한 스크립트의 해시가 hana-lock.json에 적혀요. 스크립트가 바뀌면 다시 승인하기 전까지 거부돼요.
  • 다른 패키지가 필요로 해서 딸려 온 패키지의 스크립트는 자동으로 허용되지 않아요. 패키지마다 따로 승인해요.
  • 스크립트는 hana addhana install 안에서만 돌아요. hana run은 절대 실행하지 않아요.
  • 스크립트를 실행하기 전에 무슨 명령인지 화면에 보여 줘요.

승인하지 않은 스크립트는 건너뛰고 안내만 해요. 스크립트에는 샌드박스가 없으니, 믿을 수 있는 패키지에만 승인하세요.

알아 둘 것

  • 패키지 안의 함수는 같은 패키지의 다른 함수그 패키지가 가져온 다른 패키지를 마음대로 불러요. 가져가는 사람이 그것들을 따로 가져올 필요가 없고, 내 스크립트에 같은 이름의 함수가 있어도 서로 가리지 않아요.
  • 패키지 맨 위에 만든 변수와 문장은 그 패키지의 것이에요. 패키지는 처음 가져올 때 딱 한 번 준비되고(맨 위 문장이 한 번 실행돼요), 그 패키지의 함수는 그 변수를 읽고 바꿀 수 있어요. 여러 곳에서 가져와도 같은 변수를 함께 써요. 반대로 내 스크립트의 변수는 패키지의 함수에서 보이지 않아요.
  • 클래스 이름은 프로그램 하나에 하나예요. 서로 다른 두 패키지(또는 내 스크립트)가 같은 이름의 클래스를 가지고 있으면 가져올 때 오류가 나서 알려 줘요. 하나를 <이름>을 <별칭>으로 가져오자로 가져와 다른 이름을 붙이면 돼요. 패키지를 만들 때는 클래스 이름이 다른 곳과 겹치지 않게 지어 주세요.
  • 패키지 경로는 github.com/주인/저장소처럼 호스트 이름(점이 있는)과 주인, 저장소 이름으로 이루어져야 해요. 저장소 안의 하위 폴더를 패키지로 쓸 수는 없어요.
  • 비공개 저장소도 받을 수 있어요. 내려받기는 컴퓨터의 git이 하니까, git에 로그인해 두거나(자격 증명 관리자) ssh 키를 등록해 두면 돼요. 터미널에서 실행하면 git이 로그인을 물어볼 수도 있어요. ssh 주소로 받고 싶다면 환경 변수 HANA_GIT_PROTOCOL=ssh를 설정하세요(git@github.com:주인/저장소로 받아요). 로그인이 안 되면 “로그인이 필요한 비공개 저장소이거나 저장소가 없어요”라고 알려 줘요.
  • Hana 런타임이 함께 주는 timezone 같은 패키지는 hana add 없이 이름만으로 가져와요.
  • 패키지를 쓰는 프로그램을 실행 파일로 묶으면 패키지의 하리 코드는 프로그램 안에 들어가고, 네이티브 라이브러리는 실행 파일 옆에 함께 나와요.
놀이터
결과
코드를 작성하고 '실행' 버튼을 눌러보세요.