66
77use StaticPHP \Artifact \ArtifactDownloader ;
88use StaticPHP \Artifact \Downloader \DownloadResult ;
9+ use StaticPHP \Exception \DownloaderException ;
10+ use StaticPHP \Util \FileSystem ;
911
1012/** git */
1113class Git implements DownloadTypeInterface
@@ -15,8 +17,55 @@ public function download(string $name, array $config, ArtifactDownloader $downlo
1517 $ path = DOWNLOAD_PATH . "/ {$ name }" ;
1618 logger ()->debug ("Cloning git repository for {$ name } from {$ config ['url ' ]}" );
1719 $ shallow = !$ downloader ->getOption ('no-shallow-clone ' , false );
18- default_shell ()->executeGitClone ($ config ['url ' ], $ config ['rev ' ], $ path , $ shallow , $ config ['submodules ' ] ?? null );
19- $ version = "dev- {$ config ['rev ' ]}" ;
20- return DownloadResult::git ($ name , $ config , extract: $ config ['extract ' ] ?? null , version: $ version );
20+
21+ // direct branch clone
22+ if (isset ($ config ['rev ' ])) {
23+ default_shell ()->executeGitClone ($ config ['url ' ], $ config ['rev ' ], $ path , $ shallow , $ config ['submodules ' ] ?? null );
24+ $ version = "dev- {$ config ['rev ' ]}" ;
25+ return DownloadResult::git ($ name , $ config , extract: $ config ['extract ' ] ?? null , version: $ version );
26+ }
27+ if (!isset ($ config ['regex ' ])) {
28+ throw new DownloaderException ('Either "rev" or "regex" must be specified for git download type. ' );
29+ }
30+
31+ // regex matches branch first, we need to fetch all refs in emptyfirst
32+ $ gitdir = sys_get_temp_dir () . '/ ' . $ name ;
33+ FileSystem::resetDir ($ gitdir );
34+ $ shell = PHP_OS_FAMILY === 'Windows ' ? cmd (false ) : shell (false );
35+ $ result = $ shell ->cd ($ gitdir )
36+ ->exec (SPC_GIT_EXEC . ' init ' )
37+ ->exec (SPC_GIT_EXEC . ' remote add origin ' . escapeshellarg ($ config ['url ' ]))
38+ ->execWithResult (SPC_GIT_EXEC . ' ls-remote origin ' );
39+ if ($ result [0 ] !== 0 ) {
40+ throw new DownloaderException ("Failed to ls-remote from {$ config ['url ' ]}" );
41+ }
42+ $ refs = $ result [1 ];
43+ $ matched_version_branch = [];
44+ $ matched_count = 0 ;
45+
46+ $ regex = '/^ ' . $ config ['regex ' ] . '$/ ' ;
47+ foreach ($ refs as $ ref ) {
48+ $ matches = null ;
49+ if (preg_match ('/^[0-9a-f]{40}\s+refs\/heads\/(.+)$/ ' , $ ref , $ matches )) {
50+ ++$ matched_count ;
51+ $ branch = $ matches [1 ];
52+ if (preg_match ($ regex , $ branch , $ vermatch ) && isset ($ vermatch ['version ' ])) {
53+ $ matched_version_branch [$ vermatch ['version ' ]] = $ vermatch [0 ];
54+ }
55+ }
56+ }
57+ // sort versions
58+ uksort ($ matched_version_branch , function ($ a , $ b ) {
59+ return version_compare ($ b , $ a );
60+ });
61+ if (!empty ($ matched_version_branch )) {
62+ // use the highest version
63+ $ version = array_key_first ($ matched_version_branch );
64+ $ branch = $ matched_version_branch [$ version ];
65+ logger ()->info ("Matched version {$ version } from branch {$ branch } for {$ name }" );
66+ default_shell ()->executeGitClone ($ config ['url ' ], $ branch , $ path , $ shallow , $ config ['submodules ' ] ?? null );
67+ return DownloadResult::git ($ name , $ config , extract: $ config ['extract ' ] ?? null , version: $ version );
68+ }
69+ throw new DownloaderException ("No matching branch found for regex {$ config ['regex ' ]} (checked {$ matched_count } branches). " );
2170 }
2271}
0 commit comments