diff --git a/.gitignore b/.gitignore index f25d582782..4bc9df70c3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,16 @@ /v.*.c /v.c.out /v.exe -/tools/vget -/tools/vget.exe /tools/performance_compare /tools/performance_compare.exe +/tools/vrepl +/tools/vrepl.exe +/tools/vtest +/tools/vtest.exe +/tools/vup +/tools/vup.exe +/tools/vpm +/tools/vpm.exe *.exe *.o .*.c @@ -30,7 +36,3 @@ vjs ._* .vrepl_temp.v a.out -tools/vrepl -tools/vtest -tools/vup -examples/sqlite diff --git a/examples/.gitignore b/examples/.gitignore index 01b5e0feaa..0b6f509d10 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -10,3 +10,4 @@ /database/mysql /hello_v_js /fibonacci +/sqlite diff --git a/tools/vget.v b/tools/vget.v deleted file mode 100644 index 3cba94489f..0000000000 --- a/tools/vget.v +++ /dev/null @@ -1,94 +0,0 @@ -module main - -import ( - http - os - json -) - -const ( - //url = 'http://localhost:8089' - url = 'https://vpm.best' -) - -struct Mod { - id int - name string - url string - nr_downloads int -} - -fn get_vmodules_dir_path() string { - home := os.home_dir() - - return '${home}.vmodules' -} - -fn ensure_vmodules_dir_exist() { - home_vmodules := get_vmodules_dir_path() - - if !os.dir_exists( home_vmodules ) { - println('Creating $home_vmodules/ ...') - os.mkdir(home_vmodules) - } -} - -fn change_to_vmodules_dir() { - os.chdir(get_vmodules_dir_path()) -} - -fn main() { - if os.args.len <= 1 { - println('usage: vget module [module] [module] [...]') - exit(2) - } - - ensure_vmodules_dir_exist() - change_to_vmodules_dir() - - mut errors := 0 - names := os.args.slice(1, os.args.len) - for name in names { - modurl := url + '/jsmod/$name' - r := http.get(modurl) or { panic(err) } - - if r.status_code == 404 { - println('Skipping module "$name", since $url reported that "$name" does not exist.') - errors++ - continue - } - - if r.status_code != 200 { - println('Skipping module "$name", since $url responded with $r.status_code http status code. Please try again later.') - errors++ - continue - } - - s := r.text - mod := json.decode(Mod, s) or { - errors++ - println('Skipping module "$name", since its information is not in json format.') - continue - } - - if( '' == mod.url || '' == mod.name ){ - errors++ - // a possible 404 error, which means a missing module? - println('Skipping module "$name", since it is missing name or url information.') - continue - } - - final_module_path := get_vmodules_dir_path() + '/' + mod.name.replace('.', '/') - - println('Installing module "$name" from $mod.url to $final_module_path ...') - _ = os.exec('git clone --depth=1 $mod.url $final_module_path') or { - errors++ - println('Could not install module "$name" to "$final_module_path" .') - println('Error details: $err') - continue - } - } - if errors > 0 { - exit(1) - } -} diff --git a/tools/vpm.v b/tools/vpm.v new file mode 100644 index 0000000000..2e2fb76733 --- /dev/null +++ b/tools/vpm.v @@ -0,0 +1,182 @@ +module main + +import ( + http + os + json +) + +const ( + //url = 'http://localhost:8089' + url = 'https://vpm.best' + valid_vpm_commands = ['help', 'search', 'install', 'update', 'remove'] +) + +struct Mod { + id int + name string + url string + nr_downloads int +} + +fn main() { + ensure_vmodules_dir_exist() + change_to_vmodules_dir() + // This tool is intended to be launched by the v frontend, + // so its first argument is the path to the v frontend executable. + args := os.args // args are: vpm vexepath SUBCOMMAND module names + if args.len < 3 { + vpm_help([]string) + exit(5) + } + vpm_command := args[2] + module_names := args[3..] + //println('module names: ') println(module_names) + match vpm_command { + 'help' { vpm_help(module_names) } + 'search' { vpm_search(module_names) } + 'install' { vpm_install(module_names) } + 'update' { vpm_update(module_names) } + 'remove' { vpm_remove(module_names) } + else { + println('Error: you tried to run "v $vpm_command"') + println('... but the v package management tool vpm only knows about these commands:') + for validcmd in valid_vpm_commands { + println(' v $validcmd') + } + exit(3) + } + } +} + +fn vpm_search(module_names []string){ + if user_asks_for_help(module_names) { + println('Usage:') + println(' v search keyword1 [keyword2] [...]') + println(' ^^^^^^^^^^^^^^^^^ will search https://vpm.vlang.io/ for matching modules,') + println(' and will show details about them') + exit(0) + } + if module_names.len == 0 { + println(' v search requires *at least one* keyword') + exit(2) + } + todo('search') +} + +fn vpm_install(module_names []string){ + if user_asks_for_help(module_names) { + println('Usage:') + println(' v install module [module] [module] [...]') + println(' ^^^^^^^^^^^^^ will install the modules you specified') + exit(0) + } + if module_names.len == 0 { + println(' v install requires *at least one* module name') + exit(2) + } + + mut errors := 0 + for name in module_names { + modurl := url + '/jsmod/$name' + r := http.get(modurl) or { panic(err) } + + if r.status_code == 404 { + println('Skipping module "$name", since $url reported that "$name" does not exist.') + errors++ + continue + } + + if r.status_code != 200 { + println('Skipping module "$name", since $url responded with $r.status_code http status code. Please try again later.') + errors++ + continue + } + + s := r.text + mod := json.decode(Mod, s) or { + errors++ + println('Skipping module "$name", since its information is not in json format.') + continue + } + + if( '' == mod.url || '' == mod.name ){ + errors++ + // a possible 404 error, which means a missing module? + println('Skipping module "$name", since it is missing name or url information.') + continue + } + + final_module_path := get_vmodules_dir_path() + '/' + mod.name.replace('.', '/') + + println('Installing module "$name" from $mod.url to $final_module_path ...') + _ = os.exec('git clone --depth=1 $mod.url $final_module_path') or { + errors++ + println('Could not install module "$name" to "$final_module_path" .') + println('Error details: $err') + continue + } + } + if errors > 0 { + exit(1) + } +} + +fn vpm_update(module_names []string){ + if user_asks_for_help(module_names) { + println('Usage: ') + println(' a) v update module [module] [module] [...]') + println(' ^^^^^^^^^^^^ will update the listed modules to their latest versions') + println(' b) v update') + println(' ^^^^^^^^^^^^ will update ALL installed modules to their latest versions') + exit(0) + } + todo('update') +} + +fn vpm_remove(module_names []string){ + if user_asks_for_help(module_names) { + println('Usage: ') + println(' a) v remove module [module] [module] [...]') + println(' ^^^^^^^^^^^^ will remove the listed modules') + println(' b) v remove') + println(' ^^^^^^^^^^^^ will remove ALL installed modules') + exit(0) + } + todo('remove') +} + +fn get_vmodules_dir_path() string { + return os.home_dir() + '.vmodules' +} + +fn ensure_vmodules_dir_exist() { + home_vmodules := get_vmodules_dir_path() + if !os.dir_exists( home_vmodules ) { + println('Creating $home_vmodules/ ...') + os.mkdir(home_vmodules) + } +} + +fn change_to_vmodules_dir() { + os.chdir(get_vmodules_dir_path()) +} + +fn todo(vpm_command string){ + println('TODO: v $vpm_command') + exit(4) +} + +fn user_asks_for_help(module_names []string) bool { + return ('-h' in module_names) || ('--help' in module_names) || ('help' in module_names) +} + +fn vpm_help(module_names []string){ + println('Usage:') + println(' b) v search keyword1 [keyword2] [...]') + println(' c) v install module [module] [module] [...]') + println(' d) v update [module] [...]') + println(' e) v remove [module] [...]') + println('') + println(' You can also pass -h or --help after each vpm command from the above, to see more details about it.') +} diff --git a/tools/vrepl.v b/tools/vrepl.v index eda08e0d46..2607f90fb4 100644 --- a/tools/vrepl.v +++ b/tools/vrepl.v @@ -189,9 +189,10 @@ pub fn run_repl() []string { } fn main() { - if os.args.len != 2 || !os.file_exists(os.args[1]) { - println('Usage: vrepl [vexe]\n') - println('vexe: v binary file') + if os.args.len < 2 || !os.file_exists(os.args[1]) { + println('Usage:') + println(' vrepl vexepath\n') + println(' ... where vexepath is the full path to the v executable file') return } run_repl() diff --git a/v.v b/v.v index 52fce2fb81..582b02aaa3 100755 --- a/v.v +++ b/v.v @@ -17,17 +17,19 @@ fn main() { // There's no `flags` module yet, so args have to be parsed manually args := compiler.env_vflags_and_os_args() options := args.filter(it.starts_with('-')) - commands := args.filter(!it.starts_with('-')) + //NB: commands should be explicitly set by the command line (os.args) + // NOT passed through VFLAGS, otherwise the naked `v` invocation for + // the repl does not work when you have VFLAGS with -cc or -cflags set + // which may be surprising to v users. + stuff_after_executable := os.args[1..] + commands := stuff_after_executable.filter(!it.starts_with('-')) + // Print the version and exit. if '-v' in options || '--version' in options || 'version' in commands { version_hash := compiler.vhash() println('V $compiler.Version $version_hash') return } - else if '-h' in options || '--help' in options || 'help' in commands { - println(compiler.help_text) - return - } else if 'translate' in commands { println('Translating C to V will be available in V 0.3') return @@ -36,7 +38,11 @@ fn main() { compiler.launch_tool('vup') return } - else if 'get' in commands { + else if ('search' in commands) || ('install' in commands) || ('update' in commands) || ('remove' in commands){ + compiler.launch_tool('vpm') + return + } + else if ('get' in commands) { // obsoleted println('use `v install` to install modules from vpm.vlang.io ') return } @@ -44,10 +50,6 @@ fn main() { compiler.create_symlink() return } - else if 'install' in commands { - compiler.install_v(args) - return - } // TODO quit if the v 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 @@ -61,6 +63,11 @@ fn main() { compiler.launch_tool('vtest') return } + // No args? REPL + else if 'runrepl' in commands || commands.len == 0 || (args.len == 2 && args[1] == '-') { + compiler.launch_tool('vrepl') + return + } // Generate the docs and exit else if 'doc' in commands { vexe := os.executable() @@ -70,15 +77,20 @@ fn main() { os.system('$vexe build module vlib/' + args.last()) txt := os.read_file('$compiler.v_modules_path/vlib/${mod}.vh') or { panic(err) - } + } println(txt) exit(0) // v.gen_doc_html_for_module(args.last()) - } else { + } + else if '-h' in options || '--help' in options || 'help' in commands { + println(compiler.help_text) + return + } + else { //println('unknown command/argument\n') //println(compiler.help_text) - } - + } + // Construct the V object from command line arguments mut v := compiler.new_v(args) if v.pref.is_verbose { @@ -92,14 +104,8 @@ fn main() { v.run_compiled_executable_and_exit() } - // No args? REPL - if args.len < 2 || (args.len == 2 && args[1] == '-') || 'runrepl' in args { - compiler.run_repl() - return - } - mut tmark := benchmark.new_benchmark() - v.compile() + v.compile() if v.pref.is_stats { tmark.stop() println( 'compilation took: ' + tmark.total_duration().str() + 'ms') diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index 1c46d7d41a..906287195a 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -993,54 +993,6 @@ pub fn vfmt(args[]string) { println('vfmt is temporarily disabled') } -pub fn install_v(args[]string) { - if args.len < 3 { - println('usage: v install [module] [module] [...]') - return - } - names := args.slice(2, args.len) - vexec := vexe_path() - vroot := os.dir(vexec) - vget := '$vroot/tools/vget' - if true { - //println('Building vget...') - os.chdir(vroot + '/tools') - vget_compilation := os.exec('"$vexec" -o $vget vget.v') or { - verror(err) - return - } - if vget_compilation.exit_code != 0 { - verror( vget_compilation.output ) - return - } - } - vgetresult := os.exec('$vget ' + names.join(' ')) or { - verror(err) - return - } - if vgetresult.exit_code != 0 { - verror( vgetresult.output ) - return - } -} - -pub fn run_repl() { - vexec := vexe_path() - vroot := os.dir(vexec) - vrepl := '$vroot/tools/vrepl' - - os.chdir(vroot + '/tools') - vrepl_compilation := os.exec('"$vexec" -o $vrepl vrepl.v') or { - verror(err) - return - } - if vrepl_compilation.exit_code != 0 { - verror(vrepl_compilation.output) - return - } - vreplresult := os.system('$vrepl "$vexec"') -} - pub fn create_symlink() { vexe := vexe_path() link_path := '/usr/local/bin/v' diff --git a/vlib/compiler/vhelp.v b/vlib/compiler/vhelp.v index 047b330b98..71fa2315e8 100644 --- a/vlib/compiler/vhelp.v +++ b/vlib/compiler/vhelp.v @@ -66,12 +66,17 @@ Commands: build Compile a module into an object file. runrepl Run the V REPL. If V is running in a tty terminal, the REPL is interactive, otherwise it just reads from stdin. symlink Useful on Unix systems. Symlinks the current V executable to /usr/local/bin/v, so that V is globally available. - install Install a user module from https://vpm.vlang.io/. test v Run all V test files, and compile all V examples. test folder/ Run all V test files located in the folder and its subfolders. You can also pass individual _test.v files too. fmt Run vfmt to format the source code. [wip] doc Run vdoc over the source code and produce documentation. translate Translates C to V. [wip, will be available in V 0.3] + +V package management commands: + search keywords Search the https://vpm.vlang.io/ module repository for matching modules and shows their details. + install Install a user module from https://vpm.vlang.io/. + update [module] Updates an already installed module, or ALL installed modules at once, when no module name is given. + remove [module] Removes an installed module, or ALL installed modules at once, when no module name is given. ' )