From a7e464fee950a9551af7c724e8aea9b3edc6576a Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 1 Aug 2019 01:34:28 +0200 Subject: [PATCH] user modules + `v install` from vpm --- compiler/main.v | 95 ++++++++++++++++++++++++++++++++--------------- compiler/parser.v | 2 +- tools/vget.v | 33 ++++++++++++++++ vlib/os/os.v | 3 ++ vlib/vweb/vweb.v | 2 +- 5 files changed, 103 insertions(+), 32 deletions(-) create mode 100644 tools/vget.v diff --git a/compiler/main.v b/compiler/main.v index b65f5470ec..4cb36c891b 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -70,6 +70,7 @@ mut: lang_dir string // "~/code/v" out_name string // "program.exe" vroot string + mod string // module being built with -lib } struct Preferences { @@ -120,6 +121,29 @@ fn main() { update_v() return } + if 'get' in args { + println('use `v install` to install modules from vpm.vlang.io') + return + } + if 'install' in args { + mod := args.last() + if args.len != 3 || mod.len < 2 { + println('usage: v install [module]') + return + } + vroot := os.dir(os.executable()) + vget := '$vroot/tools/vget' + if !os.file_exists(vget) { + println('Building vget...') + os.chdir(vroot + '/tools') + vexec := os.args[0] + os.exec('$vexec vget.v') + println('Done.') + } + println('Installing module ${mod}...') + os.exec('$vget $mod') + return + } // TODO quit if the compiler is too old // u := os.file_last_mod_unix('v') // If there's no tmp path with current version yet, the user must be using a pre-built package @@ -171,8 +195,7 @@ fn main() { fn (v mut V) compile() { mut cgen := v.cgen cgen.genln('// Generated by V') - // Add user files to compile - v.add_user_v_files() + v.add_v_files_to_compile() if v.pref.is_verbose { println('all .v files:') println(v.files) @@ -888,7 +911,7 @@ fn (v &V) v_files_from_dir(dir string) []string { } // Parses imports, adds necessary libs, and then user files -fn (v mut V) add_user_v_files() { +fn (v mut V) add_v_files_to_compile() { mut dir := v.dir v.log('add_v_files($dir)') // Need to store user files separately, because they have to be added after libs, but we dont know @@ -932,6 +955,7 @@ fn (v mut V) add_user_v_files() { file_imports << *p.import_table } // Parse lib imports +/* if v.pref.build_mode == .default_mode { // strange ( for mod in v.table.imports ) dosent loop all items // for mod in v.table.imports { @@ -952,27 +976,29 @@ fn (v mut V) add_user_v_files() { } } else { - // strange ( for mod in v.table.imports ) dosent loop all items - // for mod in v.table.imports { - for i := 0; i < v.table.imports.len; i++ { - mod := v.table.imports[i] - mod_path := v.module_path(mod) - idir := os.getwd() - mut import_path := '$idir/$mod_path' - //if !os.file_exists(import_path) || !os.is_dir(import_path){ +*/ + // strange ( for mod in v.table.imports ) dosent loop all items + // for mod in v.table.imports { + for i := 0; i < v.table.imports.len; i++ { + mod := v.table.imports[i] + mod_path := v.module_path(mod) + mut import_path := '$ModPath/$mod_path' + //println('ip=$import_path') + if !os.dir_exists(import_path){ + import_path = '$v.lang_dir/vlib/$mod_path' if !os.dir_exists(import_path){ - import_path = '$v.lang_dir/vlib/$mod_path' - } - vfiles := v.v_files_from_dir(import_path) - if vfiles.len == 0 { - panic('cannot import module $mod (no .v files in "$import_path").') - } - // Add all imports referenced by these libs - for file in vfiles { - mut p := v.new_parser(file, Pass.imports) - p.parse() - file_imports << *p.import_table - } + panic('module "$mod" not found') + } + } + vfiles := v.v_files_from_dir(import_path) + if vfiles.len == 0 { + panic('cannot import module $mod (no .v files in "$import_path").') + } + // Add all imports referenced by these libs + for file in vfiles { + mut p := v.new_parser(file, Pass.imports) + p.parse() + file_imports << *p.import_table } } if v.pref.is_verbose { @@ -989,9 +1015,12 @@ fn (v mut V) add_user_v_files() { } // add imports in correct order for mod in deps_resolved.imports() { + // Building this module? Skip. TODO it's a hack. + if mod == v.mod { + continue + } mod_p := v.module_path(mod) - idir := os.getwd() - mut module_path := '$idir/$mod_p' + mut module_path := '$ModPath/$mod_p' // If we are in default mode, we don't parse vlib .v files, but header .vh files in // TmpPath/vlib // These were generated by vfmt @@ -1008,8 +1037,9 @@ fn (v mut V) add_user_v_files() { } } } - // add remaining files (not mods) + // add remaining files (not modules) for fit in file_imports { + //println('fit $fit.file_path') if !fit.file_path in v.files { v.files << fit.file_path } @@ -1062,13 +1092,16 @@ fn new_v(args[]string) *V { mut out_name := get_arg(joined_args, 'o', 'a.out') // build mode mut build_mode := BuildMode.default_mode - if args.contains('-lib') { + mut mod := '' + //if args.contains('-lib') { + if joined_args.contains('build module ') { build_mode = .build // v -lib ~/v/os => os.o - base := dir.all_after('/') - println('Building module ${base}...') + mod = os.dir(dir) + mod = mod.all_after('/') + println('Building module "${mod}" dir="$dir"...') //out_name = '$TmpPath/vlib/${base}.o' - out_name = base + '.o' + out_name = mod + '.o' // Cross compiling? Use separate dirs for each os /* if target_os != os.user_os() { @@ -1216,6 +1249,7 @@ fn new_v(args[]string) *V { cgen: new_cgen(out_name_c) vroot: vroot pref: pref + mod: mod } } @@ -1362,3 +1396,4 @@ fn update_v() { println(s) } } + diff --git a/compiler/parser.v b/compiler/parser.v index 9ae076ef51..0ba0ec21a6 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -156,7 +156,7 @@ fn (p mut Parser) parse() { } p.fgenln('\n') p.builtin_pkg = p.mod == 'builtin' - p.can_chash = p.mod == 'ft' || p.mod == 'glfw' || p.mod=='ui' // TODO tmp remove + p.can_chash = p.mod == 'ft' || p.mod == 'glfw' || p.mod=='glfw2' || p.mod=='ui' // TODO tmp remove // Import pass - the first and the smallest pass that only analyzes imports // fully qualify the module name, eg base64 to encoding.base64 fq_mod := p.table.qualify_module(p.mod, p.file_path) diff --git a/tools/vget.v b/tools/vget.v new file mode 100644 index 0000000000..742f6b35b6 --- /dev/null +++ b/tools/vget.v @@ -0,0 +1,33 @@ +module main + +import ( + http + os + json +) + +const ( + //url = 'http://localhost:8089' + url = 'http://vpm.vlang.io' +) + +struct Mod { + id int + name string + url string + nr_downloads int +} + +fn main() { + if os.args.len != 2 { + println('usage: vget [module]') + return + } + name := os.args.last() + s := http.get_text(url + '/jsmod/$name') + mod := json.decode(Mod, s) or { return } + home := os.home_dir() + os.exec('git -C "$home/.vmodules" clone $mod.url') + println(s) +} + diff --git a/vlib/os/os.v b/vlib/os/os.v index 36010ef924..68a80f752a 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -483,6 +483,9 @@ pub fn ext(path string) string { // dir returns all but the last element of path, typically the path's directory. pub fn dir(path string) string { + if path == '.' { + return getwd() + } mut pos := -1 // TODO PathSeparator defined in os_win.v doesn't work when building V, // because v.c is generated for a nix system. diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index d26f052869..4da6bda4ec 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -32,7 +32,6 @@ pub fn (ctx Context) json(s string) { ctx.conn.write('HTTP/1.1 200 OK Content-Type: application/json $h - $s ') } @@ -71,6 +70,7 @@ $html } pub fn run(port int) { + println('Running vweb app on http://localhost:$port ...') l := net.listen(port) or { panic('failed to listen') return } for { conn := l.accept() or {