1 | module main |
2 | |
3 | import os |
4 | import v.util.version |
5 | import v.util.recompilation |
6 | |
7 | const vexe = os.real_path(os.getenv_opt('VEXE') or { @VEXE }) |
8 | |
9 | const vroot = os.dir(vexe) |
10 | |
11 | struct App { |
12 | is_verbose bool |
13 | is_prod bool |
14 | vexe string |
15 | vroot string |
16 | } |
17 | |
18 | fn new_app() App { |
19 | return App{ |
20 | is_verbose: '-v' in os.args |
21 | is_prod: '-prod' in os.args |
22 | vexe: vexe |
23 | vroot: vroot |
24 | } |
25 | } |
26 | |
27 | fn main() { |
28 | app := new_app() |
29 | recompilation.must_be_enabled(app.vroot, 'Please install V from source, to use `v up` .') |
30 | os.chdir(app.vroot)! |
31 | println('Updating V...') |
32 | app.update_from_master() |
33 | v_hash := version.githash(false) |
34 | current_hash := version.githash(true) |
35 | // println(v_hash) |
36 | // println(current_hash) |
37 | if v_hash == current_hash { |
38 | println('V is already updated.') |
39 | app.show_current_v_version() |
40 | return |
41 | } |
42 | $if windows { |
43 | app.backup('cmd/tools/vup.exe') |
44 | } |
45 | if !app.recompile_v() { |
46 | app.show_current_v_version() |
47 | eprintln('Recompiling V *failed*.') |
48 | eprintln('Try running `${get_make_cmd_name()}` .') |
49 | exit(1) |
50 | } |
51 | app.recompile_vup() |
52 | app.show_current_v_version() |
53 | } |
54 | |
55 | fn (app App) vprintln(s string) { |
56 | if app.is_verbose { |
57 | println(s) |
58 | } |
59 | } |
60 | |
61 | fn (app App) update_from_master() { |
62 | app.vprintln('> updating from master ...') |
63 | if !os.exists('.git') { |
64 | // initialize as if it had been cloned |
65 | app.git_command('init') |
66 | app.git_command('remote add origin https://github.com/vlang/v') |
67 | app.git_command('fetch') |
68 | app.git_command('reset --hard origin/master') |
69 | app.git_command('clean --quiet -xdf --exclude v.exe --exclude cmd/tools/vup.exe') |
70 | } else { |
71 | // pull latest |
72 | app.git_command('pull https://github.com/vlang/v master') |
73 | } |
74 | } |
75 | |
76 | fn (app App) recompile_v() bool { |
77 | // Note: app.vexe is more reliable than just v (which may be a symlink) |
78 | opts := if app.is_prod { '-prod' } else { '' } |
79 | vself := '${os.quoted_path(app.vexe)} ${opts} self' |
80 | app.vprintln('> recompiling v itself with `${vself}` ...') |
81 | self_result := os.execute(vself) |
82 | if self_result.exit_code == 0 { |
83 | println(self_result.output.trim_space()) |
84 | return true |
85 | } else { |
86 | app.vprintln('`${vself}` failed, running `make`...') |
87 | app.vprintln(self_result.output.trim_space()) |
88 | } |
89 | return app.make(vself) |
90 | } |
91 | |
92 | fn (app App) recompile_vup() bool { |
93 | vup_result := os.execute('${os.quoted_path(app.vexe)} -g cmd/tools/vup.v') |
94 | if vup_result.exit_code != 0 { |
95 | eprintln('recompiling vup.v failed:') |
96 | eprintln(vup_result.output) |
97 | return false |
98 | } |
99 | return true |
100 | } |
101 | |
102 | fn (app App) make(vself string) bool { |
103 | make := get_make_cmd_name() |
104 | make_result := os.execute(make) |
105 | if make_result.exit_code != 0 { |
106 | eprintln('> ${make} failed:') |
107 | eprintln('> make output:') |
108 | eprintln(make_result.output) |
109 | return false |
110 | } |
111 | app.vprintln(make_result.output) |
112 | return true |
113 | } |
114 | |
115 | fn (app App) show_current_v_version() { |
116 | vout := os.execute('${os.quoted_path(app.vexe)} version') |
117 | if vout.exit_code >= 0 { |
118 | mut vversion := vout.output.trim_space() |
119 | if vout.exit_code == 0 { |
120 | latest_v_commit := vversion.split(' ').last().all_after('.') |
121 | latest_v_commit_time := os.execute('git show -s --format=%ci ${latest_v_commit}') |
122 | if latest_v_commit_time.exit_code == 0 { |
123 | vversion += ', timestamp: ' + latest_v_commit_time.output.trim_space() |
124 | } |
125 | } |
126 | println('Current V version: ${vversion}') |
127 | } |
128 | } |
129 | |
130 | fn (app App) backup(file string) { |
131 | backup_file := '${file}_old.exe' |
132 | if os.exists(backup_file) { |
133 | os.rm(backup_file) or { eprintln('failed removing ${backup_file}: ${err.msg()}') } |
134 | } |
135 | os.mv(file, backup_file) or { eprintln('failed moving ${file}: ${err.msg()}') } |
136 | } |
137 | |
138 | fn (app App) git_command(command string) { |
139 | app.vprintln('git_command: git ${command}') |
140 | git_result := os.execute('git ${command}') |
141 | if git_result.exit_code < 0 { |
142 | app.get_git() |
143 | // Try it again with (maybe) git installed |
144 | os.execute_or_exit('git ${command}') |
145 | } |
146 | if git_result.exit_code != 0 { |
147 | eprintln(git_result.output) |
148 | exit(1) |
149 | } |
150 | app.vprintln(git_result.output) |
151 | } |
152 | |
153 | fn (app App) get_git() { |
154 | $if windows { |
155 | println('Downloading git 32 bit for Windows, please wait.') |
156 | // We'll use 32 bit because maybe someone out there is using 32-bit windows |
157 | res_download := os.execute('bitsadmin.exe /transfer "vgit" https://github.com/git-for-windows/git/releases/download/v2.30.0.windows.2/Git-2.30.0.2-32-bit.exe "${os.getwd()}/git32.exe"') |
158 | if res_download.exit_code != 0 { |
159 | eprintln('Unable to install git automatically: please install git manually') |
160 | panic(res_download.output) |
161 | } |
162 | res_git32 := os.execute(os.quoted_path(os.join_path_single(os.getwd(), 'git32.exe'))) |
163 | if res_git32.exit_code != 0 { |
164 | eprintln('Unable to install git automatically: please install git manually') |
165 | panic(res_git32.output) |
166 | } |
167 | } $else { // Probably some kind of *nix, usually need to get using a package manager. |
168 | eprintln("error: Install `git` using your system's package manager") |
169 | } |
170 | } |
171 | |
172 | fn get_make_cmd_name() string { |
173 | $if windows { |
174 | return 'make.bat' |
175 | } $else { |
176 | return 'make' |
177 | } |
178 | } |