mirror of
https://github.com/vlang/v.git
synced 2025-09-13 09:25:45 -04:00
tools.vcreate: rework cli arg handling to extend scaffolding and fix issues (#19889)
This commit is contained in:
parent
9308bcd48a
commit
e9258c2a08
@ -3,9 +3,9 @@ module main
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
fn (mut c Create) set_bin_project_files() {
|
fn (mut c Create) set_bin_project_files() {
|
||||||
main_path := os.join_path('src', 'main.v')
|
base := if c.new_dir { c.name } else { '' }
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: if c.new_dir { os.join_path(c.name, main_path) } else { main_path }
|
path: os.join_path(base, 'src', 'main.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -3,8 +3,9 @@ module main
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
fn (mut c Create) set_lib_project_files() {
|
fn (mut c Create) set_lib_project_files() {
|
||||||
|
base := if c.new_dir { c.name } else { '' }
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: os.join_path(c.name, 'src', c.name + '.v')
|
path: os.join_path(base, 'src', c.name + '.v')
|
||||||
content: 'module ${c.name}
|
content: 'module ${c.name}
|
||||||
|
|
||||||
// square calculates the second power of `x`
|
// square calculates the second power of `x`
|
||||||
@ -14,7 +15,7 @@ pub fn square(x int) int {
|
|||||||
'
|
'
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: os.join_path(c.name, 'tests', 'square_test.v')
|
path: os.join_path(base, 'tests', 'square_test.v')
|
||||||
content: 'import ${c.name}
|
content: 'import ${c.name}
|
||||||
|
|
||||||
fn test_square() {
|
fn test_square() {
|
||||||
|
@ -3,8 +3,9 @@ module main
|
|||||||
import os { join_path }
|
import os { join_path }
|
||||||
|
|
||||||
fn (mut c Create) set_web_project_files() {
|
fn (mut c Create) set_web_project_files() {
|
||||||
|
base := if c.new_dir { c.name } else { '' }
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'databases', 'config_databases_sqlite.v')
|
path: join_path(base, 'src', 'databases', 'config_databases_sqlite.v')
|
||||||
content: "module databases
|
content: "module databases
|
||||||
|
|
||||||
import db.sqlite // can change to 'db.mysql', 'db.pg'
|
import db.sqlite // can change to 'db.mysql', 'db.pg'
|
||||||
@ -16,7 +17,7 @@ pub fn create_db_connection() !sqlite.DB {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'templates', 'header_component.html')
|
path: join_path(base, 'src', 'templates', 'header_component.html')
|
||||||
content: "<nav>
|
content: "<nav>
|
||||||
<div class='nav-wrapper'>
|
<div class='nav-wrapper'>
|
||||||
<a href='javascript:window.history.back();' class='left'>
|
<a href='javascript:window.history.back();' class='left'>
|
||||||
@ -35,7 +36,7 @@ pub fn create_db_connection() !sqlite.DB {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'templates', 'products.css')
|
path: join_path(base, 'src', 'templates', 'products.css')
|
||||||
content: 'h1.title {
|
content: 'h1.title {
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
color: #3b7bbf;
|
color: #3b7bbf;
|
||||||
@ -49,7 +50,7 @@ div.products-table {
|
|||||||
}'
|
}'
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'templates', 'products.html')
|
path: join_path(base, 'src', 'templates', 'products.html')
|
||||||
content: "<!DOCTYPE html>
|
content: "<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
@ -146,7 +147,7 @@ div.products-table {
|
|||||||
</html>"
|
</html>"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'auth_controllers.v')
|
path: join_path(base, 'src', 'auth_controllers.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import vweb
|
import vweb
|
||||||
@ -163,7 +164,7 @@ pub fn (mut app App) controller_auth(username string, password string) vweb.Resu
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'auth_dto.v')
|
path: join_path(base, 'src', 'auth_dto.v')
|
||||||
content: 'module main
|
content: 'module main
|
||||||
|
|
||||||
struct AuthRequestDto {
|
struct AuthRequestDto {
|
||||||
@ -173,7 +174,7 @@ struct AuthRequestDto {
|
|||||||
'
|
'
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'auth_services.v')
|
path: join_path(base, 'src', 'auth_services.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import crypto.hmac
|
import crypto.hmac
|
||||||
@ -268,7 +269,7 @@ fn auth_verify(token string) bool {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'index.html')
|
path: join_path(base, 'src', 'index.html')
|
||||||
content: "<!DOCTYPE html>
|
content: "<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
@ -347,7 +348,7 @@ fn auth_verify(token string) bool {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'main.v')
|
path: join_path(base, 'src', 'main.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import vweb
|
import vweb
|
||||||
@ -392,7 +393,7 @@ pub fn (mut app App) index() vweb.Result {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'product_controller.v')
|
path: join_path(base, 'src', 'product_controller.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import vweb
|
import vweb
|
||||||
@ -458,7 +459,7 @@ pub fn (mut app App) controller_create_product(product_name string) vweb.Result
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'product_entities.v')
|
path: join_path(base, 'src', 'product_entities.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
@[table: 'products']
|
@[table: 'products']
|
||||||
@ -471,7 +472,7 @@ struct Product {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'product_service.v')
|
path: join_path(base, 'src', 'product_service.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import databases
|
import databases
|
||||||
@ -518,7 +519,7 @@ fn (mut app App) service_get_all_products_from(user_id int) ![]Product {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'product_view_api.v')
|
path: join_path(base, 'src', 'product_view_api.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@ -557,7 +558,7 @@ pub fn get_product(token string) ![]User {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'product_view.v')
|
path: join_path(base, 'src', 'product_view.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import vweb
|
import vweb
|
||||||
@ -579,7 +580,7 @@ pub fn (mut app App) products() !vweb.Result {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'user_controllers.v')
|
path: join_path(base, 'src', 'user_controllers.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import vweb
|
import vweb
|
||||||
@ -649,7 +650,7 @@ pub fn (mut app App) controller_create_user(username string, password string) vw
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'user_entities.v')
|
path: join_path(base, 'src', 'user_entities.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
@[table: 'users']
|
@[table: 'users']
|
||||||
@ -664,7 +665,7 @@ mut:
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'user_services.v')
|
path: join_path(base, 'src', 'user_services.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import crypto.bcrypt
|
import crypto.bcrypt
|
||||||
@ -733,7 +734,7 @@ fn (mut app App) service_get_user(id int) !User {
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
c.files << ProjectFiles{
|
c.files << ProjectFiles{
|
||||||
path: join_path(c.name, 'src', 'user_view_api.v')
|
path: join_path(base, 'src', 'user_view_api.v')
|
||||||
content: "module main
|
content: "module main
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
@ -10,6 +10,6 @@ spawn $v_root/v init
|
|||||||
expect "Input your project description: " { send "\r" } timeout { exit 1 }
|
expect "Input your project description: " { send "\r" } timeout { exit 1 }
|
||||||
expect "Input your project version: (0.0.0) " { send "\r" } timeout { exit 1 }
|
expect "Input your project version: (0.0.0) " { send "\r" } timeout { exit 1 }
|
||||||
expect "Input your project license: (MIT) " { send "\r" } timeout { exit 1 }
|
expect "Input your project license: (MIT) " { send "\r" } timeout { exit 1 }
|
||||||
expect "Complete!" {} timeout {} timeout { exit 1 }
|
# The completion message is verified in `vcreate_init_test.v`.
|
||||||
|
|
||||||
expect eof
|
expect eof
|
||||||
|
@ -13,6 +13,6 @@ expect "Input your project description: " { send "\r" } timeout { exit 1 }
|
|||||||
expect "Input your project version: (0.0.0) " { send "\r" } timeout { exit 1 }
|
expect "Input your project version: (0.0.0) " { send "\r" } timeout { exit 1 }
|
||||||
expect "Input your project license: (MIT) " { send "\r" } timeout { exit 1 }
|
expect "Input your project license: (MIT) " { send "\r" } timeout { exit 1 }
|
||||||
expect "The directory name `$project_dir_name` is invalid as a module name. The module name in `v.mod` was set to `$corrected_mod_name`" {} timeout { exit 1 }
|
expect "The directory name `$project_dir_name` is invalid as a module name. The module name in `v.mod` was set to `$corrected_mod_name`" {} timeout { exit 1 }
|
||||||
expect "Complete!" {} timeout {} timeout { exit 1 }
|
expect "Created binary (application) project `$corrected_mod_name`" {} timeout {} timeout { exit 1 }
|
||||||
|
|
||||||
expect eof
|
expect eof
|
||||||
|
17
cmd/tools/vcreate/tests/init_with_model_arg.expect
Executable file
17
cmd/tools/vcreate/tests/init_with_model_arg.expect
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env expect
|
||||||
|
|
||||||
|
set timeout 3
|
||||||
|
|
||||||
|
# Pass v_root as arg, since we chdir into a temp directory during testing and create a project there.
|
||||||
|
set v_root [lindex $argv 0]
|
||||||
|
set model [lindex $argv 1]
|
||||||
|
|
||||||
|
spawn $v_root/v init $model
|
||||||
|
|
||||||
|
expect "Input your project description: " { send "My Awesome V Application.\r" } timeout { exit 1 }
|
||||||
|
expect "Input your project version: (0.0.0) " { send "0.0.1\r" } timeout { exit 1 }
|
||||||
|
expect "Input your project license: (MIT) " { send "\r" } timeout { exit 1 }
|
||||||
|
expect "Initialising ..." {} timeout { exit 1 }
|
||||||
|
# The completion message is verified in `vcreate_init_test.v`.
|
||||||
|
|
||||||
|
expect eof
|
@ -4,15 +4,15 @@ set timeout 3
|
|||||||
|
|
||||||
# Pass v_root as arg, since we chdir into a temp directory during testing and create a project there.
|
# Pass v_root as arg, since we chdir into a temp directory during testing and create a project there.
|
||||||
set v_root [lindex $argv 0]
|
set v_root [lindex $argv 0]
|
||||||
set project_name [lindex $argv 1]
|
set model [lindex $argv 1]
|
||||||
set model [lindex $argv 2]
|
set project_name [lindex $argv 2]
|
||||||
|
|
||||||
spawn $v_root/v new $project_name $model
|
spawn $v_root/v new $model $project_name
|
||||||
|
|
||||||
expect "Input your project description: " { send "My Awesome V Project.\r" } timeout { exit 1 }
|
expect "Input your project description: " { send "My Awesome V Project.\r" } timeout { exit 1 }
|
||||||
expect "Input your project version: (0.0.0) " { send "0.0.1\r" } timeout { exit 1 }
|
expect "Input your project version: (0.0.0) " { send "0.0.1\r" } timeout { exit 1 }
|
||||||
expect "Input your project license: (MIT) " { send "\r" } timeout { exit 1 }
|
expect "Input your project license: (MIT) " { send "\r" } timeout { exit 1 }
|
||||||
expect "Initialising ..." {} timeout { exit 1 }
|
expect "Initialising ..." {} timeout { exit 1 }
|
||||||
expect "Complete!" {} timeout { exit 1 }
|
expect "Created library project `$project_name`" {} timeout { exit 1 }
|
||||||
|
|
||||||
expect eof
|
expect eof
|
||||||
|
@ -12,6 +12,6 @@ expect "Input your project description: " { send "\r" } timeout { exit 1 }
|
|||||||
expect "Input your project version: (0.0.0) " { send "\r" } timeout { exit 1 }
|
expect "Input your project version: (0.0.0) " { send "\r" } timeout { exit 1 }
|
||||||
expect "Input your project license: (MIT) " { send "\r" } timeout { exit 1 }
|
expect "Input your project license: (MIT) " { send "\r" } timeout { exit 1 }
|
||||||
expect "Initialising ..." {} timeout { exit 1 }
|
expect "Initialising ..." {} timeout { exit 1 }
|
||||||
expect "Complete!" {} timeout { exit 1 }
|
expect "Created binary (application) project `$project_name`" {} timeout { exit 1 }
|
||||||
|
|
||||||
expect eof
|
expect eof
|
||||||
|
@ -13,6 +13,6 @@ expect "Input your project description: " { send "My Awesome V Project.\r" } tim
|
|||||||
expect "Input your project version: (0.0.0) " { send "0.1.0\r" } timeout { exit 1 }
|
expect "Input your project version: (0.0.0) " { send "0.1.0\r" } timeout { exit 1 }
|
||||||
expect "Input your project license: (MIT) " { send "GPL\r" } timeout { exit 1 }
|
expect "Input your project license: (MIT) " { send "GPL\r" } timeout { exit 1 }
|
||||||
expect "Initialising ..." {} timeout { exit 1 }
|
expect "Initialising ..." {} timeout { exit 1 }
|
||||||
expect "Complete!" {} timeout { exit 1 }
|
expect "Created binary (application) project `$project_name`" {} timeout { exit 1 }
|
||||||
|
|
||||||
expect eof
|
expect eof
|
||||||
|
@ -3,18 +3,11 @@
|
|||||||
module main
|
module main
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import cli { Command, Flag }
|
||||||
|
|
||||||
// Note: this program follows a similar convention to Rust: `init` makes the
|
// Note: this program follows a similar convention as Rust cargo:
|
||||||
// structure of the program in the _current_ directory, while `new`
|
// `init` creates the structure of project in the current directory,
|
||||||
// makes the program structure in a _sub_ directory. Besides that, the
|
// `new` creates the structure of a project in a sub directory.
|
||||||
// functionality is essentially the same.
|
|
||||||
|
|
||||||
// Note: here are the currently supported invocations so far:
|
|
||||||
// - `v init` -> initialize a new project in the current folder
|
|
||||||
// - `v new` -> create a new project in the directory specified during setup, using the "bin" template by default.
|
|
||||||
// - `v new my_bin_project bin` -> create a new project directory `my_bin_project`, using the bin template.
|
|
||||||
// - `v new my_lib_project lib` -> create a new project directory `my_lib_project`, using the lib template.
|
|
||||||
// - `v new my_web_project web` -> create a new project directory `my_web_project`, using the vweb template.
|
|
||||||
|
|
||||||
struct Create {
|
struct Create {
|
||||||
mut:
|
mut:
|
||||||
@ -24,6 +17,7 @@ mut:
|
|||||||
license string
|
license string
|
||||||
files []ProjectFiles
|
files []ProjectFiles
|
||||||
new_dir bool
|
new_dir bool
|
||||||
|
template Template
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProjectFiles {
|
struct ProjectFiles {
|
||||||
@ -31,89 +25,125 @@ struct ProjectFiles {
|
|||||||
content string
|
content string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Template {
|
||||||
|
bin
|
||||||
|
lib
|
||||||
|
web
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
cmd := os.args[1]
|
flags := [
|
||||||
match cmd {
|
Flag{
|
||||||
'new' {
|
flag: .bool
|
||||||
// list of models allowed
|
name: 'bin'
|
||||||
project_models := ['bin', 'lib', 'web']
|
description: 'Use the template for an executable application [default].'
|
||||||
if os.args.len == 4 {
|
},
|
||||||
// validation
|
Flag{
|
||||||
if os.args.last() !in project_models {
|
flag: .bool
|
||||||
mut error_str := 'It is not possible create a "${os.args[os.args.len - 2]}" project.\n'
|
name: 'lib'
|
||||||
error_str += 'See the list of allowed projects:\n'
|
description: 'Use the template for a library project.'
|
||||||
for model in project_models {
|
},
|
||||||
error_str += 'v new ${os.args[os.args.len - 2]} ${model}\n'
|
Flag{
|
||||||
|
flag: .bool
|
||||||
|
name: 'web'
|
||||||
|
description: 'Use the template for a vweb project.'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
mut cmd := Command{
|
||||||
|
flags: [
|
||||||
|
Flag{
|
||||||
|
flag: .bool
|
||||||
|
name: 'help'
|
||||||
|
description: 'Print help information.'
|
||||||
|
global: true
|
||||||
|
},
|
||||||
|
]
|
||||||
|
posix_mode: true
|
||||||
|
commands: [
|
||||||
|
Command{
|
||||||
|
name: 'new'
|
||||||
|
usage: '<project_name>'
|
||||||
|
description: [
|
||||||
|
'Creates a new V project in a directory with the specified project name.',
|
||||||
|
'',
|
||||||
|
'A setup prompt is started to create a `v.mod` file with the projects metadata.',
|
||||||
|
'The <project_name> argument can be omitted and entered in the prompts dialog.',
|
||||||
|
'If git is installed, `git init` will be performed during the setup.',
|
||||||
|
].join_lines()
|
||||||
|
parent: &Command{
|
||||||
|
name: 'v'
|
||||||
}
|
}
|
||||||
eprintln(error_str)
|
posix_mode: true
|
||||||
exit(1)
|
disable_man: true
|
||||||
|
flags: flags
|
||||||
|
pre_execute: validate
|
||||||
|
execute: new_project
|
||||||
|
},
|
||||||
|
Command{
|
||||||
|
name: 'init'
|
||||||
|
description: [
|
||||||
|
'Sets up a V project within the current directory.',
|
||||||
|
'',
|
||||||
|
"If no `v.mod` exists, a setup prompt is started to create one with the project's metadata.",
|
||||||
|
'If no `.v` file exists, a project template is generated. If the current directory is not a',
|
||||||
|
'git project and git is installed, `git init` will be performed during the setup.',
|
||||||
|
].join_lines()
|
||||||
|
parent: &Command{
|
||||||
|
name: 'v'
|
||||||
}
|
}
|
||||||
|
posix_mode: true
|
||||||
|
disable_man: true
|
||||||
|
flags: flags
|
||||||
|
pre_execute: validate
|
||||||
|
execute: init_project
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
new_project(os.args[2..])
|
cmd.parse(os.args)
|
||||||
}
|
|
||||||
'init' {
|
|
||||||
init_project(os.args[2..])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cerror('unknown command: ${cmd}')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println('Complete!')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_project(args []string) {
|
fn validate(cmd Command) ! {
|
||||||
mut c := Create{}
|
if cmd.flags.get_bool('help')! {
|
||||||
c.new_dir = true
|
cmd.execute_help()
|
||||||
c.prompt(args)
|
exit(0)
|
||||||
|
}
|
||||||
|
if cmd.args.len > 1 {
|
||||||
|
cerror('too many arguments.\n')
|
||||||
|
cmd.execute_help()
|
||||||
|
exit(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_project(cmd Command) ! {
|
||||||
|
mut c := Create{
|
||||||
|
template: get_template(cmd)
|
||||||
|
new_dir: true
|
||||||
|
}
|
||||||
|
c.prompt(cmd.args)
|
||||||
println('Initialising ...')
|
println('Initialising ...')
|
||||||
if args.len == 2 {
|
// Generate project files based on `Create.files`.
|
||||||
// E.g.: `v new my_project lib`
|
|
||||||
match os.args.last() {
|
|
||||||
'bin' {
|
|
||||||
c.set_bin_project_files()
|
|
||||||
}
|
|
||||||
'lib' {
|
|
||||||
c.set_lib_project_files()
|
|
||||||
}
|
|
||||||
'web' {
|
|
||||||
c.set_web_project_files()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
eprintln('${os.args.last()} model not exist')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// E.g.: `v new my_project`
|
|
||||||
c.set_bin_project_files()
|
|
||||||
}
|
|
||||||
|
|
||||||
// gen project based in the `Create.files` info
|
|
||||||
c.create_files_and_directories()
|
c.create_files_and_directories()
|
||||||
|
|
||||||
c.write_vmod()
|
c.write_vmod()
|
||||||
c.write_gitattributes()
|
c.write_gitattributes()
|
||||||
c.write_editorconfig()
|
c.write_editorconfig()
|
||||||
c.create_git_repo(c.name)
|
c.create_git_repo(c.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_project(args []string) {
|
fn init_project(cmd Command) ! {
|
||||||
mut c := Create{}
|
mut c := Create{
|
||||||
|
template: get_template(cmd)
|
||||||
|
}
|
||||||
dir_name := check_name(os.file_name(os.getwd()))
|
dir_name := check_name(os.file_name(os.getwd()))
|
||||||
if !os.exists('v.mod') {
|
if !os.exists('v.mod') {
|
||||||
mod_dir_has_hyphens := dir_name.contains('-')
|
mod_dir_has_hyphens := dir_name.contains('-')
|
||||||
c.name = if mod_dir_has_hyphens { dir_name.replace('-', '_') } else { dir_name }
|
c.name = if mod_dir_has_hyphens { dir_name.replace('-', '_') } else { dir_name }
|
||||||
c.prompt(args)
|
c.prompt(cmd.args)
|
||||||
c.write_vmod()
|
c.write_vmod()
|
||||||
if mod_dir_has_hyphens {
|
if mod_dir_has_hyphens {
|
||||||
println('The directory name `${dir_name}` is invalid as a module name. The module name in `v.mod` was set to `${c.name}`')
|
println('The directory name `${dir_name}` is invalid as a module name. The module name in `v.mod` was set to `${c.name}`')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !os.exists('src/main.v') {
|
println('Initialising ...')
|
||||||
c.set_bin_project_files()
|
|
||||||
}
|
|
||||||
c.create_files_and_directories()
|
c.create_files_and_directories()
|
||||||
c.write_gitattributes()
|
c.write_gitattributes()
|
||||||
c.write_editorconfig()
|
c.write_editorconfig()
|
||||||
@ -124,15 +154,18 @@ fn (mut c Create) prompt(args []string) {
|
|||||||
if c.name == '' {
|
if c.name == '' {
|
||||||
c.name = check_name(args[0] or { os.input('Input your project name: ') })
|
c.name = check_name(args[0] or { os.input('Input your project name: ') })
|
||||||
if c.name == '' {
|
if c.name == '' {
|
||||||
|
eprintln('')
|
||||||
cerror('project name cannot be empty')
|
cerror('project name cannot be empty')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
if c.name.contains('-') {
|
if c.name.contains('-') {
|
||||||
cerror('"${c.name}" should not contain hyphens')
|
eprintln('')
|
||||||
|
cerror('`${c.name}` should not contain hyphens')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
if os.is_dir(c.name) {
|
if os.is_dir(c.name) {
|
||||||
cerror('${c.name} folder already exists')
|
eprintln('')
|
||||||
|
cerror('`${c.name}` folder already exists')
|
||||||
exit(3)
|
exit(3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,12 +182,28 @@ fn (mut c Create) prompt(args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_template(cmd Command) Template {
|
||||||
|
bin := cmd.flags.get_bool('bin') or { false }
|
||||||
|
lib := cmd.flags.get_bool('lib') or { false }
|
||||||
|
web := cmd.flags.get_bool('web') or { false }
|
||||||
|
if (bin && lib) || (bin && web) || (lib && web) {
|
||||||
|
eprintln("error: can't use more then one template")
|
||||||
|
exit(2)
|
||||||
|
}
|
||||||
|
return match true {
|
||||||
|
lib { .lib }
|
||||||
|
web { .web }
|
||||||
|
else { .bin }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn cerror(e string) {
|
fn cerror(e string) {
|
||||||
eprintln('\nerror: ${e}')
|
eprintln('error: ${e}.')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_name(name string) string {
|
fn check_name(name string) string {
|
||||||
if name.trim_space().len == 0 {
|
if name.trim_space().len == 0 {
|
||||||
|
eprintln('')
|
||||||
cerror('project name cannot be empty')
|
cerror('project name cannot be empty')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
@ -221,11 +270,12 @@ indent_style = tab
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (c &Create) create_git_repo(dir string) {
|
fn (c &Create) create_git_repo(dir string) {
|
||||||
// Create Git Repo and .gitignore file
|
// Initialize git and add a .gitignore file.
|
||||||
if !os.is_dir('${dir}/.git') {
|
if !os.is_dir('${dir}/.git') {
|
||||||
res := os.execute('git init ${dir}')
|
res := os.execute('git init ${dir}')
|
||||||
if res.exit_code != 0 {
|
if res.exit_code != 0 {
|
||||||
cerror('Unable to create git repo')
|
eprintln('')
|
||||||
|
cerror('unable to initialize a git repository')
|
||||||
exit(4)
|
exit(4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,8 +312,22 @@ bin/
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Create) create_files_and_directories() {
|
fn (mut c Create) create_files_and_directories() {
|
||||||
|
// Set project template files for `v new` or when no `.v` files exists during `v init`.
|
||||||
|
if c.new_dir || os.walk_ext('.', '.v').len == 0 {
|
||||||
|
match c.template {
|
||||||
|
.bin { c.set_bin_project_files() }
|
||||||
|
.lib { c.set_lib_project_files() }
|
||||||
|
.web { c.set_web_project_files() }
|
||||||
|
}
|
||||||
|
}
|
||||||
for file in c.files {
|
for file in c.files {
|
||||||
os.mkdir_all(os.dir(file.path)) or { panic(err) }
|
os.mkdir_all(os.dir(file.path)) or { panic(err) }
|
||||||
os.write_file(file.path, file.content) or { panic(err) }
|
os.write_file(file.path, file.content) or { panic(err) }
|
||||||
}
|
}
|
||||||
|
kind := match c.template {
|
||||||
|
.bin { 'binary (application)' }
|
||||||
|
.lib { 'library' }
|
||||||
|
.web { 'web' }
|
||||||
|
}
|
||||||
|
println('Created ${kind} project `${c.name}`')
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,11 @@ fn testsuite_end() {
|
|||||||
fn init_and_check() ! {
|
fn init_and_check() ! {
|
||||||
os.chdir(test_path)!
|
os.chdir(test_path)!
|
||||||
|
|
||||||
// Keep track of the last modified time of the main file to ensure it is not modifed if it already exists.
|
// Keep track of the last modified time of the main file to ensure it is not modified if it already exists.
|
||||||
main_exists := os.exists('src/main.v')
|
main_exists := os.exists('src/main.v')
|
||||||
main_last_modified := if main_exists { os.file_last_mod_unix('src/main.v') } else { 0 }
|
main_last_modified := if main_exists { os.file_last_mod_unix('src/main.v') } else { 0 }
|
||||||
|
|
||||||
// Initilize project.
|
// Initialize project.
|
||||||
os.execute_or_exit('${expect_exe} ${os.join_path(expect_tests_path, 'init.expect')} ${vroot}')
|
os.execute_or_exit('${expect_exe} ${os.join_path(expect_tests_path, 'init.expect')} ${vroot}')
|
||||||
|
|
||||||
x := os.execute_or_exit('${vexe} run .')
|
x := os.execute_or_exit('${vexe} run .')
|
||||||
@ -147,13 +147,13 @@ indent_style = tab
|
|||||||
prepare_test_path()!
|
prepare_test_path()!
|
||||||
os.write_file('.gitattributes', git_attributes_content)!
|
os.write_file('.gitattributes', git_attributes_content)!
|
||||||
os.write_file('.editorconfig', editor_config_content)!
|
os.write_file('.editorconfig', editor_config_content)!
|
||||||
os.execute_or_exit('${expect_exe} ${os.join_path(expect_tests_path, 'init.expect')} ${vroot}')
|
res := os.execute_or_exit('${expect_exe} ${os.join_path(expect_tests_path, 'init.expect')} ${vroot}')
|
||||||
|
assert res.output.contains('Created binary (application) project `${test_project_dir_name}`')
|
||||||
assert os.read_file('.gitattributes')! == git_attributes_content
|
assert os.read_file('.gitattributes')! == git_attributes_content
|
||||||
assert os.read_file('.editorconfig')! == editor_config_content
|
assert os.read_file('.editorconfig')! == editor_config_content
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_v_init_in_dir_with_invalid_mod_name() {
|
fn test_v_init_in_dir_with_invalid_mod_name_input() {
|
||||||
// A project with a directory name with hyphens, which is invalid for a module name.
|
// A project with a directory name with hyphens, which is invalid for a module name.
|
||||||
dir_name_with_invalid_mod_name := 'my-proj'
|
dir_name_with_invalid_mod_name := 'my-proj'
|
||||||
corrected_mod_name := 'my_proj'
|
corrected_mod_name := 'my_proj'
|
||||||
@ -168,3 +168,21 @@ fn test_v_init_in_dir_with_invalid_mod_name() {
|
|||||||
}
|
}
|
||||||
assert mod.name == corrected_mod_name
|
assert mod.name == corrected_mod_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_v_init_with_model_arg_input() {
|
||||||
|
prepare_test_path()!
|
||||||
|
model := '--lib'
|
||||||
|
res := os.execute_or_exit('${expect_exe} ${os.join_path(expect_tests_path, 'init_with_model_arg.expect')} ${vroot} ${model}')
|
||||||
|
assert res.output.contains('Created library project `${test_project_dir_name}`'), res.output
|
||||||
|
project_path := os.join_path(test_path)
|
||||||
|
mod := vmod.from_file(os.join_path(project_path, 'v.mod')) or {
|
||||||
|
assert false, err.str()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert mod.name == test_project_dir_name
|
||||||
|
assert mod.description == 'My Awesome V Application.'
|
||||||
|
assert mod.version == '0.0.1'
|
||||||
|
assert mod.license == 'MIT'
|
||||||
|
// Assert existence of a model-specific file.
|
||||||
|
assert os.exists(os.join_path(project_path, 'tests', 'square_test.v'))
|
||||||
|
}
|
||||||
|
@ -68,12 +68,13 @@ fn test_new_with_name_arg_input() {
|
|||||||
fn test_new_with_model_arg_input() {
|
fn test_new_with_model_arg_input() {
|
||||||
prepare_test_path()!
|
prepare_test_path()!
|
||||||
project_name := 'my_lib'
|
project_name := 'my_lib'
|
||||||
model := 'lib'
|
model := '--lib'
|
||||||
os.execute_opt('${expect_exe} ${os.join_path(expect_tests_path, 'new_with_model_arg.expect')} ${vroot} ${project_name} ${model}') or {
|
os.execute_opt('${expect_exe} ${os.join_path(expect_tests_path, 'new_with_model_arg.expect')} ${vroot} ${model} ${project_name}') or {
|
||||||
assert false, err.msg()
|
assert false, err.msg()
|
||||||
}
|
}
|
||||||
|
project_path := os.join_path(test_module_path, project_name)
|
||||||
// Assert mod data set in `new_with_model_arg.expect`.
|
// Assert mod data set in `new_with_model_arg.expect`.
|
||||||
mod := vmod.from_file(os.join_path(test_module_path, project_name, 'v.mod')) or {
|
mod := vmod.from_file(os.join_path(project_path, 'v.mod')) or {
|
||||||
assert false, err.str()
|
assert false, err.str()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -81,4 +82,6 @@ fn test_new_with_model_arg_input() {
|
|||||||
assert mod.description == 'My Awesome V Project.'
|
assert mod.description == 'My Awesome V Project.'
|
||||||
assert mod.version == '0.0.1'
|
assert mod.version == '0.0.1'
|
||||||
assert mod.license == 'MIT'
|
assert mod.license == 'MIT'
|
||||||
|
// Assert existence of a model-specific file.
|
||||||
|
assert os.exists(os.join_path(project_path, 'tests', 'square_test.v'))
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,9 @@ module help
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
// Topics whose module uses the cli module.
|
||||||
|
const cli_topics = ['new', 'init']
|
||||||
|
|
||||||
fn hdir(base string) string {
|
fn hdir(base string) string {
|
||||||
return os.join_path(base, 'vlib', 'v', 'help')
|
return os.join_path(base, 'vlib', 'v', 'help')
|
||||||
}
|
}
|
||||||
@ -38,6 +41,10 @@ pub fn print_and_exit(topic string, opts ExitOptions) {
|
|||||||
exit(fail_code)
|
exit(fail_code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if topic in help.cli_topics {
|
||||||
|
os.system('${@VEXE} ${topic} --help')
|
||||||
|
exit(opts.exit_code)
|
||||||
|
}
|
||||||
mut topic_path := ''
|
mut topic_path := ''
|
||||||
for path in os.walk_ext(help_dir(), '.txt') {
|
for path in os.walk_ext(help_dir(), '.txt') {
|
||||||
if topic == os.file_name(path).all_before('.txt') {
|
if topic == os.file_name(path).all_before('.txt') {
|
||||||
|
@ -49,3 +49,12 @@ fn test_topic_sub_help() {
|
|||||||
assert res.exit_code == 0, res.output
|
assert res.exit_code == 0, res.output
|
||||||
assert res.output != ''
|
assert res.output != ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_help_topic_with_cli_mod() {
|
||||||
|
res := os.execute_or_exit(vexe + ' help init')
|
||||||
|
assert res.output.contains('Usage: v init [flags]')
|
||||||
|
assert res.output.contains('Sets up a V project within the current directory.')
|
||||||
|
assert res.output.contains('Flags:')
|
||||||
|
assert res.output.contains('--bin Use the template for an executable application [default]')
|
||||||
|
assert res.output.contains('--lib Use the template for a library project.')
|
||||||
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
Sets up a V project within the current directory.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
v init
|
|
||||||
|
|
||||||
If no '.v' file exists, then will create a 'main.v' file.
|
|
||||||
If no 'v.mod' file exists, one will be created.
|
|
||||||
If the current directory is not already controlled with 'git', will perform
|
|
||||||
'git init' (if git is installed on the system).
|
|
@ -1,13 +0,0 @@
|
|||||||
Sets up a new V project
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
v new [NAME] [DESCRIPTION]
|
|
||||||
|
|
||||||
Sets up a new V project with a 'v.mod' file, and a 'main.v' "Hello World"
|
|
||||||
file, and performs 'git init' (if git is installed on the system).
|
|
||||||
|
|
||||||
If NAME is given, the project will be setup in a new directory with that
|
|
||||||
name, and that name will be added to the 'v.mod' file. If no name is given,
|
|
||||||
the user will be prompted for a name.
|
|
||||||
|
|
||||||
If DESCRIPTION is given, the 'v.mod' file is updated with said description.
|
|
Loading…
x
Reference in New Issue
Block a user