-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 35245e2
Showing
23 changed files
with
1,232 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: [main] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
env: | ||
GH_TOKEN: ${{ secrets.GH_CLI_AUTH_TOKEN }} | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Python | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: '3.11' | ||
- uses: erg-lang/[email protected] | ||
- name: Build | ||
run: | | ||
erg --version | ||
timeout 30s erg src/main.er | ||
- name: Install | ||
run: | | ||
timeout 30s erg src/main.er -- install | ||
- name: Test | ||
run: | | ||
poise --version | ||
poise help | ||
poise build | ||
poise check | ||
poise clean | ||
poise run | ||
poise metadata | ||
poise metadata --format json | ||
poise install | ||
echo n | poise publish --debug |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
build/ | ||
|
||
test_.* | ||
.log/ | ||
|
||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
# poise | ||
|
||
The Erg package manager | ||
|
||
This package manager is bundled with erg and is available via the `erg pack` subcommand. See [here](https://github.com/erg-lang/erg/blob/main/doc/EN/tools/pack.md) for information on how to use the command. | ||
|
||
## Requirements | ||
|
||
* Git | ||
* [Github CLI](https://cli.github.com/) (if you want to publish packages) | ||
|
||
## Bootstrap | ||
|
||
```sh | ||
erg src/main.er -- install | ||
``` | ||
|
||
## Usage | ||
|
||
Actually, poise is inspired by cargo (Rust's package manager) and has almost the same command options. | ||
|
||
### Create a new package | ||
|
||
* Creating a new package in the current directory | ||
|
||
```sh | ||
erg pack init | ||
``` | ||
|
||
* Making a new directory and creating a package | ||
|
||
```sh | ||
erg pack new package_name | ||
``` | ||
|
||
### Build a package | ||
|
||
This generates the artifacts in the `build` directory. | ||
|
||
```sh | ||
erg pack build | ||
``` | ||
|
||
### Check a package | ||
|
||
This does not generate the artifacts. | ||
|
||
```sh | ||
erg pack check | ||
``` | ||
|
||
### Run a package | ||
|
||
```sh | ||
erg pack run | ||
``` | ||
|
||
### Test a package | ||
|
||
This runs the test subroutines (named with `test_` prefix) in the `tests` directory. | ||
|
||
```sh | ||
erg pack test | ||
``` | ||
|
||
### Publish a package | ||
|
||
This publishes the package to [the registry](https://github.com/erg-lang/package-index). | ||
|
||
```sh | ||
erg pack publish | ||
``` | ||
|
||
### Install a package | ||
|
||
* Install the package from the current directory | ||
|
||
```sh | ||
erg pack install | ||
``` | ||
|
||
* Install the package from the registry | ||
|
||
```sh | ||
erg pack install package_name | ||
``` | ||
|
||
### Uninstall a package | ||
|
||
* Uninstall the package from the current directory | ||
|
||
```sh | ||
erg pack uninstall | ||
``` | ||
|
||
* Uninstall the package by specifying the name | ||
|
||
```sh | ||
erg pack uninstall package_name | ||
``` | ||
|
||
### Update dependencies | ||
|
||
```sh | ||
erg pack update | ||
``` | ||
|
||
### Display the package information | ||
|
||
```sh | ||
erg pack metadata | ||
``` | ||
|
||
* Display the package information with json format | ||
|
||
```sh | ||
erg pack metadata --format json | ||
``` | ||
|
||
### Clean the build directory | ||
|
||
```sh | ||
erg pack clean | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# poise | ||
|
||
Ergパッケージマネージャ | ||
|
||
このパッケージマネージャはergに同梱されており、`erg pack`サブコマンドで利用できます。コマンドの利用方法については[こちら](https://github.com/erg-lang/erg/blob/main/doc/JA/tools/pack.md)を参照してください。 | ||
|
||
## Requirements | ||
|
||
* Git | ||
* [Github CLI](https://cli.github.com/) (パッケージを公開したい場合) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# アーキテクチャ | ||
|
||
The Erg package manager (コードネーム: poise)はErgを用いて実装されている。現状では実用可能なErgのバックエンドがCPythonバックエンドしかないため、poiseは単体のバイナリとしては提供されておらず、`erg pack`サブコマンドが内部的に呼び出すアプリケーションパッケージとなっている。将来的にErgにネイティブコードバイナリが追加された場合でもパッケージ管理は基本的に`erg pack`で行う。 | ||
|
||
poiseは以下のコマンドを持つ。 | ||
|
||
* `init`: パッケージを初期化する | ||
* `install`: パッケージをインストールする(`erg install`と同じ、パッケージの依存関係を追加する場合は`add`) | ||
* `update`: パッケージをアップデートする | ||
* `add`: パッケージの依存関係を追加する | ||
* `clean`: パッケージをクリーニングする(キャッシュの削除など) | ||
* `build`: パッケージをビルドする(`erg build`と同じ) | ||
* `run`: パッケージをビルドし、実行する | ||
* `publish`: packages.erg-lang.orgにパッケージを公開する | ||
* `test`: パッケージのテストを実行する(`erg test`と同じ) | ||
|
||
各サブコマンドの内部処理について解説する。 | ||
|
||
## init | ||
|
||
規定のディレクトリ構成をセットアップする。規定のディレクトリ構成は以下の通り[^1]。 | ||
|
||
```console | ||
/package # package root directory, this is also the package name | ||
/build # Directory to store build results | ||
/debug # Artifacts during debug build | ||
/release # Artifacts of release build | ||
/doc # Documents (in addition, by dividing into subdirectories such as `en`, `ja` etc., it is possible to correspond to each language) | ||
/src # source code | ||
/main.er # file that defines the main function | ||
/tests # Directory to store (black box) test files | ||
/package.er # file that defines package settings | ||
``` | ||
|
||
initの仕事はbuildを除くディレクトリを自動で作成することである。`--app`と`--lib`はそれぞれアプリケーションパッケージとライブラリパッケージを作成する。`--app`を指定した場合、`src`以下に`main.er`が作成される。`--lib`を指定した場合、`src/lib.er`が作成される。両方指定することも可能であり、`src/main.er`と`src/lib.er`が作成される。 | ||
|
||
## install | ||
|
||
アプリケーションパッケージをインストールする。パッケージ名を指定しなかった場合、`package.er`に記述された依存関係をインストールする。パッケージは`.erg`以下にキャッシュされ、他のパッケージでキャッシュが再利用される場合がある。 | ||
|
||
アプリケーションバッケージのインストールについて内部処理のフローを説明する。 | ||
|
||
1. `erg-lang/package-index`からパッケージのメタデータを取得する | ||
|
||
* indexはcargoに倣いsparse registryとして実装されている。すなわち、全てのパッケージ情報を単一のjsonなどで管理するのではなく、名前ごとに複数のディレクトリに分割し、そのディレクトリ内にパッケージのメタデータをjsonなどで管理する。パッケージのメタデータはjson形式である。 | ||
|
||
* 例: | ||
* `erg`: `package-index/certified/e/erg.json` | ||
* `foo-bar`: `package-index/certified/f/foo-bar.json` | ||
* `foo/bar`: `package-index/developers/foo/b/bar.json` | ||
|
||
ergのパッケージレジストリはまず開発者`developers`ごとに名前空間が別れていることに注意されたい。その後リクエストのあったパッケージは審査を経て`certified`にも登録される。 | ||
パッケージをインストールする際に開発者名が指定されなかった場合`certified`名前空間から検索されることになる。見つからなかった場合、各開発者の名前空間から検索される。 | ||
|
||
jsonの中身は以下のようにバージョンごとに整列されている。つまり、`package.er`から`name`と`version`を抜き、その他の情報がjsonにシリアライズされて配置される。 | ||
大小関係の判定はsemverに従う。 | ||
|
||
```json | ||
{ | ||
"versions": { | ||
"0.1.0": { | ||
"description": "an awesome package", | ||
"dependencies": { | ||
"foo": "0.1.0" | ||
}, | ||
... | ||
} | ||
}, | ||
... | ||
} | ||
``` | ||
|
||
2. リソースのダウンロード | ||
|
||
後述するようにパッケージはキャッシュされるので、既に同一バージョンの同一パッケージがダウンロードされている場合このステップは省かれる。 | ||
|
||
特にバージョンが指定されなかった場合、json内の一番下のバージョンがインストールされる。 | ||
|
||
Erg package systemでは、再現性のためパッケージは全て圧縮されてindex内に保存される。圧縮形式はtar.gzであり、jsonと同じディレクトリに配置される。例えば、`erg`の場合は`package-index/certified/e/erg/0.1.0.tar.gz`となる。 | ||
|
||
さらにjson内に記述されているdependenciesから再帰的に依存関係を解決し、必要なパッケージをダウンロードする。 | ||
|
||
ダウンロードされたパッケージは解凍されて`.erg`以下に配置される。例えば、`erg`の場合は`.erg/packages/github.com/certified/erg/0.1.0`となる。`foo/bar`の場合は`.erg/packages/github.com/developers/foo/bar/0.1.0`となる。 | ||
|
||
複数のモジュールが同一のパッケージの別バージョンを利用している場合、新しい方のバージョンのみを用いることができないかトライされる。これに失敗しても別バージョンが追加でインストールされるだけでビルドは継続される。この依存関係解決の結果は後述するpackage.lock.erに保存される。 | ||
|
||
パッケージをどのように読み込みリンクするかはコンパイラの責務となる。具体的には、コンパイラはpackage.erがプロジェクトルートにある場合、その中のdependenciesをプロジェクト内で使えるパッケージとして認識する。実際の名前解決には後述するpackage.lock.erを用いる。 | ||
|
||
3. ロックファイルの生成 | ||
|
||
これは2.と並行して行われる。パッケージのバージョンはsemantic versioningに従って範囲指定することができる。そしてパッケージは日々アップデートされるので、package.erの情報だけでは再現性が担保されない。そこで、パッケージのバージョンを固定するためにロックファイルが用意されている。ロックファイルは`package.lock.er`という名前で`package.er`と同一のディレクトリに配置される。 | ||
|
||
例: | ||
|
||
```erg | ||
.packages = { | ||
.foo = { .version = "0.1.0", features = ["debug"] }, | ||
.bar = { .version = "0.1.1" }, | ||
... | ||
} | ||
``` | ||
|
||
ビルド時にコンパイラはpackage.lock.erを見ながらパッケージを名前解決する。package.lock.erは手動で編集することも可能であるが、コンパイラはパッケージ管理の責務を負わないので編集後にergcを用いてコンパイルすると名前解決に失敗する可能性がある。`erg pack build`/`erg build`ならば毎回package.lock.erの検証を行うので安全である。 | ||
|
||
## update | ||
|
||
アプリケーションパッケージをアップデートする。パッケージ名を指定しなかった場合、`package.er`に記述された依存関係をアップデートする。 | ||
|
||
依存関係のアップデートは貪欲(greedy)に行われる。例えばパッケージAとBがCに依存していて、Aの場合はCのバージョンアップが可能だがBの場合は不可能な場合、Aのみがアップデートされる。従って複数のパッケージ間で汎用的に共用されるパッケージは多数のバージョンが内部的に併存する場合がある。 | ||
|
||
## build | ||
|
||
パッケージをビルドする。poiseはpackage.lock.erを検証し、パスすればコンパイラにコンパイルを命令する。 | ||
コンパイルの成果物(.pycファイルまたはネイティブコード)はbuild以下に配置される。デフォルトではdebugビルドが行われ、成果物は`build/debug`以下に出力されるが、`--release`を指定することでreleaseビルドが行われ、`build/release`以下に出力される。これはpackage.erのあるプロジェクトの場合コンパイラが配置する。 | ||
|
||
現在は未実装だが、コンパイラがインクリメンタルビルドに対応した場合、`build/{debug, release}`以下にビルド成果物がキャッシュされる。 | ||
|
||
ビルド時はtests、examples以下のファイルも検査される。またファイル内のdoc commentsもergコードブロックがあれば検査される。 | ||
|
||
--- | ||
|
||
[^1]: パッケージ内で利用されるサブパッケージは`packs`以下に配置することが推奨される。しかしErgの場合モジュール=1ファイル単位でキャッシュ&並列コンパイルされるのでRustほどパッケージ(crate)を分割するメリットはない。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.name = "poise" | ||
.version = "0.0.1" | ||
.description = "The Erg package manager" | ||
.authors = ["Shunsuke Shibayama <[email protected]>"] | ||
.license = "MIT or Apache-2.0" | ||
.repository = "https://github.com/erg-lang/poise" | ||
.type = "app" | ||
|
||
.features = { | ||
.debug = [] | ||
} | ||
|
||
.dependencies = {=} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.version = "1" | ||
.packages = [ | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
{time!;} = pyimport "time" | ||
{mkdir!;} = pyimport "os" | ||
{exists!;} = pyimport "os/path" | ||
{move!;} = pyimport "shutil" | ||
subprocess = pyimport "subprocess" | ||
ac = import "ansicolor" | ||
|
||
{Versions!;} = import "download" | ||
{Config;} = import "cfg" | ||
{download_dependencies_on_demand!;} = import "download" | ||
{load_package_er_as_json!;} = import "metadata" | ||
|
||
.compile_command! vers: Versions! = | ||
cmd as Array!(Str, _) = !["erg", "compile"] | ||
metadata = load_package_er_as_json!() | ||
if! metadata.get("py_command") isnot! None, do!: | ||
cmd.push! "--py-command" | ||
py_command = metadata["py_command"] | ||
assert py_command in Str | ||
cmd.push! py_command | ||
# pass dependencies using `--use-package` option | ||
for! vers.items(), ((name, vers),) => | ||
for! vers, (pack,) => | ||
if! pack.path == None: | ||
do!: | ||
cmd.push! "--use-package" | ||
cmd.push! "\{name}" | ||
cmd.push! pack.as_name | ||
cmd.push! "\{pack.version}" | ||
do!: | ||
cmd.push! "--use-local-package" | ||
cmd.push! "\{name}" | ||
cmd.push! pack.as_name | ||
cmd.push! "\{pack.version}" | ||
cmd.push! "\{pack.path}" | ||
cmd | ||
|
||
.build! cfg: Config = | ||
start = time!() | ||
vers = download_dependencies_on_demand!() | ||
cmd = .compile_command! vers | ||
print! "\{ac.GREEN}Building\{ac.RESET}: \{cfg.project_root.stem}" | ||
metadata = load_package_er_as_json!() | ||
if! metadata.get("pre_build") isnot! None, do!: | ||
path = metadata["pre_build"] | ||
assert path in Str | ||
print! "\{ac.GREEN}Running\{ac.RESET}: \{path} (pre-build script)" | ||
res = subprocess.run!(["erg", "run", path]) | ||
if! res.returncode != 0, do!: | ||
panic "\{ac.RED}Error\{ac.RESET}: pre-build failed!" | ||
entry as Str = if exists!("src/main.er"): | ||
do "src/main.er" | ||
do "src/lib.er" | ||
cmd.push! entry | ||
res = subprocess.run! cmd | ||
if! res.returncode != 0, do!: | ||
print! "\{ac.RED}Error\{ac.RESET}: build failed!" | ||
exit 1 | ||
if! not(exists!("build")), do!: | ||
mkdir! "build" | ||
discard move! entry.replace(".er", ".pyc"), "build/\{cfg.project_root.stem}.pyc" | ||
end = time!() | ||
elapsed = end - start | ||
print! "\{ac.GREEN}Finished\{ac.RESET}: elapsed \{"{:.3g}".format(elapsed)}s" | ||
if! metadata.get("post_build") isnot! None, do!: | ||
path = metadata["post_build"] | ||
assert path in Str | ||
print! "\{ac.GREEN}Running\{ac.RESET}: \{path} (post-build script)" | ||
res = subprocess.run!(["erg", "run", path]) | ||
if! res.returncode != 0, do!: | ||
panic "\{ac.RED}Error\{ac.RESET}: post-build failed!" |
Oops, something went wrong.