mirror of
https://github.com/bearlanguageorg/bear.git
synced 2026-08-26 14:57:18 +00:00
174 lines
5.1 KiB
V
174 lines
5.1 KiB
V
// pkg.v — `vr init` / `vr get` / `vr install`: a minimal package manager.
|
|
//
|
|
// Packages are fetched into ./vendor/<name>/ and recorded in vr.mod as
|
|
// `dep "<spec>"`. The compiler resolves `import "pkg/file"` against vendor/
|
|
// automatically (see compiler/compiler.v). Supported package specs:
|
|
//
|
|
// vr get owner/repo clone from GitHub (https://github.com/owner/repo)
|
|
// vr get https://host/repo clone any git repository
|
|
// vr get ./local/path copy a local directory
|
|
module main
|
|
|
|
import os
|
|
|
|
const manifest_file = 'vr.mod'
|
|
const vendor_dir = 'vendor'
|
|
|
|
fn toolchain_init(args []string) ! {
|
|
pkg := if args.len > 0 { args[0] } else { os.base(os.getwd()) }
|
|
if os.exists(manifest_file) {
|
|
return error('${manifest_file} already exists here')
|
|
}
|
|
os.write_file(manifest_file, 'module ${pkg}\nversion 0.1.0\n\n# deps:\n# dep "owner/repo"\n')!
|
|
os.mkdir('vendor') or {}
|
|
if !os.exists('main.vr') {
|
|
os.write_file('main.vr', 'fn main() {\n\tprintln("hello from ${pkg}")\n}\n')!
|
|
}
|
|
if !os.exists('build.vrmm') {
|
|
os.write_file('build.vrmm', '// build.vrmm — build instructions for the VuurRaaf toolchain.
|
|
//
|
|
// vr make runs main()
|
|
// vr make clean runs the clean() target
|
|
//
|
|
// Build builtins: build_compile, build_assemble, build_link, build_run,
|
|
// build_test, build_bench, build_clean, build_exec, build_exec_status,
|
|
// build_exists, build_mkdir, build_rm, build_copy, build_glob, build_ls,
|
|
// build_base, build_dir, build_join, build_root.
|
|
|
|
fn main() {
|
|
build_compile("main.vr", "main.vobj")
|
|
build_link(["main.vobj"], "main.vbin")
|
|
println("built main.vbin — run it with: vr run main.vbin")
|
|
}
|
|
|
|
fn clean() {
|
|
build_clean()
|
|
}
|
|
')!
|
|
}
|
|
println('initialized project "${pkg}" (${manifest_file}, main.vr, build.vrmm)')
|
|
}
|
|
|
|
fn toolchain_get(args []string) ! {
|
|
if args.len == 0 {
|
|
return error('usage: vr get <owner/repo | git-url | ./path>')
|
|
}
|
|
spec := args[0]
|
|
// determine the package name and how to fetch it
|
|
mut pkg := ''
|
|
if spec.starts_with('./') || spec.starts_with('/') {
|
|
pkg = os.base(spec)
|
|
} else if spec.contains('://') {
|
|
pkg = os.base(spec)
|
|
} else if spec.contains('/') {
|
|
pkg = spec.all_after('/')
|
|
} else {
|
|
pkg = spec
|
|
}
|
|
if pkg.ends_with('.git') {
|
|
pkg = pkg[..pkg.len - 4]
|
|
}
|
|
if pkg == '' || pkg == '.' {
|
|
return error('cannot derive a package name from "${spec}"')
|
|
}
|
|
os.mkdir(vendor_dir) or {}
|
|
dst := os.join_path(vendor_dir, pkg)
|
|
if os.exists(dst) {
|
|
return error('package "${pkg}" already exists at ${dst}')
|
|
}
|
|
if spec.starts_with('./') || spec.starts_with('/') {
|
|
copy_dir(spec, dst) or { return error('cannot copy ${spec}: ${err.msg()}') }
|
|
} else {
|
|
url := if spec.contains('://') { spec } else { 'https://github.com/${spec}.git' }
|
|
println('cloning ${url} -> ${dst} ...')
|
|
r := os.exec(['git', 'clone', '--depth', '1', url, dst])
|
|
if r.exit_code != 0 {
|
|
return error('git clone failed: ${r.output}')
|
|
}
|
|
}
|
|
// record the dependency in the manifest (idempotent)
|
|
if os.exists(manifest_file) {
|
|
manifest := os.read_file(manifest_file) or { '' }
|
|
if !manifest.contains('dep "${spec}"') {
|
|
os.write_file(manifest_file, manifest.trim_space() + '\ndep "${spec}"\n') or {
|
|
return error('cannot update ${manifest_file}: ${err.msg()}')
|
|
}
|
|
}
|
|
}
|
|
println('added package "${pkg}" (${spec})')
|
|
}
|
|
|
|
fn toolchain_install() ! {
|
|
if !os.exists(manifest_file) {
|
|
return error('no ${manifest_file} found — run `vr init` first')
|
|
}
|
|
manifest := os.read_file(manifest_file)!
|
|
mut n := 0
|
|
for line in manifest.split_into_lines() {
|
|
t := line.trim_space()
|
|
if !t.starts_with('dep "') {
|
|
continue
|
|
}
|
|
mut spec := t[5..]
|
|
if spec.ends_with('"') {
|
|
spec = spec[..spec.len - 1]
|
|
}
|
|
if spec == '' {
|
|
continue
|
|
}
|
|
n++
|
|
toolchain_get([spec]) or { eprintln(' install: ${err.msg()}') }
|
|
}
|
|
if n == 0 {
|
|
println('no dependencies in ${manifest_file}')
|
|
return
|
|
}
|
|
println('installed ${n} package(s) into ${vendor_dir}/')
|
|
}
|
|
|
|
// copy_dir recursively copies a local directory tree.
|
|
fn copy_dir(src string, dst string) ! {
|
|
if !os.is_dir(src) {
|
|
return error('${src} is not a directory')
|
|
}
|
|
os.mkdir_all(dst) or { return error('cannot create ${dst}: ${err.msg()}') }
|
|
for entry in os.ls(src) or { return error('cannot read ${src}: ${err.msg()}') } {
|
|
sp := os.join_path(src, entry)
|
|
dp := os.join_path(dst, entry)
|
|
if os.is_dir(sp) {
|
|
copy_dir(sp, dp)!
|
|
} else if os.is_file(sp) {
|
|
os.cp(sp, dp, os.CopyParams{}) or { return error('cannot copy ${sp}: ${err.msg()}') }
|
|
}
|
|
}
|
|
}
|
|
|
|
fn toolchain_list() ! {
|
|
if !os.exists(manifest_file) {
|
|
return error('no ${manifest_file} found here')
|
|
}
|
|
manifest := os.read_file(manifest_file)!
|
|
mod_name := manifest.all_before('\n').replace('module ', '').trim_space()
|
|
println('project: ${mod_name}')
|
|
mut found := false
|
|
for line in manifest.split_into_lines() {
|
|
t := line.trim_space()
|
|
if t.starts_with('dep "') {
|
|
found = true
|
|
mut spec := t[5..]
|
|
if spec.ends_with('"') {
|
|
spec = spec[..spec.len - 1]
|
|
}
|
|
mut pkg := os.base(spec)
|
|
if pkg.ends_with('.git') {
|
|
pkg = pkg[..pkg.len - 4]
|
|
}
|
|
status := if os.exists(os.join_path(vendor_dir, pkg)) { 'installed' } else { 'missing' }
|
|
println(' ${pkg} (${status}) <- ${spec}')
|
|
}
|
|
}
|
|
if !found {
|
|
println(' (no dependencies)')
|
|
}
|
|
}
|