-
Notifications
You must be signed in to change notification settings - Fork 37
/
BUILD.py
210 lines (171 loc) · 7.39 KB
/
BUILD.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# DX11Renderer - VDemo | DirectX11 Renderer
# Copyright(C) 2018 - Volkan Ilbeyli
#
# This program is free software : you can redistribute it and / or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.If not, see <http://www.gnu.org/licenses/>.
#
# Contact: [email protected]
""" Script for building the release configuration of the project
and packaging everything into one output folder in ARTIFACTS_PATH defined below
so that the user can double click the Application.exe and run it from one folder.
"""
import subprocess
import winreg
import os
import shutil
#------------------- GLOBAL VARIABLES/CONSTANTS -------------------
# https://developercommunity.visualstudio.com/content/problem/2813/cant-find-registry-entries-for-visual-studio-2017.html
VS_REG_PATH = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7"
DEVENV_RELATIVE_PATH = r"Common7\IDE\devenv.exe"
MSBUILD_RELATIVE_PATH = r"MSBuild\15.0\Bin\MSBuild.exe"
VS_PATH = r"PATH_NOT_FOUND" # to be assigned
DEVENV_PATH = r"PATH_NOT_FOUND" # to be assigned
MSBUILD_PATH = r"PATH_NOT_FOUND" # to be assigned
APPDATA = os.getenv('APPDATA')
LOG_DEVENV = APPDATA + r"/VQEngine/Logs/Build/devenv_out.log"
LOG_MSBUILD_S = APPDATA + r"/VQEngine/Logs/Build/msbuild_out_st.log"
LOG_MSBUILD_M = APPDATA + r"/VQEngine/Logs/Build/msbuild_out_mt.log"
SOLUTION_FILE = r"VQEngine.sln"
ARTIFACTS_PATH = r"./Build/_artifacts" # <-- Output directory
#--------------------------- ROBOCOPY & PROCESSES ----------------------------
def RunSubprocess(cmd, bPrintOut):
try:
ret = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True).decode("utf-8")
if bPrintOut:
print(ret)
return 0
except subprocess.CalledProcessError as e:
# handle robocopy exit codes
bIsRunningRobocopy = cmd.split(' ')[0].lower() == 'robocopy'
if bIsRunningRobocopy and e.returncode >= 8:
print(e.output.decode("utf-8"))
# rest of the processes' exit codes
else:
if bPrintOut:
print(e.output.decode("utf-8"))
return e.returncode
# assumes folder with no '/' or '\' in the end
def RobocopyRemoveFolder(folder, bPrintOutput):
empty = "./Empty"
os.makedirs(empty)
cmd = "Robocopy " + empty + " " + folder + " /purge"
ret = RunSubprocess(cmd, bPrintOutput)
os.rmdir(empty)
os.rmdir(folder)
return ret < 8 # success condition
# assumes folder with no '/' or '\' in the end
def RobocopyCopyFolder(src, dst, bPrintOutput):
_src = "\"" + src + "\""
_dst = "\"" + dst + "\""
cmd = "Robocopy " + _src + " " + _dst + " /E /MT:8"
ret = RunSubprocess(cmd, bPrintOutput)
return ret < 8 # success condition
#------------------------------ BUILD FUNCTIONS -------------------------------
# https://developercommunity.visualstudio.com/content/problem/2813/cant-find-registry-entries-for-visual-studio-2017.html
# reads registry to find VS2017 path
def GetVS2017Path():
vs_registry_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, VS_REG_PATH, 0, winreg.KEY_READ)
value, regtype = winreg.QueryValueEx(vs_registry_key, "15.0")
winreg.CloseKey(vs_registry_key)
return value
# returns true if devenv.exe & msbuild.eze are both found
def CheckVisualStudio():
global VS_PATH, DEVENV_PATH, MSBUILD_PATH
VS_PATH = GetVS2017Path()
DEVENV_PATH = VS_PATH + DEVENV_RELATIVE_PATH
MSBUILD_PATH = VS_PATH + MSBUILD_RELATIVE_PATH
return os.path.isfile(DEVENV_PATH) and os.path.isfile(MSBUILD_PATH)
def PrintPaths():
print("VS Path:\t\t", VS_PATH)
print("devenv.exe Path:\t", DEVENV_PATH)
print("msbuild.exe Path:\t", MSBUILD_PATH)
print(" ")
# CLEAN
def CleanProjectFolders(bPrintOutput):
print("Cleaning up project folders...")
#TODO: handle log files. either append date or delete previous
return RobocopyRemoveFolder("./Build", bPrintOutput)
# MSBUILD
def BuildProject_msbuild():
print("Building the project [MSBuild]...")
global MSBUILD_PATH, LOG_MSBUILD_S, LOG_MSBUILD_M
cmd = "\"" + MSBUILD_PATH + "\" /p:Configuration=Release /p:BuildInParallel=TRUE" # + LOG_MSBUILD_S
ret = RunSubprocess(cmd, True)
return ret == 0 # success condition
# DEVENV
def BuildProject_devenv(bPrintOutput):
print("Building the project [devenv]...")
global DEVENV_PATH, LOG_DEVENV
cmd = "\"" + DEVENV_PATH + "\" " + SOLUTION_FILE + " /build RELEASE /out " + LOG_DEVENV
ret = RunSubprocess(cmd, bPrintOutput)
return ret == 0 # success condition
# PACKAGE
def PackageBinaries(bPrintOutput):
print("Packaging the build artifacts...")
global ARTIFACTS_PATH
# cleanup artifacts
if os.path.exists(ARTIFACTS_PATH):
bCleanSuccess = RobocopyRemoveFolder(ARTIFACTS_PATH, False)
if not bCleanSuccess:
print("Cleaning up artifacts folder (" + ARTIFACTS_PATH + ") failed.")
exit()
os.makedirs(ARTIFACTS_PATH)
# copy all the executables in ./Build to ARTIFACTS_PATH
for path, subdirs, files in os.walk("./Build"):
# print("path= " + path.replace('\\', '/'))
if path.replace('\\', '/') == ARTIFACTS_PATH:
continue
for name in files:
filename = os.path.join(path, name)
extension = filename.split('.')[-1].lower()
# print("Searching file: " + filename + " -> ." + extension)
if extension == "exe" or extension == "dll":
if bPrintOutput:
print("copy " + filename + " to " + ARTIFACTS_PATH)
shutil.copy2(filename, ARTIFACTS_PATH + "/" + name)
# copy Data
if not RobocopyCopyFolder("./Data", ARTIFACTS_PATH + "/Data", bPrintOutput):
print("Error copying ./Data folder")
return False
# copy Shaders
shadersPath = "/Source/Shaders"
if not RobocopyCopyFolder("." + shadersPath, ARTIFACTS_PATH + shadersPath, bPrintOutput):
print("Error copying ./Source/Shaders folder")
return False
# copy EngineSettings.ini (NOT TESTED)
RunSubprocess("xcopy \"./Data/EngineSettings.ini\" \"./Build/_artifacts/\"\\ /Y /Q /F", True)
return True
def InitLog():
log_folder = os.path.dirname(LOG_DEVENV)
if not os.path.exists(log_folder):
os.makedirs(log_folder)
return
#---------------------------- ENTRY POINT ----------------------------
InitLog()
if CheckVisualStudio():
# PrintPaths()
bPrintLogs = False
if not CleanProjectFolders(bPrintLogs):
print("Clean Failed. TODO: output")
exit()
bPrintLogs = True
if not BuildProject_devenv(bPrintLogs):
print("Build Failed. TODO: output")
exit()
bPrintLogs = False
if not PackageBinaries(bPrintLogs):
print("Packaging failed. TODO output")
exit()
print("\nBuild Finished.\n\"" + ARTIFACTS_PATH + "\" folder contains the release version of the project executable.")
else: # VS2017 Not Found
print("Build Failed: Cannot find Visual Studio 2017.")