1+ <?php
2+
3+ namespace Dpp \Packager ;
4+
5+ use \RuntimeException ;
6+
7+ const GREEN = "\033[32m " ;
8+ const RED = "\033[31m " ;
9+ const WHITE = "\033[0m " ;
10+
11+ class Vcpkg
12+ {
13+ /**
14+ * Tag
15+ */
16+ private string $ latestTag ;
17+
18+ /**
19+ * Semver version
20+ */
21+ private string $ version ;
22+
23+ /**
24+ * True when we have done the first build to get the SHA512 sum
25+ */
26+ private bool $ firstBuildComplete = false ;
27+
28+ /**
29+ * Constructor
30+ *
31+ * Examines current diretory's git repository to get latest tag and version.
32+ */
33+ public function __construct ()
34+ {
35+ global $ argv ;
36+ if (count ($ argv ) < 2 ) {
37+ throw new RuntimeException (RED . "Missing github repository owner and access token \n" . WHITE );
38+ }
39+ echo GREEN . "Starting vcpkg updater... \n" . WHITE ;
40+
41+ /* Get the latest tag from the version of the repository checked out by default into the action */
42+ $ this ->latestTag = preg_replace ("/ \n/ " , "" , shell_exec ("git describe --tags `git rev-list --tags --max-count=1` " ));
43+ $ this ->version = preg_replace ('/^v/ ' , '' , $ this ->getTag ());
44+ echo GREEN . "Latest tag: " . $ this ->getTag () . " version: " . $ this ->getVersion () . "\n" . WHITE ;
45+ }
46+
47+ /**
48+ * Get semver version
49+ *
50+ * @return string
51+ */
52+ public function getVersion ()
53+ {
54+ return $ this ->version ;
55+ }
56+
57+ /**
58+ * Get the git tag we are building
59+ *
60+ * @return string
61+ */
62+ public function getTag ()
63+ {
64+ return $ this ->latestTag ;
65+ }
66+
67+ /**
68+ * Check out a repository by tag or branch name to ~/dpp,
69+ * using the personal access token and username passed in as command line parameters.
70+ *
71+ * @param string $tag Tag to clone
72+ * @return bool false if the repository could not be cloned
73+ */
74+ function checkoutRepository (string $ tag = "master " ): bool
75+ {
76+ global $ argv ;
77+
78+ $ repositoryUrl = 'https:// ' . urlencode ($ argv [1 ]) . ': ' . urlencode ($ argv [2 ]) . '@github.com/brainboxdotcc/DPP ' ;
79+
80+ echo GREEN . "Check out repository: $ tag (user: " . $ argv [1 ] . " token: " . $ argv [2 ] . ") \n" . WHITE ;
81+
82+ chdir (getenv ('HOME ' ));
83+ system ('rm -rf ./dpp ' );
84+ system (
'git config --global user.email "[email protected] " ' );
85+ system ('git config --global user.name "DPP VCPKG Bot" ' );
86+ system ('git clone ' . escapeshellarg ($ repositoryUrl ) . ' ./dpp --depth=1 ' );
87+
88+ /* This is noisy, silence it */
89+ $ status = chdir (getenv ("HOME " ) . '/dpp ' );
90+ system ('git fetch -at 2>/dev/null ' );
91+ system ('git checkout ' . escapeshellarg ($ tag ) . ' 2>/dev/null ' );
92+
93+ return $ status ;
94+ }
95+
96+ /**
97+ * Create ./vcpkg/ports/dpp/vcpkg.json and return the portfile contents to
98+ * build the branch that is cloned at ~/dpp
99+ *
100+ * @param string $sha512 The SHA512 sum of the tagged download, or initially
101+ * zero, which means that the vcpkg install command should obtain it the
102+ * second time around.
103+ * @return string The portfile content
104+ */
105+ function constructPortAndVersionFile (string $ sha512 = "0 " ): string
106+ {
107+ echo GREEN . "Construct portfile for " . $ this ->getVersion () . ", sha512: $ sha512 \n" . WHITE ;
108+ chdir (getenv ("HOME " ) . '/dpp ' );
109+
110+ $ portFileContent = 'vcpkg_from_github(
111+ OUT_SOURCE_PATH SOURCE_PATH
112+ REPO brainboxdotcc/DPP
113+ # Auto-generated by release CI action at brainboxdotcc/DPP
114+ REF "v ' . $ this ->getVersion () . '"
115+ SHA512 ' . $ sha512 . '
116+ )
117+
118+ vcpkg_cmake_configure(
119+ SOURCE_PATH "${SOURCE_PATH}"
120+ DISABLE_PARALLEL_CONFIGURE
121+ )
122+
123+ vcpkg_cmake_install()
124+
125+ vcpkg_cmake_config_fixup(NO_PREFIX_CORRECTION)
126+
127+ file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share/dpp")
128+ file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
129+
130+ if(VCPKG_LIBRARY_LINKAGE STREQUAL "static")
131+ file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/bin" "${CURRENT_PACKAGES_DIR}/debug/bin")
132+ endif()
133+
134+ file(
135+ INSTALL "${SOURCE_PATH}/LICENSE"
136+ DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}"
137+ RENAME copyright
138+ )
139+
140+ file(COPY "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
141+ ' ;
142+ // ./vcpkg/ports/dpp/vcpkg.json
143+ $ versionFileContent = '{
144+ "name": "dpp",
145+ "version": ' . json_encode ($ this ->getVersion ()) . ',
146+ "description": "D++ Extremely Lightweight C++ Discord Library.",
147+ "homepage": "https://dpp.dev/",
148+ "license": "Apache-2.0",
149+ "supports": "((windows & !static & !uwp) | linux | osx)",
150+ "dependencies": [
151+ "libsodium",
152+ "nlohmann-json",
153+ "openssl",
154+ "opus",
155+ "zlib",
156+ {
157+ "name": "vcpkg-cmake",
158+ "host": true
159+ },
160+ {
161+ "name": "vcpkg-cmake-config",
162+ "host": true
163+ }
164+ ]
165+ } ' ;
166+ echo GREEN . "Writing portfile... \n" . WHITE ;
167+ file_put_contents ('./vcpkg/ports/dpp/vcpkg.json ' , $ versionFileContent );
168+ return $ portFileContent ;
169+ }
170+
171+ /**
172+ * Attempt the first build of the vcpkg port. This will always fail, as it is given
173+ * an SHA512 sum of 0. When it fails the output contains the SHA512 sum, which is then
174+ * extracted from the error output using a regular expression, and saved for a second
175+ * attempt.
176+ * @param string $portFileContent Portfile content from constructPortAndVersionFile()
177+ * with an SHA512 sum of 0 passed in.
178+ * @return string SHA512 sum of build output
179+ */
180+ function firstBuild (string $ portFileContent ): string
181+ {
182+ echo GREEN . "Starting first build \n" . WHITE ;
183+
184+ chdir (getenv ("HOME " ) . '/dpp ' );
185+ echo GREEN . "Create /usr/local/share/vcpkg/ports/dpp/ \n" . WHITE ;
186+ system ('sudo mkdir -p /usr/local/share/vcpkg/ports/dpp/ ' );
187+ echo GREEN . "Copy vcpkg.json to /usr/local/share/vcpkg/ports/dpp/vcpkg.json \n" . WHITE ;
188+ system ('sudo cp -v -R ./vcpkg/ports/dpp/vcpkg.json /usr/local/share/vcpkg/ports/dpp/vcpkg.json ' );
189+ file_put_contents ('/tmp/portfile ' , $ portFileContent );
190+ system ('sudo cp -v -R /tmp/portfile /usr/local/share/vcpkg/ports/dpp/portfile.cmake ' );
191+ unlink ('/tmp/portfile ' );
192+ $ buildResults = shell_exec ('sudo /usr/local/share/vcpkg/vcpkg install dpp:x64-linux ' );
193+ $ matches = [];
194+ if (preg_match ('/Actual hash:\s+([0-9a-fA-F]+)/ ' , $ buildResults , $ matches )) {
195+ echo GREEN . "Obtained SHA512 for first build: " . $ matches [1 ] . "\n" . WHITE ;
196+ $ this ->firstBuildComplete = true ;
197+ return $ matches [1 ];
198+ }
199+ echo RED . "No SHA512 found during first build :( \n" . WHITE ;
200+ return '' ;
201+ }
202+
203+ /**
204+ * Second build using a valid SHA512 sum. This attempt should succeed, allowing us to push
205+ * the changed vcpkg portfiles into the master branch, where they can be used in a PR to
206+ * microsoft/vcpkg repository later.
207+ *
208+ * @param string $portFileContent the contents of the portfile, containing a valid SHA512
209+ * sum from the first build attempt.
210+ * @return bool False if the build failed
211+ */
212+ function secondBuild (string $ portFileContent ): bool
213+ {
214+
215+ if (!$ this ->firstBuildComplete ) {
216+ throw new RuntimeException ("No SHA512 sum is available, first build has not been run! " );
217+ }
218+
219+ echo GREEN . "Executing second build \n" . WHITE ;
220+ echo GREEN . "Copy local port files to /usr/local/share... \n" . WHITE ;
221+ chdir (getenv ("HOME " ) . '/dpp ' );
222+ file_put_contents ('./vcpkg/ports/dpp/portfile.cmake ' , $ portFileContent );
223+ system ('sudo cp -v -R ./vcpkg/ports/dpp/vcpkg.json /usr/local/share/vcpkg/ports/dpp/vcpkg.json ' );
224+ system ('sudo cp -v -R ./vcpkg/ports/dpp/portfile.cmake /usr/local/share/vcpkg/ports/dpp/portfile.cmake ' );
225+ system ('sudo cp -v -R ./vcpkg/ports/* /usr/local/share/vcpkg/ports/ ' );
226+
227+ echo GREEN . "vcpkg x-add-version... \n" . WHITE ;
228+ chdir ('/usr/local/share/vcpkg ' );
229+ system ('sudo ./vcpkg format-manifest ./ports/dpp/vcpkg.json ' );
230+ /* Note: We commit this in /usr/local, but we never push it (we can't) */
231+ system ('sudo git add . ' );
232+ system ('sudo git commit -m "[bot] VCPKG info update" ' );
233+ system ('sudo /usr/local/share/vcpkg/vcpkg x-add-version dpp ' );
234+
235+ echo GREEN . "Copy back port files from /usr/local/share... \n" . WHITE ;
236+ chdir (getenv ('HOME ' ) . '/dpp ' );
237+ system ('cp -v -R /usr/local/share/vcpkg/ports/dpp/vcpkg.json ./vcpkg/ports/dpp/vcpkg.json ' );
238+ system ('cp -v -R /usr/local/share/vcpkg/versions/baseline.json ./vcpkg/versions/baseline.json ' );
239+ system ('cp -v -R /usr/local/share/vcpkg/versions/d-/dpp.json ./vcpkg/versions/d-/dpp.json ' );
240+
241+ echo GREEN . "Commit and push changes to master branch \n" . WHITE ;
242+ system ('git add . ' );
243+ system ('git commit -m "[bot] VCPKG info update [skip ci]" ' );
244+ system ('git config pull.rebase false ' );
245+ system ('git pull ' );
246+ system ('git push origin master ' );
247+
248+ echo GREEN . "vcpkg install... \n" . WHITE ;
249+ $ resultCode = 0 ;
250+ $ output = [];
251+ exec ('sudo /usr/local/share/vcpkg/vcpkg install dpp:x64-linux ' , $ output , $ resultCode );
252+
253+ if ($ resultCode != 0 ) {
254+ echo RED . "There were build errors! \n\nBuild log: \n" . WHITE ;
255+ readfile ("/usr/local/share/vcpkg/buildtrees/dpp/install-x64-linux-dbg-out.log " );
256+ }
257+
258+ return $ resultCode == 0 ;
259+ }
260+ };
0 commit comments